diff --git a/.gitignore b/.gitignore index 1a092e8d..b26bb104 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ build/ node_modules/ coverage/ .idea/ +.vscode/ diff --git a/.vscode/i18n-ally-reviews.yml b/.vscode/i18n-ally-reviews.yml new file mode 100644 index 00000000..2db97795 --- /dev/null +++ b/.vscode/i18n-ally-reviews.yml @@ -0,0 +1,5 @@ +# Review comments generated by i18n-ally. Please commit this file. + +reviews: + ui.value.appearance-large: + description: Value large diff --git a/.vscode/settings.json b/.vscode/settings.json index 7a73a41b..d6137325 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,2 +1,50 @@ { + "i18n-ally.localesPaths": [ + "public/locales" + ], + "i18n-ally.keystyle": "flat", + "i18n-ally.sourceLanguage": "en", + "i18n-ally.keysInUse": [ + "feedback.provider.s3-or-compatible-storage", + "feedback.provider.kopia-repository-server", + "feedback.provider.local-directory-or-nas", + "feedback.provider.google-cloud-storage", + "feedback.provider.use-repository-token", + "feedback.provider.azure-blob-storage", + "feedback.provider.rclone-remote", + "feedback.provider.webdav-server", + "feedback.provider.backblaze-b2", + "feedback.provider.sftp-server", + "feedback.task.estimate-results", + "feedback.provider.required-either-known-host-data", + "feedback.provider.required-either-key-file", + "feedback.policy.files.ignore-files-help", + "feedback.policy.scheduling.cron-help", + "feedback.policy.find-count", + "feedback.policy.find-count_one", + "feedback.policy.find-count_other", + "feedback.task.estimated-results", + "feedback.snapshot.show-individual-snapshots-count_other", + "feedback.snapshot.show-individual-snapshots-count_one" + ], + "i18n-ally.extract.ignoredByFiles": { + "src\\components\\policy-editor\\PolicyEditor.jsx": [ + "Do not cross filesystem boundaries when creating a snapshot" + ], + "src\\components\\policy-editor\\UpcomingSnapshotTimes.jsx": [ + "L LT" + ], + "src\\contexts\\UIPreferencesContext.tsx": [ + "(prefers-color-scheme: dark)" + ], + "src\\pages\\Policies.jsx": [ + "policy list" + ] + }, + "i18n-ally.extract.ignored": [ + " (", + " (", + ")", + ")" + ] } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 88cc6a7a..2ae02f5e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,12 +14,18 @@ "@fortawesome/free-solid-svg-icons": "^6.5.1", "@fortawesome/react-fontawesome": "^0.2.0", "bootstrap": "^5.3.1", + "country-flag-icons": "^1.5.9", "http-proxy-middleware": "^2.0.6", + "i18next": "^23.10.1", + "i18next-browser-languagedetector": "^7.2.0", + "i18next-http-backend": "^2.5.0", "moment": "^2.30.1", "react": "^18.2.0", "react-bootstrap": "^2.8.0", "react-dom": "^18.2.0", + "react-i18next": "^14.1.0", "react-router-dom": "^5.3.4", + "react-select": "^5.8.0", "react-table": "^7.8.0" }, "devDependencies": { @@ -57,7 +63,6 @@ "version": "7.22.13", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", - "dev": true, "dependencies": { "@babel/highlight": "^7.22.13", "chalk": "^2.4.2" @@ -70,7 +75,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "dependencies": { "color-convert": "^1.9.0" }, @@ -82,7 +86,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -96,7 +99,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "dependencies": { "color-name": "1.1.3" } @@ -104,14 +106,12 @@ "node_modules/@babel/code-frame/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, "engines": { "node": ">=0.8.0" } @@ -120,7 +120,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, "engines": { "node": ">=4" } @@ -129,7 +128,6 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "dependencies": { "has-flag": "^3.0.0" }, @@ -451,7 +449,6 @@ "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", - "dev": true, "dependencies": { "@babel/types": "^7.16.7" }, @@ -569,7 +566,6 @@ "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -578,7 +574,6 @@ "version": "7.22.20", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -625,7 +620,6 @@ "version": "7.22.20", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", - "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", @@ -639,7 +633,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "dependencies": { "color-convert": "^1.9.0" }, @@ -651,7 +644,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -665,7 +657,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "dependencies": { "color-name": "1.1.3" } @@ -673,14 +664,12 @@ "node_modules/@babel/highlight/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "node_modules/@babel/highlight/node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, "engines": { "node": ">=0.8.0" } @@ -689,7 +678,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, "engines": { "node": ">=4" } @@ -698,7 +686,6 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "dependencies": { "has-flag": "^3.0.0" }, @@ -2096,11 +2083,11 @@ } }, "node_modules/@babel/runtime": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz", - "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz", + "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==", "dependencies": { - "regenerator-runtime": "^0.13.11" + "regenerator-runtime": "^0.14.0" }, "engines": { "node": ">=6.9.0" @@ -2119,6 +2106,11 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/runtime/node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, "node_modules/@babel/template": { "version": "7.22.15", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", @@ -2158,7 +2150,6 @@ "version": "7.23.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.22.5", "@babel/helper-validator-identifier": "^7.22.20", @@ -2411,6 +2402,117 @@ "postcss-selector-parser": "^6.0.10" } }, + "node_modules/@emotion/babel-plugin": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", + "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/serialize": "^1.1.2", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", + "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", + "dependencies": { + "@emotion/memoize": "^0.8.1", + "@emotion/sheet": "^1.2.2", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", + "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + }, + "node_modules/@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + }, + "node_modules/@emotion/react": { + "version": "11.11.4", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.4.tgz", + "integrity": "sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.11.0", + "@emotion/cache": "^11.11.0", + "@emotion/serialize": "^1.1.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.3.tgz", + "integrity": "sha512-iD4D6QVZFDhcbH0RAG1uVu1CwVLMWUkCvAqqlewO/rxf8+87yIBAlt4+AxMiiKPLs5hFc0owNk/sLLAOROw3cA==", + "dependencies": { + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/unitless": "^0.8.1", + "@emotion/utils": "^1.2.1", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", + "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" + }, + "node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", + "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", + "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", + "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" + }, "node_modules/@eslint/eslintrc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", @@ -2476,6 +2578,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@floating-ui/core": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.0.tgz", + "integrity": "sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==", + "dependencies": { + "@floating-ui/utils": "^0.2.1" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.3.tgz", + "integrity": "sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==", + "dependencies": { + "@floating-ui/core": "^1.0.0", + "@floating-ui/utils": "^0.2.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", + "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" + }, "node_modules/@fortawesome/fontawesome-common-types": { "version": "6.5.1", "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.1.tgz", @@ -4657,8 +4781,7 @@ "node_modules/@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, "node_modules/@types/prettier": { "version": "2.7.3", @@ -5774,7 +5897,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", - "dev": true, "dependencies": { "@babel/runtime": "^7.12.5", "cosmiconfig": "^7.0.0", @@ -6086,9 +6208,9 @@ "dev": true }, "node_modules/browserslist": { - "version": "4.20.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.4.tgz", - "integrity": "sha512-ok1d+1WpnU24XYN7oC3QWgTyMhY/avPJ/r9T00xxvUOIparA/gc+UPUMaod3i+G6s+nI2nUb9xZ5k794uIwShw==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", "dev": true, "funding": [ { @@ -6098,14 +6220,17 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "caniuse-lite": "^1.0.30001349", - "electron-to-chromium": "^1.4.147", - "escalade": "^3.1.1", - "node-releases": "^2.0.5", - "picocolors": "^1.0.0" + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" }, "bin": { "browserslist": "cli.js" @@ -6167,7 +6292,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, "engines": { "node": ">=6" } @@ -6216,9 +6340,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001352", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001352.tgz", - "integrity": "sha512-GUgH8w6YergqPQDGWhJGt8GDRnY0L/iJVQcU3eJ46GYf52R8tk0Wxp0PymuFVZboJYXGiCqwozAYZNRjVj6IcA==", + "version": "1.0.30001597", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001597.tgz", + "integrity": "sha512-7LjJvmQU6Sj7bL0j5b5WY/3n7utXUJvAe1lxhsHDbLmwX9mdL86Yjtr+5SRCyf8qME4M7pU2hswj0FpyBVCv9w==", "dev": true, "funding": [ { @@ -6228,6 +6352,10 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ] }, @@ -6657,7 +6785,6 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, "dependencies": { "safe-buffer": "~5.1.1" } @@ -6689,28 +6816,18 @@ } }, "node_modules/core-js-compat": { - "version": "3.23.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.23.1.tgz", - "integrity": "sha512-KeYrEc8t6FJsKYB2qnDwRHWaC0cJNaqlHfCpMe5q3j/W1nje3moib/txNklddLPCtGb+etcBIyJ8zuMa/LN5/A==", + "version": "3.36.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.0.tgz", + "integrity": "sha512-iV9Pd/PsgjNWBXeq8XRtWVSgz2tKAfhfvBs7qxYty+RlRd+OCksaWmOnc4JKrTc1cToXL1N0s3l/vwlxPtdElw==", "dev": true, "dependencies": { - "browserslist": "^4.20.4", - "semver": "7.0.0" + "browserslist": "^4.22.3" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" } }, - "node_modules/core-js-compat/node_modules/semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/core-js-pure": { "version": "3.23.1", "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.23.1.tgz", @@ -6732,7 +6849,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", - "dev": true, "dependencies": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", @@ -6744,6 +6860,19 @@ "node": ">=10" } }, + "node_modules/country-flag-icons": { + "version": "1.5.9", + "resolved": "https://registry.npmjs.org/country-flag-icons/-/country-flag-icons-1.5.9.tgz", + "integrity": "sha512-9jrjv2w7kRbqNtdtMdK2j3gmDIZzd5l9L2pZiQjF9J0mUcB+NKIGDNADTDHBEp8EQtjOkCOcciJGGSOpERdXPQ==" + }, + "node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -7593,9 +7722,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.155", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.155.tgz", - "integrity": "sha512-niPzKBSYPG06gxLKO0c2kEmgdRMTtIbNrBlvD31Ld8Q57b/K0218U4j8u/OOt25XE1eFOn47FcmQVdx9R1qqxA==", + "version": "1.4.708", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.708.tgz", + "integrity": "sha512-iWgEEvREL4GTXXHKohhh33+6Y8XkPI5eHihDmm8zUk5Zo7HICEW+wI/j5kJ2tbuNUCXJ/sNXa03ajW635DiJXA==", "dev": true }, "node_modules/emittery": { @@ -7662,7 +7791,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, "dependencies": { "is-arrayish": "^0.2.1" } @@ -7770,7 +7898,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, "engines": { "node": ">=10" }, @@ -8835,6 +8962,11 @@ "url": "https://github.com/avajs/find-cache-dir?sponsor=1" } }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -8871,9 +9003,9 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.4", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", - "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "funding": [ { "type": "individual", @@ -9074,8 +9206,7 @@ "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "node_modules/function.prototype.name": { "version": "1.1.5", @@ -9327,7 +9458,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "dependencies": { "function-bind": "^1.1.1" }, @@ -9523,6 +9653,14 @@ "node": ">=12" } }, + "node_modules/html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "dependencies": { + "void-elements": "3.1.0" + } + }, "node_modules/html-webpack-plugin": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz", @@ -9665,6 +9803,44 @@ "node": ">=10.17.0" } }, + "node_modules/i18next": { + "version": "23.10.1", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.10.1.tgz", + "integrity": "sha512-NDiIzFbcs3O9PXpfhkjyf7WdqFn5Vq6mhzhtkXzj51aOcNuPNcTwuYNuXCpHsanZGHlHKL35G7huoFeVic1hng==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "dependencies": { + "@babel/runtime": "^7.23.2" + } + }, + "node_modules/i18next-browser-languagedetector": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.2.0.tgz", + "integrity": "sha512-U00DbDtFIYD3wkWsr2aVGfXGAj2TgnELzOX9qv8bT0aJtvPV9CRO77h+vgmHFBMe7LAxdwvT/7VkCWGya6L3tA==", + "dependencies": { + "@babel/runtime": "^7.23.2" + } + }, + "node_modules/i18next-http-backend": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.5.0.tgz", + "integrity": "sha512-Z/aQsGZk1gSxt2/DztXk92DuDD20J+rNudT7ZCdTrNOiK8uQppfvdjq9+DFQfpAnFPn3VZS+KQIr1S/W1KxhpQ==", + "dependencies": { + "cross-fetch": "4.0.0" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -9730,7 +9906,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -9746,7 +9921,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, "engines": { "node": ">=4" } @@ -9844,8 +10018,7 @@ "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, "node_modules/is-bigint": { "version": "1.0.4", @@ -9926,7 +10099,6 @@ "version": "2.9.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", - "dev": true, "dependencies": { "has": "^1.0.3" }, @@ -13264,8 +13436,7 @@ "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "node_modules/json-schema": { "version": "0.4.0", @@ -13407,8 +13578,7 @@ "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "node_modules/loader-runner": { "version": "4.3.0", @@ -13594,6 +13764,11 @@ "node": ">= 4.0.0" } }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -13823,10 +13998,16 @@ } }, "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -13865,6 +14046,44 @@ "tslib": "^2.0.3" } }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -13881,9 +14100,9 @@ "dev": true }, "node_modules/node-releases": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", - "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==", + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", "dev": true }, "node_modules/normalize-path": { @@ -14229,7 +14448,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, "dependencies": { "callsites": "^3.0.0" }, @@ -14241,7 +14459,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -14310,8 +14527,7 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-to-regexp": { "version": "1.8.0", @@ -14325,7 +14541,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, "engines": { "node": ">=8" } @@ -14509,9 +14724,9 @@ } }, "node_modules/postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "version": "8.4.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", + "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", "dev": true, "funding": [ { @@ -14521,10 +14736,14 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -16133,6 +16352,27 @@ "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==", "dev": true }, + "node_modules/react-i18next": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-14.1.0.tgz", + "integrity": "sha512-3KwX6LHpbvGQ+sBEntjV4sYW3Zovjjl3fpoHbUwSgFHf0uRBcbeCBLR5al6ikncI5+W0EFb71QXZmfop+J6NrQ==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "html-parse-stringify": "^3.0.1" + }, + "peerDependencies": { + "i18next": ">= 23.2.3", + "react": ">= 16.8.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -17297,6 +17537,26 @@ "node": ">=10" } }, + "node_modules/react-select": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.8.0.tgz", + "integrity": "sha512-TfjLDo58XrhP6VG5M/Mi56Us0Yt8X7xD6cDybC7yoRMUNm7BGO7qk8J0TLQOua/prb8vUOtsfnXZwfm30HGsAA==", + "dependencies": { + "@babel/runtime": "^7.12.0", + "@emotion/cache": "^11.4.0", + "@emotion/react": "^11.8.1", + "@floating-ui/dom": "^1.0.1", + "@types/react-transition-group": "^4.4.0", + "memoize-one": "^6.0.0", + "prop-types": "^15.6.0", + "react-transition-group": "^4.3.0", + "use-isomorphic-layout-effect": "^1.1.2" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-table": { "version": "7.8.0", "resolved": "https://registry.npmjs.org/react-table/-/react-table-7.8.0.tgz", @@ -17405,7 +17665,8 @@ "node_modules/regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "dev": true }, "node_modules/regenerator-transform": { "version": "0.15.0", @@ -17544,7 +17805,6 @@ "version": "1.22.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, "dependencies": { "is-core-module": "^2.8.1", "path-parse": "^1.0.7", @@ -17756,8 +18016,7 @@ "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "node_modules/safer-buffer": { "version": "2.1.2", @@ -18475,6 +18734,11 @@ "postcss": "^8.2.15" } }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -18504,7 +18768,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -18896,7 +19159,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, "engines": { "node": ">=4" } @@ -19205,6 +19467,36 @@ "yarn": "*" } }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -19224,6 +19516,19 @@ "requires-port": "^1.0.0" } }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", + "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -19305,6 +19610,14 @@ "node": ">= 0.8" } }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", @@ -20201,7 +20514,6 @@ "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, "engines": { "node": ">= 6" } @@ -20271,7 +20583,6 @@ "version": "7.22.13", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", - "dev": true, "requires": { "@babel/highlight": "^7.22.13", "chalk": "^2.4.2" @@ -20281,7 +20592,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -20290,7 +20600,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -20301,7 +20610,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "requires": { "color-name": "1.1.3" } @@ -20309,26 +20617,22 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -20573,7 +20877,6 @@ "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", - "dev": true, "requires": { "@babel/types": "^7.16.7" } @@ -20663,14 +20966,12 @@ "@babel/helper-string-parser": { "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", - "dev": true + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==" }, "@babel/helper-validator-identifier": { "version": "7.22.20", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" }, "@babel/helper-validator-option": { "version": "7.16.7", @@ -20705,7 +21006,6 @@ "version": "7.22.20", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", - "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", @@ -20716,7 +21016,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -20725,7 +21024,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -20736,7 +21034,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "requires": { "color-name": "1.1.3" } @@ -20744,26 +21041,22 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -21696,11 +21989,18 @@ } }, "@babel/runtime": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz", - "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz", + "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==", "requires": { - "regenerator-runtime": "^0.13.11" + "regenerator-runtime": "^0.14.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + } } }, "@babel/runtime-corejs3": { @@ -21746,7 +22046,6 @@ "version": "7.23.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, "requires": { "@babel/helper-string-parser": "^7.22.5", "@babel/helper-validator-identifier": "^7.22.20", @@ -21883,6 +22182,106 @@ "dev": true, "requires": {} }, + "@emotion/babel-plugin": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", + "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", + "requires": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/serialize": "^1.1.2", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" + } + } + }, + "@emotion/cache": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", + "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", + "requires": { + "@emotion/memoize": "^0.8.1", + "@emotion/sheet": "^1.2.2", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "stylis": "4.2.0" + } + }, + "@emotion/hash": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", + "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + }, + "@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + }, + "@emotion/react": { + "version": "11.11.4", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.4.tgz", + "integrity": "sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw==", + "requires": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.11.0", + "@emotion/cache": "^11.11.0", + "@emotion/serialize": "^1.1.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "hoist-non-react-statics": "^3.3.1" + } + }, + "@emotion/serialize": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.3.tgz", + "integrity": "sha512-iD4D6QVZFDhcbH0RAG1uVu1CwVLMWUkCvAqqlewO/rxf8+87yIBAlt4+AxMiiKPLs5hFc0owNk/sLLAOROw3cA==", + "requires": { + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/unitless": "^0.8.1", + "@emotion/utils": "^1.2.1", + "csstype": "^3.0.2" + } + }, + "@emotion/sheet": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", + "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" + }, + "@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + }, + "@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", + "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", + "requires": {} + }, + "@emotion/utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", + "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" + }, + "@emotion/weak-memoize": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", + "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" + }, "@eslint/eslintrc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", @@ -21932,6 +22331,28 @@ } } }, + "@floating-ui/core": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.0.tgz", + "integrity": "sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==", + "requires": { + "@floating-ui/utils": "^0.2.1" + } + }, + "@floating-ui/dom": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.3.tgz", + "integrity": "sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==", + "requires": { + "@floating-ui/core": "^1.0.0", + "@floating-ui/utils": "^0.2.0" + } + }, + "@floating-ui/utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", + "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" + }, "@fortawesome/fontawesome-common-types": { "version": "6.5.1", "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.1.tgz", @@ -23654,8 +24075,7 @@ "@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, "@types/prettier": { "version": "2.7.3", @@ -24513,7 +24933,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", - "dev": true, "requires": { "@babel/runtime": "^7.12.5", "cosmiconfig": "^7.0.0", @@ -24768,16 +25187,15 @@ "dev": true }, "browserslist": { - "version": "4.20.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.4.tgz", - "integrity": "sha512-ok1d+1WpnU24XYN7oC3QWgTyMhY/avPJ/r9T00xxvUOIparA/gc+UPUMaod3i+G6s+nI2nUb9xZ5k794uIwShw==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001349", - "electron-to-chromium": "^1.4.147", - "escalade": "^3.1.1", - "node-releases": "^2.0.5", - "picocolors": "^1.0.0" + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" } }, "bser": { @@ -24820,8 +25238,7 @@ "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" }, "camel-case": { "version": "4.1.2", @@ -24858,9 +25275,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001352", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001352.tgz", - "integrity": "sha512-GUgH8w6YergqPQDGWhJGt8GDRnY0L/iJVQcU3eJ46GYf52R8tk0Wxp0PymuFVZboJYXGiCqwozAYZNRjVj6IcA==", + "version": "1.0.30001597", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001597.tgz", + "integrity": "sha512-7LjJvmQU6Sj7bL0j5b5WY/3n7utXUJvAe1lxhsHDbLmwX9mdL86Yjtr+5SRCyf8qME4M7pU2hswj0FpyBVCv9w==", "dev": true }, "case-sensitive-paths-webpack-plugin": { @@ -25196,7 +25613,6 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, "requires": { "safe-buffer": "~5.1.1" } @@ -25220,21 +25636,12 @@ "dev": true }, "core-js-compat": { - "version": "3.23.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.23.1.tgz", - "integrity": "sha512-KeYrEc8t6FJsKYB2qnDwRHWaC0cJNaqlHfCpMe5q3j/W1nje3moib/txNklddLPCtGb+etcBIyJ8zuMa/LN5/A==", + "version": "3.36.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.0.tgz", + "integrity": "sha512-iV9Pd/PsgjNWBXeq8XRtWVSgz2tKAfhfvBs7qxYty+RlRd+OCksaWmOnc4JKrTc1cToXL1N0s3l/vwlxPtdElw==", "dev": true, "requires": { - "browserslist": "^4.20.4", - "semver": "7.0.0" - }, - "dependencies": { - "semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true - } + "browserslist": "^4.22.3" } }, "core-js-pure": { @@ -25253,7 +25660,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", - "dev": true, "requires": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", @@ -25262,6 +25668,19 @@ "yaml": "^1.10.0" } }, + "country-flag-icons": { + "version": "1.5.9", + "resolved": "https://registry.npmjs.org/country-flag-icons/-/country-flag-icons-1.5.9.tgz", + "integrity": "sha512-9jrjv2w7kRbqNtdtMdK2j3gmDIZzd5l9L2pZiQjF9J0mUcB+NKIGDNADTDHBEp8EQtjOkCOcciJGGSOpERdXPQ==" + }, + "cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "requires": { + "node-fetch": "^2.6.12" + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -25877,9 +26296,9 @@ } }, "electron-to-chromium": { - "version": "1.4.155", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.155.tgz", - "integrity": "sha512-niPzKBSYPG06gxLKO0c2kEmgdRMTtIbNrBlvD31Ld8Q57b/K0218U4j8u/OOt25XE1eFOn47FcmQVdx9R1qqxA==", + "version": "1.4.708", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.708.tgz", + "integrity": "sha512-iWgEEvREL4GTXXHKohhh33+6Y8XkPI5eHihDmm8zUk5Zo7HICEW+wI/j5kJ2tbuNUCXJ/sNXa03ajW635DiJXA==", "dev": true }, "emittery": { @@ -25928,7 +26347,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, "requires": { "is-arrayish": "^0.2.1" } @@ -26020,8 +26438,7 @@ "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" }, "escodegen": { "version": "2.1.0", @@ -26841,6 +27258,11 @@ "pkg-dir": "^4.1.0" } }, + "find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, "find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -26868,9 +27290,9 @@ "dev": true }, "follow-redirects": { - "version": "1.15.4", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", - "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==" + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==" }, "fork-ts-checker-webpack-plugin": { "version": "6.5.2", @@ -26999,8 +27421,7 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "function.prototype.name": { "version": "1.1.5", @@ -27188,7 +27609,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "requires": { "function-bind": "^1.1.1" } @@ -27349,6 +27769,14 @@ "terser": "^5.10.0" } }, + "html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "requires": { + "void-elements": "3.1.0" + } + }, "html-webpack-plugin": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz", @@ -27448,6 +27876,30 @@ "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true }, + "i18next": { + "version": "23.10.1", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.10.1.tgz", + "integrity": "sha512-NDiIzFbcs3O9PXpfhkjyf7WdqFn5Vq6mhzhtkXzj51aOcNuPNcTwuYNuXCpHsanZGHlHKL35G7huoFeVic1hng==", + "requires": { + "@babel/runtime": "^7.23.2" + } + }, + "i18next-browser-languagedetector": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.2.0.tgz", + "integrity": "sha512-U00DbDtFIYD3wkWsr2aVGfXGAj2TgnELzOX9qv8bT0aJtvPV9CRO77h+vgmHFBMe7LAxdwvT/7VkCWGya6L3tA==", + "requires": { + "@babel/runtime": "^7.23.2" + } + }, + "i18next-http-backend": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.5.0.tgz", + "integrity": "sha512-Z/aQsGZk1gSxt2/DztXk92DuDD20J+rNudT7ZCdTrNOiK8uQppfvdjq9+DFQfpAnFPn3VZS+KQIr1S/W1KxhpQ==", + "requires": { + "cross-fetch": "4.0.0" + } + }, "iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -27495,7 +27947,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, "requires": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -27504,8 +27955,7 @@ "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" } } }, @@ -27581,8 +28031,7 @@ "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, "is-bigint": { "version": "1.0.4", @@ -27628,7 +28077,6 @@ "version": "2.9.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", - "dev": true, "requires": { "has": "^1.0.3" } @@ -30335,8 +30783,7 @@ "json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "json-schema": { "version": "0.4.0", @@ -30446,8 +30893,7 @@ "lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "loader-runner": { "version": "4.3.0", @@ -30599,6 +31045,11 @@ "fs-monkey": "1.0.3" } }, + "memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -30767,9 +31218,9 @@ } }, "nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true }, "natural-compare": { @@ -30800,6 +31251,35 @@ "tslib": "^2.0.3" } }, + "node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "requires": { + "whatwg-url": "^5.0.0" + }, + "dependencies": { + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } + }, "node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -30813,9 +31293,9 @@ "dev": true }, "node-releases": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", - "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==", + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", "dev": true }, "normalize-path": { @@ -31062,7 +31542,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, "requires": { "callsites": "^3.0.0" } @@ -31071,7 +31550,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, "requires": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -31122,8 +31600,7 @@ "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "path-to-regexp": { "version": "1.8.0", @@ -31136,8 +31613,7 @@ "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" }, "performance-now": { "version": "2.1.0", @@ -31271,12 +31747,12 @@ } }, "postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "version": "8.4.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", + "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", "dev": true, "requires": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } @@ -32314,6 +32790,15 @@ "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==", "dev": true }, + "react-i18next": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-14.1.0.tgz", + "integrity": "sha512-3KwX6LHpbvGQ+sBEntjV4sYW3Zovjjl3fpoHbUwSgFHf0uRBcbeCBLR5al6ikncI5+W0EFb71QXZmfop+J6NrQ==", + "requires": { + "@babel/runtime": "^7.23.9", + "html-parse-stringify": "^3.0.1" + } + }, "react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -33235,6 +33720,22 @@ } } }, + "react-select": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.8.0.tgz", + "integrity": "sha512-TfjLDo58XrhP6VG5M/Mi56Us0Yt8X7xD6cDybC7yoRMUNm7BGO7qk8J0TLQOua/prb8vUOtsfnXZwfm30HGsAA==", + "requires": { + "@babel/runtime": "^7.12.0", + "@emotion/cache": "^11.4.0", + "@emotion/react": "^11.8.1", + "@floating-ui/dom": "^1.0.1", + "@types/react-transition-group": "^4.4.0", + "memoize-one": "^6.0.0", + "prop-types": "^15.6.0", + "react-transition-group": "^4.3.0", + "use-isomorphic-layout-effect": "^1.1.2" + } + }, "react-table": { "version": "7.8.0", "resolved": "https://registry.npmjs.org/react-table/-/react-table-7.8.0.tgz", @@ -33318,7 +33819,8 @@ "regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "dev": true }, "regenerator-transform": { "version": "0.15.0", @@ -33429,7 +33931,6 @@ "version": "1.22.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, "requires": { "is-core-module": "^2.8.1", "path-parse": "^1.0.7", @@ -33569,8 +34070,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safer-buffer": { "version": "2.1.2", @@ -34127,6 +34627,11 @@ "postcss-selector-parser": "^6.0.4" } }, + "stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -34149,8 +34654,7 @@ "supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" }, "svg-parser": { "version": "2.0.4", @@ -34451,8 +34955,7 @@ "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" }, "to-regex-range": { "version": "5.0.1", @@ -34684,6 +35187,16 @@ "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", "dev": true }, + "update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -34703,6 +35216,12 @@ "requires-port": "^1.0.0" } }, + "use-isomorphic-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", + "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "requires": {} + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -34769,6 +35288,11 @@ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "dev": true }, + "void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==" + }, "w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", @@ -35494,8 +36018,7 @@ "yaml": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" }, "yargs": { "version": "17.7.2", diff --git a/package.json b/package.json index 566012bc..bff92ca3 100644 --- a/package.json +++ b/package.json @@ -8,12 +8,18 @@ "@fortawesome/free-solid-svg-icons": "^6.5.1", "@fortawesome/react-fontawesome": "^0.2.0", "bootstrap": "^5.3.1", + "country-flag-icons": "^1.5.9", "http-proxy-middleware": "^2.0.6", + "i18next": "^23.10.1", + "i18next-browser-languagedetector": "^7.2.0", + "i18next-http-backend": "^2.5.0", "moment": "^2.30.1", "react": "^18.2.0", "react-bootstrap": "^2.8.0", "react-dom": "^18.2.0", + "react-i18next": "^14.1.0", "react-router-dom": "^5.3.4", + "react-select": "^5.8.0", "react-table": "^7.8.0" }, "scripts": { diff --git a/public/locales/de/translation.json b/public/locales/de/translation.json new file mode 100644 index 00000000..ad12dcc2 --- /dev/null +++ b/public/locales/de/translation.json @@ -0,0 +1,479 @@ +{ + "common.action.back": "Zurück", + "common.action.cancel": "Abbrechen", + "common.action.click-here-to-learn-more": "Klick hier um mehr zu erfahren.", + "common.action.confirm-delete": "Löschen bestätigen", + "common.action.delete": "Löschen", + "common.action.next": "Weiter", + "common.action.return": "Zurück", + "common.action.stop": "Stop", + "common.label.loading": "Loading...", + "event.cli.copy-to-clipboard": "In die Zwischenablage kopieren", + "event.cli.show-cli-equivalent": "Klicken Sie, um das CLI-Äquivalent anzuzeigen", + "event.log.hide-log": "Hide log", + "event.log.show-log": "Show log", + "event.pin.add-pin": "Pin hinzufügen", + "event.pin.pin-snapshot": "Snapshot anheften", + "event.pin.remove-pin": "Pin entfernen", + "event.pin.update-pin": "Pin aktualisieren", + "event.policy.delete": "Richtlinie löschen", + "event.policy.edit": "Bearbeiten", + "event.policy.save": "Richtlinie speichern", + "event.policy.set-policy": "Richtlinie festlegen", + "event.repository.cancel-connection": "Cancel connection", + "event.repository.connect-to-repository": "Mit Repository verbinden", + "event.repository.create-repository": "Repository erstellen", + "event.repository.disconnect-from-repository": "Repository trennen", + "event.repository.hide-advanced-options": "Erweiterte Optionen ausblenden", + "event.repository.show-advanced-options": "Erweiterte Optionen anzeigen", + "event.repository.update-description": "Update description", + "event.snapshot.browse-directory": "Durchsuchen", + "event.snapshot.delete-selected": "event.snapshot.delete-selected", + "event.snapshot.delete-selected_one": "Möchten Sie den ausgewählten {{count}} Snapshot löschen?", + "event.snapshot.delete-selected_other": "Möchten Sie die ausgewählten {{count}} Snapshots löschen?", + "event.snapshot.description.enter-new-description": "Geben Sie eine neue Beschreibung ein", + "event.snapshot.description.remove-description": "Beschreibung entfernen", + "event.snapshot.description.update-description": "Beschreibung aktualisieren", + "event.snapshot.estimate": "Schätzung", + "event.snapshot.fetch-snapshots": "Schnappschüsse abrufen", + "event.snapshot.history.delete-selected": "Ausgewählte löschen ({{count}})", + "event.snapshot.history.delete-snapshot-source": "Snapshot-Quelle löschen", + "event.snapshot.history.deselect-all": "Alle abwählen", + "event.snapshot.history.select-all-snapshots": "Alle auswählen", + "event.snapshot.history.update-snapshot-description": "{{description}} – Klicken Sie hier, um die Snapshot-Beschreibung zu aktualisieren.", + "event.snapshot.mount-directory": "Als lokales Dateisystem mounten", + "event.snapshot.new-snapshot": "Neuer Snapshot", + "event.snapshot.restore-file-directories": "Dateien und Verzeichnisse wiederherstellen", + "event.snapshot.restore.begin-restore": "Begin restore", + "event.snapshot.restore.go-to-restore-task": "Gehen Sie zur Wiederherstellungsaufgabe", + "event.snapshot.show-policy": "Richtlinie", + "event.snapshot.snapshot-now": "Snapshot erstellen", + "event.snapshot.synchronize": "Synchronisieren", + "event.snapshot.unmount-directory": "Aushängen", + "event.task.action.cancel": "Aufgabe abbrechen", + "event.task.select.task-all": "Alle", + "event.task.select.task-failed": "Fehlgeschlagen", + "event.task.select.task-running": "Running", + "feedback.directory.header.directories": "Verzeichnisse", + "feedback.directory.header.files": "Dateien", + "feedback.directory.header.last-modification": "Letzte Änderung", + "feedback.directory.header.name": "Name", + "feedback.directory.header.size": "Größe", + "feedback.error.common": "Fehler", + "feedback.error.connection": "Verbindungsfehler:", + "feedback.header.effective": "Angewandt", + "feedback.header.username": "Nutzername", + "feedback.pin.add-pin-to-protect": "Fügen Sie eine PIN hinzu, um den Snapshot vor dem Löschen zu schützen", + "feedback.pin.do-not-delete": "Nicht löschen", + "feedback.pin.name-of-the-pin": "Name des Pins", + "feedback.policy.action.command-mode": "Befehlsmodus", + "feedback.policy.actions.after-folder": "Nach dem Ordner", + "feedback.policy.actions.after-folder-help": "Skript zur Ausführung nach dem Ordner", + "feedback.policy.actions.after-snapshot": "Nach dem Schnappschuss", + "feedback.policy.actions.after-snapshot-help": "Skript, das nach dem Snapshot ausgeführt wird", + "feedback.policy.actions.before-folder": "Vor dem Ordner", + "feedback.policy.actions.before-folder-help": "Skript, das vor dem Ordner ausgeführt werden soll", + "feedback.policy.actions.before-snapshot": "Vor dem Schnappschuss", + "feedback.policy.actions.before-snapshot-help": "Skript, das vor dem Snapshot ausgeführt werden soll", + "feedback.policy.actions.timeout": "Auszeit", + "feedback.policy.command-mode-help": "Wesentlich (muss erfolgreich sein; Standardverhalten), optional (Fehler werden toleriert) oder asynchron (Kopia startet die Aktion, wartet aber nicht auf deren Abschluss)", + "feedback.policy.compression.compression-algorithm": "Komprimierungsalgorithmus", + "feedback.policy.compression.compression-algorithm-help": "Geben Sie den Komprimierungsalgorithmus an, der beim Erstellen von Snapshots von Dateien in diesem Verzeichnis und Unterverzeichnissen verwendet werden soll", + "feedback.policy.compression.maximal-file-size": "Maximale Dateigröße", + "feedback.policy.compression.maximal-file-size-help": "Dateien, deren Größe den angegebenen Wert überschreitet, werden nicht komprimiert", + "feedback.policy.compression.maximal-file-size-hint": "Maximale Dateigröße in Bytes", + "feedback.policy.compression.minimal-file-size": "Mindestdateigröße", + "feedback.policy.compression.minimal-file-size-help": "Dateien, die kleiner als der angegebene Wert sind, werden nicht komprimiert", + "feedback.policy.compression.minimal-file-size-hint": "Mindestdateigröße in Bytes", + "feedback.policy.compression.never-compress-extensions": "Keine Komprimierung von Datei-Erweiterungen", + "feedback.policy.compression.never-compress-extensions-help": "Die folgenden Dateierweiterungen, werden nicht kompromiert (eine Erweiterung pro Zeile)", + "feedback.policy.compression.never-compress-extensions-hint": "z.B. *.mp4", + "feedback.policy.compression.only-compress-extensions": "Komprimieren Sie nur Erweiterungen", + "feedback.policy.compression.only-compress-extensions-help": "Komprimieren Sie nur Dateien mit den folgenden Dateierweiterungen (eine Erweiterung pro Zeile)", + "feedback.policy.compression.only-compress-extensions-hint": "z.B. *.txt", + "feedback.policy.confirm-delete-policy": "Sind Sie sicher, dass Sie diese Richtlinie löschen möchten?", + "feedback.policy.defined-by": "Definiert durch", + "feedback.policy.defined-by-this-policy": "Definiert durch diese Richtlinie", + "feedback.policy.error-delete-policy": "Fehler beim Löschen der Richtlinie", + "feedback.policy.error-handling.ignore-directory-errors": "Verzeichnisfehler ignorieren", + "feedback.policy.error-handling.ignore-directory-errors-help": "Verzeichnislesefehler werden als nicht schwerwiegend behandelt.", + "feedback.policy.error-handling.ignore-file-errors": "Dateifehler ignorieren", + "feedback.policy.error-handling.ignore-file-errors-help": "Dateilesefehler werden als nicht schwerwiegend behandelt.", + "feedback.policy.error-handling.ignore-unknown-directories": "Unbekannte Verzeichniseinträge ignorieren", + "feedback.policy.error-handling.ignore-unknown-directories-help": "Nicht erkannte/nicht unterstützte Verzeichniseinträge werden als nicht schwerwiegende Fehler behandelt.", + "feedback.policy.error-saving-policy": "Fehler beim Speichern der Richtlinie", + "feedback.policy.files.ignore-files": "Dateien ignorieren", + "feedback.policy.files.ignore-files-help": "Liste der zu ignorierenden Datei- und Verzeichnisnamen.
Siehe Dokumentation zum Ignorieren von Dateien.", + "feedback.policy.files.ignore-files-hint": "z.B. /file.txt", + "feedback.policy.files.ignore-rule-files": "Regeldateien ignorieren", + "feedback.policy.files.ignore-rule-files-from-parent-directories": "Regeldateien aus übergeordneten Verzeichnissen ignorieren", + "feedback.policy.files.ignore-rule-files-from-parent-directories-help": "Wenn diese Option festgelegt ist, werden die Dateien, die Ignorierungsregeln angeben (.kopiaignore usw.), aus dem übergeordneten Verzeichnis ignoriert", + "feedback.policy.files.ignore-rule-files-help": "Liste zusätzlicher Dateien mit Ignorierregeln (jede Datei konfiguriert Ignorierungsregeln für das Verzeichnis und seine Unterverzeichnisse)", + "feedback.policy.files.ignore-rule-files-hint": "z.B. .kopiaignore", + "feedback.policy.files.ignore-rules-from-parent-directories": "Regeln aus übergeordneten Verzeichnissen ignorieren", + "feedback.policy.files.ignore-rules-from-parent-directories-help": "Wenn diese Option festgelegt ist, werden Ignorierregeln aus dem übergeordneten Verzeichnis ignoriert", + "feedback.policy.files.ignore-well-known-cache-directories": "Bekannte Cache-Verzeichnisse ignorieren", + "feedback.policy.files.ignore-well-known-cache-directories-help": "Ignorieren Sie Verzeichnisse, die CACHEDIR.TAG und ähnliches enthalten", + "feedback.policy.files.scan-only-one-filesystem": "Scannen Sie nur ein Dateisystem", + "feedback.policy.files.scan-only-one-filesystem-help": "Überschreiten Sie beim Erstellen eines Snapshots keine Dateisystemgrenzen", + "feedback.policy.find-count": "feedback.policy.find-count", + "feedback.policy.find-count_one": "Es wurde {{count}} Richtlinie gefunden, die den Kriterien entspricht", + "feedback.policy.find-count_other": "Es wurden {{count}} Richtlinien gefunden, die den Kriterien entsprechen", + "feedback.policy.find-hint": "Geben Sie das Verzeichnis ein, um die Richtlinie zu finden oder festzulegen", + "feedback.policy.find-none": "Keine Richtlinien gefunden", + "feedback.policy.find-none-create": "Für das Verzeichnis {{path}} wurde keine Richtlinie gefunden. \nBitte richten Sie eine neue Richtlinie ein.", + "feedback.policy.header.actions": "Aktionen", + "feedback.policy.header.compression": "Kompression", + "feedback.policy.header.defined": "Definiert", + "feedback.policy.header.error-handling": "Fehlerbehandlung", + "feedback.policy.header.files": "Dateien", + "feedback.policy.header.folder-actions": "Ordneraktionen", + "feedback.policy.header.host": "Host", + "feedback.policy.header.logging": "Protokollierung", + "feedback.policy.header.other": "Andere", + "feedback.policy.header.path": "Pfad", + "feedback.policy.header.scheduling": "Terminplanung", + "feedback.policy.header.snapshot-action": "Snapshot-Aktionen", + "feedback.policy.header.snapshot-retention": "Snapshot-Aufbewahrung", + "feedback.policy.header.upload": "Hochladen", + "feedback.policy.kind.all": "Alle Richtlinien", + "feedback.policy.kind.applicable": "Anwendbare Richtlinien", + "feedback.policy.kind.global": "Globale Richtlinien", + "feedback.policy.kind.local": "Lokale Richtlinien", + "feedback.policy.kind.per-host-policies": "Richtlinien pro Host", + "feedback.policy.kind.per-user-policies": "Richtlinien pro Benutzer", + "feedback.policy.logging.cache-hit": "Cache-Treffer", + "feedback.policy.logging.cache-hit-help": "Protokollieren Sie die Ausführlichkeit, wenn ein Cache verwendet wird, anstatt die Datei hochzuladen", + "feedback.policy.logging.cache-miss": "Cache-Fehler", + "feedback.policy.logging.cache-miss-help": "Protokollausführlichkeit, wenn ein Cache nicht verwendet werden kann und eine Datei gehasht werden muss", + "feedback.policy.logging.directory-ignored": "Verzeichnis ignoriert", + "feedback.policy.logging.directory-ignored-help": "Protokollieren Sie die Ausführlichkeit, wenn ein Verzeichnis ignoriert wird", + "feedback.policy.logging.directory-snapshotted": "Verzeichnis-Snapshot erstellt", + "feedback.policy.logging.directory-snapshotted-help": "Protokollieren Sie die Ausführlichkeit, wenn ein Verzeichnis-Snapshot erstellt wird", + "feedback.policy.logging.file-ignored": "Datei ignoriert", + "feedback.policy.logging.file-ignored-help": "Protokollieren Sie die Ausführlichkeit, wenn eine Datei, ein symbolischer Link usw. ignoriert wird", + "feedback.policy.logging.file-snapshotted": "Datei-Snapshot erstellt", + "feedback.policy.logging.file-snapshotted-help": "Protokollieren Sie die Ausführlichkeit, wenn eine Datei, ein symbolischer Link usw. als Snapshot erstellt wird", + "feedback.policy.other.disable-parent-policy-evaluation": "Deaktivieren Sie die Evaluierung der übergeordneten Richtlinien", + "feedback.policy.other.disable-parent-policy-evaluation-help": "Verhindert, dass sich übergeordnete Richtlinien auf dieses Verzeichnis und seine Unterverzeichnisse auswirken", + "feedback.policy.other.json-representation": "JSON-Darstellung", + "feedback.policy.other.json-representation-help": "Dies ist die interne Darstellung einer Richtlinie", + "feedback.policy.policies-defined-by-path-absolute": "Richtlinien können nur für absolute Pfade definiert werden.", + "feedback.policy.retention.annual-snapshot-retain": "Jährlich", + "feedback.policy.retention.annual-snapshot-retain-help": "Wie viele jährliche Snapshots pro Quelle aufbewahrt werden sollen. \nDer neueste Snapshot jedes Kalenderjahres wird aufbewahrt", + "feedback.policy.retention.annual-snapshot-retain-hint": "Anzahl der jährlichen Schnappschüsse", + "feedback.policy.retention.daily-snapshot-retain": "Täglich", + "feedback.policy.retention.daily-snapshot-retain-help": "Gibt an, wie viele tägliche Snapshots pro Quelle aufbewahrt werden sollen. \nDer neueste Schnappschuss jedes Tages wird beibehalten", + "feedback.policy.retention.daily-snapshot-retain-hint": "Anzahl der täglichen Snapshots", + "feedback.policy.retention.hourly-snapshot-retain": "Stündlich", + "feedback.policy.retention.hourly-snapshot-retain-help": "Gibt an, wie viele stündliche Snapshots pro Quelle aufbewahrt werden sollen. \nDer neueste Snapshot jeder Stunde wird beibehalten", + "feedback.policy.retention.hourly-snapshot-retain-hint": "Anzahl der stündlichen Snapshots", + "feedback.policy.retention.ignore-identical-snapshots": "Ignorieren Sie identische Snapshots", + "feedback.policy.retention.ignore-identical-snapshots-help": "Speichern Sie KEINEN Snapshot, wenn keine Dateien geändert wurden", + "feedback.policy.retention.keep-latest-help": "Anzahl der neuesten Schnappschüsse", + "feedback.policy.retention.latest-snapshot-retain": "Neueste Schnappschüsse", + "feedback.policy.retention.latest-snapshot-retain-help": "Anzahl der aktuellsten Snapshots, die pro Quelle aufbewahrt werden sollen", + "feedback.policy.retention.monthly-snapshot-retain": "Monatlich", + "feedback.policy.retention.monthly-snapshot-retain-help": "Wie viele monatliche Snapshots pro Quelle aufbewahrt werden sollen. \nDer neueste Snapshot jedes Kalendermonats bleibt erhalten", + "feedback.policy.retention.monthly-snapshot-retain-hint": "Anzahl der monatlichen Snapshots", + "feedback.policy.retention.weekly-snapshot-retain": "Wöchentlich", + "feedback.policy.retention.weekly-snapshot-retain-help": "Gibt an, wie viele wöchentliche Snapshots pro Quelle aufbewahrt werden sollen. \nDer neueste Schnappschuss jeder Woche wird beibehalten", + "feedback.policy.retention.weekly-snapshot-retain-hint": "Anzahl der wöchentlichen Snapshots", + "feedback.policy.scheduling.cron-expressions": "Cron-Ausdrücke", + "feedback.policy.scheduling.cron-expressions-hint": "Minute Stunde Tag Monat Wochentag #Kommentar", + "feedback.policy.scheduling.cron-help": "Snapshot-Zeitpläne mit UNIX-Crontab-Syntax (einer pro Zeile):
Siehe Details zum unterstützten Format.", + "feedback.policy.scheduling.manual-snapshots-only": "Nur manuelle Snapshots", + "feedback.policy.scheduling.manual-snapshots-only-help": "Schnappschüsse nur manuell erstellen (geplante Schnappschüsse werden deaktiviert)", + "feedback.policy.scheduling.missed-snapshots-startup": "Führen Sie beim Start verpasste Snapshots aus", + "feedback.policy.scheduling.missed-snapshots-startup-help": "Führen Sie alle verpassten Snapshots sofort aus, wenn Kopia startet (nur relevant für Time-of-Day-Snapshots).", + "feedback.policy.scheduling.no-upcoming-snapshots": "Keine bevorstehenden Schnappschüsse", + "feedback.policy.scheduling.snapshot-frequency": "Häufigkeit der Snapshots", + "feedback.policy.scheduling.snapshot-frequency-help": "Gibt an, wie oft Snapshots in KopiaUI oder Kopia-Server erstellt werden sollen (hat außerhalb des Servermodus keine Auswirkung)", + "feedback.policy.scheduling.times-of-day": "Tageszeiten", + "feedback.policy.scheduling.times-of-day-help": "Schnappschüsse zu den angegebenen Tageszeiten erstellen (24-Stunden-Format)", + "feedback.policy.scheduling.times-of-day-hint": "z.B. 17:00", + "feedback.policy.scheduling.upcoming": "Bevorstehend", + "feedback.policy.scheduling.upcoming-snapshots": "Kommende Schnappschüsse", + "feedback.policy.scheduling.upcoming-snapshots-help": "Zeiten bevorstehender Snapshots, berechnet auf Grundlage von Richtlinienparametern", + "feedback.policy.time-of-day.invalid": "Ungültige Tageszeit: {{tod}}", + "feedback.policy.timeout-help": "Timeout in Sekunden, bevor Kopia den Prozess abbricht", + "feedback.policy.upload.maximum-parallel-file-reads": "Maximale parallele Dateilesevorgänge", + "feedback.policy.upload.maximum-parallel-file-reads-help": "Maximale Anzahl von Dateien, die parallel gelesen werden (standardmäßig die Anzahl der logischen Prozessoren)", + "feedback.policy.upload.maximum-parallel-file-reads-hint": "Maximale Anzahl paralleler Dateilesevorgänge", + "feedback.policy.upload.maximum-parallel-snapshots": "Maximale parallele Snapshots", + "feedback.policy.upload.maximum-parallel-snapshots-help": "Maximale Anzahl von Snapshots, die gleichzeitig hochgeladen werden können", + "feedback.policy.upload.maximum-parallel-snapshots-hint-set": "Maximale Anzahl paralleler Snapshots", + "feedback.policy.upload.maximum-parallel-snapshots-hint-unset": "muss mithilfe einer globalen, Benutzer- oder Hostrichtlinie angegeben werden", + "feedback.prodiver.gcs.paste-json-credentials": "Fügen Sie hier JSON-Anmeldeinformationen ein", + "feedback.provider.azure-blob-storage": "Azure Blob Storage", + "feedback.provider.azure.access-key": "Zugangsschlüssel", + "feedback.provider.azure.azure-storage-domain": "Azure Storage-Domäne", + "feedback.provider.azure.container": "Container", + "feedback.provider.azure.enter-access-key": "Geben Sie den geheimen Zugangsschlüssel ein", + "feedback.provider.azure.enter-azure-storage-domain": "Geben Sie die Speicherdomäne ein oder lassen Sie sie leer, um die Standardeinstellung „blob.core.windows.net“ zu verwenden.", + "feedback.provider.azure.enter-container-name": "Geben Sie den Containernamen ein", + "feedback.provider.azure.enter-object-name-prefix": "Geben Sie das Präfix für den Objektnamen ein oder lassen Sie es leer", + "feedback.provider.azure.enter-sas-token": "Geben Sie den geheimen SAS-Token ein", + "feedback.provider.azure.enter-storage-account": "Geben Sie den Namen des Speicherkontos ein", + "feedback.provider.azure.object-name-prefix": "Präfix des Objektnamens", + "feedback.provider.azure.sas-token": "SAS-Token", + "feedback.provider.azure.storage-account": "Speicherkonto", + "feedback.provider.b2.bucket-name": "B2-Bucket", + "feedback.provider.b2.enter-account-key": "Geben Sie den geheimen Anwendungs- oder Kontoschlüssel ein", + "feedback.provider.b2.enter-account-key-id": "Geben Sie die Anwendungs- oder Kontoschlüssel-ID ein", + "feedback.provider.b2.enter-bucket-name": "Geben Sie den Bucket-Namen ein", + "feedback.provider.b2.enter-object-name-prefix": "Geben Sie das Präfix für den Objektnamen ein oder lassen Sie es leer", + "feedback.provider.b2.key": "Schlüssel", + "feedback.provider.b2.key-id": "Schlüssel-ID", + "feedback.provider.b2.object-name-prefix": "Präfix des Objektnamens", + "feedback.provider.backblaze-b2": "Backblaze B2", + "feedback.provider.filesystem.directory-path": "Verzeichnispfad", + "feedback.provider.filesystem.enter-directory-path": "Geben Sie den Verzeichnispfad ein, in dem Sie die Repository-Dateien speichern möchten", + "feedback.provider.gcs.bucket-name": "GCS-Bucket", + "feedback.provider.gcs.credentials-file": "Anmeldeinformationsdatei", + "feedback.provider.gcs.credentials-json": "Anmeldeinformationen JSON", + "feedback.provider.gcs.enter-bucket-name": "Geben Sie den Bucket-Namen ein", + "feedback.provider.gcs.enter-credentials-file-name": "Geben Sie den Namen der JSON-Datei mit den Anmeldeinformationen ein", + "feedback.provider.gcs.enter-object-name-prefix": "Geben Sie das Präfix für den Objektnamen ein oder lassen Sie es leer", + "feedback.provider.gcs.object-name-prefix": "Präfix des Objektnamens", + "feedback.provider.google-cloud-storage": "Google Cloud-Speicher", + "feedback.provider.kopia-repository-server": "Kopia-Repository-Server", + "feedback.provider.local-directory-or-nas": "Lokales Verzeichnis oder NAS", + "feedback.provider.rclone-remote": "Rclone Remote", + "feedback.provider.rclone.rclone-executable-path": "Rclone Pfad", + "feedback.provider.rclone.rclone-executable-path-hint": "Geben Sie den Pfad zur ausführbaren rclone-Datei ein", + "feedback.provider.rclone.rclone-remote-path": "Rclone-Remote-Pfad", + "feedback.provider.rclone.rclone-remote-path-hint": "Geben Sie : ein", + "feedback.provider.repositoryserver.enter-server-certificate-fingerprint": "Geben Sie den Fingerabdruck des vertrauenswürdigen Serverzertifikats ein, der beim Serverstart gedruckt wird", + "feedback.provider.repositoryserver.enter-server-url": "Geben Sie die Server-URL ein (https://:port)", + "feedback.provider.repositoryserver.server-address": "Serveradresse", + "feedback.provider.repositoryserver.server-certificate-fingerprint": "Fingerabdruck des vertrauenswürdigen Serverzertifikats (SHA256)", + "feedback.provider.repositorytoken.paste-token": "Verbindungstoken einfügen", + "feedback.provider.repositorytoken.token": "Token", + "feedback.provider.required-either-key-file": "Es ist entweder Passwort, Schlüsseldatei oder Schlüsseldaten erforderlich.", + "feedback.provider.required-either-known-host-data": "Es sind entweder Known Hosts File oder Known Hosts Data erforderlich, aber nicht beides.", + "feedback.provider.s3-or-compatible-storage": "Amazon S3 oder kompatibler Speicher", + "feedback.provider.s3.access-key-id": "Zugriffsschlüssel-ID", + "feedback.provider.s3.access-key-id-hint": "Geben Sie die Zugriffsschlüssel-ID ein", + "feedback.provider.s3.bucket-name": "Bucket", + "feedback.provider.s3.bucket-name-hint": "Geben Sie den Bucket-Namen ein", + "feedback.provider.s3.enter-object-name-prefix-hint": "Geben Sie das Präfix für den Objektnamen ein oder lassen Sie es leer", + "feedback.provider.s3.object-name-prefix": "Präfix des Objektnamens", + "feedback.provider.s3.override-region": "Region überschreiben", + "feedback.provider.s3.override-region-hint": "Geben Sie eine bestimmte Region ein (z. B. us-west-1) oder lassen Sie das Feld leer", + "feedback.provider.s3.secret-access-key": "Geheimer Zugangsschlüssel", + "feedback.provider.s3.secret-access-key-hint": "Geben Sie den geheimen Zugangsschlüssel ein", + "feedback.provider.s3.server-endpoint": "Serverendpunkt", + "feedback.provider.s3.server-endpoint-hint": "Geben Sie die Serveradresse ein (z. B. s3.amazonaws.com)", + "feedback.provider.s3.session-token": "Sitzungstoken", + "feedback.provider.s3.session-token-hint": "Geben Sie das Sitzungstoken ein oder lassen Sie es leer", + "feedback.provider.sftp-key-data": "Schlüsseldaten", + "feedback.provider.sftp-key-data-hint": "Fügen Sie den Inhalt der Schlüsseldatei ein", + "feedback.provider.sftp-server": "SFTP-Server", + "feedback.provider.sftp.enter-password": "Passwort eingeben", + "feedback.provider.sftp.enter-path-host-file": "Geben Sie den Pfad zur Datei „known_hosts“ ein", + "feedback.provider.sftp.enter-path-to-key-file": "Geben Sie den Pfad zur Schlüsseldatei ein", + "feedback.provider.sftp.enter-remote-path": "Geben Sie den Remote-Pfad zum Repository ein, z. B. „/mnt/data/repository“.", + "feedback.provider.sftp.enter-ssh-arguments": "Geben Sie SSH-Befehlsargumente ein ('user@host -s sftp' wird automatisch angehängt)", + "feedback.provider.sftp.enter-ssh-host-name": "SSH-Hostname (z. B. example.com)", + "feedback.provider.sftp.host": "Host", + "feedback.provider.sftp.known-host-data": "Daten bekannter Hosts", + "feedback.provider.sftp.launch-external-ssh-command": "Starten Sie einen externen SSH-Befehl ohne Passwort", + "feedback.provider.sftp.launch-external-ssh-command-hint": "Standardmäßig stellt Kopia über einen internen SSH-Client eine Verbindung zum Server her, der begrenzte Optionen unterstützt. \nAlternativ kann ein externer SSH-Befehl ohne Passwort gestartet werden, der zusätzliche Optionen unterstützt, aber im Allgemeinen weniger effizient ist als der integrierte Client.", + "feedback.provider.sftp.password": "Passwort", + "feedback.provider.sftp.paste-content-of-known-host": "Fügen Sie den Inhalt der Datei „known_hosts“ ein", + "feedback.provider.sftp.path": "Pfad", + "feedback.provider.sftp.path-host-file": "Pfad zur Datei „known_hosts“.", + "feedback.provider.sftp.path-key-file": "Pfad zur Schlüsseldatei", + "feedback.provider.sftp.port": "Port", + "feedback.provider.sftp.port-number": "Portnummer (z. B. 22)", + "feedback.provider.sftp.provide-passwordless-ssh-command": "Geben Sie den auszuführenden passwortlosen SSH-Befehl an (normalerweise „ssh“).", + "feedback.provider.sftp.ssh-arguments": "SSH-Argumente", + "feedback.provider.sftp.ssh-command": "SSH-Befehl", + "feedback.provider.sftp.user": "Benutzer", + "feedback.provider.sftp.user-name": "Nutzername", + "feedback.provider.use-repository-token": "Repository-Token", + "feedback.provider.webdav-server": "WebDAV-Server", + "feedback.provider.webdav.enter-password": "Passwort eingeben", + "feedback.provider.webdav.enter-username": "Geben Sie den Benutzernamen ein", + "feedback.provider.webdav.password": "Passwort", + "feedback.provider.webdav.server-url": "WebDAV-Server-URL", + "feedback.provider.webdav.username": "Nutzername", + "feedback.repository.additional-parameters-hint": "Beim Erstellen des Repositorys über die Befehlszeile können zusätzliche Parameter festgelegt werden.", + "feedback.repository.attribute.algorithm-eco": "Fehlerkorrekturalgorithmus", + "feedback.repository.attribute.algorithm-encryption": "Verschlüsselungsalgorithmus", + "feedback.repository.attribute.algorithm-hash": "Hash-Algorithmus", + "feedback.repository.attribute.algorithm-splitter": "Splitter-Algorithmus", + "feedback.repository.attribute.config-file": "Konfigurationsdatei", + "feedback.repository.attribute.connected-as": "Verbunden als", + "feedback.repository.attribute.internal-compression": "Interne Kompression", + "feedback.repository.attribute.repository-eco": "Aufwand für die Fehlerkorrektur", + "feedback.repository.attribute.repository-format": "Repository-Format", + "feedback.repository.attribute.repository-provider": "Anbieter", + "feedback.repository.attribute.server-url": "Server URL", + "feedback.repository.configuration": "Speicherkonfiguration", + "feedback.repository.connect-as": "Verbinden als", + "feedback.repository.connect-in-read-only-mode": "Stellen Sie eine Verbindung im schreibgeschützten Modus her", + "feedback.repository.connect-in-read-only-mode-hint": "Der schreibgeschützte Modus verhindert jegliche Änderungen am Repository.", + "feedback.repository.connect-to-repository": "Mit Repository verbinden", + "feedback.repository.create-repository-new": "Neues Repository erstellen", + "feedback.repository.create-repository-new-help": "Geben Sie ein sicheres Passwort ein, um das Kopia-Repository im bereitgestellten Speicher zu erstellen.", + "feedback.repository.eco-disabled": "Disabled", + "feedback.repository.eec-warning": "[EXPERIMENTELL] Eine Fehlerkorrektur kann zum Schutz vor bestimmten Arten von Datenbeschädigungen aufgrund spontaner Bitwechsel im Speichermedium beitragen.", + "feedback.repository.encryption": "Verschlüsselung", + "feedback.repository.enter-repository-password": "Geben Sie das Repository-Passwort ein", + "feedback.repository.hostname": "Hostname", + "feedback.repository.hostname-hint": "Überschreiben Sie dies, wenn Sie einen Snapshot wiederherstellen, der auf einem anderen Computer erstellt wurde", + "feedback.repository.internal-compression-supported-no": "nein", + "feedback.repository.internal-compression-supported-yes": "ja", + "feedback.repository.kopia-server-parameters": "Kopia-Serverparameter", + "feedback.repository.name-default": "Mein Repository", + "feedback.repository.override-hint": "Klicken Sie zum Überschreiben auf „Erweiterte Optionen anzeigen“.", + "feedback.repository.provider-selection": "Wählen Sie ein Repository aus", + "feedback.repository.provider-selection-hint": "Wählen Sie ein Repository aus, um ein neues zu erstellen oder eine Verbindung zu einem bestehenden Repository herzustellen:", + "feedback.repository.repository-description": "Beschreibung des Repository", + "feedback.repository.repository-description-help": "Hilft bei der Unterscheidung zwischen mehreren verbundenen Repositorys", + "feedback.repository.repository-description-hint": "Geben Sie eine Repository-Beschreibung ein", + "feedback.repository.repository-description-required": "Repository description is required", + "feedback.repository.repository-initializing": "Initializing repository...", + "feedback.repository.repository-is-read-only": "Repository is read-only", + "feedback.repository.repository-password": "Repository-Passwort", + "feedback.repository.repository-password-confirm": "Bestätigen Sie das Repository-Passwort", + "feedback.repository.repository-password-confirm-again": "Geben Sie das Repository-Passwort erneut ein", + "feedback.repository.repository-password-help": "Wird zum Verschlüsseln des Repository-Inhalts verwendet", + "feedback.repository.repository-token-enter": "Geben Sie das Repository-Token ein", + "feedback.repository.server-password": "Server-Passwort", + "feedback.repository.server-password-hint": "Geben Sie das Passwort ein, um eine Verbindung zum Server herzustellen", + "feedback.repository.status-connected": "Mit Repository verbunden", + "feedback.repository.username": "Nutzername", + "feedback.repository.username-hint": "Überschreiben Sie dies, wenn Sie einen Snapshot wiederherstellen, der von einem anderen Benutzer erstellt wurde", + "feedback.snapshot.create.enter-path-to-snapshot-hint": "Pfad des Schnapshots eingeben", + "feedback.snapshot.create.must-specify-path": "Pfad zur Erstellung des Snapshot muss angegeben werden.", + "feedback.snapshot.create.snapshot-new": "Neuer Snapshot", + "feedback.snapshot.description": "Beschreibung", + "feedback.snapshot.description.snapshot-description": "Beschreibung des Snapshots", + "feedback.snapshot.directory.browsing-not-supported": "Das Durchsuchen von Verzeichnissen wird in einem Webbrowser nicht unterstützt. \nVerwenden Sie die Kopia-Benutzeroberfläche.", + "feedback.snapshot.directory.restore-all-files-help": "Sie können alle unten angezeigten Dateien und Verzeichnisse mounten/wiederherstellen oder Dateien einzeln wiederherstellen.", + "feedback.snapshot.header.actions": "Aktionen", + "feedback.snapshot.header.details": "Details", + "feedback.snapshot.header.directories": "Ordner", + "feedback.snapshot.header.files": "Dateien", + "feedback.snapshot.header.last-snapshot": "Letzter Snapshot", + "feedback.snapshot.header.next-snapshot": "Nächster Snapshot", + "feedback.snapshot.header.retention": "Beibehaltung", + "feedback.snapshot.header.root": "Wurzelverzeichnis", + "feedback.snapshot.header.selected": "Ausgewählt", + "feedback.snapshot.header.snapshot-owner": "Eigentümer", + "feedback.snapshot.header.snapshot-path": "Pfad", + "feedback.snapshot.header.snapshot-size": "Größe", + "feedback.snapshot.header.start-time": "Startzeit", + "feedback.snapshot.header.status": "Status", + "feedback.snapshot.history.snapshot-displaying": "Anzeigen", + "feedback.snapshot.history.wipe-all-snapshots": "Löschen Sie alle Snapshots und die Richtlinie für diese Quelle.", + "feedback.snapshot.restore.continue-on-errors": "Continue on errors", + "feedback.snapshot.restore.continue-on-errors-help": "When a restore error occurs, attempt to continue instead of failing fast.", + "feedback.snapshot.restore.destination": "Destination", + "feedback.snapshot.restore.destination-help": "You can also restore to a .zip or .tar file by providing the appropriate extension.", + "feedback.snapshot.restore.destination-hint": "Enter destination path", + "feedback.snapshot.restore.disable-zip-compression": "Disable ZIP compression", + "feedback.snapshot.restore.disable-zip-compression-help": "Do not compress when restoring to a ZIP file (faster).", + "feedback.snapshot.restore.minimal-file-size-for-shallow-restore": "Minimal file size for shallow restore", + "feedback.snapshot.restore.overwrite-directory": "Overwrite directories", + "feedback.snapshot.restore.overwrite-files": "Overwrite files", + "feedback.snapshot.restore.overwrite-symbolic-links": "Overwrite symbolic links", + "feedback.snapshot.restore.restore-file-modification-time": "Restore file modification time", + "feedback.snapshot.restore.restore-file-ownership": "Restore file ownership", + "feedback.snapshot.restore.restore-file-permissions": "Restore file permissions", + "feedback.snapshot.restore.shallow-restore-at-depth": "Shallow restore at depth", + "feedback.snapshot.restore.skip-previously-restored-files": "Skip previously restored files and symlinks", + "feedback.snapshot.restore.snapshot-restore": "Restore", + "feedback.snapshot.restore.write-files-atomically": "Write files atomically", + "feedback.snapshot.restore.write-sparse-files": "Write sparse files", + "feedback.snapshot.show-individual-snapshots-count": "feedback.snapshot.show-individual-snapshots-count", + "feedback.snapshot.show-individual-snapshots-count_one": "{{count}} einzelnen Schnappschuss anzeigen", + "feedback.snapshot.show-individual-snapshots-count_other": "{{count}} einzelne Schnappschüsse anzeigen", + "feedback.snapshot.start-after-previous-snapshot": "Der Snapshot startet, sobald der vorherige abgeschlossen ist", + "feedback.snapshot.status.status-overdue": "überfällig", + "feedback.snapshot.status.status-pending": "Wartend", + "feedback.tab.policies": "Richtlinien", + "feedback.tab.preferences": "Einstellungen", + "feedback.tab.repository": "Repository", + "feedback.tab.repository-is-not-connected": "Das Repository ist nicht verbunden", + "feedback.tab.snapshots": "Snapshots", + "feedback.tab.tasks": "Aufgaben", + "feedback.task.estimated-results": "{{description}} Bytes: {{bytes}} ({{bytes.excluded}} exkludiert) Files: {{files}} ({{files.excluded}} exkludiert) Directories: {{directories}} ({{directories.excluded}} exkludiert) Errors: {{errors}} ({{errors.ignored}} ignoriert)", + "feedback.task.header.counter": "Counter", + "feedback.task.header.value": "Value", + "feedback.task.logs": "Protokoll", + "feedback.task.no-tasks-help": "Hier erscheint eine Liste von Aufgaben, sobald Snapshots, Wartungsaufgaben oder Wiederherstellungen durchgeführt werden.", + "feedback.task.search-tasks-by-hint": "Durchsuchen Sie Aufgabenprotokolle nach Beschreibung", + "feedback.task.status.task-canceled": "Aufgabe abgebrochen", + "feedback.task.status.task-canceled-after": "Aufgabe abgebrochen nach", + "feedback.task.status.task-canceling": "Canceling", + "feedback.task.status.task-error": "Task error", + "feedback.task.status.task-failed-after": "Fehlgeschlagen nach", + "feedback.task.status.task-finished": "Abgeschlossen", + "feedback.task.status.task-finished-in": "Abgeschlossen in", + "feedback.task.status.task-running-for": "Task running for", + "feedback.task.status.task-started": "Gestartet", + "feedback.task.status.task-succeeded-after": "Task succeeded after", + "feedback.task.table.header-description": "Beschreibung", + "feedback.task.table.header-kind": "Art", + "feedback.task.table.header-start-time": "Startzeit", + "feedback.task.table.header-status": "Status", + "feedback.task.tasks-total": "Gesamt", + "feedback.ui.appearance": "Darstellung", + "feedback.ui.appearance-help": "Gibt die Darstellung des Nutzerinterfaces an", + "feedback.ui.appearance-hint": "Select font size", + "feedback.ui.byte-representation-description": "Darstellung der Speichergrößen", + "feedback.ui.byte-representation-help": "Gibt die aktuelle Darstellung von Speichergrößen an", + "feedback.ui.byte-representation-select": "Darstellung der Speichgröße auswählen", + "feedback.ui.pagesize-description": "Anzahl an Einträgen", + "feedback.ui.pagesize-help": "Gibt die Anzahl der Einträge in Listen an", + "feedback.ui.pagesize-hint": "Anzahl Einträge", + "feedback.ui.theme-description": "Design", + "feedback.ui.theme-help": "Das aktuell ausgewählte Design", + "feedback.ui.theme-select": "Select theme", + "feedback.validation.invalid-times-of-day": "Ungültige Tageszeiten", + "feedback.validation.optional.valid-number-or-empty": "Muss eine gültige Zahl sein oder leer sein", + "feedback.validation.passwords-dont-match": "Passwörter stimmen nicht überein", + "feedback.validation.required.directory": "Pflichtfeld", + "feedback.validation.required.field": "Pflichtfeld", + "feedback.validation.required.valid-number-or-empty": "Muss eine gültige Zahl oder leer sein", + "value.algorithm.eco-disabled": "Deaktiviert", + "value.algorithm.suffix-not-recommended": "(NICHT EMPFOHLEN)", + "value.algorithm.suffix-recommended": "(EMPFOHLEN)", + "value.log.details-0-no-output": "0 - keine Ausgabe", + "value.log.details-1-minimal-details": "1 – minimale Details", + "value.log.details-10-maximum-details": "10 - maximale Details", + "value.log.details-5-normal-details": "5 - normale Details", + "value.log.details-inherit-from-parent": "(vom übergeordneten Element erben)", + "value.policy.async": "Asynchron ausführen, Fehler ignorieren", + "value.policy.essential": "Muss gelingen", + "value.policy.inherent-from-parent": "Vom Elternteil erben", + "value.policy.none": "keine Angabe", + "value.policy.optional": "Fehler ignorieren", + "value.provider.s3.http-connection-insecure": "HTTP-Verbindung verwenden (unsicher)", + "value.provider.s3.no-tls-verification": "TLS-Zertifikat nicht überprüfen", + "value.repository.latest-format": "Neuestes Format", + "value.repository.legacy-format": "Legacy-Format kompatibel mit v0.8", + "value.snapshot-frequency.10-minutes": "alle 10 Minuten", + "value.snapshot-frequency.12-hours": "alle 12 Stunden", + "value.snapshot-frequency.15-minutes": "alle 15 Minuten", + "value.snapshot-frequency.20-minutes": "alle 20 Minuten", + "value.snapshot-frequency.3-hours": "alle 3 Stunden", + "value.snapshot-frequency.30-minutes": "alle 30 Minuten", + "value.snapshot-frequency.6-hours": "alle 6 Stunden", + "value.snapshot-frequency.hour": "jede Stunde", + "value.ui.appearance-large": "groß", + "value.ui.appearance-medium": "mittel", + "value.ui.appearance-small": "klein", + "value.ui.byte-representation-base10": "Basis-10 (KB, MB, GB, TB)", + "value.ui.byte-representation-base2": "Basis-2 (KiB, MiB, GiB, TiB)", + "value.ui.theme-dark": "dunkel", + "value.ui.theme-light": "hell", + "value.ui.theme-ocean": "ozeanisch", + "value.ui.theme-pastel": "pastelfarbend", + "value.validation.optional-no": "nein", + "value.validation.optional-yes": "Ja" +} diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json new file mode 100644 index 00000000..b54d423f --- /dev/null +++ b/public/locales/en/translation.json @@ -0,0 +1,479 @@ +{ + "common.action.back": "Back", + "common.action.cancel": "Cancel", + "common.action.click-here-to-learn-more": "Click here to learn more.", + "common.action.confirm-delete": "Confirm Delete", + "common.action.delete": "Delete", + "common.action.next": "Next", + "common.action.return": "Return", + "common.action.stop": "Stop", + "common.label.loading": "Loading...", + "event.cli.copy-to-clipboard": "Copy to clipboard", + "event.cli.show-cli-equivalent": "Click to show CLI equivalent", + "event.log.hide-log": "Hide log", + "event.log.show-log": "Show log", + "event.pin.add-pin": "Add Pin", + "event.pin.pin-snapshot": "Pin Snapshot", + "event.pin.remove-pin": "Remove Pin", + "event.pin.update-pin": "Update Pin", + "event.policy.delete": "Delete policy", + "event.policy.edit": "Edit", + "event.policy.save": "Save policy", + "event.policy.set-policy": "Set policy", + "event.repository.cancel-connection": "Cancel connection", + "event.repository.connect-to-repository": "Connect to repository", + "event.repository.create-repository": "Create repository", + "event.repository.disconnect-from-repository": "Disconnect from repository", + "event.repository.hide-advanced-options": "Hide advanced options", + "event.repository.show-advanced-options": "Show Advanced Options", + "event.repository.update-description": "Update description", + "event.snapshot.browse-directory": "Browse", + "event.snapshot.delete-selected": "event.snapshot.delete-selected", + "event.snapshot.delete-selected_one": "Do you want to delete the selected {{count}} snapshot?", + "event.snapshot.delete-selected_other": "Do you want to delete the selected {{count}} snapshots?", + "event.snapshot.description.enter-new-description": "Enter new description", + "event.snapshot.description.remove-description": "Remove Description", + "event.snapshot.description.update-description": "Update Description", + "event.snapshot.estimate": "Estimate", + "event.snapshot.fetch-snapshots": "Fetch snapshots", + "event.snapshot.history.delete-selected": "Delete Selected ({{count}})", + "event.snapshot.history.delete-snapshot-source": "Delete Snapshot Source", + "event.snapshot.history.deselect-all": "Deselect All", + "event.snapshot.history.select-all-snapshots": "Select All", + "event.snapshot.history.update-snapshot-description": "{{description}} - Click to update snapshot description.", + "event.snapshot.mount-directory": "Mount as Local Filesystem", + "event.snapshot.new-snapshot": "New Snapshot", + "event.snapshot.restore-file-directories": "Restore files and directories\n", + "event.snapshot.restore.begin-restore": "Begin restore", + "event.snapshot.restore.go-to-restore-task": "Go To Restore Task", + "event.snapshot.show-policy": "Policy", + "event.snapshot.snapshot-now": "Snapshot now", + "event.snapshot.synchronize": "Synchronize", + "event.snapshot.unmount-directory": "Unmount", + "event.task.action.cancel": "Cancel task", + "event.task.select.task-all": "All", + "event.task.select.task-failed": "Failed", + "event.task.select.task-running": "Running", + "feedback.directory.header.directories": "Directories", + "feedback.directory.header.files": "Files", + "feedback.directory.header.last-modification": "Last Modification", + "feedback.directory.header.name": "Name", + "feedback.directory.header.size": "Size", + "feedback.error.common": "Error", + "feedback.error.connection": "Connect Error:", + "feedback.header.effective": "Effective", + "feedback.header.username": "Username", + "feedback.pin.add-pin-to-protect": "Add a pin to protect snapshot from deletion", + "feedback.pin.do-not-delete": "do-not-delete", + "feedback.pin.name-of-the-pin": "Name of the pin", + "feedback.policy.action.command-mode": "Command Mode", + "feedback.policy.actions.after-folder": "After Folder", + "feedback.policy.actions.after-folder-help": "Script to run after folder", + "feedback.policy.actions.after-snapshot": "After Snapshot", + "feedback.policy.actions.after-snapshot-help": "Script to run after snapshot", + "feedback.policy.actions.before-folder": "Before Folder", + "feedback.policy.actions.before-folder-help": "Script to run before folder", + "feedback.policy.actions.before-snapshot": "Before Snapshot", + "feedback.policy.actions.before-snapshot-help": "Script to run before snapshot", + "feedback.policy.actions.timeout": "Timeout", + "feedback.policy.command-mode-help": "Essential (must succeed; default behavior), optional (failures are tolerated), or async (Kopia will start the action but not wait for it to finish)", + "feedback.policy.compression.compression-algorithm": "Compression Algorithm", + "feedback.policy.compression.compression-algorithm-help": "Specify compression algorithm to use when snapshotting files in this directory and subdirectories", + "feedback.policy.compression.maximal-file-size": "Maximum file size", + "feedback.policy.compression.maximal-file-size-help": "Files whose size exceeds the provided value will not be compressed", + "feedback.policy.compression.maximal-file-size-hint": "Maximum file size in bytes", + "feedback.policy.compression.minimal-file-size": "Minimum File Size", + "feedback.policy.compression.minimal-file-size-help": "Files that are smaller than the provided value will not be compressed", + "feedback.policy.compression.minimal-file-size-hint": "minimum file size in bytes", + "feedback.policy.compression.never-compress-extensions": "Never compress extensions", + "feedback.policy.compression.never-compress-extensions-help": "Never compress the following file extensions (one extension per line)", + "feedback.policy.compression.never-compress-extensions-hint": "e.g. *.mp4", + "feedback.policy.compression.only-compress-extensions": "Only compress extensions", + "feedback.policy.compression.only-compress-extensions-help": "Only compress files with the following file extensions (one extension per line)", + "feedback.policy.compression.only-compress-extensions-hint": "e.g. *.txt", + "feedback.policy.confirm-delete-policy": "Are you sure you want to delete this policy?", + "feedback.policy.defined-by": "Defined by", + "feedback.policy.defined-by-this-policy": "Defined by this policy", + "feedback.policy.error-delete-policy": "Error deleting policy", + "feedback.policy.error-handling.ignore-directory-errors": "Ignore Directory Errors", + "feedback.policy.error-handling.ignore-directory-errors-help": "Treat directory read errors as non-fatal.", + "feedback.policy.error-handling.ignore-file-errors": "Ignore File Errors", + "feedback.policy.error-handling.ignore-file-errors-help": "Treat file read errors as non-fatal.", + "feedback.policy.error-handling.ignore-unknown-directories": "Ignore Unknown Directory Entries", + "feedback.policy.error-handling.ignore-unknown-directories-help": "Treat unrecognized/unsupported directory entries as non-fatal errors.", + "feedback.policy.error-saving-policy": "Error saving policy", + "feedback.policy.files.ignore-files": "Ignore Files", + "feedback.policy.files.ignore-files-help": "List of file and directory names to ignore.
See documentation on ignoring files.", + "feedback.policy.files.ignore-files-hint": "e.g. /file.txt", + "feedback.policy.files.ignore-rule-files": "Ignore Rule Files", + "feedback.policy.files.ignore-rule-files-from-parent-directories": "Ignore Rule Files From Parent Directories", + "feedback.policy.files.ignore-rule-files-from-parent-directories-help": "When set, the files specifying ignore rules (.kopiaignore, etc.) from the parent directory are ignored", + "feedback.policy.files.ignore-rule-files-help": "List of additional files containing ignore rules (each file configures ignore rules for the directory and its subdirectories)", + "feedback.policy.files.ignore-rule-files-hint": "e.g. .kopiaignore", + "feedback.policy.files.ignore-rules-from-parent-directories": "Ignore Rules From Parent Directories", + "feedback.policy.files.ignore-rules-from-parent-directories-help": "When set, ignore rules from the parent directory are ignored", + "feedback.policy.files.ignore-well-known-cache-directories": "Ignore Well-Known Cache Directories", + "feedback.policy.files.ignore-well-known-cache-directories-help": "Ignore directories containing CACHEDIR.TAG and similar", + "feedback.policy.files.scan-only-one-filesystem": "Scan only one filesystem", + "feedback.policy.files.scan-only-one-filesystem-help": "Do not cross filesystem boundaries when creating a snapshot", + "feedback.policy.find-count": "feedback.policy.find-count", + "feedback.policy.find-count_one": "Found {{count}} policy matching the criteria", + "feedback.policy.find-count_other": "Found {{count}} policies matching the criteria", + "feedback.policy.find-hint": "Enter directory to find or set policy", + "feedback.policy.find-none": "No policies found", + "feedback.policy.find-none-create": " No policy found for directory {{path}}. Please setup a new policy.", + "feedback.policy.header.actions": "Actions", + "feedback.policy.header.compression": "Compression", + "feedback.policy.header.defined": "Defined", + "feedback.policy.header.error-handling": "Error Handling", + "feedback.policy.header.files": "Files", + "feedback.policy.header.folder-actions": "Folder Actions", + "feedback.policy.header.host": "Host", + "feedback.policy.header.logging": "Logging", + "feedback.policy.header.other": "Other", + "feedback.policy.header.path": "Path", + "feedback.policy.header.scheduling": "Scheduling", + "feedback.policy.header.snapshot-action": "Snapshot Actions", + "feedback.policy.header.snapshot-retention": "Snapshot Retention", + "feedback.policy.header.upload": "Upload", + "feedback.policy.kind.all": "All policies", + "feedback.policy.kind.applicable": "Applicable policies", + "feedback.policy.kind.global": "Global policies", + "feedback.policy.kind.local": "Local policies", + "feedback.policy.kind.per-host-policies": "Per-Host policies", + "feedback.policy.kind.per-user-policies": "Per-User policies", + "feedback.policy.logging.cache-hit": "Cache hit", + "feedback.policy.logging.cache-hit-help": "Log verbosity when a cache is used instead of uploading the file", + "feedback.policy.logging.cache-miss": "Cache miss", + "feedback.policy.logging.cache-miss-help": "Log verbosity when a cache cannot be used and a file must be hashed", + "feedback.policy.logging.directory-ignored": "Directory ignored", + "feedback.policy.logging.directory-ignored-help": "Log verbosity when a directory is ignored", + "feedback.policy.logging.directory-snapshotted": "Directory snapshotted", + "feedback.policy.logging.directory-snapshotted-help": "Log verbosity when a directory is snapshotted", + "feedback.policy.logging.file-ignored": "File ignored", + "feedback.policy.logging.file-ignored-help": "Log verbosity when a file, symbolic link, etc. is ignored", + "feedback.policy.logging.file-snapshotted": "File snapshotted", + "feedback.policy.logging.file-snapshotted-help": "Log verbosity when a file, symbolic link, etc. is snapshotted", + "feedback.policy.other.disable-parent-policy-evaluation": "Disable Parent Policy Evaluation", + "feedback.policy.other.disable-parent-policy-evaluation-help": "Prevents any parent policies from affecting this directory and its subdirectories", + "feedback.policy.other.json-representation": "JSON Representation", + "feedback.policy.other.json-representation-help": "This is the internal representation of a policy", + "feedback.policy.policies-defined-by-path-absolute": "Policies can only be defined for absolute paths.", + "feedback.policy.retention.annual-snapshot-retain": "Annual", + "feedback.policy.retention.annual-snapshot-retain-help": "How many annual snapshots to retain per source. The latest snapshot from each calendar year will be retained", + "feedback.policy.retention.annual-snapshot-retain-hint": "Number of annual snapshots", + "feedback.policy.retention.daily-snapshot-retain": "Daily", + "feedback.policy.retention.daily-snapshot-retain-help": "How many daily snapshots to retain per source. The latest snapshot from each day will be retained", + "feedback.policy.retention.daily-snapshot-retain-hint": "Number of daily snapshots", + "feedback.policy.retention.hourly-snapshot-retain": "Hourly", + "feedback.policy.retention.hourly-snapshot-retain-help": "How many hourly snapshots to retain per source. The latest snapshot from each hour will be retained", + "feedback.policy.retention.hourly-snapshot-retain-hint": "number of hourly snapshots", + "feedback.policy.retention.ignore-identical-snapshots": "Ignore Identical Snapshots", + "feedback.policy.retention.ignore-identical-snapshots-help": "Do NOT save a snapshot when no files have been changed", + "feedback.policy.retention.keep-latest-help": "number of latest snapshots", + "feedback.policy.retention.latest-snapshot-retain": "Latest Snapshots", + "feedback.policy.retention.latest-snapshot-retain-help": "Number of the most recent snapshots to retain per source", + "feedback.policy.retention.monthly-snapshot-retain": "Monthly", + "feedback.policy.retention.monthly-snapshot-retain-help": "How many monthly snapshots to retain per source. The latest snapshot from each calendar month will be retained", + "feedback.policy.retention.monthly-snapshot-retain-hint": "Number of monthly snapshots", + "feedback.policy.retention.weekly-snapshot-retain": "Weekly", + "feedback.policy.retention.weekly-snapshot-retain-help": "How many weekly snapshots to retain per source. The latest snapshot from each week will be retained", + "feedback.policy.retention.weekly-snapshot-retain-hint": "Number of weekly snapshots", + "feedback.policy.scheduling.cron-expressions": "Cron Expressions", + "feedback.policy.scheduling.cron-expressions-hint": "minute hour day month weekday #comment", + "feedback.policy.scheduling.cron-help": "Snapshot schedules using UNIX crontab syntax (one per line):
See supported format details.", + "feedback.policy.scheduling.manual-snapshots-only": "Manual Snapshots Only", + "feedback.policy.scheduling.manual-snapshots-only-help": "Only create snapshots manually (disables scheduled snapshots)", + "feedback.policy.scheduling.missed-snapshots-startup": "Run Missed Snapshots on Startup", + "feedback.policy.scheduling.missed-snapshots-startup-help": "Immediately run any missed snapshots when kopia starts (only relevant for Time-of-day snapshots)", + "feedback.policy.scheduling.no-upcoming-snapshots": "No upcoming snapshots", + "feedback.policy.scheduling.snapshot-frequency": "Snapshot Frequency", + "feedback.policy.scheduling.snapshot-frequency-help": "How frequently to create snapshots in KopiaUI or Kopia server (has no effect outside of the server mode)", + "feedback.policy.scheduling.times-of-day": "Times Of Day", + "feedback.policy.scheduling.times-of-day-help": "Create snapshots at the specified times of day (24hr format)", + "feedback.policy.scheduling.times-of-day-hint": "e.g. 17:00", + "feedback.policy.scheduling.upcoming": "Upcoming", + "feedback.policy.scheduling.upcoming-snapshots": "Upcoming Snapshots", + "feedback.policy.scheduling.upcoming-snapshots-help": "Times of upcoming snapshots calculated based on policy parameters", + "feedback.policy.time-of-day.invalid": "Invalid time of day: {{tod}}", + "feedback.policy.timeout-help": "Timeout in seconds before Kopia kills the process", + "feedback.policy.upload.maximum-parallel-file-reads": "Maximum Parallel File Reads", + "feedback.policy.upload.maximum-parallel-file-reads-help": "Maximum number of files that will be read in parallel (defaults to the number of logical processors)", + "feedback.policy.upload.maximum-parallel-file-reads-hint": "max number of parallel file reads", + "feedback.policy.upload.maximum-parallel-snapshots": "Maximum Parallel Snapshots", + "feedback.policy.upload.maximum-parallel-snapshots-help": "Maximum number of snapshots that can be uploaded simultaneously", + "feedback.policy.upload.maximum-parallel-snapshots-hint-set": "max number of parallel snapshots", + "feedback.policy.upload.maximum-parallel-snapshots-hint-unset": "must be specified using global, user, or host policy", + "feedback.prodiver.gcs.paste-json-credentials": "Paste JSON credentials here", + "feedback.provider.azure-blob-storage": "Azure Blob Storage", + "feedback.provider.azure.access-key": "Access Key", + "feedback.provider.azure.azure-storage-domain": "Azure Storage Domain", + "feedback.provider.azure.container": "Container", + "feedback.provider.azure.enter-access-key": "Enter secret access key", + "feedback.provider.azure.enter-azure-storage-domain": "Enter storage domain or leave empty for default 'blob.core.windows.net'", + "feedback.provider.azure.enter-container-name": "Enter container name", + "feedback.provider.azure.enter-object-name-prefix": "Enter object name prefix or leave empty", + "feedback.provider.azure.enter-sas-token": "Enter secret SAS Token", + "feedback.provider.azure.enter-storage-account": "Enter storage account name", + "feedback.provider.azure.object-name-prefix": "Object Name Prefix", + "feedback.provider.azure.sas-token": "SAS Token", + "feedback.provider.azure.storage-account": "Storage Account", + "feedback.provider.b2.bucket-name": "B2 Bucket", + "feedback.provider.b2.enter-account-key": "Enter secret application or account key", + "feedback.provider.b2.enter-account-key-id": "Enter application or account key ID", + "feedback.provider.b2.enter-bucket-name": "Enter bucket name", + "feedback.provider.b2.enter-object-name-prefix": "Enter object name prefix or leave empty", + "feedback.provider.b2.key": "Key", + "feedback.provider.b2.key-id": "Key ID", + "feedback.provider.b2.object-name-prefix": "Object Name Prefix", + "feedback.provider.backblaze-b2": "Backblaze B2", + "feedback.provider.filesystem.directory-path": "Directory Path", + "feedback.provider.filesystem.enter-directory-path": "Enter directory path where you want to store repository files", + "feedback.provider.gcs.bucket-name": "GCS Bucket", + "feedback.provider.gcs.credentials-file": "Credentials File", + "feedback.provider.gcs.credentials-json": "Credentials JSON", + "feedback.provider.gcs.enter-bucket-name": "Enter bucket name", + "feedback.provider.gcs.enter-credentials-file-name": "Enter name of credentials JSON file", + "feedback.provider.gcs.enter-object-name-prefix": "Enter object name prefix or leave empty", + "feedback.provider.gcs.object-name-prefix": "Object Name Prefix", + "feedback.provider.google-cloud-storage": "Google Cloud Storage", + "feedback.provider.kopia-repository-server": "Kopia Repository Server", + "feedback.provider.local-directory-or-nas": "Local Directory or NAS", + "feedback.provider.rclone-remote": "Rclone Remote", + "feedback.provider.rclone.rclone-executable-path": "Rclone Executable Path", + "feedback.provider.rclone.rclone-executable-path-hint": "Enter path to rclone executable", + "feedback.provider.rclone.rclone-remote-path": "Rclone Remote Path", + "feedback.provider.rclone.rclone-remote-path-hint": "Enter :", + "feedback.provider.repositoryserver.enter-server-certificate-fingerprint": "Enter trusted server certificate fingerprint printed at server startup", + "feedback.provider.repositoryserver.enter-server-url": "Enter server URL (https://:port)", + "feedback.provider.repositoryserver.server-address": "Server address", + "feedback.provider.repositoryserver.server-certificate-fingerprint": "Trusted server certificate fingerprint (SHA256)", + "feedback.provider.repositorytoken.paste-token": "Paste connection token", + "feedback.provider.repositorytoken.token": "Token", + "feedback.provider.required-either-key-file": "One of Password, Key File or Key Data is required.", + "feedback.provider.required-either-known-host-data": "Either Known Hosts File or Known Hosts Data is required, but not both.", + "feedback.provider.s3-or-compatible-storage": "Amazon S3 or Compatible Storage", + "feedback.provider.s3.access-key-id": "Access Key ID", + "feedback.provider.s3.access-key-id-hint": "Enter access key ID", + "feedback.provider.s3.bucket-name": "Bucket", + "feedback.provider.s3.bucket-name-hint": "Enter bucket name", + "feedback.provider.s3.enter-object-name-prefix-hint": "Enter object name prefix or leave empty", + "feedback.provider.s3.object-name-prefix": "Object Name Prefix", + "feedback.provider.s3.override-region": "Override Region", + "feedback.provider.s3.override-region-hint": "Enter specific region (e.g., us-west-1) or leave empty", + "feedback.provider.s3.secret-access-key": "Secret Access Key", + "feedback.provider.s3.secret-access-key-hint": "Enter secret access key", + "feedback.provider.s3.server-endpoint": "Server Endpoint", + "feedback.provider.s3.server-endpoint-hint": "Enter server address (e.g., s3.amazonaws.com)", + "feedback.provider.s3.session-token": "Session Token", + "feedback.provider.s3.session-token-hint": "Enter session token or leave empty", + "feedback.provider.sftp-key-data": "Key data", + "feedback.provider.sftp-key-data-hint": "Paste contents of the key file", + "feedback.provider.sftp-server": "SFTP Server", + "feedback.provider.sftp.enter-password": "Enter password", + "feedback.provider.sftp.enter-path-host-file": "Enter path to the known_hosts file", + "feedback.provider.sftp.enter-path-to-key-file": "Enter path to the key file", + "feedback.provider.sftp.enter-remote-path": "Enter remote path to repository, e.g., '/mnt/data/repository'", + "feedback.provider.sftp.enter-ssh-arguments": "Enter SSH command arguments ('user@host -s sftp' will be appended automatically)", + "feedback.provider.sftp.enter-ssh-host-name": "ssh host name (e.g., example.com)", + "feedback.provider.sftp.host": "Host", + "feedback.provider.sftp.known-host-data": "Known Hosts Data", + "feedback.provider.sftp.launch-external-ssh-command": "Launch external password-less SSH command", + "feedback.provider.sftp.launch-external-ssh-command-hint": "By default Kopia connects to the server using internal SSH client which supports limited options. Alternatively it may launch external password-less SSH command, which supports additional options, but is generally less efficient than the built-in client.", + "feedback.provider.sftp.password": "Password", + "feedback.provider.sftp.paste-content-of-known-host": "Paste the contents of the known_hosts file", + "feedback.provider.sftp.path": "Path", + "feedback.provider.sftp.path-host-file": "Path to known_hosts file", + "feedback.provider.sftp.path-key-file": "Path to key file", + "feedback.provider.sftp.port": "Port", + "feedback.provider.sftp.port-number": "Port number (e.g., 22)", + "feedback.provider.sftp.provide-passwordless-ssh-command": "Provide the passwordless SSH command to execute (typically 'ssh')", + "feedback.provider.sftp.ssh-arguments": "SSH Arguments", + "feedback.provider.sftp.ssh-command": "SSH Command", + "feedback.provider.sftp.user": "User", + "feedback.provider.sftp.user-name": "User name", + "feedback.provider.use-repository-token": "Use Repository Token", + "feedback.provider.webdav-server": "WebDAV Server", + "feedback.provider.webdav.enter-password": "Enter password", + "feedback.provider.webdav.enter-username": "Enter username", + "feedback.provider.webdav.password": "Password", + "feedback.provider.webdav.server-url": "WebDAV Server URL", + "feedback.provider.webdav.username": "Username", + "feedback.repository.additional-parameters-hint": "Additional parameters can be set when creating repository using command line.", + "feedback.repository.attribute.algorithm-eco": "Error correction algorithm", + "feedback.repository.attribute.algorithm-encryption": "Encryption algorithm", + "feedback.repository.attribute.algorithm-hash": "Hash algorithm", + "feedback.repository.attribute.algorithm-splitter": "Splitter algorithm", + "feedback.repository.attribute.config-file": "Config file", + "feedback.repository.attribute.connected-as": "Connected as", + "feedback.repository.attribute.internal-compression": "Internal compression", + "feedback.repository.attribute.repository-eco": "Error correction overhead", + "feedback.repository.attribute.repository-format": "Repository format", + "feedback.repository.attribute.repository-provider": "Provider", + "feedback.repository.attribute.server-url": "Server URL", + "feedback.repository.configuration": "Storage Configuration", + "feedback.repository.connect-as": "Connect as", + "feedback.repository.connect-in-read-only-mode": "Connect in read-only mode", + "feedback.repository.connect-in-read-only-mode-hint": "Read-only mode prevents any changes to the repository.", + "feedback.repository.connect-to-repository": "Connect to repository", + "feedback.repository.create-repository-new": "Create New Repository", + "feedback.repository.create-repository-new-help": "Enter a strong password to create Kopia repository in the provided storage.", + "feedback.repository.eco-disabled": "Disabled", + "feedback.repository.eec-warning": "[EXPERIMENTAL] Error correction can help protect from certain kinds of data corruption due to spontaneous bit flips in the storage media.", + "feedback.repository.encryption": "Encryption", + "feedback.repository.enter-repository-password": "Enter repository password", + "feedback.repository.hostname": "Hostname", + "feedback.repository.hostname-hint": "Override this when restoring a snapshot taken on another machine", + "feedback.repository.internal-compression-supported-no": "no", + "feedback.repository.internal-compression-supported-yes": "yes", + "feedback.repository.kopia-server-parameters": "Kopia Server Parameters", + "feedback.repository.name-default": "My Repository", + "feedback.repository.override-hint": "To override, click 'Show Advanced Options'", + "feedback.repository.provider-selection": "Select Storage Type", + "feedback.repository.provider-selection-hint": "To connect to a repository or create one, select the preferred storage type:", + "feedback.repository.repository-description": "Repository description", + "feedback.repository.repository-description-help": "Helps to distinguish between multiple connected repositories", + "feedback.repository.repository-description-hint": "Enter repository description", + "feedback.repository.repository-description-required": "Repository description is required", + "feedback.repository.repository-initializing": "Initializing repository...", + "feedback.repository.repository-is-read-only": "Repository is read-only", + "feedback.repository.repository-password": "Repository Password", + "feedback.repository.repository-password-confirm": "Confirm Repository Password", + "feedback.repository.repository-password-confirm-again": "enter repository password again", + "feedback.repository.repository-password-help": "Used to encrypt the repository's contents", + "feedback.repository.repository-token-enter": "Enter Repository Token", + "feedback.repository.server-password": "Server password", + "feedback.repository.server-password-hint": "Enter password to connect to server", + "feedback.repository.status-connected": "Connected to repository", + "feedback.repository.username": "Username", + "feedback.repository.username-hint": "Override this when restoring a snapshot taken by another user", + "feedback.snapshot.create.enter-path-to-snapshot-hint": "Enter path to snapshot", + "feedback.snapshot.create.must-specify-path": "Must specify directory to snapshot.", + "feedback.snapshot.create.snapshot-new": "New Snapshot", + "feedback.snapshot.description": "Description", + "feedback.snapshot.description.snapshot-description": "Snapshot Description", + "feedback.snapshot.directory.browsing-not-supported": "Directory browsing is not supported in a web browser. Use Kopia UI.", + "feedback.snapshot.directory.restore-all-files-help": "You can mount/restore all the files and directories that you see below or restore files individually.", + "feedback.snapshot.header.actions": "Actions", + "feedback.snapshot.header.details": "Details", + "feedback.snapshot.header.directories": "Dirs", + "feedback.snapshot.header.files": "Files", + "feedback.snapshot.header.last-snapshot": "Last Snapshot", + "feedback.snapshot.header.next-snapshot": "Next Snapshot", + "feedback.snapshot.header.retention": "Retention", + "feedback.snapshot.header.root": "Root", + "feedback.snapshot.header.selected": "Selected", + "feedback.snapshot.header.snapshot-owner": "Owner", + "feedback.snapshot.header.snapshot-path": "Path", + "feedback.snapshot.header.snapshot-size": "Size", + "feedback.snapshot.header.start-time": "Start time", + "feedback.snapshot.header.status": "Status", + "feedback.snapshot.history.snapshot-displaying": "Displaying", + "feedback.snapshot.history.wipe-all-snapshots": "Wipe all snapshots and the policy for this source.", + "feedback.snapshot.restore.continue-on-errors": "Continue on errors", + "feedback.snapshot.restore.continue-on-errors-help": "When a restore error occurs, attempt to continue instead of failing fast.", + "feedback.snapshot.restore.destination": "Destination", + "feedback.snapshot.restore.destination-help": "You can also restore to a .zip or .tar file by providing the appropriate extension.", + "feedback.snapshot.restore.destination-hint": "Enter destination path", + "feedback.snapshot.restore.disable-zip-compression": "Disable ZIP compression", + "feedback.snapshot.restore.disable-zip-compression-help": "Do not compress when restoring to a ZIP file (faster).", + "feedback.snapshot.restore.minimal-file-size-for-shallow-restore": "Minimal file size for shallow restore", + "feedback.snapshot.restore.overwrite-directory": "Overwrite directories", + "feedback.snapshot.restore.overwrite-files": "Overwrite files", + "feedback.snapshot.restore.overwrite-symbolic-links": "Overwrite symbolic links", + "feedback.snapshot.restore.restore-file-modification-time": "Restore file modification time", + "feedback.snapshot.restore.restore-file-ownership": "Restore file ownership", + "feedback.snapshot.restore.restore-file-permissions": "Restore file permissions", + "feedback.snapshot.restore.shallow-restore-at-depth": "Shallow restore at depth", + "feedback.snapshot.restore.skip-previously-restored-files": "Skip previously restored files and symlinks", + "feedback.snapshot.restore.snapshot-restore": "Restore", + "feedback.snapshot.restore.write-files-atomically": "Write files atomically", + "feedback.snapshot.restore.write-sparse-files": "Write sparse files", + "feedback.snapshot.show-individual-snapshots-count": "feedback.snapshot.show-individual-snapshots-count", + "feedback.snapshot.show-individual-snapshots-count_one": "Show {{count}} individual snapshot", + "feedback.snapshot.show-individual-snapshots-count_other": "Show {{count}} individual snapshots", + "feedback.snapshot.start-after-previous-snapshot": "Snapshot will start after the previous snapshot completes", + "feedback.snapshot.status.status-overdue": "overdue", + "feedback.snapshot.status.status-pending": "Pending", + "feedback.tab.policies": "Policies", + "feedback.tab.preferences": "Preferences", + "feedback.tab.repository": "Repository", + "feedback.tab.repository-is-not-connected": "Repository is not connected", + "feedback.tab.snapshots": "Snapshots", + "feedback.tab.tasks": "Tasks", + "feedback.task.estimated-results": "{{description}} Bytes: {{bytes}} ({{bytes.excluded}} excluded) Files: {{files}} ({{files.excluded}} excluded) Directories: {{directories}} ({{directories.excluded}} excluded) Errors: {{errors}} ({{errors.ignored}} ignored)", + "feedback.task.header.counter": "Counter", + "feedback.task.header.value": "Value", + "feedback.task.logs": "Logs", + "feedback.task.no-tasks-help": "A list of tasks will appear here when you create snapshots, restore, run maintenance, etc.", + "feedback.task.search-tasks-by-hint": "Search task logs by description", + "feedback.task.status.task-canceled": "Task canceled", + "feedback.task.status.task-canceled-after": "Task canceled after", + "feedback.task.status.task-canceling": "Canceling", + "feedback.task.status.task-error": "Task error", + "feedback.task.status.task-failed-after": "Failed after", + "feedback.task.status.task-finished": "Finished", + "feedback.task.status.task-finished-in": "Finished in", + "feedback.task.status.task-running-for": "Task running for", + "feedback.task.status.task-started": "Started", + "feedback.task.status.task-succeeded-after": "Task succeeded after", + "feedback.task.table.header-description": "Description", + "feedback.task.table.header-kind": "Kind", + "feedback.task.table.header-start-time": "Start time", + "feedback.task.table.header-status": "Status", + "feedback.task.tasks-total": "Total", + "feedback.ui.appearance": "Appearance", + "feedback.ui.appearance-help": "Specifies the appearance of the user interface", + "feedback.ui.appearance-hint": "Select font size", + "feedback.ui.byte-representation-description": "Select byte representation", + "feedback.ui.byte-representation-help": "Specifies the representation of bytes", + "feedback.ui.byte-representation-select": "Select byte representation", + "feedback.ui.pagesize-description": "Page size", + "feedback.ui.pagesize-help": "Specifies the pagination size in tables", + "feedback.ui.pagesize-hint": "Page size", + "feedback.ui.theme-description": "Theme", + "feedback.ui.theme-help": "The current active theme", + "feedback.ui.theme-select": "Select theme", + "feedback.validation.invalid-times-of-day": "Invalid Times of Day", + "feedback.validation.optional.valid-number-or-empty": "Must be a valid number or empty", + "feedback.validation.passwords-dont-match": "Passwords don't match", + "feedback.validation.required.directory": "Required field", + "feedback.validation.required.field": "Required field", + "feedback.validation.required.valid-number-or-empty": "Must be a valid number or empty", + "value.algorithm.eco-disabled": "Disabled", + "value.algorithm.suffix-not-recommended": "(NOT RECOMMENDED)", + "value.algorithm.suffix-recommended": "(RECOMMENDED)", + "value.log.details-0-no-output": "0 - no output", + "value.log.details-1-minimal-details": "1 - minimal details", + "value.log.details-10-maximum-details": "10 - maximum details", + "value.log.details-5-normal-details": "5 - normal details", + "value.log.details-inherit-from-parent": "(inherit from parent)", + "value.policy.async": "Run asynchronously, ignore failures", + "value.policy.essential": "Must succeed", + "value.policy.inherent-from-parent": "inherit from parent", + "value.policy.none": "none", + "value.policy.optional": "Ignore failures", + "value.provider.s3.http-connection-insecure": "Use HTTP connection (insecure)", + "value.provider.s3.no-tls-verification": "Do not verify TLS certificate", + "value.repository.latest-format": "Latest format", + "value.repository.legacy-format": "Legacy format compatible with v0.8", + "value.snapshot-frequency.10-minutes": "every 10 minutes", + "value.snapshot-frequency.12-hours": "every 12 hours", + "value.snapshot-frequency.15-minutes": "every 15 minutes", + "value.snapshot-frequency.20-minutes": "every 20 minutes", + "value.snapshot-frequency.3-hours": "every 3 hours", + "value.snapshot-frequency.30-minutes": "every 30 minutes", + "value.snapshot-frequency.6-hours": "every 6 hours", + "value.snapshot-frequency.hour": "every hour", + "value.ui.appearance-large": "large", + "value.ui.appearance-medium": "medium", + "value.ui.appearance-small": "small", + "value.ui.byte-representation-base10": "Base-10 (KB, MB, GB, TB)", + "value.ui.byte-representation-base2": "Base-2 (KiB, MiB, GiB, TiB)", + "value.ui.theme-dark": "dark", + "value.ui.theme-light": "light", + "value.ui.theme-ocean": "ocean", + "value.ui.theme-pastel": "pastel", + "value.validation.optional-no": "no", + "value.validation.optional-yes": "yes" +} diff --git a/public/locales/es/translation.json b/public/locales/es/translation.json new file mode 100644 index 00000000..56f673b1 --- /dev/null +++ b/public/locales/es/translation.json @@ -0,0 +1,479 @@ +{ + "common.action.back": "Atrás", + "common.action.cancel": "Cancelar", + "common.action.click-here-to-learn-more": "Clic aquí para saber más.", + "common.action.confirm-delete": "Confirmar eliminación", + "common.action.delete": "Borrar", + "common.action.next": "Próximo", + "common.action.return": "Volver", + "common.action.stop": "Detener", + "common.label.loading": "Cargando...", + "event.cli.copy-to-clipboard": "Copiar al portapapeles", + "event.cli.show-cli-equivalent": "Haga clic para mostrar el equivalente de CLI", + "event.log.hide-log": "Ocultar registro", + "event.log.show-log": "Mostrar registro", + "event.pin.add-pin": "Agregar PIN", + "event.pin.pin-snapshot": "Instantánea de pin", + "event.pin.remove-pin": "Quitar pin", + "event.pin.update-pin": "Actualizar PIN", + "event.policy.delete": "Eliminar política", + "event.policy.edit": "Editar", + "event.policy.save": "Guardar política", + "event.policy.set-policy": "Establecer política", + "event.repository.cancel-connection": "Cancelar conexión", + "event.repository.connect-to-repository": "Conectarse al repositorio", + "event.repository.create-repository": "Crear repositorio", + "event.repository.disconnect-from-repository": "Desconectar del repositorio", + "event.repository.hide-advanced-options": "Ocultar opciones avanzadas", + "event.repository.show-advanced-options": "Mostrar opciones avanzadas", + "event.repository.update-description": "Actualizar descripción", + "event.snapshot.browse-directory": "Navegar", + "event.snapshot.delete-selected": "event.snapshot.delete-selected", + "event.snapshot.delete-selected_one": "¿Quieres eliminar la instantánea {{count}} seleccionada?", + "event.snapshot.delete-selected_other": "¿Quieres eliminar las {{count}} instantáneas seleccionadas?", + "event.snapshot.description.enter-new-description": "Ingrese una nueva descripción", + "event.snapshot.description.remove-description": "Eliminar descripción", + "event.snapshot.description.update-description": "Descripción de la actualización", + "event.snapshot.estimate": "Estimar", + "event.snapshot.fetch-snapshots": "Obtener instantáneas", + "event.snapshot.history.delete-selected": "Eliminar seleccionados ({{count}})", + "event.snapshot.history.delete-snapshot-source": "Eliminar fuente de instantánea", + "event.snapshot.history.deselect-all": "Deseleccionar todo", + "event.snapshot.history.select-all-snapshots": "Seleccionar todo", + "event.snapshot.history.update-snapshot-description": "{{description}}: haga clic para actualizar la descripción de la instantánea.", + "event.snapshot.mount-directory": "Montar como sistema de archivos local", + "event.snapshot.new-snapshot": "Nueva instantánea", + "event.snapshot.restore-file-directories": "Restaurar archivos y directorios", + "event.snapshot.restore.begin-restore": "Comenzar la restauración", + "event.snapshot.restore.go-to-restore-task": "Ir a restaurar tarea", + "event.snapshot.show-policy": "Política", + "event.snapshot.snapshot-now": "Instantánea ahora", + "event.snapshot.synchronize": "Sincronizar", + "event.snapshot.unmount-directory": "Desmontar", + "event.task.action.cancel": "Cancelar tarea", + "event.task.select.task-all": "Todas", + "event.task.select.task-failed": "Fallidas", + "event.task.select.task-running": "En ejecución", + "feedback.directory.header.directories": "Directorios", + "feedback.directory.header.files": "Archivos", + "feedback.directory.header.last-modification": "Última modificación", + "feedback.directory.header.name": "Nombre", + "feedback.directory.header.size": "Tamaño", + "feedback.error.common": "Error", + "feedback.error.connection": "Error de conexión:", + "feedback.header.effective": "Eficaz", + "feedback.header.username": "Nombre de usuario", + "feedback.pin.add-pin-to-protect": "Agregue un pin para proteger la instantánea contra la eliminación", + "feedback.pin.do-not-delete": "no borres", + "feedback.pin.name-of-the-pin": "nombre del pin", + "feedback.policy.action.command-mode": "Modo de comando", + "feedback.policy.actions.after-folder": "Después de la carpeta", + "feedback.policy.actions.after-folder-help": "Script para ejecutar después de la carpeta", + "feedback.policy.actions.after-snapshot": "Después de la instantánea", + "feedback.policy.actions.after-snapshot-help": "Script para ejecutar después de la instantánea", + "feedback.policy.actions.before-folder": "Antes de la carpeta", + "feedback.policy.actions.before-folder-help": "Script para ejecutar antes de la carpeta", + "feedback.policy.actions.before-snapshot": "Antes de la instantánea", + "feedback.policy.actions.before-snapshot-help": "Script para ejecutar antes de la instantánea", + "feedback.policy.actions.timeout": "Se acabó el tiempo", + "feedback.policy.command-mode-help": "Esencial (debe tener éxito; comportamiento predeterminado), opcional (se toleran los errores) o asíncrono (Kopia iniciará la acción pero no esperará a que finalice)", + "feedback.policy.compression.compression-algorithm": "Algoritmo de compresión", + "feedback.policy.compression.compression-algorithm-help": "Especifique el algoritmo de compresión que se utilizará al tomar instantáneas de archivos en este directorio y subdirectorios.", + "feedback.policy.compression.maximal-file-size": "Tamaño máximo de archivo", + "feedback.policy.compression.maximal-file-size-help": "Los archivos cuyo tamaño exceda el valor proporcionado no se comprimirán", + "feedback.policy.compression.maximal-file-size-hint": "Tamaño máximo de archivo en bytes", + "feedback.policy.compression.minimal-file-size": "Tamaño mínimo de archivo", + "feedback.policy.compression.minimal-file-size-help": "Los archivos que sean más pequeños que el valor proporcionado no se comprimirán", + "feedback.policy.compression.minimal-file-size-hint": "tamaño mínimo de archivo en bytes", + "feedback.policy.compression.never-compress-extensions": "Nunca comprimir extensiones", + "feedback.policy.compression.never-compress-extensions-help": "Nunca comprima las siguientes extensiones de archivo (una extensión por línea)", + "feedback.policy.compression.never-compress-extensions-hint": "p.ej. *.mp4", + "feedback.policy.compression.only-compress-extensions": "Solo comprimir extensiones", + "feedback.policy.compression.only-compress-extensions-help": "Comprima únicamente archivos con las siguientes extensiones de archivo (una extensión por línea)", + "feedback.policy.compression.only-compress-extensions-hint": "p.ej. *.txt", + "feedback.policy.confirm-delete-policy": "¿Está seguro de que desea eliminar esta política?", + "feedback.policy.defined-by": "Definido por", + "feedback.policy.defined-by-this-policy": "Definido por esta política", + "feedback.policy.error-delete-policy": "Error al eliminar la política", + "feedback.policy.error-handling.ignore-directory-errors": "Ignorar errores de directorio", + "feedback.policy.error-handling.ignore-directory-errors-help": "Trate los errores de lectura de directorio como no fatales.", + "feedback.policy.error-handling.ignore-file-errors": "Ignorar errores de archivos", + "feedback.policy.error-handling.ignore-file-errors-help": "Trate los errores de lectura de archivos como no fatales.", + "feedback.policy.error-handling.ignore-unknown-directories": "Ignorar entradas de directorio desconocidas", + "feedback.policy.error-handling.ignore-unknown-directories-help": "Trate las entradas de directorio no reconocidas/no admitidas como errores no fatales.", + "feedback.policy.error-saving-policy": "Error al guardar la política", + "feedback.policy.files.ignore-files": "Ignorar archivos", + "feedback.policy.files.ignore-files-help": "Lista de nombres de archivos y directorios para ignorar.
Consulte la documentación sobre cómo ignorar archivos.", + "feedback.policy.files.ignore-files-hint": "p.ej. /archivo.txt", + "feedback.policy.files.ignore-rule-files": "Ignorar archivos de reglas", + "feedback.policy.files.ignore-rule-files-from-parent-directories": "Ignorar archivos de reglas de directorios principales", + "feedback.policy.files.ignore-rule-files-from-parent-directories-help": "Cuando se establece, los archivos que especifican reglas de ignorar (.kopiaignore, etc.) del directorio principal se ignoran", + "feedback.policy.files.ignore-rule-files-help": "Lista de archivos adicionales que contienen reglas de ignorar (cada archivo configura reglas de ignorar para el directorio y sus subdirectorios)", + "feedback.policy.files.ignore-rule-files-hint": "p.ej. .kopiaignore", + "feedback.policy.files.ignore-rules-from-parent-directories": "Ignorar reglas de directorios principales", + "feedback.policy.files.ignore-rules-from-parent-directories-help": "Cuando se establece, se ignoran las reglas de ignorar del directorio principal.", + "feedback.policy.files.ignore-well-known-cache-directories": "Ignorar directorios de caché conocidos", + "feedback.policy.files.ignore-well-known-cache-directories-help": "Ignorar directorios que contengan CACHEDIR.TAG y similares", + "feedback.policy.files.scan-only-one-filesystem": "Escanea solo un sistema de archivos", + "feedback.policy.files.scan-only-one-filesystem-help": "No cruce los límites del sistema de archivos al crear una instantánea", + "feedback.policy.find-count": "comentarios.política.find-count", + "feedback.policy.find-count_one": "Se encontró {{count}} política que coincide con los criterios", + "feedback.policy.find-count_other": "Se encontraron {{count}} políticas que coinciden con los criterios", + "feedback.policy.find-hint": "Ingrese al directorio para buscar o establecer una política", + "feedback.policy.find-none": "No se encontraron políticas", + "feedback.policy.find-none-create": "No se encontró ninguna política para el directorio {{ruta}}. \nConfigure una nueva política.", + "feedback.policy.header.actions": "Comportamiento", + "feedback.policy.header.compression": "Compresión", + "feedback.policy.header.defined": "Definido", + "feedback.policy.header.error-handling": "Manejo de errores", + "feedback.policy.header.files": "Archivos", + "feedback.policy.header.folder-actions": "Acciones de carpeta", + "feedback.policy.header.host": "Anfitrión", + "feedback.policy.header.logging": "Inicio sesión", + "feedback.policy.header.other": "Otro", + "feedback.policy.header.path": "Camino", + "feedback.policy.header.scheduling": "Planificación", + "feedback.policy.header.snapshot-action": "Acciones de instantáneas", + "feedback.policy.header.snapshot-retention": "Retención de instantáneas", + "feedback.policy.header.upload": "Subir", + "feedback.policy.kind.all": "Todas las pólizas", + "feedback.policy.kind.applicable": "Políticas aplicables", + "feedback.policy.kind.global": "Políticas globales", + "feedback.policy.kind.local": "Políticas locales", + "feedback.policy.kind.per-host-policies": "Políticas por host", + "feedback.policy.kind.per-user-policies": "Políticas por usuario", + "feedback.policy.logging.cache-hit": "Golpe de caché", + "feedback.policy.logging.cache-hit-help": "Registrar detalle cuando se utiliza un caché en lugar de cargar el archivo", + "feedback.policy.logging.cache-miss": "Falta de caché", + "feedback.policy.logging.cache-miss-help": "Detalle del registro cuando no se puede usar un caché y se debe aplicar hash a un archivo", + "feedback.policy.logging.directory-ignored": "Directorio ignorado", + "feedback.policy.logging.directory-ignored-help": "Registrar detalle cuando se ignora un directorio", + "feedback.policy.logging.directory-snapshotted": "Directorio fotografiado", + "feedback.policy.logging.directory-snapshotted-help": "Registrar la detalle cuando se toma una instantánea de un directorio", + "feedback.policy.logging.file-ignored": "Archivo ignorado", + "feedback.policy.logging.file-ignored-help": "Registrar la detalle cuando se ignora un archivo, enlace simbólico, etc.", + "feedback.policy.logging.file-snapshotted": "Archivo capturado", + "feedback.policy.logging.file-snapshotted-help": "Registre la detalle cuando se toma una instantánea de un archivo, enlace simbólico, etc.", + "feedback.policy.other.disable-parent-policy-evaluation": "Deshabilitar la evaluación de la política principal", + "feedback.policy.other.disable-parent-policy-evaluation-help": "Evita que las políticas principales afecten a este directorio y sus subdirectorios", + "feedback.policy.other.json-representation": "Representación JSON", + "feedback.policy.other.json-representation-help": "Esta es la representación interna de una política.", + "feedback.policy.policies-defined-by-path-absolute": "Las políticas sólo se pueden definir para rutas absolutas.", + "feedback.policy.retention.annual-snapshot-retain": "Anual", + "feedback.policy.retention.annual-snapshot-retain-help": "Cuántas instantáneas anuales conservar por fuente. \nSe conservará la última instantánea de cada año calendario.", + "feedback.policy.retention.annual-snapshot-retain-hint": "Número de instantáneas anuales", + "feedback.policy.retention.daily-snapshot-retain": "A diario", + "feedback.policy.retention.daily-snapshot-retain-help": "Cuántas instantáneas diarias conservar por fuente. \nSe conservará la última instantánea de cada día.", + "feedback.policy.retention.daily-snapshot-retain-hint": "Número de instantáneas diarias", + "feedback.policy.retention.hourly-snapshot-retain": "Cada hora", + "feedback.policy.retention.hourly-snapshot-retain-help": "Cuántas instantáneas por hora conservar por fuente. \nSe conservará la última instantánea de cada hora.", + "feedback.policy.retention.hourly-snapshot-retain-hint": "número de instantáneas por hora", + "feedback.policy.retention.ignore-identical-snapshots": "Ignorar instantáneas idénticas", + "feedback.policy.retention.ignore-identical-snapshots-help": "NO guarde una instantánea cuando no se hayan modificado archivos", + "feedback.policy.retention.keep-latest-help": "número de instantáneas más recientes", + "feedback.policy.retention.latest-snapshot-retain": "Últimas instantáneas", + "feedback.policy.retention.latest-snapshot-retain-help": "Número de instantáneas más recientes para conservar por fuente", + "feedback.policy.retention.monthly-snapshot-retain": "Mensual", + "feedback.policy.retention.monthly-snapshot-retain-help": "Cuántas instantáneas mensuales conservar por fuente. \nSe conservará la última instantánea de cada mes calendario.", + "feedback.policy.retention.monthly-snapshot-retain-hint": "Número de instantáneas mensuales", + "feedback.policy.retention.weekly-snapshot-retain": "Semanalmente", + "feedback.policy.retention.weekly-snapshot-retain-help": "Cuántas instantáneas semanales conservar por fuente. \nSe conservará la última instantánea de cada semana.", + "feedback.policy.retention.weekly-snapshot-retain-hint": "Número de instantáneas semanales", + "feedback.policy.scheduling.cron-expressions": "Expresiones cron", + "feedback.policy.scheduling.cron-expressions-hint": "minuto hora día mes día laborable", + "feedback.policy.scheduling.cron-help": "Programaciones de instantáneas utilizando la sintaxis crontab de UNIX (una por línea):
Consulte detalles de los formatos admitidos.", + "feedback.policy.scheduling.manual-snapshots-only": "Solo instantáneas manuales", + "feedback.policy.scheduling.manual-snapshots-only-help": "Cree instantáneas solo manualmente (deshabilita las instantáneas programadas)", + "feedback.policy.scheduling.missed-snapshots-startup": "Ejecute instantáneas perdidas al iniciar", + "feedback.policy.scheduling.missed-snapshots-startup-help": "Ejecute inmediatamente cualquier instantánea perdida cuando se inicie kopia (solo relevante para instantáneas de la hora del día)", + "feedback.policy.scheduling.no-upcoming-snapshots": "No hay instantáneas próximas", + "feedback.policy.scheduling.snapshot-frequency": "Frecuencia de instantáneas", + "feedback.policy.scheduling.snapshot-frequency-help": "Con qué frecuencia crear instantáneas en KopiaUI o el servidor Kopia (no tiene efecto fuera del modo servidor)", + "feedback.policy.scheduling.times-of-day": "Tiempos del Día", + "feedback.policy.scheduling.times-of-day-help": "Cree instantáneas a las horas especificadas del día (formato de 24 horas)", + "feedback.policy.scheduling.times-of-day-hint": "p.ej. 17:00", + "feedback.policy.scheduling.upcoming": "Próximo", + "feedback.policy.scheduling.upcoming-snapshots": "Próximas instantáneas", + "feedback.policy.scheduling.upcoming-snapshots-help": "Horarios de las próximas instantáneas calculados en función de los parámetros de la política", + "feedback.policy.time-of-day.invalid": "Hora del día no válida: {{tod}}", + "feedback.policy.timeout-help": "Tiempo de espera en segundos antes de que Kopia finalice el proceso", + "feedback.policy.upload.maximum-parallel-file-reads": "Lecturas máximas de archivos paralelos", + "feedback.policy.upload.maximum-parallel-file-reads-help": "Número máximo de archivos que se leerán en paralelo (el valor predeterminado es el número de procesadores lógicos)", + "feedback.policy.upload.maximum-parallel-file-reads-hint": "número máximo de lecturas de archivos paralelos", + "feedback.policy.upload.maximum-parallel-snapshots": "Instantáneas paralelas máximas", + "feedback.policy.upload.maximum-parallel-snapshots-help": "Número máximo de instantáneas que se pueden cargar simultáneamente", + "feedback.policy.upload.maximum-parallel-snapshots-hint-set": "número máximo de instantáneas paralelas", + "feedback.policy.upload.maximum-parallel-snapshots-hint-unset": "debe especificarse mediante la política global, de usuario o de host", + "feedback.prodiver.gcs.paste-json-credentials": "Pegue las credenciales JSON aquí", + "feedback.provider.azure-blob-storage": "Almacenamiento de blobs de Azure", + "feedback.provider.azure.access-key": "Llave de acceso", + "feedback.provider.azure.azure-storage-domain": "Dominio de almacenamiento de Azure", + "feedback.provider.azure.container": "Envase", + "feedback.provider.azure.enter-access-key": "Introduzca la clave de acceso secreta", + "feedback.provider.azure.enter-azure-storage-domain": "Ingrese el dominio de almacenamiento o déjelo vacío para el valor predeterminado 'blob.core.windows.net'", + "feedback.provider.azure.enter-container-name": "Introduzca el nombre del contenedor", + "feedback.provider.azure.enter-object-name-prefix": "Introduzca el prefijo del nombre del objeto o déjelo vacío", + "feedback.provider.azure.enter-sas-token": "Ingrese el token SAS secreto", + "feedback.provider.azure.enter-storage-account": "Ingrese el nombre de la cuenta de almacenamiento", + "feedback.provider.azure.object-name-prefix": "Prefijo del nombre del objeto", + "feedback.provider.azure.sas-token": "Ficha SAS", + "feedback.provider.azure.storage-account": "Cuenta de almacenamiento", + "feedback.provider.b2.bucket-name": "Balde B2", + "feedback.provider.b2.enter-account-key": "Ingrese la aplicación secreta o la clave de cuenta", + "feedback.provider.b2.enter-account-key-id": "Ingrese la ID de la clave de la aplicación o de la cuenta", + "feedback.provider.b2.enter-bucket-name": "Introduce el nombre del depósito", + "feedback.provider.b2.enter-object-name-prefix": "Introduzca el prefijo del nombre del objeto o déjelo vacío", + "feedback.provider.b2.key": "Llave", + "feedback.provider.b2.key-id": "ID de clave", + "feedback.provider.b2.object-name-prefix": "Prefijo del nombre del objeto", + "feedback.provider.backblaze-b2": "Resplandor B2", + "feedback.provider.filesystem.directory-path": "Ruta de directorio", + "feedback.provider.filesystem.enter-directory-path": "Ingrese la ruta del directorio donde desea almacenar los archivos del repositorio", + "feedback.provider.gcs.bucket-name": "Cucharón GCS", + "feedback.provider.gcs.credentials-file": "Archivo de credenciales", + "feedback.provider.gcs.credentials-json": "Credenciales JSON", + "feedback.provider.gcs.enter-bucket-name": "Introduce el nombre del depósito", + "feedback.provider.gcs.enter-credentials-file-name": "Ingrese el nombre del archivo JSON de credenciales", + "feedback.provider.gcs.enter-object-name-prefix": "Introduzca el prefijo del nombre del objeto o déjelo vacío", + "feedback.provider.gcs.object-name-prefix": "Prefijo del nombre del objeto", + "feedback.provider.google-cloud-storage": "Almacenamiento en la nube de Google", + "feedback.provider.kopia-repository-server": "Servidor de repositorio de Kopia", + "feedback.provider.local-directory-or-nas": "Directorio local o NAS", + "feedback.provider.rclone-remote": "Clon remoto", + "feedback.provider.rclone.rclone-executable-path": "Ruta ejecutable de Rclone", + "feedback.provider.rclone.rclone-executable-path-hint": "Ingrese la ruta al ejecutable rclone", + "feedback.provider.rclone.rclone-remote-path": "Ruta remota de clonación", + "feedback.provider.rclone.rclone-remote-path-hint": "Ingrese :", + "feedback.provider.repositoryserver.enter-server-certificate-fingerprint": "Ingrese la huella digital del certificado del servidor confiable impresa al iniciar el servidor", + "feedback.provider.repositoryserver.enter-server-url": "Ingrese la URL del servidor (https://:puerto)", + "feedback.provider.repositoryserver.server-address": "Dirección del servidor", + "feedback.provider.repositoryserver.server-certificate-fingerprint": "Huella digital del certificado del servidor de confianza (SHA256)", + "feedback.provider.repositorytoken.paste-token": "Pegar token de conexión", + "feedback.provider.repositorytoken.token": "Simbólico", + "feedback.provider.required-either-key-file": "Se requiere una de las opciones Contraseña, Archivo de claves o Datos clave.", + "feedback.provider.required-either-known-host-data": "Se requiere archivo de hosts conocidos o datos de hosts conocidos, pero no ambos.", + "feedback.provider.s3-or-compatible-storage": "Amazon S3 o almacenamiento compatible", + "feedback.provider.s3.access-key-id": "ID de clave de acceso", + "feedback.provider.s3.access-key-id-hint": "Introduzca el ID de la clave de acceso", + "feedback.provider.s3.bucket-name": "Balde", + "feedback.provider.s3.bucket-name-hint": "Introduce el nombre del depósito", + "feedback.provider.s3.enter-object-name-prefix-hint": "Introduzca el prefijo del nombre del objeto o déjelo vacío", + "feedback.provider.s3.object-name-prefix": "Prefijo del nombre del objeto", + "feedback.provider.s3.override-region": "Anular región", + "feedback.provider.s3.override-region-hint": "Ingrese una región específica (por ejemplo, us-west-1) o déjela vacía", + "feedback.provider.s3.secret-access-key": "Clave de acceso secreta", + "feedback.provider.s3.secret-access-key-hint": "Introduzca la clave de acceso secreta", + "feedback.provider.s3.server-endpoint": "Punto final del servidor", + "feedback.provider.s3.server-endpoint-hint": "Ingrese la dirección del servidor (por ejemplo, s3.amazonaws.com)", + "feedback.provider.s3.session-token": "Token de sesión", + "feedback.provider.s3.session-token-hint": "Ingrese el token de sesión o déjelo vacío", + "feedback.provider.sftp-key-data": "Llave de datos", + "feedback.provider.sftp-key-data-hint": "Pegar el contenido del archivo clave", + "feedback.provider.sftp-server": "Servidor SFTP", + "feedback.provider.sftp.enter-password": "Introducir la contraseña", + "feedback.provider.sftp.enter-path-host-file": "Ingrese la ruta al archivo conocido_hosts", + "feedback.provider.sftp.enter-path-to-key-file": "Ingrese la ruta al archivo clave", + "feedback.provider.sftp.enter-remote-path": "Ingrese la ruta remota al repositorio, por ejemplo, '/mnt/data/repository'", + "feedback.provider.sftp.enter-ssh-arguments": "Ingrese los argumentos del comando SSH ('user@host -s sftp' se agregará automáticamente)", + "feedback.provider.sftp.enter-ssh-host-name": "nombre de host ssh (por ejemplo, ejemplo.com)", + "feedback.provider.sftp.host": "Anfitrión", + "feedback.provider.sftp.known-host-data": "Datos de hosts conocidos", + "feedback.provider.sftp.launch-external-ssh-command": "Inicie el comando SSH externo sin contraseña", + "feedback.provider.sftp.launch-external-ssh-command-hint": "De forma predeterminada, Kopia se conecta al servidor mediante un cliente SSH interno que admite opciones limitadas. \nAlternativamente, puede iniciar un comando SSH externo sin contraseña, que admite opciones adicionales, pero generalmente es menos eficiente que el cliente integrado.", + "feedback.provider.sftp.password": "Contraseña", + "feedback.provider.sftp.paste-content-of-known-host": "Pegue el contenido del archivo conocido_hosts", + "feedback.provider.sftp.path": "Camino", + "feedback.provider.sftp.path-host-file": "Ruta al archivoknown_hosts", + "feedback.provider.sftp.path-key-file": "Ruta al archivo clave", + "feedback.provider.sftp.port": "Puerto", + "feedback.provider.sftp.port-number": "Número de puerto (por ejemplo, 22)", + "feedback.provider.sftp.provide-passwordless-ssh-command": "Proporcione el comando SSH sin contraseña para ejecutar (normalmente 'ssh')", + "feedback.provider.sftp.ssh-arguments": "Argumentos SSH", + "feedback.provider.sftp.ssh-command": "Comando SSH", + "feedback.provider.sftp.user": "Usuario", + "feedback.provider.sftp.user-name": "Nombre de usuario", + "feedback.provider.use-repository-token": "Usar token de repositorio", + "feedback.provider.webdav-server": "Servidor WebDAV", + "feedback.provider.webdav.enter-password": "Introducir la contraseña", + "feedback.provider.webdav.enter-username": "Introduzca su nombre de usuario", + "feedback.provider.webdav.password": "Contraseña", + "feedback.provider.webdav.server-url": "URL del servidor WebDAV", + "feedback.provider.webdav.username": "Nombre de usuario", + "feedback.repository.additional-parameters-hint": "Se pueden configurar parámetros adicionales al crear un repositorio usando la línea de comando.", + "feedback.repository.attribute.algorithm-eco": "Algoritmo de corrección de errores", + "feedback.repository.attribute.algorithm-encryption": "Algoritmo de cifrado", + "feedback.repository.attribute.algorithm-hash": "Algoritmo de hash", + "feedback.repository.attribute.algorithm-splitter": "Algoritmo de división", + "feedback.repository.attribute.config-file": "Archivo de configuración", + "feedback.repository.attribute.connected-as": "Conectado como", + "feedback.repository.attribute.internal-compression": "Compresión interna", + "feedback.repository.attribute.repository-eco": "Overhead de corrección de errores", + "feedback.repository.attribute.repository-format": "Formato del repositorio", + "feedback.repository.attribute.repository-provider": "Proveedor", + "feedback.repository.attribute.server-url": "URL del servidor", + "feedback.repository.configuration": "Configuración de almacenamiento", + "feedback.repository.connect-as": "Conectar como", + "feedback.repository.connect-in-read-only-mode": "Conéctese en modo de solo lectura", + "feedback.repository.connect-in-read-only-mode-hint": "El modo de solo lectura evita cualquier cambio en el repositorio.", + "feedback.repository.connect-to-repository": "Conectarse al repositorio", + "feedback.repository.create-repository-new": "Crear nuevo repositorio", + "feedback.repository.create-repository-new-help": "Ingrese una contraseña segura para crear el repositorio de Kopia en el almacenamiento proporcionado.", + "feedback.repository.eco-disabled": "Deshabilitado", + "feedback.repository.eec-warning": "[EXPERIMENTAL] La corrección de errores puede ayudar a proteger contra ciertos tipos de corrupción de datos debido a cambios espontáneos de bits en los medios de almacenamiento.", + "feedback.repository.encryption": "Cifrado", + "feedback.repository.enter-repository-password": "Ingrese la contraseña del repositorio", + "feedback.repository.hostname": "Nombre de host", + "feedback.repository.hostname-hint": "Anule esto al restaurar una instantánea tomada en otra máquina", + "feedback.repository.internal-compression-supported-no": "no", + "feedback.repository.internal-compression-supported-yes": "sí", + "feedback.repository.kopia-server-parameters": "Parámetros del servidor Kopia", + "feedback.repository.name-default": "Mi repositorio", + "feedback.repository.override-hint": "Para anular, haga clic en 'Mostrar opciones avanzadas'", + "feedback.repository.provider-selection": "Seleccione el tipo de almacenamiento", + "feedback.repository.provider-selection-hint": "Para conectarse a un repositorio o crear uno, seleccione el tipo de almacenamiento preferido:", + "feedback.repository.repository-description": "Descripción del repositorio", + "feedback.repository.repository-description-help": "Ayuda a distinguir entre múltiples repositorios conectados", + "feedback.repository.repository-description-hint": "Ingrese la descripción del repositorio", + "feedback.repository.repository-description-required": "La descripción del repositorio es obligatoria", + "feedback.repository.repository-initializing": "Inicializando el repositorio...", + "feedback.repository.repository-is-read-only": "El repositorio es de sólo lectura", + "feedback.repository.repository-password": "Contraseña del repositorio", + "feedback.repository.repository-password-confirm": "Confirmar contraseña del repositorio", + "feedback.repository.repository-password-confirm-again": "ingrese la contraseña del repositorio nuevamente", + "feedback.repository.repository-password-help": "Se utiliza para cifrar el contenido del repositorio.", + "feedback.repository.repository-token-enter": "Ingrese el token del repositorio", + "feedback.repository.server-password": "Contraseña del servidor", + "feedback.repository.server-password-hint": "Ingrese la contraseña para conectarse al servidor", + "feedback.repository.status-connected": "Conectado al repositorio", + "feedback.repository.username": "Nombre de usuario", + "feedback.repository.username-hint": "Anule esto al restaurar una instantánea tomada por otro usuario", + "feedback.snapshot.create.enter-path-to-snapshot-hint": "Ingrese la ruta a la instantánea", + "feedback.snapshot.create.must-specify-path": "Debe especificar el directorio para la instantánea.", + "feedback.snapshot.create.snapshot-new": "Nueva instantánea", + "feedback.snapshot.description": "Descripción", + "feedback.snapshot.description.snapshot-description": "Descripción de la instantánea", + "feedback.snapshot.directory.browsing-not-supported": "La exploración de directorios no es compatible con un navegador web. \nUtilice la interfaz de usuario de Kopia.", + "feedback.snapshot.directory.restore-all-files-help": "Puede montar/restaurar todos los archivos y directorios que ve a continuación o restaurar archivos individualmente.", + "feedback.snapshot.header.actions": "Acciones", + "feedback.snapshot.header.details": "Detalles", + "feedback.snapshot.header.directories": "directorios", + "feedback.snapshot.header.files": "Archivos", + "feedback.snapshot.header.last-snapshot": "Última instantánea", + "feedback.snapshot.header.next-snapshot": "Siguiente instantánea", + "feedback.snapshot.header.retention": "Retención", + "feedback.snapshot.header.root": "Raíz", + "feedback.snapshot.header.selected": "Seleccionado", + "feedback.snapshot.header.snapshot-owner": "Dueño", + "feedback.snapshot.header.snapshot-path": "Ruta", + "feedback.snapshot.header.snapshot-size": "Tamaño", + "feedback.snapshot.header.start-time": "Hora de inicio", + "feedback.snapshot.header.status": "Estado", + "feedback.snapshot.history.snapshot-displaying": "Mostrando", + "feedback.snapshot.history.wipe-all-snapshots": "Borre todas las instantáneas y la política de esta fuente.", + "feedback.snapshot.restore.continue-on-errors": "Continuar en caso de errores", + "feedback.snapshot.restore.continue-on-errors-help": "Cuando se produce un error durante la restauración, intenta continuar en lugar de detenerse rápidamente.", + "feedback.snapshot.restore.destination": "Destino", + "feedback.snapshot.restore.destination-help": "También puedes restaurar a un archivo .zip o .tar proporcionando la extensión adecuada.", + "feedback.snapshot.restore.destination-hint": "Introducir la ruta de destino", + "feedback.snapshot.restore.disable-zip-compression": "Desactivar compresión ZIP", + "feedback.snapshot.restore.disable-zip-compression-help": "No comprimir al restaurar en un archivo ZIP (más rápido).", + "feedback.snapshot.restore.minimal-file-size-for-shallow-restore": "Tamaño mínimo de archivo para restauración superficial", + "feedback.snapshot.restore.overwrite-directory": "Sobrescribir directorios", + "feedback.snapshot.restore.overwrite-files": "Sobrescribir archivos", + "feedback.snapshot.restore.overwrite-symbolic-links": "Sobrescribir enlaces simbólicos", + "feedback.snapshot.restore.restore-file-modification-time": "Restaurar hora de modificación de archivos", + "feedback.snapshot.restore.restore-file-ownership": "Restaurar propiedad de archivos", + "feedback.snapshot.restore.restore-file-permissions": "Restaurar permisos de archivos", + "feedback.snapshot.restore.shallow-restore-at-depth": "Restauración superficial a una profundidad específica", + "feedback.snapshot.restore.skip-previously-restored-files": "Saltar archivos y enlaces simbólicos restaurados previamente", + "feedback.snapshot.restore.snapshot-restore": "Restaurar", + "feedback.snapshot.restore.write-files-atomically": "Escribir archivos atómicamente", + "feedback.snapshot.restore.write-sparse-files": "Escribir archivos dispersos", + "feedback.snapshot.show-individual-snapshots-count": "feedback.snapshot.show-individual-snapshots-count", + "feedback.snapshot.show-individual-snapshots-count_one": "Mostrar {{count}} instantánea individual", + "feedback.snapshot.show-individual-snapshots-count_other": "Mostrar {{count}} instantáneas individuales", + "feedback.snapshot.start-after-previous-snapshot": "La instantánea comenzará después de que se complete la instantánea anterior", + "feedback.snapshot.status.status-overdue": "atrasado", + "feedback.snapshot.status.status-pending": "Pendiente", + "feedback.tab.policies": "Políticas", + "feedback.tab.preferences": "Preferencias", + "feedback.tab.repository": "Depósito", + "feedback.tab.repository-is-not-connected": "El repositorio no está conectado", + "feedback.tab.snapshots": "Copias de respaldo", + "feedback.tab.tasks": "Tareas", + "feedback.task.estimated-results": "{{description}} Bytes: {{bytes}} ({{bytes.excluded}} excluido) Files: {{files}} ({{files.excluded}} excluido) Directories: {{directories}} ({{directories.excluded}} excluido) Errors: {{errors}} ({{errors.ignored}} ignorado)", + "feedback.task.header.counter": "Contador", + "feedback.task.header.value": "Valor", + "feedback.task.logs": "Registros", + "feedback.task.no-tasks-help": "Aquí aparecerá una lista de tareas cuando crees instantáneas, restaures, ejecutes mantenimiento, etc.", + "feedback.task.search-tasks-by-hint": "Buscar registros de tareas por descripción", + "feedback.task.status.task-canceled": "Tarea cancelada", + "feedback.task.status.task-canceled-after": "Tarea cancelada después", + "feedback.task.status.task-canceling": "Cancelando", + "feedback.task.status.task-error": "Error en la tarea", + "feedback.task.status.task-failed-after": "falló después", + "feedback.task.status.task-finished": "Finalizada", + "feedback.task.status.task-finished-in": "Terminado en", + "feedback.task.status.task-running-for": "Tarea en ejecución durante", + "feedback.task.status.task-started": "Iniciada", + "feedback.task.status.task-succeeded-after": "La tarea se completó con éxito después de", + "feedback.task.table.header-description": "Descripción", + "feedback.task.table.header-kind": "Tipo", + "feedback.task.table.header-start-time": "Hora de inicio", + "feedback.task.table.header-status": "Estado", + "feedback.task.tasks-total": "Total", + "feedback.ui.appearance": "Apariencia", + "feedback.ui.appearance-help": "Especifica la apariencia de la interfaz de usuario", + "feedback.ui.appearance-hint": "Selecciona el tamaño de letra", + "feedback.ui.byte-representation-description": "Selecciona la representación de bytes", + "feedback.ui.byte-representation-help": "Especifica la representación de bytes", + "feedback.ui.byte-representation-select": "Selecciona la representación de bytes", + "feedback.ui.pagesize-description": "Tamaño de página", + "feedback.ui.pagesize-help": "Especifica el tamaño de paginación en las tablas", + "feedback.ui.pagesize-hint": "Tamaño de página", + "feedback.ui.theme-description": "Tema", + "feedback.ui.theme-help": "El tema activo actual", + "feedback.ui.theme-select": "Seleccionar tema", + "feedback.validation.invalid-times-of-day": "Horas del día no válidas", + "feedback.validation.optional.valid-number-or-empty": "Debe ser un número válido o vacío.", + "feedback.validation.passwords-dont-match": "Las contraseñas no coinciden", + "feedback.validation.required.directory": "Campo requerido", + "feedback.validation.required.field": "Campo requerido", + "feedback.validation.required.valid-number-or-empty": "Debe ser un número válido o vacío.", + "value.algorithm.eco-disabled": "Desactivado", + "value.algorithm.suffix-not-recommended": "(NO RECOMENDADO)", + "value.algorithm.suffix-recommended": "(RECOMENDADO)", + "value.log.details-0-no-output": "0 - sin salida", + "value.log.details-1-minimal-details": "1 - detalles mínimos", + "value.log.details-10-maximum-details": "10 - detalles máximos", + "value.log.details-5-normal-details": "5 - detalles normales", + "value.log.details-inherit-from-parent": "(heredado de los padres)", + "value.policy.async": "Ejecutar de forma asíncrona, ignorar los fallos", + "value.policy.essential": "debe tener éxito", + "value.policy.inherent-from-parent": "heredar de los padres", + "value.policy.none": "ninguno", + "value.policy.optional": "ignorar los fracasos", + "value.provider.s3.http-connection-insecure": "Usar conexión HTTP (insegura)", + "value.provider.s3.no-tls-verification": "No verificar el certificado TLS", + "value.repository.latest-format": "Último formato", + "value.repository.legacy-format": "Formato heredado compatible con v0.8", + "value.snapshot-frequency.10-minutes": "cada 10 minutos", + "value.snapshot-frequency.12-hours": "cada 12 horas", + "value.snapshot-frequency.15-minutes": "cada 15 minutos", + "value.snapshot-frequency.20-minutes": "cada 20 minutos", + "value.snapshot-frequency.3-hours": "cada 3 horas", + "value.snapshot-frequency.30-minutes": "cada 30 minutos", + "value.snapshot-frequency.6-hours": "cada 6 horas", + "value.snapshot-frequency.hour": "cada hora", + "value.ui.appearance-large": "grande", + "value.ui.appearance-medium": "mediano", + "value.ui.appearance-small": "pequeño", + "value.ui.byte-representation-base10": "Base-10 (KB, MB, GB, TB)", + "value.ui.byte-representation-base2": "Base-2 (KiB, MiB, GiB, TiB)", + "value.ui.theme-dark": "oscuro", + "value.ui.theme-light": "claro", + "value.ui.theme-ocean": "oceánico", + "value.ui.theme-pastel": "pastel", + "value.validation.optional-no": "no", + "value.validation.optional-yes": "Sí" +} diff --git a/public/locales/fr/translation.json b/public/locales/fr/translation.json new file mode 100644 index 00000000..89191828 --- /dev/null +++ b/public/locales/fr/translation.json @@ -0,0 +1,479 @@ +{ + "common.action.back": "Dos", + "common.action.cancel": "Annuler", + "common.action.click-here-to-learn-more": "Cliquez ici pour en savoir plus.", + "common.action.confirm-delete": "Confirmation de la suppression", + "common.action.delete": "Supprimer", + "common.action.next": "Suivant", + "common.action.return": "Retour", + "common.action.stop": "Arrêter", + "common.label.loading": "Chargement...", + "event.cli.copy-to-clipboard": "Copier dans le presse-papier", + "event.cli.show-cli-equivalent": "Cliquez pour afficher l'équivalent CLI", + "event.log.hide-log": "Masquer le journal", + "event.log.show-log": "Afficher le journal", + "event.pin.add-pin": "Ajouter une épingle", + "event.pin.pin-snapshot": "Épingler un instantané", + "event.pin.remove-pin": "Supprimer l'épingle", + "event.pin.update-pin": "Mettre à jour l'épingle", + "event.policy.delete": "Supprimer la stratégie", + "event.policy.edit": "Modifier", + "event.policy.save": "Enregistrer la politique", + "event.policy.set-policy": "Définir la politique", + "event.repository.cancel-connection": "Annuler la connexion", + "event.repository.connect-to-repository": "Se connecter au référentiel", + "event.repository.create-repository": "Créer un référentiel", + "event.repository.disconnect-from-repository": "Déconnexion du répertoire", + "event.repository.hide-advanced-options": "Masquer les options avancées", + "event.repository.show-advanced-options": "Montrer les options avancées", + "event.repository.update-description": "Mettre à jour la description", + "event.snapshot.browse-directory": "Parcourir", + "event.snapshot.delete-selected": "event.snapshot.delete-selected", + "event.snapshot.delete-selected_one": "Voulez-vous supprimer l'instantané {{count}} sélectionné ?", + "event.snapshot.delete-selected_other": "Voulez-vous supprimer les {{count}} instantanés sélectionnés ?", + "event.snapshot.description.enter-new-description": "Entrez une nouvelle description", + "event.snapshot.description.remove-description": "Supprimer la description", + "event.snapshot.description.update-description": "Description de la mise à jour", + "event.snapshot.estimate": "Estimation", + "event.snapshot.fetch-snapshots": "Récupérer des instantanés", + "event.snapshot.history.delete-selected": "Supprimer la sélection ({{count}})", + "event.snapshot.history.delete-snapshot-source": "Supprimer la source de l'instantané", + "event.snapshot.history.deselect-all": "Tout déselectionner", + "event.snapshot.history.select-all-snapshots": "Tout sélectionner", + "event.snapshot.history.update-snapshot-description": "{{description}} : cliquez pour mettre à jour la description de l'instantané.", + "event.snapshot.mount-directory": "Monter en tant que système de fichiers local", + "event.snapshot.new-snapshot": "Nouvel instantané", + "event.snapshot.restore-file-directories": "Restaurer des fichiers et des répertoires", + "event.snapshot.restore.begin-restore": "Démarrer la restauration", + "event.snapshot.restore.go-to-restore-task": "Aller à la tâche de restauration", + "event.snapshot.show-policy": "Politique", + "event.snapshot.snapshot-now": "Instantané maintenant", + "event.snapshot.synchronize": "Synchroniser", + "event.snapshot.unmount-directory": "Démonter", + "event.task.action.cancel": "Annuler la tâche", + "event.task.select.task-all": "Tous", + "event.task.select.task-failed": "Échoué", + "event.task.select.task-running": "En cours", + "feedback.directory.header.directories": "Annuaires", + "feedback.directory.header.files": "Des dossiers", + "feedback.directory.header.last-modification": "Dernière modification", + "feedback.directory.header.name": "Nom", + "feedback.directory.header.size": "Taille", + "feedback.error.common": "Erreur", + "feedback.error.connection": "Erreur de connexion :", + "feedback.header.effective": "Efficace", + "feedback.header.username": "Nom d'utilisateur", + "feedback.pin.add-pin-to-protect": "Ajouter une épingle pour protéger l'instantané de la suppression", + "feedback.pin.do-not-delete": "ne pas supprimer", + "feedback.pin.name-of-the-pin": "Nom de la broche", + "feedback.policy.action.command-mode": "Mode commande", + "feedback.policy.actions.after-folder": "Après le dossier", + "feedback.policy.actions.after-folder-help": "Script à exécuter après le dossier", + "feedback.policy.actions.after-snapshot": "Après l'instantané", + "feedback.policy.actions.after-snapshot-help": "Script à exécuter après l'instantané", + "feedback.policy.actions.before-folder": "Avant le dossier", + "feedback.policy.actions.before-folder-help": "Script à exécuter avant le dossier", + "feedback.policy.actions.before-snapshot": "Avant l'instantané", + "feedback.policy.actions.before-snapshot-help": "Script à exécuter avant l'instantané", + "feedback.policy.actions.timeout": "Temps mort", + "feedback.policy.command-mode-help": "Essentiel (doit réussir ; comportement par défaut), facultatif (les échecs sont tolérés) ou asynchrone (Kopia démarrera l'action mais n'attendra pas qu'elle se termine)", + "feedback.policy.compression.compression-algorithm": "Algorithme de compression", + "feedback.policy.compression.compression-algorithm-help": "Spécifiez l'algorithme de compression à utiliser lors de la capture instantanée des fichiers dans ce répertoire et ses sous-répertoires.", + "feedback.policy.compression.maximal-file-size": "Taille maximale du fichier", + "feedback.policy.compression.maximal-file-size-help": "Les fichiers dont la taille dépasse la valeur fournie ne seront pas compressés", + "feedback.policy.compression.maximal-file-size-hint": "Taille maximale du fichier en octets", + "feedback.policy.compression.minimal-file-size": "Taille minimale du fichier", + "feedback.policy.compression.minimal-file-size-help": "Les fichiers plus petits que la valeur fournie ne seront pas compressés", + "feedback.policy.compression.minimal-file-size-hint": "taille minimale du fichier en octets", + "feedback.policy.compression.never-compress-extensions": "Ne compressez jamais les extensions", + "feedback.policy.compression.never-compress-extensions-help": "Ne compressez jamais les extensions de fichiers suivantes (une extension par ligne)", + "feedback.policy.compression.never-compress-extensions-hint": "par exemple. *.mp4", + "feedback.policy.compression.only-compress-extensions": "Compresser uniquement les extensions", + "feedback.policy.compression.only-compress-extensions-help": "Compressez uniquement les fichiers avec les extensions de fichiers suivantes (une extension par ligne)", + "feedback.policy.compression.only-compress-extensions-hint": "par exemple. *.txt", + "feedback.policy.confirm-delete-policy": "Êtes-vous sûr de vouloir supprimer cette stratégie ?", + "feedback.policy.defined-by": "Défini par", + "feedback.policy.defined-by-this-policy": "Défini par cette politique", + "feedback.policy.error-delete-policy": "Erreur lors de la suppression de la stratégie", + "feedback.policy.error-handling.ignore-directory-errors": "Ignorer les erreurs de répertoire", + "feedback.policy.error-handling.ignore-directory-errors-help": "Traitez les erreurs de lecture de répertoire comme non fatales.", + "feedback.policy.error-handling.ignore-file-errors": "Ignorer les erreurs de fichiers", + "feedback.policy.error-handling.ignore-file-errors-help": "Traitez les erreurs de lecture de fichiers comme non fatales.", + "feedback.policy.error-handling.ignore-unknown-directories": "Ignorer les entrées de répertoire inconnues", + "feedback.policy.error-handling.ignore-unknown-directories-help": "Traitez les entrées de répertoire non reconnues/non prises en charge comme des erreurs non fatales.", + "feedback.policy.error-saving-policy": "Politique d'enregistrement des erreurs", + "feedback.policy.files.ignore-files": "Ignorer les fichiers", + "feedback.policy.files.ignore-files-help": "Liste des noms de fichiers et de répertoires à ignorer.
Voir la documentation sur l'ignorance des fichiers.", + "feedback.policy.files.ignore-files-hint": "par exemple. /fichier.txt", + "feedback.policy.files.ignore-rule-files": "Ignorer les fichiers de règles", + "feedback.policy.files.ignore-rule-files-from-parent-directories": "Ignorer les fichiers de règles des répertoires parents", + "feedback.policy.files.ignore-rule-files-from-parent-directories-help": "Lorsqu'il est défini, les fichiers spécifiant les règles d'ignorer (.kopiaignore, etc.) du répertoire parent sont ignorés", + "feedback.policy.files.ignore-rule-files-help": "Liste de fichiers supplémentaires contenant des règles d'ignorance (chaque fichier configure les règles d'ignorance pour le répertoire et ses sous-répertoires)", + "feedback.policy.files.ignore-rule-files-hint": "par exemple. .kopiaignore", + "feedback.policy.files.ignore-rules-from-parent-directories": "Ignorer les règles des répertoires parents", + "feedback.policy.files.ignore-rules-from-parent-directories-help": "Lorsqu'elles sont définies, les règles d'ignorance du répertoire parent sont ignorées", + "feedback.policy.files.ignore-well-known-cache-directories": "Ignorer les répertoires de cache bien connus", + "feedback.policy.files.ignore-well-known-cache-directories-help": "Ignorer les répertoires contenant CACHEDIR.TAG et similaires", + "feedback.policy.files.scan-only-one-filesystem": "Analyser un seul système de fichiers", + "feedback.policy.files.scan-only-one-filesystem-help": "Ne franchissez pas les limites du système de fichiers lors de la création d'un instantané", + "feedback.policy.find-count": "feedback.policy.find-count", + "feedback.policy.find-count_one": "{{count}} politiques correspondant aux critères ont été trouvées", + "feedback.policy.find-count_other": "{{count}} politiques correspondant aux critères ont été trouvées", + "feedback.policy.find-hint": "Entrez dans le répertoire pour rechercher ou définir une politique", + "feedback.policy.find-none": "Aucune politique trouvée", + "feedback.policy.find-none-create": "Aucune stratégie trouvée pour le répertoire {{path}}. \nVeuillez configurer une nouvelle politique.", + "feedback.policy.header.actions": "Actions", + "feedback.policy.header.compression": "Compression", + "feedback.policy.header.defined": "Défini", + "feedback.policy.header.error-handling": "La gestion des erreurs", + "feedback.policy.header.files": "Des dossiers", + "feedback.policy.header.folder-actions": "Actions sur les dossiers", + "feedback.policy.header.host": "Hôte", + "feedback.policy.header.logging": "Enregistrement", + "feedback.policy.header.other": "Autre", + "feedback.policy.header.path": "Chemin", + "feedback.policy.header.scheduling": "Planification", + "feedback.policy.header.snapshot-action": "Actions d'instantané", + "feedback.policy.header.snapshot-retention": "Conservation des instantanés", + "feedback.policy.header.upload": "Télécharger", + "feedback.policy.kind.all": "Toutes les politiques", + "feedback.policy.kind.applicable": "Politiques applicables", + "feedback.policy.kind.global": "Politiques mondiales", + "feedback.policy.kind.local": "Politiques locales", + "feedback.policy.kind.per-host-policies": "Politiques par hôte", + "feedback.policy.kind.per-user-policies": "Politiques par utilisateur", + "feedback.policy.logging.cache-hit": "Accès au cache", + "feedback.policy.logging.cache-hit-help": "Consigner la verbosité lorsqu'un cache est utilisé au lieu de télécharger le fichier", + "feedback.policy.logging.cache-miss": "Manque de cache", + "feedback.policy.logging.cache-miss-help": "Enregistrer la verbosité lorsqu'un cache ne peut pas être utilisé et qu'un fichier doit être haché", + "feedback.policy.logging.directory-ignored": "Répertoire ignoré", + "feedback.policy.logging.directory-ignored-help": "Consigner la verbosité lorsqu'un répertoire est ignoré", + "feedback.policy.logging.directory-snapshotted": "Répertoire instantané", + "feedback.policy.logging.directory-snapshotted-help": "Consigner la verbosité lorsqu'un répertoire est instantané", + "feedback.policy.logging.file-ignored": "Fichier ignoré", + "feedback.policy.logging.file-ignored-help": "Consigner la verbosité lorsqu'un fichier, un lien symbolique, etc. est ignoré", + "feedback.policy.logging.file-snapshotted": "Fichier instantané", + "feedback.policy.logging.file-snapshotted-help": "Consigner la verbosité lorsqu'un fichier, un lien symbolique, etc. est capturé", + "feedback.policy.other.disable-parent-policy-evaluation": "Désactiver l'évaluation de la stratégie parentale", + "feedback.policy.other.disable-parent-policy-evaluation-help": "Empêche toute stratégie parent d'affecter ce répertoire et ses sous-répertoires", + "feedback.policy.other.json-representation": "Représentation JSON", + "feedback.policy.other.json-representation-help": "C'est la représentation interne d'une politique", + "feedback.policy.policies-defined-by-path-absolute": "Les stratégies ne peuvent être définies que pour des chemins absolus.", + "feedback.policy.retention.annual-snapshot-retain": "Annuel", + "feedback.policy.retention.annual-snapshot-retain-help": "Combien d’instantanés annuels conserver par source. \nLe dernier instantané de chaque année civile sera conservé", + "feedback.policy.retention.annual-snapshot-retain-hint": "Nombre d'instantanés annuels", + "feedback.policy.retention.daily-snapshot-retain": "Tous les jours", + "feedback.policy.retention.daily-snapshot-retain-help": "Combien d’instantanés quotidiens conserver par source. \nLe dernier instantané de chaque jour sera conservé", + "feedback.policy.retention.daily-snapshot-retain-hint": "Nombre d'instantanés quotidiens", + "feedback.policy.retention.hourly-snapshot-retain": "Horaire", + "feedback.policy.retention.hourly-snapshot-retain-help": "Combien d’instantanés horaires conserver par source. \nLe dernier instantané de chaque heure sera conservé", + "feedback.policy.retention.hourly-snapshot-retain-hint": "nombre d'instantanés horaires", + "feedback.policy.retention.ignore-identical-snapshots": "Ignorer les instantanés identiques", + "feedback.policy.retention.ignore-identical-snapshots-help": "Ne PAS enregistrer un instantané lorsqu'aucun fichier n'a été modifié", + "feedback.policy.retention.keep-latest-help": "nombre de derniers instantanés", + "feedback.policy.retention.latest-snapshot-retain": "Derniers instantanés", + "feedback.policy.retention.latest-snapshot-retain-help": "Nombre d'instantanés les plus récents à conserver par source", + "feedback.policy.retention.monthly-snapshot-retain": "Mensuel", + "feedback.policy.retention.monthly-snapshot-retain-help": "Combien d’instantanés mensuels conserver par source. \nLe dernier instantané de chaque mois civil sera conservé", + "feedback.policy.retention.monthly-snapshot-retain-hint": "Nombre d'instantanés mensuels", + "feedback.policy.retention.weekly-snapshot-retain": "Hebdomadaire", + "feedback.policy.retention.weekly-snapshot-retain-help": "Combien d’instantanés hebdomadaires conserver par source. \nLe dernier instantané de chaque semaine sera conservé", + "feedback.policy.retention.weekly-snapshot-retain-hint": "Nombre d'instantanés hebdomadaires", + "feedback.policy.scheduling.cron-expressions": "Expressions Cron", + "feedback.policy.scheduling.cron-expressions-hint": "minute heure jour mois jour de la semaine", + "feedback.policy.scheduling.cron-help": "Planifications d'instantanés utilisant la syntaxe crontab UNIX (une par ligne) :
Voir les détails sur les formats pris en charge.", + "feedback.policy.scheduling.manual-snapshots-only": "Instantanés manuels uniquement", + "feedback.policy.scheduling.manual-snapshots-only-help": "Créez uniquement des instantanés manuellement (désactive les instantanés planifiés)", + "feedback.policy.scheduling.missed-snapshots-startup": "Exécuter des instantanés manqués au démarrage", + "feedback.policy.scheduling.missed-snapshots-startup-help": "Exécutez immédiatement tous les instantanés manqués au démarrage de kopia (uniquement pertinent pour les instantanés d'heure)", + "feedback.policy.scheduling.no-upcoming-snapshots": "Aucun instantané à venir", + "feedback.policy.scheduling.snapshot-frequency": "Fréquence des instantanés", + "feedback.policy.scheduling.snapshot-frequency-help": "À quelle fréquence créer des instantanés dans KopiaUI ou le serveur Kopia (n'a aucun effet en dehors du mode serveur)", + "feedback.policy.scheduling.times-of-day": "Heures du jour", + "feedback.policy.scheduling.times-of-day-help": "Créez des instantanés aux heures spécifiées de la journée (format 24 heures)", + "feedback.policy.scheduling.times-of-day-hint": "par exemple. 17h00", + "feedback.policy.scheduling.upcoming": "A venir", + "feedback.policy.scheduling.upcoming-snapshots": "Instantanés à venir", + "feedback.policy.scheduling.upcoming-snapshots-help": "Heures des instantanés à venir calculées en fonction des paramètres de politique", + "feedback.policy.time-of-day.invalid": "Heure de la journée non valide : {{tod}}", + "feedback.policy.timeout-help": "Délai d'attente en secondes avant que Kopia ne tue le processus", + "feedback.policy.upload.maximum-parallel-file-reads": "Nombre maximal de lectures de fichiers parallèles", + "feedback.policy.upload.maximum-parallel-file-reads-help": "Nombre maximum de fichiers qui seront lus en parallèle (par défaut, le nombre de processeurs logiques)", + "feedback.policy.upload.maximum-parallel-file-reads-hint": "nombre maximum de lectures de fichiers parallèles", + "feedback.policy.upload.maximum-parallel-snapshots": "Nombre maximal d'instantanés parallèles", + "feedback.policy.upload.maximum-parallel-snapshots-help": "Nombre maximum d'instantanés pouvant être téléchargés simultanément", + "feedback.policy.upload.maximum-parallel-snapshots-hint-set": "nombre maximum d'instantanés parallèles", + "feedback.policy.upload.maximum-parallel-snapshots-hint-unset": "doit être spécifié à l'aide d'une stratégie globale, utilisateur ou hôte", + "feedback.prodiver.gcs.paste-json-credentials": "Collez les informations d'identification JSON ici", + "feedback.provider.azure-blob-storage": "Stockage Blob Azure", + "feedback.provider.azure.access-key": "Clef d'accès", + "feedback.provider.azure.azure-storage-domain": "Domaine de stockage Azure", + "feedback.provider.azure.container": "Récipient", + "feedback.provider.azure.enter-access-key": "Entrez la clé d'accès secrète", + "feedback.provider.azure.enter-azure-storage-domain": "Entrez le domaine de stockage ou laissez vide pour « blob.core.windows.net » par défaut.", + "feedback.provider.azure.enter-container-name": "Entrez le nom du conteneur", + "feedback.provider.azure.enter-object-name-prefix": "Entrez le préfixe du nom de l'objet ou laissez vide", + "feedback.provider.azure.enter-sas-token": "Entrez le jeton SAS secret", + "feedback.provider.azure.enter-storage-account": "Saisissez le nom du compte de stockage", + "feedback.provider.azure.object-name-prefix": "Préfixe du nom de l'objet", + "feedback.provider.azure.sas-token": "Jeton SAS", + "feedback.provider.azure.storage-account": "Compte de stockage", + "feedback.provider.b2.bucket-name": "Godet B2", + "feedback.provider.b2.enter-account-key": "Entrez l'application secrète ou la clé de compte", + "feedback.provider.b2.enter-account-key-id": "Saisissez l'ID de la clé de l'application ou du compte", + "feedback.provider.b2.enter-bucket-name": "Saisissez le nom du compartiment", + "feedback.provider.b2.enter-object-name-prefix": "Entrez le préfixe du nom de l'objet ou laissez vide", + "feedback.provider.b2.key": "Clé", + "feedback.provider.b2.key-id": "ID de clé", + "feedback.provider.b2.object-name-prefix": "Préfixe du nom de l'objet", + "feedback.provider.backblaze-b2": "Backblaze B2", + "feedback.provider.filesystem.directory-path": "Chemin du répertoire", + "feedback.provider.filesystem.enter-directory-path": "Entrez le chemin du répertoire dans lequel vous souhaitez stocker les fichiers du référentiel", + "feedback.provider.gcs.bucket-name": "Godet GCS", + "feedback.provider.gcs.credentials-file": "Fichier d'informations d'identification", + "feedback.provider.gcs.credentials-json": "Identifiants JSON", + "feedback.provider.gcs.enter-bucket-name": "Saisissez le nom du compartiment", + "feedback.provider.gcs.enter-credentials-file-name": "Entrez le nom du fichier JSON d'informations d'identification", + "feedback.provider.gcs.enter-object-name-prefix": "Entrez le préfixe du nom de l'objet ou laissez vide", + "feedback.provider.gcs.object-name-prefix": "Préfixe du nom de l'objet", + "feedback.provider.google-cloud-storage": "Stockage Google Cloud", + "feedback.provider.kopia-repository-server": "Serveur de référentiel Kopia", + "feedback.provider.local-directory-or-nas": "Répertoire local ou NAS", + "feedback.provider.rclone-remote": "Rclone à distance", + "feedback.provider.rclone.rclone-executable-path": "Chemin de l'exécutable Rclone", + "feedback.provider.rclone.rclone-executable-path-hint": "Entrez le chemin de l'exécutable rclone", + "feedback.provider.rclone.rclone-remote-path": "Chemin distant Rclone", + "feedback.provider.rclone.rclone-remote-path-hint": "Entrez  :", + "feedback.provider.repositoryserver.enter-server-certificate-fingerprint": "Saisissez l'empreinte digitale du certificat de serveur de confiance imprimée au démarrage du serveur", + "feedback.provider.repositoryserver.enter-server-url": "Entrez l'URL du serveur (https://:port)", + "feedback.provider.repositoryserver.server-address": "Adresse du serveur", + "feedback.provider.repositoryserver.server-certificate-fingerprint": "Empreinte digitale du certificat de serveur de confiance (SHA256)", + "feedback.provider.repositorytoken.paste-token": "Coller le jeton de connexion", + "feedback.provider.repositorytoken.token": "Jeton", + "feedback.provider.required-either-key-file": "L'un des éléments suivants : Mot de passe, Fichier clé ou Données clés est requis.", + "feedback.provider.required-either-known-host-data": "Le Fichier des hôtes connus ou les Données des hôtes connus sont requis, mais pas les deux.", + "feedback.provider.s3-or-compatible-storage": "Amazon S3 ou stockage compatible", + "feedback.provider.s3.access-key-id": "ID de clé d'accès", + "feedback.provider.s3.access-key-id-hint": "Entrez l'ID de la clé d'accès", + "feedback.provider.s3.bucket-name": "Seau", + "feedback.provider.s3.bucket-name-hint": "Saisissez le nom du compartiment", + "feedback.provider.s3.enter-object-name-prefix-hint": "Entrez le préfixe du nom de l'objet ou laissez vide", + "feedback.provider.s3.object-name-prefix": "Préfixe du nom de l'objet", + "feedback.provider.s3.override-region": "Remplacer la région", + "feedback.provider.s3.override-region-hint": "Entrez une région spécifique (par exemple, us-west-1) ou laissez vide", + "feedback.provider.s3.secret-access-key": "Clé d'accès secrète", + "feedback.provider.s3.secret-access-key-hint": "Entrez la clé d'accès secrète", + "feedback.provider.s3.server-endpoint": "Point de terminaison du serveur", + "feedback.provider.s3.server-endpoint-hint": "Saisissez l'adresse du serveur (par exemple, s3.amazonaws.com)", + "feedback.provider.s3.session-token": "Jeton de session", + "feedback.provider.s3.session-token-hint": "Entrez le jeton de session ou laissez vide", + "feedback.provider.sftp-key-data": "Données clé", + "feedback.provider.sftp-key-data-hint": "Collez le contenu du fichier de clé", + "feedback.provider.sftp-server": "Serveur SFTP", + "feedback.provider.sftp.enter-password": "Entrer le mot de passe", + "feedback.provider.sftp.enter-path-host-file": "Entrez le chemin d'accès au fichier known_hosts", + "feedback.provider.sftp.enter-path-to-key-file": "Entrez le chemin d'accès au fichier de clé", + "feedback.provider.sftp.enter-remote-path": "Entrez le chemin distant vers le référentiel, par exemple « /mnt/data/repository »", + "feedback.provider.sftp.enter-ssh-arguments": "Entrez les arguments de la commande SSH (« user@host -s sftp » sera ajouté automatiquement)", + "feedback.provider.sftp.enter-ssh-host-name": "nom d'hôte ssh (par exemple, example.com)", + "feedback.provider.sftp.host": "Hôte", + "feedback.provider.sftp.known-host-data": "Données sur les hôtes connus", + "feedback.provider.sftp.launch-external-ssh-command": "Lancer une commande SSH externe sans mot de passe", + "feedback.provider.sftp.launch-external-ssh-command-hint": "Par défaut, Kopia se connecte au serveur à l'aide d'un client SSH interne qui prend en charge des options limitées. \nAlternativement, il peut lancer une commande SSH externe sans mot de passe, qui prend en charge des options supplémentaires, mais est généralement moins efficace que le client intégré.", + "feedback.provider.sftp.password": "Mot de passe", + "feedback.provider.sftp.paste-content-of-known-host": "Collez le contenu du fichier known_hosts", + "feedback.provider.sftp.path": "Chemin", + "feedback.provider.sftp.path-host-file": "Chemin d'accès au fichier known_hosts", + "feedback.provider.sftp.path-key-file": "Chemin d'accès au fichier de clé", + "feedback.provider.sftp.port": "Port", + "feedback.provider.sftp.port-number": "Numéro de port (par exemple, 22)", + "feedback.provider.sftp.provide-passwordless-ssh-command": "Fournissez la commande SSH sans mot de passe à exécuter (généralement « ssh »)", + "feedback.provider.sftp.ssh-arguments": "Arguments SSH", + "feedback.provider.sftp.ssh-command": "Commande SSH", + "feedback.provider.sftp.user": "Utilisateur", + "feedback.provider.sftp.user-name": "Nom d'utilisateur", + "feedback.provider.use-repository-token": "Utiliser le jeton de référentiel", + "feedback.provider.webdav-server": "Serveur WebDAV", + "feedback.provider.webdav.enter-password": "Entrer le mot de passe", + "feedback.provider.webdav.enter-username": "Saisissez votre nom d'utilisateur", + "feedback.provider.webdav.password": "Mot de passe", + "feedback.provider.webdav.server-url": "URL du serveur WebDAV", + "feedback.provider.webdav.username": "Nom d'utilisateur", + "feedback.repository.additional-parameters-hint": "Des paramètres supplémentaires peuvent être définis lors de la création du référentiel à l'aide de la ligne de commande.", + "feedback.repository.attribute.algorithm-eco": "Algorithme de correction d'erreur", + "feedback.repository.attribute.algorithm-encryption": "Algorithme de chiffrement", + "feedback.repository.attribute.algorithm-hash": "Algorithme de hachage", + "feedback.repository.attribute.algorithm-splitter": "Algorithme de découpage", + "feedback.repository.attribute.config-file": "Fichier de configuration", + "feedback.repository.attribute.connected-as": "Connecté en tant que", + "feedback.repository.attribute.internal-compression": "Compression interne", + "feedback.repository.attribute.repository-eco": "Surcoût de correction d'erreurs", + "feedback.repository.attribute.repository-format": "Format du répertoire", + "feedback.repository.attribute.repository-provider": "Fournisseur", + "feedback.repository.attribute.server-url": "URL du serveur", + "feedback.repository.configuration": "Configuration du stockage", + "feedback.repository.connect-as": "Se connecter en tant que", + "feedback.repository.connect-in-read-only-mode": "Connectez-vous en mode lecture seule", + "feedback.repository.connect-in-read-only-mode-hint": "Le mode lecture seule empêche toute modification du référentiel.", + "feedback.repository.connect-to-repository": "Se connecter au référentiel", + "feedback.repository.create-repository-new": "Créer un nouveau référentiel", + "feedback.repository.create-repository-new-help": "Entrez un mot de passe fort pour créer le référentiel Kopia dans le stockage fourni.", + "feedback.repository.eco-disabled": "Désactivé", + "feedback.repository.eec-warning": "[EXPERIMENTAL] La correction d'erreurs peut aider à protéger contre certains types de corruption de données dues à des retournements de bits spontanés dans le support de stockage.", + "feedback.repository.encryption": "Chiffrement", + "feedback.repository.enter-repository-password": "Entrez le mot de passe du référentiel", + "feedback.repository.hostname": "Nom d'hôte", + "feedback.repository.hostname-hint": "Remplacez ceci lors de la restauration d'un instantané pris sur une autre machine", + "feedback.repository.internal-compression-supported-no": "non", + "feedback.repository.internal-compression-supported-yes": "oui", + "feedback.repository.kopia-server-parameters": "Paramètres du serveur Kopia", + "feedback.repository.name-default": "Mon référentiel", + "feedback.repository.override-hint": "Pour remplacer, cliquez sur \"Afficher les options avancées\".", + "feedback.repository.provider-selection": "Sélectionnez le type de stockage", + "feedback.repository.provider-selection-hint": "Pour vous connecter à un référentiel ou en créer un, sélectionnez le type de stockage préféré :", + "feedback.repository.repository-description": "Description du référentiel", + "feedback.repository.repository-description-help": "Aide à distinguer plusieurs référentiels connectés", + "feedback.repository.repository-description-hint": "Entrez la description du référentiel", + "feedback.repository.repository-description-required": "La description du répertoire est obligatoire", + "feedback.repository.repository-initializing": "Initialisation du répertoire...", + "feedback.repository.repository-is-read-only": "Le répertoire est en lecture seule", + "feedback.repository.repository-password": "Mot de passe du référentiel", + "feedback.repository.repository-password-confirm": "Confirmer le mot de passe du référentiel", + "feedback.repository.repository-password-confirm-again": "entrez à nouveau le mot de passe du référentiel", + "feedback.repository.repository-password-help": "Utilisé pour chiffrer le contenu du référentiel", + "feedback.repository.repository-token-enter": "Entrez le jeton de référentiel", + "feedback.repository.server-password": "Mot de passe du serveur", + "feedback.repository.server-password-hint": "Entrez le mot de passe pour vous connecter au serveur", + "feedback.repository.status-connected": "Connecté au répertoire", + "feedback.repository.username": "Nom d'utilisateur", + "feedback.repository.username-hint": "Remplacez ceci lors de la restauration d'un instantané pris par un autre utilisateur", + "feedback.snapshot.create.enter-path-to-snapshot-hint": "Entrez le chemin d'accès à l'instantané", + "feedback.snapshot.create.must-specify-path": "Doit spécifier le répertoire dans lequel prendre l'instantané.", + "feedback.snapshot.create.snapshot-new": "Nouvel instantané", + "feedback.snapshot.description": "Description", + "feedback.snapshot.description.snapshot-description": "Description de l'instantané", + "feedback.snapshot.directory.browsing-not-supported": "La navigation dans les répertoires n'est pas prise en charge dans un navigateur Web. \nUtilisez l'interface utilisateur de Kopia.", + "feedback.snapshot.directory.restore-all-files-help": "Vous pouvez monter/restaurer tous les fichiers et répertoires que vous voyez ci-dessous ou restaurer les fichiers individuellement.", + "feedback.snapshot.header.actions": "Actions", + "feedback.snapshot.header.details": "Détails", + "feedback.snapshot.header.directories": "Directeurs", + "feedback.snapshot.header.files": "Des dossiers", + "feedback.snapshot.header.last-snapshot": "Dernier instantané", + "feedback.snapshot.header.next-snapshot": "Instantané suivant", + "feedback.snapshot.header.retention": "Rétention", + "feedback.snapshot.header.root": "Racine", + "feedback.snapshot.header.selected": "Choisi", + "feedback.snapshot.header.snapshot-owner": "Propriétaire", + "feedback.snapshot.header.snapshot-path": "Chemin", + "feedback.snapshot.header.snapshot-size": "Taille", + "feedback.snapshot.header.start-time": "Heure de début", + "feedback.snapshot.header.status": "Statut", + "feedback.snapshot.history.snapshot-displaying": "Affichage", + "feedback.snapshot.history.wipe-all-snapshots": "Effacez tous les instantanés et la stratégie de cette source.", + "feedback.snapshot.restore.continue-on-errors": "Continuer en cas d'erreurs", + "feedback.snapshot.restore.continue-on-errors-help": "Lorsqu'une erreur de restauration se produit, essayez de continuer au lieu d'échouer rapidement.", + "feedback.snapshot.restore.destination": "Destination", + "feedback.snapshot.restore.destination-help": "Vous pouvez également restaurer vers un fichier .zip ou .tar en fournissant l'extension appropriée.", + "feedback.snapshot.restore.destination-hint": "Entrez le chemin de destination", + "feedback.snapshot.restore.disable-zip-compression": "Désactiver la compression ZIP", + "feedback.snapshot.restore.disable-zip-compression-help": "Ne pas compresser lors de la restauration vers un fichier ZIP (plus rapide).", + "feedback.snapshot.restore.minimal-file-size-for-shallow-restore": "Taille minimale des fichiers pour une restauration superficielle", + "feedback.snapshot.restore.overwrite-directory": "Écraser les répertoires", + "feedback.snapshot.restore.overwrite-files": "Écraser les fichiers", + "feedback.snapshot.restore.overwrite-symbolic-links": "Écraser les liens symboliques", + "feedback.snapshot.restore.restore-file-modification-time": "Restaurer l'heure de modification des fichiers", + "feedback.snapshot.restore.restore-file-ownership": "Restaurer la propriété des fichiers", + "feedback.snapshot.restore.restore-file-permissions": "Restaurer les permissions des fichiers", + "feedback.snapshot.restore.shallow-restore-at-depth": "Restauration superficielle à une profondeur spécifique", + "feedback.snapshot.restore.skip-previously-restored-files": "Ignorer les fichiers et liens symboliques déjà restaurés", + "feedback.snapshot.restore.snapshot-restore": "Restaurer", + "feedback.snapshot.restore.write-files-atomically": "Écrire les fichiers de manière atomique", + "feedback.snapshot.restore.write-sparse-files": "Écrire les fichiers en mode sparse", + "feedback.snapshot.show-individual-snapshots-count": "feedback.snapshot.show-individual-snapshots-count", + "feedback.snapshot.show-individual-snapshots-count_one": "Afficher {{count}} instantané individuel", + "feedback.snapshot.show-individual-snapshots-count_other": "Afficher {{count}} instantanés individuels", + "feedback.snapshot.start-after-previous-snapshot": "L'instantané démarrera après la fin de l'instantané précédent", + "feedback.snapshot.status.status-overdue": "en retard", + "feedback.snapshot.status.status-pending": "En attente", + "feedback.tab.policies": "Politiques", + "feedback.tab.preferences": "Préférences", + "feedback.tab.repository": "Répertoire", + "feedback.tab.repository-is-not-connected": "Le référentiel n'est pas connecté", + "feedback.tab.snapshots": "Instantanés", + "feedback.tab.tasks": "Tâches", + "feedback.task.estimated-results": "{{description}} Bytes: {{bytes}} ({{bytes.excluded}} exclu) Files: {{files}} ({{files.excluded}} exclu) Directories: {{directories}} ({{directories.excluded}} exclu) Errors: {{errors}} ({{errors.ignored}} ignoré)", + "feedback.task.header.counter": "Compteur", + "feedback.task.header.value": "Valeur", + "feedback.task.logs": "Journaux", + "feedback.task.no-tasks-help": "Une liste de tâches apparaîtra ici lorsque vous créerez des instantanés, restaurerez, exécuterez des opérations de maintenance, etc.", + "feedback.task.search-tasks-by-hint": "Rechercher les journaux de tâches par description", + "feedback.task.status.task-canceled": "Tâche annulée", + "feedback.task.status.task-canceled-after": "Tâche annulée après", + "feedback.task.status.task-canceling": "Annulation en cours", + "feedback.task.status.task-error": "Erreur de tâche", + "feedback.task.status.task-failed-after": "Échec après", + "feedback.task.status.task-finished": "Terminé", + "feedback.task.status.task-finished-in": "Terminé en", + "feedback.task.status.task-running-for": "Tâche en cours depuis", + "feedback.task.status.task-started": "Démarré", + "feedback.task.status.task-succeeded-after": "Tâche réussie après", + "feedback.task.table.header-description": "Description", + "feedback.task.table.header-kind": "Type", + "feedback.task.table.header-start-time": "Heure de début", + "feedback.task.table.header-status": "Statut", + "feedback.task.tasks-total": "Total", + "feedback.ui.appearance": "Apparence", + "feedback.ui.appearance-help": "Spécifie l'apparence de l'interface utilisateur", + "feedback.ui.appearance-hint": "Sélectionnez la taille de police", + "feedback.ui.byte-representation-description": "Sélectionnez la représentation des octets", + "feedback.ui.byte-representation-help": "Spécifie la représentation des octets", + "feedback.ui.byte-representation-select": "Sélectionnez la représentation des octets", + "feedback.ui.pagesize-description": "Taille de la page", + "feedback.ui.pagesize-help": "Spécifie la taille de pagination dans les tableaux", + "feedback.ui.pagesize-hint": "Taille de la page", + "feedback.ui.theme-description": "Thème", + "feedback.ui.theme-help": "Le thème actif actuel", + "feedback.ui.theme-select": "Sélectionnez un thème", + "feedback.validation.invalid-times-of-day": "Heures de la journée invalides", + "feedback.validation.optional.valid-number-or-empty": "Doit être un numéro valide ou vide", + "feedback.validation.passwords-dont-match": "Les mots de passe ne correspondent pas", + "feedback.validation.required.directory": "champs requis", + "feedback.validation.required.field": "champs requis", + "feedback.validation.required.valid-number-or-empty": "Doit être un numéro valide ou vide", + "value.algorithm.eco-disabled": "Désactivé", + "value.algorithm.suffix-not-recommended": "(NON RECOMMANDÉ)", + "value.algorithm.suffix-recommended": "(RECOMMANDÉ)", + "value.log.details-0-no-output": "0 - aucune sortie", + "value.log.details-1-minimal-details": "1 - détails minimes", + "value.log.details-10-maximum-details": "10 - détails maximum", + "value.log.details-5-normal-details": "5 - détails normaux", + "value.log.details-inherit-from-parent": "(hériter du parent)", + "value.policy.async": "Exécutez de manière asynchrone, ignorez les échecs", + "value.policy.essential": "Doit réussir", + "value.policy.inherent-from-parent": "hériter du parent", + "value.policy.none": "aucun", + "value.policy.optional": "Ignorer les échecs", + "value.provider.s3.http-connection-insecure": "Utiliser une connexion HTTP (non sécurisée)", + "value.provider.s3.no-tls-verification": "Ne pas vérifier le certificat TLS", + "value.repository.latest-format": "Dernier format", + "value.repository.legacy-format": "Format hérité compatible avec la v0.8", + "value.snapshot-frequency.10-minutes": "toutes les 10 minutes", + "value.snapshot-frequency.12-hours": "toutes les 12 heures", + "value.snapshot-frequency.15-minutes": "toutes les 15 minutes", + "value.snapshot-frequency.20-minutes": "toutes les 20 minutes", + "value.snapshot-frequency.3-hours": "toutes les 3 heures", + "value.snapshot-frequency.30-minutes": "toutes les 30 minutes", + "value.snapshot-frequency.6-hours": "toutes les 6 heures", + "value.snapshot-frequency.hour": "Toutes les heures", + "value.ui.appearance-large": "grande", + "value.ui.appearance-medium": "moyenne", + "value.ui.appearance-small": "petite", + "value.ui.byte-representation-base10": "Base-10 (Ko, Mo, Go, To)", + "value.ui.byte-representation-base2": "Base-2 (Kio, MiB, GiB, TiB)", + "value.ui.theme-dark": "sombre", + "value.ui.theme-light": "clair", + "value.ui.theme-ocean": "océan", + "value.ui.theme-pastel": "pastel", + "value.validation.optional-no": "non", + "value.validation.optional-yes": "Oui" +} diff --git a/public/locales/it/translation.json b/public/locales/it/translation.json new file mode 100644 index 00000000..28f68e50 --- /dev/null +++ b/public/locales/it/translation.json @@ -0,0 +1,479 @@ +{ + "common.action.back": "Indietro", + "common.action.cancel": "Annulla", + "common.action.click-here-to-learn-more": "Clicca qui per saperne di più.", + "common.action.confirm-delete": "Conferma cancellazione", + "common.action.delete": "Eliminare", + "common.action.next": "Prossimo", + "common.action.return": "Ritorno", + "common.action.stop": "Arresta", + "common.label.loading": "Caricamento...", + "event.cli.copy-to-clipboard": "Copia negli appunti", + "event.cli.show-cli-equivalent": "Fare clic per mostrare l'equivalente CLI", + "event.log.hide-log": "Nascondi log", + "event.log.show-log": "Mostra log", + "event.pin.add-pin": "Aggiungi puntina", + "event.pin.pin-snapshot": "Pin istantanea", + "event.pin.remove-pin": "Rimuovi perno", + "event.pin.update-pin": "Aggiorna perno", + "event.policy.delete": "Elimina politica", + "event.policy.edit": "Modificare", + "event.policy.save": "Salva politica", + "event.policy.set-policy": "Imposta la politica", + "event.repository.cancel-connection": "Annulla connessione", + "event.repository.connect-to-repository": "Connettiti al deposito", + "event.repository.create-repository": "Crea archivio", + "event.repository.disconnect-from-repository": "Disconnetti dal repository", + "event.repository.hide-advanced-options": "Nascondi opzioni avanzate", + "event.repository.show-advanced-options": "Mostra opzioni avanzate", + "event.repository.update-description": "Aggiorna descrizione", + "event.snapshot.browse-directory": "Navigare", + "event.snapshot.delete-selected": "event.snapshot.delete-selected", + "event.snapshot.delete-selected_one": "Vuoi eliminare lo snapshot {{count}} selezionato?", + "event.snapshot.delete-selected_other": "Vuoi eliminare le istantanee {{count}} selezionate?", + "event.snapshot.description.enter-new-description": "Inserisci una nuova descrizione", + "event.snapshot.description.remove-description": "Rimuovi descrizione", + "event.snapshot.description.update-description": "Descrizione dell'aggiornamento", + "event.snapshot.estimate": "Stima", + "event.snapshot.fetch-snapshots": "Recupera istantanee", + "event.snapshot.history.delete-selected": "Elimina selezionati ({{count}})", + "event.snapshot.history.delete-snapshot-source": "Elimina origine istantanea", + "event.snapshot.history.deselect-all": "Deselezionare tutto", + "event.snapshot.history.select-all-snapshots": "Seleziona tutto", + "event.snapshot.history.update-snapshot-description": "{{description}}: fai clic per aggiornare la descrizione dell'istantanea.", + "event.snapshot.mount-directory": "Monta come file system locale", + "event.snapshot.new-snapshot": "Nuova Istantanea", + "event.snapshot.restore-file-directories": "Ripristina file e directory", + "event.snapshot.restore.begin-restore": "Inizia il ripristino", + "event.snapshot.restore.go-to-restore-task": "Vai a Ripristina attività", + "event.snapshot.show-policy": "Politica", + "event.snapshot.snapshot-now": "Scatta subito un'istantanea", + "event.snapshot.synchronize": "Sincronizza", + "event.snapshot.unmount-directory": "Smonta", + "event.task.action.cancel": "Annulla attività", + "event.task.select.task-all": "Tutte", + "event.task.select.task-failed": "Fallite", + "event.task.select.task-running": "In esecuzione", + "feedback.directory.header.directories": "Directory", + "feedback.directory.header.files": "File", + "feedback.directory.header.last-modification": "Ultima modifica", + "feedback.directory.header.name": "Nome", + "feedback.directory.header.size": "Misurare", + "feedback.error.common": "Errore", + "feedback.error.connection": "Errore di connessione:", + "feedback.header.effective": "Efficace", + "feedback.header.username": "Nome utente", + "feedback.pin.add-pin-to-protect": "Aggiungi un segnaposto per proteggere l'istantanea dall'eliminazione", + "feedback.pin.do-not-delete": "non cancellare", + "feedback.pin.name-of-the-pin": "Nome del perno", + "feedback.policy.action.command-mode": "Modalità di comando", + "feedback.policy.actions.after-folder": "Dopo la cartella", + "feedback.policy.actions.after-folder-help": "Script da eseguire dopo la cartella", + "feedback.policy.actions.after-snapshot": "Dopo l'istantanea", + "feedback.policy.actions.after-snapshot-help": "Script da eseguire dopo lo snapshot", + "feedback.policy.actions.before-folder": "Prima della cartella", + "feedback.policy.actions.before-folder-help": "Script da eseguire prima della cartella", + "feedback.policy.actions.before-snapshot": "Prima dell'istantanea", + "feedback.policy.actions.before-snapshot-help": "Script da eseguire prima dello snapshot", + "feedback.policy.actions.timeout": "Tempo scaduto", + "feedback.policy.command-mode-help": "Essenziale (deve avere successo; comportamento predefinito), facoltativo (gli errori sono tollerati) o asincrono (Kopia avvierà l'azione ma non aspetterà che finisca)", + "feedback.policy.compression.compression-algorithm": "Algoritmo di compressione", + "feedback.policy.compression.compression-algorithm-help": "Specificare l'algoritmo di compressione da utilizzare durante lo snapshot dei file in questa directory e nelle sottodirectory", + "feedback.policy.compression.maximal-file-size": "Dimensione massima del file", + "feedback.policy.compression.maximal-file-size-help": "I file la cui dimensione supera il valore fornito non verranno compressi", + "feedback.policy.compression.maximal-file-size-hint": "Dimensione massima del file in byte", + "feedback.policy.compression.minimal-file-size": "Dimensione minima del file", + "feedback.policy.compression.minimal-file-size-help": "I file più piccoli del valore fornito non verranno compressi", + "feedback.policy.compression.minimal-file-size-hint": "dimensione minima del file in byte", + "feedback.policy.compression.never-compress-extensions": "Non comprimere mai le estensioni", + "feedback.policy.compression.never-compress-extensions-help": "Non comprimere mai le seguenti estensioni di file (un'estensione per riga)", + "feedback.policy.compression.never-compress-extensions-hint": "per esempio. *.mp4", + "feedback.policy.compression.only-compress-extensions": "Comprimi solo le estensioni", + "feedback.policy.compression.only-compress-extensions-help": "Comprimi solo file con le seguenti estensioni di file (un'estensione per riga)", + "feedback.policy.compression.only-compress-extensions-hint": "per esempio. *.txt", + "feedback.policy.confirm-delete-policy": "Sei sicuro di voler eliminare questa politica?", + "feedback.policy.defined-by": "Definito da", + "feedback.policy.defined-by-this-policy": "Definito da questa politica", + "feedback.policy.error-delete-policy": "Errore durante l'eliminazione della policy", + "feedback.policy.error-handling.ignore-directory-errors": "Ignora gli errori della directory", + "feedback.policy.error-handling.ignore-directory-errors-help": "Trattare gli errori di lettura della directory come non fatali.", + "feedback.policy.error-handling.ignore-file-errors": "Ignora gli errori dei file", + "feedback.policy.error-handling.ignore-file-errors-help": "Considera gli errori di lettura dei file come non fatali.", + "feedback.policy.error-handling.ignore-unknown-directories": "Ignora le voci della directory sconosciute", + "feedback.policy.error-handling.ignore-unknown-directories-help": "Trattare le voci di directory non riconosciute/non supportate come errori non irreversibili.", + "feedback.policy.error-saving-policy": "Errore durante il salvataggio della norma", + "feedback.policy.files.ignore-files": "Ignora file", + "feedback.policy.files.ignore-files-help": "Elenco di nomi di file e directory da ignorare.
Vedi la documentazione su come ignorare i file.", + "feedback.policy.files.ignore-files-hint": "per esempio. /file.txt", + "feedback.policy.files.ignore-rule-files": "Ignora file di regole", + "feedback.policy.files.ignore-rule-files-from-parent-directories": "Ignora i file delle regole dalle directory principali", + "feedback.policy.files.ignore-rule-files-from-parent-directories-help": "Quando impostato, i file che specificano le regole di ignora (.kopiaignore, ecc.) dalla directory principale vengono ignorati", + "feedback.policy.files.ignore-rule-files-help": "Elenco di file aggiuntivi contenenti regole di ignoranza (ogni file configura le regole di ignoranza per la directory e le sue sottodirectory)", + "feedback.policy.files.ignore-rule-files-hint": "per esempio. .kopiaignore", + "feedback.policy.files.ignore-rules-from-parent-directories": "Ignora le regole delle directory principali", + "feedback.policy.files.ignore-rules-from-parent-directories-help": "Se impostato, le regole di ignora dalla directory principale vengono ignorate", + "feedback.policy.files.ignore-well-known-cache-directories": "Ignora le directory della cache ben note", + "feedback.policy.files.ignore-well-known-cache-directories-help": "Ignorare le directory contenenti CACHEDIR.TAG e simili", + "feedback.policy.files.scan-only-one-filesystem": "Scansiona solo un filesystem", + "feedback.policy.files.scan-only-one-filesystem-help": "Non oltrepassare i limiti del file system durante la creazione di uno snapshot", + "feedback.policy.find-count": "feedback.policy.find-count", + "feedback.policy.find-count_one": "Trovata {{count}} policy corrispondente ai criteri", + "feedback.policy.find-count_other": "Trovate {{count}} politiche che corrispondono ai criteri", + "feedback.policy.find-hint": "Inserisci la directory per trovare o impostare la policy", + "feedback.policy.find-none": "Nessuna politica trovata", + "feedback.policy.find-none-create": "Nessuna policy trovata per la directory {{path}}. \nImposta una nuova policy.", + "feedback.policy.header.actions": "Azioni", + "feedback.policy.header.compression": "Compressione", + "feedback.policy.header.defined": "Definito", + "feedback.policy.header.error-handling": "Gestione degli errori", + "feedback.policy.header.files": "File", + "feedback.policy.header.folder-actions": "Azioni delle cartelle", + "feedback.policy.header.host": "Ospite", + "feedback.policy.header.logging": "Registrazione", + "feedback.policy.header.other": "Altro", + "feedback.policy.header.path": "Sentiero", + "feedback.policy.header.scheduling": "Pianificazione", + "feedback.policy.header.snapshot-action": "Azioni istantanee", + "feedback.policy.header.snapshot-retention": "Conservazione delle istantanee", + "feedback.policy.header.upload": "Caricamento", + "feedback.policy.kind.all": "Tutte le politiche", + "feedback.policy.kind.applicable": "Politiche applicabili", + "feedback.policy.kind.global": "Politiche globali", + "feedback.policy.kind.local": "Politiche locali", + "feedback.policy.kind.per-host-policies": "Politiche per host", + "feedback.policy.kind.per-user-policies": "Criteri per utente", + "feedback.policy.logging.cache-hit": "Hit della cache", + "feedback.policy.logging.cache-hit-help": "Registra la verbosità quando viene utilizzata una cache invece di caricare il file", + "feedback.policy.logging.cache-miss": "Mancata cache", + "feedback.policy.logging.cache-miss-help": "Registra la verbosità quando non è possibile utilizzare una cache ed è necessario sottoporre ad hashing un file", + "feedback.policy.logging.directory-ignored": "Directory ignorata", + "feedback.policy.logging.directory-ignored-help": "Registra la verbosità quando una directory viene ignorata", + "feedback.policy.logging.directory-snapshotted": "Directory istantanea", + "feedback.policy.logging.directory-snapshotted-help": "Registra la verbosità quando viene eseguito lo snapshot di una directory", + "feedback.policy.logging.file-ignored": "File ignorato", + "feedback.policy.logging.file-ignored-help": "Registra la verbosità quando un file, un collegamento simbolico, ecc. viene ignorato", + "feedback.policy.logging.file-snapshotted": "File istantaneo", + "feedback.policy.logging.file-snapshotted-help": "Registra la verbosità quando viene eseguito lo snapshot di un file, di un collegamento simbolico e così via", + "feedback.policy.other.disable-parent-policy-evaluation": "Disabilita la valutazione della policy principale", + "feedback.policy.other.disable-parent-policy-evaluation-help": "Impedisce che eventuali policy principali influenzino questa directory e le relative sottodirectory", + "feedback.policy.other.json-representation": "Rappresentazione JSON", + "feedback.policy.other.json-representation-help": "Questa è la rappresentazione interna di una politica", + "feedback.policy.policies-defined-by-path-absolute": "Le policy possono essere definite solo per percorsi assoluti.", + "feedback.policy.retention.annual-snapshot-retain": "Annuale", + "feedback.policy.retention.annual-snapshot-retain-help": "Numero di snapshot annuali da conservare per origine. \nVerrà conservata l'ultima istantanea di ogni anno solare", + "feedback.policy.retention.annual-snapshot-retain-hint": "Numero di snapshot annuali", + "feedback.policy.retention.daily-snapshot-retain": "Quotidiano", + "feedback.policy.retention.daily-snapshot-retain-help": "Numero di snapshot giornalieri conservare per origine. \nVerrà conservata l'ultima istantanea di ogni giorno", + "feedback.policy.retention.daily-snapshot-retain-hint": "Numero di snapshot giornalieri", + "feedback.policy.retention.hourly-snapshot-retain": "Ogni ora", + "feedback.policy.retention.hourly-snapshot-retain-help": "Numero di snapshot orari da conservare per origine. \nVerrà conservata l'ultima istantanea di ogni ora", + "feedback.policy.retention.hourly-snapshot-retain-hint": "numero di snapshot orari", + "feedback.policy.retention.ignore-identical-snapshots": "Ignora istantanee identiche", + "feedback.policy.retention.ignore-identical-snapshots-help": "NON salvare un'istantanea quando nessun file è stato modificato", + "feedback.policy.retention.keep-latest-help": "numero di istantanee più recenti", + "feedback.policy.retention.latest-snapshot-retain": "Ultime istantanee", + "feedback.policy.retention.latest-snapshot-retain-help": "Numero degli snapshot più recenti da conservare per origine", + "feedback.policy.retention.monthly-snapshot-retain": "Mensile", + "feedback.policy.retention.monthly-snapshot-retain-help": "Quanti snapshot mensili conservare per origine. \nVerrà conservata l'ultima istantanea di ogni mese di calendario", + "feedback.policy.retention.monthly-snapshot-retain-hint": "Numero di snapshot mensili", + "feedback.policy.retention.weekly-snapshot-retain": "settimanalmente", + "feedback.policy.retention.weekly-snapshot-retain-help": "Numero di snapshot settimanali da conservare per origine. \nVerrà conservata l'ultima istantanea di ogni settimana", + "feedback.policy.retention.weekly-snapshot-retain-hint": "Numero di snapshot settimanali", + "feedback.policy.scheduling.cron-expressions": "Espressioni Cron", + "feedback.policy.scheduling.cron-expressions-hint": "minuto ora giorno mese giorno feriale", + "feedback.policy.scheduling.cron-help": "Pianificazioni di istantanee utilizzando la sintassi crontab UNIX (una per riga):
Vedi dettagli sui formati supportati.", + "feedback.policy.scheduling.manual-snapshots-only": "Solo istantanee manuali", + "feedback.policy.scheduling.manual-snapshots-only-help": "Crea istantanee solo manualmente (disabilita le istantanee pianificate)", + "feedback.policy.scheduling.missed-snapshots-startup": "Esegui le istantanee perse all'avvio", + "feedback.policy.scheduling.missed-snapshots-startup-help": "Esegui immediatamente eventuali istantanee perse all'avvio di Kopia (rilevante solo per le istantanee dell'ora del giorno)", + "feedback.policy.scheduling.no-upcoming-snapshots": "Nessuna istantanea imminente", + "feedback.policy.scheduling.snapshot-frequency": "Frequenza dell'istantanea", + "feedback.policy.scheduling.snapshot-frequency-help": "La frequenza con cui creare istantanee in KopiaUI o nel server Kopia (non ha effetto al di fuori della modalità server)", + "feedback.policy.scheduling.times-of-day": "Momenti della giornata", + "feedback.policy.scheduling.times-of-day-help": "Crea istantanee alle ore del giorno specificate (formato 24 ore)", + "feedback.policy.scheduling.times-of-day-hint": "per esempio. 17:00", + "feedback.policy.scheduling.upcoming": "Prossimamente", + "feedback.policy.scheduling.upcoming-snapshots": "Prossime istantanee", + "feedback.policy.scheduling.upcoming-snapshots-help": "Tempi degli snapshot imminenti calcolati in base ai parametri della policy", + "feedback.policy.time-of-day.invalid": "Ora del giorno non valida: {{tod}}", + "feedback.policy.timeout-help": "Timeout in secondi prima che Kopia interrompa il processo", + "feedback.policy.upload.maximum-parallel-file-reads": "Numero massimo di letture di file parallele", + "feedback.policy.upload.maximum-parallel-file-reads-help": "Numero massimo di file che verranno letti in parallelo (il valore predefinito è il numero di processori logici)", + "feedback.policy.upload.maximum-parallel-file-reads-hint": "numero massimo di letture di file parallele", + "feedback.policy.upload.maximum-parallel-snapshots": "Numero massimo di istantanee parallele", + "feedback.policy.upload.maximum-parallel-snapshots-help": "Numero massimo di snapshot che possono essere caricati contemporaneamente", + "feedback.policy.upload.maximum-parallel-snapshots-hint-set": "numero massimo di snapshot paralleli", + "feedback.policy.upload.maximum-parallel-snapshots-hint-unset": "deve essere specificato utilizzando la policy globale, utente o host", + "feedback.prodiver.gcs.paste-json-credentials": "Incolla qui le credenziali JSON", + "feedback.provider.azure-blob-storage": "Archiviazione BLOB di Azure", + "feedback.provider.azure.access-key": "Chiave di accesso", + "feedback.provider.azure.azure-storage-domain": "Dominio di archiviazione di Azure", + "feedback.provider.azure.container": "Contenitore", + "feedback.provider.azure.enter-access-key": "Inserisci la chiave di accesso segreta", + "feedback.provider.azure.enter-azure-storage-domain": "Inserisci il dominio di archiviazione o lascia vuoto il campo predefinito \"blob.core.windows.net\"", + "feedback.provider.azure.enter-container-name": "Inserisci il nome del contenitore", + "feedback.provider.azure.enter-object-name-prefix": "Inserisci il prefisso del nome dell'oggetto o lascia vuoto", + "feedback.provider.azure.enter-sas-token": "Inserisci il token SAS segreto", + "feedback.provider.azure.enter-storage-account": "Immettere il nome dell'account di archiviazione", + "feedback.provider.azure.object-name-prefix": "Prefisso nome oggetto", + "feedback.provider.azure.sas-token": "Gettone SAS", + "feedback.provider.azure.storage-account": "Conto di archiviazione", + "feedback.provider.b2.bucket-name": "Benna B2", + "feedback.provider.b2.enter-account-key": "Inserisci l'applicazione segreta o la chiave dell'account", + "feedback.provider.b2.enter-account-key-id": "Inserisci l'ID della chiave dell'applicazione o dell'account", + "feedback.provider.b2.enter-bucket-name": "Inserisci il nome del bucket", + "feedback.provider.b2.enter-object-name-prefix": "Inserisci il prefisso del nome dell'oggetto o lascia vuoto", + "feedback.provider.b2.key": "Chiave", + "feedback.provider.b2.key-id": "ID chiave", + "feedback.provider.b2.object-name-prefix": "Prefisso nome oggetto", + "feedback.provider.backblaze-b2": "Backblaze B2", + "feedback.provider.filesystem.directory-path": "Percorso della directory", + "feedback.provider.filesystem.enter-directory-path": "Inserisci il percorso della directory in cui desideri archiviare i file del repository", + "feedback.provider.gcs.bucket-name": "Benna GCS", + "feedback.provider.gcs.credentials-file": "File delle credenziali", + "feedback.provider.gcs.credentials-json": "Credenziali JSON", + "feedback.provider.gcs.enter-bucket-name": "Inserisci il nome del bucket", + "feedback.provider.gcs.enter-credentials-file-name": "Immettere il nome del file JSON delle credenziali", + "feedback.provider.gcs.enter-object-name-prefix": "Inserisci il prefisso del nome dell'oggetto o lascia vuoto", + "feedback.provider.gcs.object-name-prefix": "Prefisso nome oggetto", + "feedback.provider.google-cloud-storage": "Archiviazione Google Cloud", + "feedback.provider.kopia-repository-server": "Server di archivio Kopia", + "feedback.provider.local-directory-or-nas": "Directory locale o NAS", + "feedback.provider.rclone-remote": "RClone remoto", + "feedback.provider.rclone.rclone-executable-path": "Percorso eseguibile Rclone", + "feedback.provider.rclone.rclone-executable-path-hint": "Immettere il percorso dell'eseguibile rclone", + "feedback.provider.rclone.rclone-remote-path": "Rclone percorso remoto", + "feedback.provider.rclone.rclone-remote-path-hint": "Inserisci :", + "feedback.provider.repositoryserver.enter-server-certificate-fingerprint": "Inserisci l'impronta digitale del certificato del server attendibile stampata all'avvio del server", + "feedback.provider.repositoryserver.enter-server-url": "Inserisci l'URL del server (https://:porta)", + "feedback.provider.repositoryserver.server-address": "Indirizzo del server", + "feedback.provider.repositoryserver.server-certificate-fingerprint": "Impronta digitale del certificato del server affidabile (SHA256)", + "feedback.provider.repositorytoken.paste-token": "Incolla token di connessione", + "feedback.provider.repositorytoken.token": "Gettone", + "feedback.provider.required-either-key-file": "È richiesta una tra Password, File chiave o Dati chiave.", + "feedback.provider.required-either-known-host-data": "È richiesto il file degli host conosciuti o i dati degli host conosciuti, ma non entrambi.", + "feedback.provider.s3-or-compatible-storage": "Amazon S3 o spazio di archiviazione compatibile", + "feedback.provider.s3.access-key-id": "ID chiave di accesso", + "feedback.provider.s3.access-key-id-hint": "Immettere l'ID della chiave di accesso", + "feedback.provider.s3.bucket-name": "Secchio", + "feedback.provider.s3.bucket-name-hint": "Inserisci il nome del bucket", + "feedback.provider.s3.enter-object-name-prefix-hint": "Inserisci il prefisso del nome dell'oggetto o lascia vuoto", + "feedback.provider.s3.object-name-prefix": "Prefisso nome oggetto", + "feedback.provider.s3.override-region": "Sostituisci regione", + "feedback.provider.s3.override-region-hint": "Inserisci una regione specifica (ad esempio, us-west-1) o lascia vuoto", + "feedback.provider.s3.secret-access-key": "Chiave di accesso segreta", + "feedback.provider.s3.secret-access-key-hint": "Inserisci la chiave di accesso segreta", + "feedback.provider.s3.server-endpoint": "Punto finale del server", + "feedback.provider.s3.server-endpoint-hint": "Inserisci l'indirizzo del server (ad esempio, s3.amazonaws.com)", + "feedback.provider.s3.session-token": "Gettone di sessione", + "feedback.provider.s3.session-token-hint": "Inserisci il token della sessione o lascia vuoto", + "feedback.provider.sftp-key-data": "Dati chiave", + "feedback.provider.sftp-key-data-hint": "Incolla il contenuto del file chiave", + "feedback.provider.sftp-server": "Server SFTP", + "feedback.provider.sftp.enter-password": "Inserire la password", + "feedback.provider.sftp.enter-path-host-file": "Inserisci il percorso del fileknown_hosts", + "feedback.provider.sftp.enter-path-to-key-file": "Immettere il percorso del file chiave", + "feedback.provider.sftp.enter-remote-path": "Inserisci il percorso remoto del repository, ad esempio \"/mnt/data/repository\"", + "feedback.provider.sftp.enter-ssh-arguments": "Inserisci gli argomenti del comando SSH ('user@host -s sftp' verrà aggiunto automaticamente)", + "feedback.provider.sftp.enter-ssh-host-name": "nome host ssh (ad esempio, example.com)", + "feedback.provider.sftp.host": "Ospite", + "feedback.provider.sftp.known-host-data": "Dati degli host conosciuti", + "feedback.provider.sftp.launch-external-ssh-command": "Avvia il comando SSH esterno senza password", + "feedback.provider.sftp.launch-external-ssh-command-hint": "Per impostazione predefinita Kopia si connette al server utilizzando il client SSH interno che supporta opzioni limitate. \nIn alternativa, può avviare un comando SSH esterno senza password, che supporta opzioni aggiuntive, ma generalmente è meno efficiente del client integrato.", + "feedback.provider.sftp.password": "Parola d'ordine", + "feedback.provider.sftp.paste-content-of-known-host": "Incolla il contenuto del fileknown_hosts", + "feedback.provider.sftp.path": "Sentiero", + "feedback.provider.sftp.path-host-file": "Percorso del fileknown_hosts", + "feedback.provider.sftp.path-key-file": "Percorso del file chiave", + "feedback.provider.sftp.port": "Porta", + "feedback.provider.sftp.port-number": "Numero di porta (ad esempio, 22)", + "feedback.provider.sftp.provide-passwordless-ssh-command": "Fornire il comando SSH senza password da eseguire (in genere 'ssh')", + "feedback.provider.sftp.ssh-arguments": "Argomenti SSH", + "feedback.provider.sftp.ssh-command": "Comando SSH", + "feedback.provider.sftp.user": "Utente", + "feedback.provider.sftp.user-name": "Nome utente", + "feedback.provider.use-repository-token": "Utilizza token di archivio", + "feedback.provider.webdav-server": "Server WebDAV", + "feedback.provider.webdav.enter-password": "Inserire la password", + "feedback.provider.webdav.enter-username": "Inserire username", + "feedback.provider.webdav.password": "Parola d'ordine", + "feedback.provider.webdav.server-url": "URL del server WebDAV", + "feedback.provider.webdav.username": "Nome utente", + "feedback.repository.additional-parameters-hint": "È possibile impostare parametri aggiuntivi durante la creazione del repository utilizzando la riga di comando.", + "feedback.repository.attribute.algorithm-eco": "Algoritmo di correzione degli errori", + "feedback.repository.attribute.algorithm-encryption": "Algoritmo di crittografia", + "feedback.repository.attribute.algorithm-hash": "Algoritmo di hash", + "feedback.repository.attribute.algorithm-splitter": "Algoritmo di suddivisione", + "feedback.repository.attribute.config-file": "File di configurazione", + "feedback.repository.attribute.connected-as": "Connesso come", + "feedback.repository.attribute.internal-compression": "Compressione interna", + "feedback.repository.attribute.repository-eco": "Overhead di correzione degli errori", + "feedback.repository.attribute.repository-format": "Formato del repository", + "feedback.repository.attribute.repository-provider": "Provider", + "feedback.repository.attribute.server-url": "URL del server", + "feedback.repository.configuration": "Configurazione di archiviazione", + "feedback.repository.connect-as": "Connetti come", + "feedback.repository.connect-in-read-only-mode": "Connetti in modalità di sola lettura", + "feedback.repository.connect-in-read-only-mode-hint": "La modalità di sola lettura impedisce qualsiasi modifica al repository.", + "feedback.repository.connect-to-repository": "Connettiti al deposito", + "feedback.repository.create-repository-new": "Crea nuovo archivio", + "feedback.repository.create-repository-new-help": "Inserisci una password complessa per creare il repository Kopia nello spazio di archiviazione fornito.", + "feedback.repository.eco-disabled": "Disabilitato", + "feedback.repository.eec-warning": "[SPERIMENTALE] La correzione degli errori può aiutare a proteggere da alcuni tipi di danneggiamento dei dati dovuti a inversioni di bit spontanee nei supporti di memorizzazione.", + "feedback.repository.encryption": "Crittografia", + "feedback.repository.enter-repository-password": "Inserisci la password dell'archivio", + "feedback.repository.hostname": "Nome host", + "feedback.repository.hostname-hint": "Sostituiscilo quando ripristini uno snapshot acquisito su un altro computer", + "feedback.repository.internal-compression-supported-no": "no", + "feedback.repository.internal-compression-supported-yes": "sì", + "feedback.repository.kopia-server-parameters": "Parametri del server Copia", + "feedback.repository.name-default": "Il mio deposito", + "feedback.repository.override-hint": "Per eseguire l'override, fai clic su \"Mostra opzioni avanzate\"", + "feedback.repository.provider-selection": "Seleziona il tipo di archiviazione", + "feedback.repository.provider-selection-hint": "Per connettersi a un repository o crearne uno, selezionare il tipo di archiviazione preferito:", + "feedback.repository.repository-description": "Descrizione del deposito", + "feedback.repository.repository-description-help": "Aiuta a distinguere tra più repository connessi", + "feedback.repository.repository-description-hint": "Inserisci la descrizione del repository", + "feedback.repository.repository-description-required": "La descrizione del repository è obbligatoria", + "feedback.repository.repository-initializing": "Inizializzazione del repository...", + "feedback.repository.repository-is-read-only": "Il repository è in sola lettura", + "feedback.repository.repository-password": "Password dell'archivio", + "feedback.repository.repository-password-confirm": "Conferma la password dell'archivio", + "feedback.repository.repository-password-confirm-again": "immettere nuovamente la password del repository", + "feedback.repository.repository-password-help": "Utilizzato per crittografare il contenuto del repository", + "feedback.repository.repository-token-enter": "Inserisci il token del repository", + "feedback.repository.server-password": "Password del server", + "feedback.repository.server-password-hint": "Inserisci la password per connetterti al server", + "feedback.repository.status-connected": "Connesso al repository", + "feedback.repository.username": "Nome utente", + "feedback.repository.username-hint": "Sostituiscilo quando ripristini uno snapshot scattato da un altro utente", + "feedback.snapshot.create.enter-path-to-snapshot-hint": "Inserisci il percorso dello snapshot", + "feedback.snapshot.create.must-specify-path": "È necessario specificare la directory in cui eseguire lo snapshot.", + "feedback.snapshot.create.snapshot-new": "Nuova istantanea", + "feedback.snapshot.description": "Descrizione", + "feedback.snapshot.description.snapshot-description": "Descrizione dell'istantanea", + "feedback.snapshot.directory.browsing-not-supported": "L'esplorazione delle directory non è supportata in un browser Web. \nUtilizza l'interfaccia utente di Copia.", + "feedback.snapshot.directory.restore-all-files-help": "Puoi montare/ripristinare tutti i file e le directory che vedi di seguito o ripristinare i file individualmente.", + "feedback.snapshot.header.actions": "Azioni", + "feedback.snapshot.header.details": "Dettagli", + "feedback.snapshot.header.directories": "Dir", + "feedback.snapshot.header.files": "File", + "feedback.snapshot.header.last-snapshot": "Ultima istantanea", + "feedback.snapshot.header.next-snapshot": "Prossima istantanea", + "feedback.snapshot.header.retention": "Ritenzione", + "feedback.snapshot.header.root": "Radice", + "feedback.snapshot.header.selected": "Selezionato", + "feedback.snapshot.header.snapshot-owner": "Proprietario", + "feedback.snapshot.header.snapshot-path": "Percorso", + "feedback.snapshot.header.snapshot-size": "Misurare", + "feedback.snapshot.header.start-time": "Ora di inizio", + "feedback.snapshot.header.status": "Stato", + "feedback.snapshot.history.snapshot-displaying": "Visualizzazione", + "feedback.snapshot.history.wipe-all-snapshots": "Cancella tutti gli snapshot e la policy per questa origine.", + "feedback.snapshot.restore.continue-on-errors": "Continua in caso di errori", + "feedback.snapshot.restore.continue-on-errors-help": "Quando si verifica un errore durante il ripristino, prova a continuare invece di interrompere rapidamente.", + "feedback.snapshot.restore.destination": "Destinazione", + "feedback.snapshot.restore.destination-help": "Puoi anche ripristinare in un file .zip o .tar fornendo l'estensione appropriata.", + "feedback.snapshot.restore.destination-hint": "Inserisci il percorso di destinazione", + "feedback.snapshot.restore.disable-zip-compression": "Disabilita la compressione ZIP", + "feedback.snapshot.restore.disable-zip-compression-help": "Non comprimere quando si ripristina in un file ZIP (più veloce).", + "feedback.snapshot.restore.minimal-file-size-for-shallow-restore": "Dimensione minima del file per il ripristino superficiale", + "feedback.snapshot.restore.overwrite-directory": "Sovrascrivi le directory", + "feedback.snapshot.restore.overwrite-files": "Sovrascrivi i file", + "feedback.snapshot.restore.overwrite-symbolic-links": "Sovrascrivi i collegamenti simbolici", + "feedback.snapshot.restore.restore-file-modification-time": "Ripristina l'orario di modifica dei file", + "feedback.snapshot.restore.restore-file-ownership": "Ripristina la proprietà dei file", + "feedback.snapshot.restore.restore-file-permissions": "Ripristina i permessi dei file", + "feedback.snapshot.restore.shallow-restore-at-depth": "Ripristino superficiale a una profondità specifica", + "feedback.snapshot.restore.skip-previously-restored-files": "Salta i file e i collegamenti simbolici già ripristinati in precedenza", + "feedback.snapshot.restore.snapshot-restore": "Ripristina", + "feedback.snapshot.restore.write-files-atomically": "Scrivi i file atomicamente", + "feedback.snapshot.restore.write-sparse-files": "Scrivi file sparsi", + "feedback.snapshot.show-individual-snapshots-count": "feedback.snapshot.show-individual-snapshots-count", + "feedback.snapshot.show-individual-snapshots-count_one": "Mostra {{count}} istantanea individuale", + "feedback.snapshot.show-individual-snapshots-count_other": "Mostra {{count}} istantanee individuali", + "feedback.snapshot.start-after-previous-snapshot": "L'istantanea inizierà dopo il completamento dell'istantanea precedente", + "feedback.snapshot.status.status-overdue": "in ritardo", + "feedback.snapshot.status.status-pending": "In attesa", + "feedback.tab.policies": "Politiche", + "feedback.tab.preferences": "Preferenze", + "feedback.tab.repository": "Repository", + "feedback.tab.repository-is-not-connected": "Il repository non è connesso", + "feedback.tab.snapshots": "Istantanee", + "feedback.tab.tasks": "Attività", + "feedback.task.estimated-results": "{{description}} Bytes: {{bytes}} ({{bytes.excluded}} escluso) Files: {{files}} ({{files.excluded}} escluso) Directories: {{directories}} ({{directories.excluded}} escluso) Errors: {{errors}} ({{errors.ignored}} ignorato)", + "feedback.task.header.counter": "Contatore", + "feedback.task.header.value": "Valore", + "feedback.task.logs": "Log", + "feedback.task.no-tasks-help": "Un elenco di attività apparirà qui quando crei istantanee, ripristini, esegui manutenzione, ecc.", + "feedback.task.search-tasks-by-hint": "Cerca i registri delle attività in base alla descrizione", + "feedback.task.status.task-canceled": "Attività annullata", + "feedback.task.status.task-canceled-after": "Attività annullata dopo", + "feedback.task.status.task-canceling": "Annullamento in corso", + "feedback.task.status.task-error": "Errore nell'attività", + "feedback.task.status.task-failed-after": "Fallito dopo", + "feedback.task.status.task-finished": "Completata", + "feedback.task.status.task-finished-in": "Finito tra", + "feedback.task.status.task-running-for": "Attività in esecuzione da", + "feedback.task.status.task-started": "Avviata", + "feedback.task.status.task-succeeded-after": "Attività completata dopo", + "feedback.task.table.header-description": "Descrizione", + "feedback.task.table.header-kind": "Tipo", + "feedback.task.table.header-start-time": "Ora di inizio", + "feedback.task.table.header-status": "Stato", + "feedback.task.tasks-total": "Totale", + "feedback.ui.appearance": "Aspetto", + "feedback.ui.appearance-help": "Specifica l'aspetto dell'interfaccia utente", + "feedback.ui.appearance-hint": "Seleziona la dimensione del carattere", + "feedback.ui.byte-representation-description": "Seleziona la rappresentazione dei byte", + "feedback.ui.byte-representation-help": "Specifica la rappresentazione dei byte", + "feedback.ui.byte-representation-select": "Seleziona la rappresentazione dei byte", + "feedback.ui.pagesize-description": "Dimensione pagina", + "feedback.ui.pagesize-help": "Specifica la dimensione di paginazione nelle tabelle", + "feedback.ui.pagesize-hint": "Dimensione pagina", + "feedback.ui.theme-description": "Tema", + "feedback.ui.theme-help": "Il tema attivo corrente", + "feedback.ui.theme-select": "Seleziona il tema", + "feedback.validation.invalid-times-of-day": "Orari del giorno non validi", + "feedback.validation.optional.valid-number-or-empty": "Deve essere un numero valido o vuoto", + "feedback.validation.passwords-dont-match": "Le password non corrispondono", + "feedback.validation.required.directory": "campo obbligatorio", + "feedback.validation.required.field": "campo obbligatorio", + "feedback.validation.required.valid-number-or-empty": "Deve essere un numero valido o vuoto", + "value.algorithm.eco-disabled": "Disabilitato", + "value.algorithm.suffix-not-recommended": "(NON CONSIGLIATO)", + "value.algorithm.suffix-recommended": "(CONSIGLIATO)", + "value.log.details-0-no-output": "0 - nessuna uscita", + "value.log.details-1-minimal-details": "1 - dettagli minimi", + "value.log.details-10-maximum-details": "10 - dettagli massimi", + "value.log.details-5-normal-details": "5 - dettagli normali", + "value.log.details-inherit-from-parent": "(eredita dal genitore)", + "value.policy.async": "Esegui in modo asincrono, ignora gli errori", + "value.policy.essential": "Deve avere successo", + "value.policy.inherent-from-parent": "ereditare dal genitore", + "value.policy.none": "nessuno", + "value.policy.optional": "Ignora i fallimenti", + "value.provider.s3.http-connection-insecure": "Utilizza connessione HTTP (non sicura)", + "value.provider.s3.no-tls-verification": "Non verificare il certificato TLS", + "value.repository.latest-format": "Ultimo formato", + "value.repository.legacy-format": "Formato legacy compatibile con v0.8", + "value.snapshot-frequency.10-minutes": "ogni 10 minuti", + "value.snapshot-frequency.12-hours": "ogni 12 ore", + "value.snapshot-frequency.15-minutes": "ogni 15 minuti", + "value.snapshot-frequency.20-minutes": "ogni 20 minuti", + "value.snapshot-frequency.3-hours": "ogni 3 ore", + "value.snapshot-frequency.30-minutes": "ogni 30 minuti", + "value.snapshot-frequency.6-hours": "ogni 6 ore", + "value.snapshot-frequency.hour": "ogni ora", + "value.ui.appearance-large": "grande", + "value.ui.appearance-medium": "medio", + "value.ui.appearance-small": "piccolo", + "value.ui.byte-representation-base10": "Base 10 (KB, MB, GB, TB)", + "value.ui.byte-representation-base2": "Base-2 (KiB, MiB, GiB, TiB)", + "value.ui.theme-dark": "scuro", + "value.ui.theme-light": "chiaro", + "value.ui.theme-ocean": "oceano", + "value.ui.theme-pastel": "pastello", + "value.validation.optional-no": "no", + "value.validation.optional-yes": "SÌ" +} diff --git a/public/locales/jp/translation.json b/public/locales/jp/translation.json new file mode 100644 index 00000000..c2da5c8e --- /dev/null +++ b/public/locales/jp/translation.json @@ -0,0 +1,479 @@ +{ + "common.action.back": "Back", + "common.action.cancel": "Cancel", + "common.action.click-here-to-learn-more": "Click here to learn more.", + "common.action.confirm-delete": "Confirm Delete", + "common.action.delete": "削除", + "common.action.next": "Next", + "common.action.return": "戻る", + "common.action.stop": "停止", + "common.label.loading": "読み込み中...", + "event.cli.copy-to-clipboard": "Copy to clipboard", + "event.cli.show-cli-equivalent": "Click to show CLI equivalent", + "event.log.hide-log": "ログを非表示", + "event.log.show-log": "ログを表示", + "event.pin.add-pin": "Add Pin", + "event.pin.pin-snapshot": "Pin Snapshot", + "event.pin.remove-pin": "Remove Pin", + "event.pin.update-pin": "Update Pin", + "event.policy.delete": "Delete policy", + "event.policy.edit": "Edit", + "event.policy.save": "Save policy", + "event.policy.set-policy": "Set policy", + "event.repository.cancel-connection": "接続をキャンセル", + "event.repository.connect-to-repository": "Connect to repository", + "event.repository.create-repository": "Create repository", + "event.repository.disconnect-from-repository": "リポジトリから切断", + "event.repository.hide-advanced-options": "Hide advanced options", + "event.repository.show-advanced-options": "Show Advanced Options", + "event.repository.update-description": "説明を更新", + "event.snapshot.browse-directory": "Browse", + "event.snapshot.delete-selected": "event.snapshot.delete-selected", + "event.snapshot.delete-selected_one": "Do you want to delete the selected {{count}} snapshot?", + "event.snapshot.delete-selected_other": "Do you want to delete the selected {{count}} snapshots?", + "event.snapshot.description.enter-new-description": "Enter new description", + "event.snapshot.description.remove-description": "Remove Description", + "event.snapshot.description.update-description": "Update Description", + "event.snapshot.estimate": "Estimate", + "event.snapshot.fetch-snapshots": "Fetch snapshots", + "event.snapshot.history.delete-selected": "Delete Selected ({{count}})", + "event.snapshot.history.delete-snapshot-source": "Delete Snapshot Source", + "event.snapshot.history.deselect-all": "Deselect All", + "event.snapshot.history.select-all-snapshots": "Select All", + "event.snapshot.history.update-snapshot-description": "{{description}} - Click to update snapshot description.", + "event.snapshot.mount-directory": "Mount as Local Filesystem", + "event.snapshot.new-snapshot": "新しいスナップショット", + "event.snapshot.restore-file-directories": "Restore files and directories", + "event.snapshot.restore.begin-restore": "復元を開始", + "event.snapshot.restore.go-to-restore-task": "Go To Restore Task", + "event.snapshot.show-policy": "ポリシー", + "event.snapshot.snapshot-now": "Snapshot now", + "event.snapshot.synchronize": "同期", + "event.snapshot.unmount-directory": "Unmount", + "event.task.action.cancel": "Cancel task", + "event.task.select.task-all": "すべて", + "event.task.select.task-failed": "失敗", + "event.task.select.task-running": "実行中", + "feedback.directory.header.directories": "Directories", + "feedback.directory.header.files": "Files", + "feedback.directory.header.last-modification": "Last Modification", + "feedback.directory.header.name": "Name", + "feedback.directory.header.size": "Size", + "feedback.error.common": "Error", + "feedback.error.connection": "Connect Error:", + "feedback.header.effective": "Effective", + "feedback.header.username": "Username", + "feedback.pin.add-pin-to-protect": "Add a pin to protect snapshot from deletion", + "feedback.pin.do-not-delete": "do-not-delete", + "feedback.pin.name-of-the-pin": "Name of the pin", + "feedback.policy.action.command-mode": "Command Mode", + "feedback.policy.actions.after-folder": "After Folder", + "feedback.policy.actions.after-folder-help": "Script to run after folder", + "feedback.policy.actions.after-snapshot": "After Snapshot", + "feedback.policy.actions.after-snapshot-help": "Script to run after snapshot", + "feedback.policy.actions.before-folder": "Before Folder", + "feedback.policy.actions.before-folder-help": "Script to run before folder", + "feedback.policy.actions.before-snapshot": "Before Snapshot", + "feedback.policy.actions.before-snapshot-help": "Script to run before snapshot", + "feedback.policy.actions.timeout": "Timeout", + "feedback.policy.command-mode-help": "Essential (must succeed; default behavior), optional (failures are tolerated), or async (Kopia will start the action but not wait for it to finish)", + "feedback.policy.compression.compression-algorithm": "Compression Algorithm", + "feedback.policy.compression.compression-algorithm-help": "Specify compression algorithm to use when snapshotting files in this directory and subdirectories", + "feedback.policy.compression.maximal-file-size": "Maximum file size", + "feedback.policy.compression.maximal-file-size-help": "Files whose size exceeds the provided value will not be compressed", + "feedback.policy.compression.maximal-file-size-hint": "Maximum file size in bytes", + "feedback.policy.compression.minimal-file-size": "Minimum File Size", + "feedback.policy.compression.minimal-file-size-help": "Files that are smaller than the provided value will not be compressed", + "feedback.policy.compression.minimal-file-size-hint": "minimum file size in bytes", + "feedback.policy.compression.never-compress-extensions": "Never compress extensions", + "feedback.policy.compression.never-compress-extensions-help": "Never compress the following file extensions (one extension per line)", + "feedback.policy.compression.never-compress-extensions-hint": "e.g. *.mp4", + "feedback.policy.compression.only-compress-extensions": "Only compress extensions", + "feedback.policy.compression.only-compress-extensions-help": "Only compress files with the following file extensions (one extension per line)", + "feedback.policy.compression.only-compress-extensions-hint": "e.g. *.txt", + "feedback.policy.confirm-delete-policy": "Are you sure you want to delete this policy?", + "feedback.policy.defined-by": "Defined by", + "feedback.policy.defined-by-this-policy": "Defined by this policy", + "feedback.policy.error-delete-policy": "Error deleting policy", + "feedback.policy.error-handling.ignore-directory-errors": "Ignore Directory Errors", + "feedback.policy.error-handling.ignore-directory-errors-help": "Treat directory read errors as non-fatal.", + "feedback.policy.error-handling.ignore-file-errors": "Ignore File Errors", + "feedback.policy.error-handling.ignore-file-errors-help": "Treat file read errors as non-fatal.", + "feedback.policy.error-handling.ignore-unknown-directories": "Ignore Unknown Directory Entries", + "feedback.policy.error-handling.ignore-unknown-directories-help": "Treat unrecognized/unsupported directory entries as non-fatal errors.", + "feedback.policy.error-saving-policy": "Error saving policy", + "feedback.policy.files.ignore-files": "Ignore Files", + "feedback.policy.files.ignore-files-help": "List of file and directory names to ignore.
See documentation on ignoring files.", + "feedback.policy.files.ignore-files-hint": "e.g. /file.txt", + "feedback.policy.files.ignore-rule-files": "Ignore Rule Files", + "feedback.policy.files.ignore-rule-files-from-parent-directories": "Ignore Rule Files From Parent Directories", + "feedback.policy.files.ignore-rule-files-from-parent-directories-help": "When set, the files specifying ignore rules (.kopiaignore, etc.) from the parent directory are ignored", + "feedback.policy.files.ignore-rule-files-help": "List of additional files containing ignore rules (each file configures ignore rules for the directory and its subdirectories)", + "feedback.policy.files.ignore-rule-files-hint": "e.g. .kopiaignore", + "feedback.policy.files.ignore-rules-from-parent-directories": "Ignore Rules From Parent Directories", + "feedback.policy.files.ignore-rules-from-parent-directories-help": "When set, ignore rules from the parent directory are ignored", + "feedback.policy.files.ignore-well-known-cache-directories": "Ignore Well-Known Cache Directories", + "feedback.policy.files.ignore-well-known-cache-directories-help": "Ignore directories containing CACHEDIR.TAG and similar", + "feedback.policy.files.scan-only-one-filesystem": "Scan only one filesystem", + "feedback.policy.files.scan-only-one-filesystem-help": "Do not cross filesystem boundaries when creating a snapshot", + "feedback.policy.find-count": "feedback.policy.find-count", + "feedback.policy.find-count_one": "Found {{count}} policy matching the criteria", + "feedback.policy.find-count_other": "Found {{count}} policies matching the criteria", + "feedback.policy.find-hint": "Enter directory to find or set policy", + "feedback.policy.find-none": "feedback.policy.find-none", + "feedback.policy.find-none-create": "No policy found for directory {{path}}. Please setup a new policy.", + "feedback.policy.header.actions": "Actions", + "feedback.policy.header.compression": "Compression", + "feedback.policy.header.defined": "Defined", + "feedback.policy.header.error-handling": "Error Handling", + "feedback.policy.header.files": "Files", + "feedback.policy.header.folder-actions": "Folder Actions", + "feedback.policy.header.host": "Host", + "feedback.policy.header.logging": "Logging", + "feedback.policy.header.other": "Other", + "feedback.policy.header.path": "Path", + "feedback.policy.header.scheduling": "Scheduling", + "feedback.policy.header.snapshot-action": "Snapshot Actions", + "feedback.policy.header.snapshot-retention": "Snapshot Retention", + "feedback.policy.header.upload": "Upload", + "feedback.policy.kind.all": "All policies", + "feedback.policy.kind.applicable": "Applicable policies", + "feedback.policy.kind.global": "Global policies", + "feedback.policy.kind.local": "Local policies", + "feedback.policy.kind.per-host-policies": "Per-Host policies", + "feedback.policy.kind.per-user-policies": "Per-User policies", + "feedback.policy.logging.cache-hit": "Cache hit", + "feedback.policy.logging.cache-hit-help": "Log verbosity when a cache is used instead of uploading the file", + "feedback.policy.logging.cache-miss": "Cache miss", + "feedback.policy.logging.cache-miss-help": "Log verbosity when a cache cannot be used and a file must be hashed", + "feedback.policy.logging.directory-ignored": "Directory ignored", + "feedback.policy.logging.directory-ignored-help": "Log verbosity when a directory is ignored", + "feedback.policy.logging.directory-snapshotted": "Directory snapshotted", + "feedback.policy.logging.directory-snapshotted-help": "Log verbosity when a directory is snapshotted", + "feedback.policy.logging.file-ignored": "File ignored", + "feedback.policy.logging.file-ignored-help": "Log verbosity when a file, symbolic link, etc. is ignored", + "feedback.policy.logging.file-snapshotted": "File snapshotted", + "feedback.policy.logging.file-snapshotted-help": "Log verbosity when a file, symbolic link, etc. is snapshotted", + "feedback.policy.other.disable-parent-policy-evaluation": "Disable Parent Policy Evaluation", + "feedback.policy.other.disable-parent-policy-evaluation-help": "Prevents any parent policies from affecting this directory and its subdirectories", + "feedback.policy.other.json-representation": "JSON Representation", + "feedback.policy.other.json-representation-help": "This is the internal representation of a policy", + "feedback.policy.policies-defined-by-path-absolute": "Policies can only be defined for absolute paths.", + "feedback.policy.retention.annual-snapshot-retain": "Annual", + "feedback.policy.retention.annual-snapshot-retain-help": "How many annual snapshots to retain per source. The latest snapshot from each calendar year will be retained", + "feedback.policy.retention.annual-snapshot-retain-hint": "Number of annual snapshots", + "feedback.policy.retention.daily-snapshot-retain": "Daily", + "feedback.policy.retention.daily-snapshot-retain-help": "How many daily snapshots to retain per source. The latest snapshot from each day will be retained", + "feedback.policy.retention.daily-snapshot-retain-hint": "Number of daily snapshots", + "feedback.policy.retention.hourly-snapshot-retain": "Hourly", + "feedback.policy.retention.hourly-snapshot-retain-help": "How many hourly snapshots to retain per source. The latest snapshot from each hour will be retained", + "feedback.policy.retention.hourly-snapshot-retain-hint": "number of hourly snapshots", + "feedback.policy.retention.ignore-identical-snapshots": "Ignore Identical Snapshots", + "feedback.policy.retention.ignore-identical-snapshots-help": "Do NOT save a snapshot when no files have been changed", + "feedback.policy.retention.keep-latest-help": "number of latest snapshots", + "feedback.policy.retention.latest-snapshot-retain": "Latest Snapshots", + "feedback.policy.retention.latest-snapshot-retain-help": "Number of the most recent snapshots to retain per source", + "feedback.policy.retention.monthly-snapshot-retain": "Monthly", + "feedback.policy.retention.monthly-snapshot-retain-help": "How many monthly snapshots to retain per source. The latest snapshot from each calendar month will be retained", + "feedback.policy.retention.monthly-snapshot-retain-hint": "Number of monthly snapshots", + "feedback.policy.retention.weekly-snapshot-retain": "Weekly", + "feedback.policy.retention.weekly-snapshot-retain-help": "How many weekly snapshots to retain per source. The latest snapshot from each week will be retained", + "feedback.policy.retention.weekly-snapshot-retain-hint": "Number of weekly snapshots", + "feedback.policy.scheduling.cron-expressions": "Cron Expressions", + "feedback.policy.scheduling.cron-expressions-hint": "minute hour day month weekday", + "feedback.policy.scheduling.cron-help": "Snapshot schedules using UNIX crontab syntax (one per line):
See supported format details.", + "feedback.policy.scheduling.manual-snapshots-only": "Manual Snapshots Only", + "feedback.policy.scheduling.manual-snapshots-only-help": "Only create snapshots manually (disables scheduled snapshots)", + "feedback.policy.scheduling.missed-snapshots-startup": "Run Missed Snapshots on Startup", + "feedback.policy.scheduling.missed-snapshots-startup-help": "Immediately run any missed snapshots when kopia starts (only relevant for Time-of-day snapshots)", + "feedback.policy.scheduling.no-upcoming-snapshots": "No upcoming snapshots", + "feedback.policy.scheduling.snapshot-frequency": "Snapshot Frequency", + "feedback.policy.scheduling.snapshot-frequency-help": "How frequently to create snapshots in KopiaUI or Kopia server (has no effect outside of the server mode)", + "feedback.policy.scheduling.times-of-day": "Times Of Day", + "feedback.policy.scheduling.times-of-day-help": "Create snapshots at the specified times of day (24hr format)", + "feedback.policy.scheduling.times-of-day-hint": "e.g. 17:00", + "feedback.policy.scheduling.upcoming": "Upcoming", + "feedback.policy.scheduling.upcoming-snapshots": "Upcoming Snapshots", + "feedback.policy.scheduling.upcoming-snapshots-help": "Times of upcoming snapshots calculated based on policy parameters", + "feedback.policy.time-of-day.invalid": "Invalid time of day: {{tod}}", + "feedback.policy.timeout-help": "Timeout in seconds before Kopia kills the process", + "feedback.policy.upload.maximum-parallel-file-reads": "Maximum Parallel File Reads", + "feedback.policy.upload.maximum-parallel-file-reads-help": "Maximum number of files that will be read in parallel (defaults to the number of logical processors)", + "feedback.policy.upload.maximum-parallel-file-reads-hint": "max number of parallel file reads", + "feedback.policy.upload.maximum-parallel-snapshots": "Maximum Parallel Snapshots", + "feedback.policy.upload.maximum-parallel-snapshots-help": "Maximum number of snapshots that can be uploaded simultaneously", + "feedback.policy.upload.maximum-parallel-snapshots-hint-set": "max number of parallel snapshots", + "feedback.policy.upload.maximum-parallel-snapshots-hint-unset": "must be specified using global, user, or host policy", + "feedback.prodiver.gcs.paste-json-credentials": "Paste JSON credentials here", + "feedback.provider.azure-blob-storage": "Azure Blob Storage", + "feedback.provider.azure.access-key": "Access Key", + "feedback.provider.azure.azure-storage-domain": "Azure Storage Domain", + "feedback.provider.azure.container": "Container", + "feedback.provider.azure.enter-access-key": "Enter secret access key", + "feedback.provider.azure.enter-azure-storage-domain": "feedback.validation.azure.azure-storage-domain-hint", + "feedback.provider.azure.enter-container-name": "Enter container name", + "feedback.provider.azure.enter-object-name-prefix": "Enter object name prefix or leave empty", + "feedback.provider.azure.enter-sas-token": "Enter secret SAS Token", + "feedback.provider.azure.enter-storage-account": "Enter storage account name", + "feedback.provider.azure.object-name-prefix": "Object Name Prefix", + "feedback.provider.azure.sas-token": "SAS Token", + "feedback.provider.azure.storage-account": "Storage Account", + "feedback.provider.b2.bucket-name": "B2 Bucket", + "feedback.provider.b2.enter-account-key": "Enter secret application or account key", + "feedback.provider.b2.enter-account-key-id": "Enter application or account key ID", + "feedback.provider.b2.enter-bucket-name": "Enter bucket name", + "feedback.provider.b2.enter-object-name-prefix": "Enter object name prefix or leave empty", + "feedback.provider.b2.key": "Key", + "feedback.provider.b2.key-id": "Key ID", + "feedback.provider.b2.object-name-prefix": "Object Name Prefix", + "feedback.provider.backblaze-b2": "Backblaze B2", + "feedback.provider.filesystem.directory-path": "Directory Path", + "feedback.provider.filesystem.enter-directory-path": "Enter directory path where you want to store repository files", + "feedback.provider.gcs.bucket-name": "GCS Bucket", + "feedback.provider.gcs.credentials-file": "Credentials File", + "feedback.provider.gcs.credentials-json": "Credentials JSON", + "feedback.provider.gcs.enter-bucket-name": "Enter bucket name", + "feedback.provider.gcs.enter-credentials-file-name": "Enter name of credentials JSON file", + "feedback.provider.gcs.enter-object-name-prefix": "Enter object name prefix or leave empty", + "feedback.provider.gcs.object-name-prefix": "Object Name Prefix", + "feedback.provider.google-cloud-storage": "Google Cloud Storage", + "feedback.provider.kopia-repository-server": "Kopia Repository Server", + "feedback.provider.local-directory-or-nas": "Local Directory or NAS", + "feedback.provider.rclone-remote": "Rclone Remote", + "feedback.provider.rclone.rclone-executable-path": "Rclone Executable Path", + "feedback.provider.rclone.rclone-executable-path-hint": "Enter path to rclone executable", + "feedback.provider.rclone.rclone-remote-path": "Rclone Remote Path", + "feedback.provider.rclone.rclone-remote-path-hint": "Enter :", + "feedback.provider.repositoryserver.enter-server-certificate-fingerprint": "Enter trusted server certificate fingerprint printed at server startup", + "feedback.provider.repositoryserver.enter-server-url": "Enter server URL (https://:port)", + "feedback.provider.repositoryserver.server-address": "Server address", + "feedback.provider.repositoryserver.server-certificate-fingerprint": "Trusted server certificate fingerprint (SHA256)", + "feedback.provider.repositorytoken.paste-token": "Paste connection token", + "feedback.provider.repositorytoken.token": "Token", + "feedback.provider.required-either-key-file": "One of Password, Key File or Key Data is required.", + "feedback.provider.required-either-known-host-data": "Either Known Hosts File or Known Hosts Data is required, but not both.", + "feedback.provider.s3-or-compatible-storage": "Amazon S3 or Compatible Storage", + "feedback.provider.s3.access-key-id": "Access Key ID", + "feedback.provider.s3.access-key-id-hint": "Enter access key ID", + "feedback.provider.s3.bucket-name": "Bucket", + "feedback.provider.s3.bucket-name-hint": "Enter bucket name", + "feedback.provider.s3.enter-object-name-prefix-hint": "Enter object name prefix or leave empty", + "feedback.provider.s3.object-name-prefix": "Object Name Prefix", + "feedback.provider.s3.override-region": "Override Region", + "feedback.provider.s3.override-region-hint": "Enter specific region (e.g., us-west-1) or leave empty", + "feedback.provider.s3.secret-access-key": "Secret Access Key", + "feedback.provider.s3.secret-access-key-hint": "Enter secret access key", + "feedback.provider.s3.server-endpoint": "Server Endpoint", + "feedback.provider.s3.server-endpoint-hint": "Enter server address (e.g., s3.amazonaws.com)", + "feedback.provider.s3.session-token": "Session Token", + "feedback.provider.s3.session-token-hint": "Enter session token or leave empty", + "feedback.provider.sftp-key-data": "Key Data", + "feedback.provider.sftp-key-data-hint": "Paste contents of the key file", + "feedback.provider.sftp-server": "SFTP Server", + "feedback.provider.sftp.enter-password": "Enter password", + "feedback.provider.sftp.enter-path-host-file": "Enter path to the known_hosts file", + "feedback.provider.sftp.enter-path-to-key-file": "Enter path to the key file", + "feedback.provider.sftp.enter-remote-path": "Enter remote path to repository, e.g., '/mnt/data/repository'", + "feedback.provider.sftp.enter-ssh-arguments": "Enter SSH command arguments ('user@host -s sftp' will be appended automatically)", + "feedback.provider.sftp.enter-ssh-host-name": "ssh host name (e.g., example.com)", + "feedback.provider.sftp.host": "Host", + "feedback.provider.sftp.known-host-data": "Known Hosts Data", + "feedback.provider.sftp.launch-external-ssh-command": "Launch external password-less SSH command", + "feedback.provider.sftp.launch-external-ssh-command-hint": "By default Kopia connects to the server using internal SSH client which supports limited options. Alternatively it may launch external password-less SSH command, which supports additional options, but is generally less efficient than the built-in client.", + "feedback.provider.sftp.password": "Password", + "feedback.provider.sftp.paste-content-of-known-host": "Paste the contents of the known_hosts file", + "feedback.provider.sftp.path": "Path", + "feedback.provider.sftp.path-host-file": "Path to known_hosts file", + "feedback.provider.sftp.path-key-file": "Path to key file", + "feedback.provider.sftp.port": "Port", + "feedback.provider.sftp.port-number": "Port number (e.g., 22)", + "feedback.provider.sftp.provide-passwordless-ssh-command": "Provide the passwordless SSH command to execute (typically 'ssh')", + "feedback.provider.sftp.ssh-arguments": "SSH Arguments", + "feedback.provider.sftp.ssh-command": "SSH Command", + "feedback.provider.sftp.user": "User", + "feedback.provider.sftp.user-name": "User name", + "feedback.provider.use-repository-token": "Use Repository Token", + "feedback.provider.webdav-server": "WebDAV Server", + "feedback.provider.webdav.enter-password": "Enter password", + "feedback.provider.webdav.enter-username": "Enter username", + "feedback.provider.webdav.password": "Password", + "feedback.provider.webdav.server-url": "WebDAV Server URL", + "feedback.provider.webdav.username": "Username", + "feedback.repository.additional-parameters-hint": "Additional parameters can be set when creating repository using command line.", + "feedback.repository.attribute.algorithm-eco": "エラー訂正アルゴリズム", + "feedback.repository.attribute.algorithm-encryption": "暗号化アルゴリズム", + "feedback.repository.attribute.algorithm-hash": "ハッシュアルゴリズム", + "feedback.repository.attribute.algorithm-splitter": "分割アルゴリズム", + "feedback.repository.attribute.config-file": "設定ファイル", + "feedback.repository.attribute.connected-as": "接続されたユーザー", + "feedback.repository.attribute.internal-compression": "内部圧縮", + "feedback.repository.attribute.repository-eco": "エラー訂正オーバーヘッド", + "feedback.repository.attribute.repository-format": "リポジトリの形式", + "feedback.repository.attribute.repository-provider": "プロバイダー", + "feedback.repository.attribute.server-url": "サーバーのURL", + "feedback.repository.configuration": "Storage Configuration", + "feedback.repository.connect-as": "Connect as", + "feedback.repository.connect-in-read-only-mode": "Connect in read-only mode", + "feedback.repository.connect-in-read-only-mode-hint": "Read-only mode prevents any changes to the repository.", + "feedback.repository.connect-to-repository": "Connect to repository", + "feedback.repository.create-repository-new": "Create New Repository", + "feedback.repository.create-repository-new-help": "Enter a strong password to create Kopia repository in the provided storage.", + "feedback.repository.eco-disabled": "無効", + "feedback.repository.eec-warning": "[EXPERIMENTAL] Error correction can help protect from certain kinds of data corruption due to spontaneous bit flips in the storage media.", + "feedback.repository.encryption": "Encryption", + "feedback.repository.enter-repository-password": "Enter repository password", + "feedback.repository.hostname": "Hostname", + "feedback.repository.hostname-hint": "Override this when restoring a snapshot taken on another machine", + "feedback.repository.internal-compression-supported-no": "いいえ", + "feedback.repository.internal-compression-supported-yes": "はい", + "feedback.repository.kopia-server-parameters": "Kopia Server Parameters", + "feedback.repository.name-default": "My Repository", + "feedback.repository.override-hint": "To override, click 'Show Advanced Options'", + "feedback.repository.provider-selection": "Select Storage Type", + "feedback.repository.provider-selection-hint": "To connect to a repository or create one, select the preferred storage type:", + "feedback.repository.repository-description": "Repository description", + "feedback.repository.repository-description-help": "Helps to distinguish between multiple connected repositories", + "feedback.repository.repository-description-hint": "Enter repository description", + "feedback.repository.repository-description-required": "リポジトリの説明は必須です", + "feedback.repository.repository-initializing": "リポジトリの初期化中...", + "feedback.repository.repository-is-read-only": "リポジトリは読み取り専用です", + "feedback.repository.repository-password": "Repository Password", + "feedback.repository.repository-password-confirm": "Confirm Repository Password", + "feedback.repository.repository-password-confirm-again": "enter repository password again", + "feedback.repository.repository-password-help": "Used to encrypt the repository's contents", + "feedback.repository.repository-token-enter": "Enter Repository Token", + "feedback.repository.server-password": "Server password", + "feedback.repository.server-password-hint": "Enter password to connect to server", + "feedback.repository.status-connected": "リポジトリに接続済み", + "feedback.repository.username": "Username", + "feedback.repository.username-hint": "Override this when restoring a snapshot taken by another user", + "feedback.snapshot.create.enter-path-to-snapshot-hint": "Enter path to snapshot", + "feedback.snapshot.create.must-specify-path": "Must specify directory to snapshot.", + "feedback.snapshot.create.snapshot-new": "New Snapshot", + "feedback.snapshot.description": "Description", + "feedback.snapshot.description.snapshot-description": "Snapshot Description", + "feedback.snapshot.directory.browsing-not-supported": "Directory browsing is not supported in a web browser. Use Kopia UI.", + "feedback.snapshot.directory.restore-all-files-help": "You can mount/restore all the files and directories that you see below or restore files individually.", + "feedback.snapshot.header.actions": "アクション", + "feedback.snapshot.header.details": "Details", + "feedback.snapshot.header.directories": "Dirs", + "feedback.snapshot.header.files": "Files", + "feedback.snapshot.header.last-snapshot": "最後のスナップショット", + "feedback.snapshot.header.next-snapshot": "次のスナップショット", + "feedback.snapshot.header.retention": "Retention", + "feedback.snapshot.header.root": "Root", + "feedback.snapshot.header.selected": "Selected", + "feedback.snapshot.header.snapshot-owner": "オーナー", + "feedback.snapshot.header.snapshot-path": "パス", + "feedback.snapshot.header.snapshot-size": "Size", + "feedback.snapshot.header.start-time": "Start time", + "feedback.snapshot.header.status": "ステータス", + "feedback.snapshot.history.snapshot-displaying": "Displaying", + "feedback.snapshot.history.wipe-all-snapshots": "Wipe all snapshots and the policy for this source.", + "feedback.snapshot.restore.continue-on-errors": "エラーが発生した場合に続行", + "feedback.snapshot.restore.continue-on-errors-help": "復元エラーが発生した場合、即座に失敗せずに続行を試みます。", + "feedback.snapshot.restore.destination": "宛先", + "feedback.snapshot.restore.destination-help": "適切な拡張子を指定することで、.zipまたは.tarファイルにも復元できます。", + "feedback.snapshot.restore.destination-hint": "宛先パスを入力", + "feedback.snapshot.restore.disable-zip-compression": "ZIP圧縮を無効にする", + "feedback.snapshot.restore.disable-zip-compression-help": "ZIPファイルへの復元時に圧縮しない(高速)。", + "feedback.snapshot.restore.minimal-file-size-for-shallow-restore": "浅い復元の最小ファイルサイズ", + "feedback.snapshot.restore.overwrite-directory": "ディレクトリを上書き", + "feedback.snapshot.restore.overwrite-files": "ファイルを上書き", + "feedback.snapshot.restore.overwrite-symbolic-links": "シンボリックリンクを上書き", + "feedback.snapshot.restore.restore-file-modification-time": "ファイルの変更時刻を復元", + "feedback.snapshot.restore.restore-file-ownership": "ファイル所有権を復元", + "feedback.snapshot.restore.restore-file-permissions": "ファイルのアクセス権を復元", + "feedback.snapshot.restore.shallow-restore-at-depth": "指定の深さで浅い復元", + "feedback.snapshot.restore.skip-previously-restored-files": "以前に復元されたファイルとシンボリックリンクをスキップ", + "feedback.snapshot.restore.snapshot-restore": "復元", + "feedback.snapshot.restore.write-files-atomically": "ファイルをアトミックに書き込む", + "feedback.snapshot.restore.write-sparse-files": "スパースファイルを書き込む", + "feedback.snapshot.show-individual-snapshots-count": "feedback.snapshot.show-individual-snapshots-count", + "feedback.snapshot.show-individual-snapshots-count_one": "Show {{count}} individual snapshot", + "feedback.snapshot.show-individual-snapshots-count_other": "Show {{count}} individual snapshots", + "feedback.snapshot.start-after-previous-snapshot": "前のスナップショットが完了した後にスナップショットが開始されます", + "feedback.snapshot.status.status-overdue": "overdue", + "feedback.snapshot.status.status-pending": "保留中", + "feedback.tab.policies": "ポリシー", + "feedback.tab.preferences": "設定", + "feedback.tab.repository": "リポジトリ", + "feedback.tab.repository-is-not-connected": "Repository is not connected", + "feedback.tab.snapshots": "スナップショット", + "feedback.tab.tasks": "タスク", + "feedback.task.estimated-results": "{{description}} Bytes: {{bytes}} ({{bytes.excluded}} excluded) Files: {{files}} ({{files.excluded}} excluded) Directories: {{directories}} ({{directories.excluded}} excluded) Errors: {{errors}} ({{errors.ignored}} ignored)", + "feedback.task.header.counter": "カウンター", + "feedback.task.header.value": "値", + "feedback.task.logs": "ログ", + "feedback.task.no-tasks-help": "スナップショットを作成したり、復元したり、メンテナンスを実行したりすると、ここにタスクの一覧が表示されます。", + "feedback.task.search-tasks-by-hint": "Search task logs by description", + "feedback.task.status.task-canceled": "Task canceled", + "feedback.task.status.task-canceled-after": "Task canceled after", + "feedback.task.status.task-canceling": "キャンセル中", + "feedback.task.status.task-error": "タスクエラー", + "feedback.task.status.task-failed-after": "Failed after", + "feedback.task.status.task-finished": "完了済み", + "feedback.task.status.task-finished-in": "Finished in", + "feedback.task.status.task-running-for": "タスク実行中", + "feedback.task.status.task-started": "開始済み", + "feedback.task.status.task-succeeded-after": "タスクは成功しました。", + "feedback.task.table.header-description": "説明", + "feedback.task.table.header-kind": "種類", + "feedback.task.table.header-start-time": "開始時刻", + "feedback.task.table.header-status": "ステータス", + "feedback.task.tasks-total": "Total", + "feedback.ui.appearance": "外観", + "feedback.ui.appearance-help": "ユーザーインターフェースの外観を指定します", + "feedback.ui.appearance-hint": "フォントサイズを選択", + "feedback.ui.byte-representation-description": "バイトの表現を選択", + "feedback.ui.byte-representation-help": "バイトの表現を指定します", + "feedback.ui.byte-representation-select": "バイトの表現を選択", + "feedback.ui.pagesize-description": "ページサイズ", + "feedback.ui.pagesize-help": "テーブルのページネーションサイズを指定します", + "feedback.ui.pagesize-hint": "ページサイズ", + "feedback.ui.theme-description": "テーマ", + "feedback.ui.theme-help": "現在のアクティブなテーマ", + "feedback.ui.theme-select": "テーマを選択", + "feedback.validation.invalid-times-of-day": "Invalid Times of Day", + "feedback.validation.optional.valid-number-or-empty": "Must be a valid number or empty", + "feedback.validation.passwords-dont-match": "Passwords don't match", + "feedback.validation.required.directory": "Required field", + "feedback.validation.required.field": "Required field", + "feedback.validation.required.valid-number-or-empty": "Must be a valid number or empty", + "value.algorithm.eco-disabled": "Disabled", + "value.algorithm.suffix-not-recommended": "(NOT RECOMMENDED)", + "value.algorithm.suffix-recommended": "(RECOMMENDED)", + "value.log.details-0-no-output": "0 - no output", + "value.log.details-1-minimal-details": "1 - minimal details", + "value.log.details-10-maximum-details": "10 - maximum details", + "value.log.details-5-normal-details": "5 - normal details", + "value.log.details-inherit-from-parent": "(inherit from parent)", + "value.policy.async": "Run asynchronously, ignore failures", + "value.policy.essential": "Must succeed", + "value.policy.inherent-from-parent": "inherit from parent", + "value.policy.none": "none", + "value.policy.optional": "Ignore failures", + "value.provider.s3.http-connection-insecure": "Use HTTP connection (insecure)", + "value.provider.s3.no-tls-verification": "Do not verify TLS certificate", + "value.repository.latest-format": "Latest format", + "value.repository.legacy-format": "Legacy format compatible with v0.8", + "value.snapshot-frequency.10-minutes": "every 10 minutes", + "value.snapshot-frequency.12-hours": "every 12 hours", + "value.snapshot-frequency.15-minutes": "every 15 minutes", + "value.snapshot-frequency.20-minutes": "every 20 minutes", + "value.snapshot-frequency.3-hours": "every 3 hours", + "value.snapshot-frequency.30-minutes": "every 30 minutes", + "value.snapshot-frequency.6-hours": "every 6 hours", + "value.snapshot-frequency.hour": "every hour", + "value.ui.appearance-large": "大", + "value.ui.appearance-medium": "中", + "value.ui.appearance-small": "小", + "value.ui.byte-representation-base10": "Base-10 (KB, MB, GB, TB)", + "value.ui.byte-representation-base2": "Base-2 (KiB, MiB, GiB, TiB)", + "value.ui.theme-dark": "ダーク", + "value.ui.theme-light": "ライト", + "value.ui.theme-ocean": "オーシャン", + "value.ui.theme-pastel": "パステル", + "value.validation.optional-no": "no", + "value.validation.optional-yes": "yes" +} diff --git a/public/locales/pl/translation.json b/public/locales/pl/translation.json new file mode 100644 index 00000000..342a06d4 --- /dev/null +++ b/public/locales/pl/translation.json @@ -0,0 +1,479 @@ +{ + "common.action.back": "Z powrotem", + "common.action.cancel": "Anuluj", + "common.action.click-here-to-learn-more": "Kliknij tutaj, aby dowiedzieć się więcej.", + "common.action.confirm-delete": "Potwierdź usunięcie", + "common.action.delete": "Usuń", + "common.action.next": "Dalej", + "common.action.return": "Wróć", + "common.action.stop": "Zatrzymaj", + "common.label.loading": "Wczytywanie...", + "event.cli.copy-to-clipboard": "Skopiuj do schowka", + "event.cli.show-cli-equivalent": "Kliknij, aby wyświetlić odpowiednik CLI", + "event.log.hide-log": "Schowaj log", + "event.log.show-log": "Pokaż log", + "event.pin.add-pin": "Dodaj Pin", + "event.pin.pin-snapshot": "Dodaj pinezkę", + "event.pin.remove-pin": "Usuń pinezkę", + "event.pin.update-pin": "Zmień piezkę", + "event.policy.delete": "Usuń regułę", + "event.policy.edit": "Edytuj", + "event.policy.save": "Zapisz regułę", + "event.policy.set-policy": "Ustaw regułę", + "event.repository.cancel-connection": "Przerwij próbę połączenia", + "event.repository.connect-to-repository": "Połącz się z repozytorium", + "event.repository.create-repository": "Utwórz repozytorium", + "event.repository.disconnect-from-repository": "Odłącz od repozytorium", + "event.repository.hide-advanced-options": "Ukryj opcje zaawansowane", + "event.repository.show-advanced-options": "Pokaż ustawienia zaawansowane", + "event.repository.update-description": "Zmień opis", + "event.snapshot.browse-directory": "Przeglądać", + "event.snapshot.delete-selected": "Usuń zaznaczone", + "event.snapshot.delete-selected_one": "Czy chcesz usunąć wybraną kopię?", + "event.snapshot.delete-selected_other": "Czy chcesz usunąć wybrane kopie ({{count}})?", + "event.snapshot.description.enter-new-description": "Wprowadź nowy opis", + "event.snapshot.description.remove-description": "Usuń opis", + "event.snapshot.description.update-description": "Aktualizuj opis", + "event.snapshot.estimate": "Oszacuj", + "event.snapshot.fetch-snapshots": "Odśwież", + "event.snapshot.history.delete-selected": "Usuń wybrane ({{count}})", + "event.snapshot.history.delete-snapshot-source": "Usuń źródło kopii zapasowyc", + "event.snapshot.history.deselect-all": "Odznacz wszystkie", + "event.snapshot.history.select-all-snapshots": "Zaznacz wszystkie", + "event.snapshot.history.update-snapshot-description": "{{description}} - Kliknij aby zaktualizować opis.", + "event.snapshot.mount-directory": "Zamontuj jako lokalny system plików", + "event.snapshot.new-snapshot": "Nowa kopia zapasowa", + "event.snapshot.restore-file-directories": "Przywróć pliki i katalogi", + "event.snapshot.restore.begin-restore": "Rozpocznij przywracanie", + "event.snapshot.restore.go-to-restore-task": "Przejdź do zadania przywracania", + "event.snapshot.show-policy": "Pokaz regułę", + "event.snapshot.snapshot-now": "Utwórz kopię teraz", + "event.snapshot.synchronize": "Synchronizuj", + "event.snapshot.unmount-directory": "Odmontuj", + "event.task.action.cancel": "Anuluj zadanie", + "event.task.select.task-all": "wszystkie", + "event.task.select.task-failed": "nieudane", + "event.task.select.task-running": "w toku", + "feedback.directory.header.directories": "Katalogi", + "feedback.directory.header.files": "Pliki", + "feedback.directory.header.last-modification": "Ostatnia modyfikacja", + "feedback.directory.header.name": "Nazwa", + "feedback.directory.header.size": "Rozmiar", + "feedback.error.common": "Błąd", + "feedback.error.connection": "Błąd połączenia:", + "feedback.header.effective": "Skuteczny", + "feedback.header.username": "Nazwa użytkownika", + "feedback.pin.add-pin-to-protect": "Dodaj pinezkę, aby zabezpieczyć kopię zapasową przed usunięciem", + "feedback.pin.do-not-delete": "nie kasuj", + "feedback.pin.name-of-the-pin": "Nazwa pinu", + "feedback.policy.action.command-mode": "Tryb poleceń", + "feedback.policy.actions.after-folder": "Po folderze", + "feedback.policy.actions.after-folder-help": "Skrypt uruchamiany po folderze", + "feedback.policy.actions.after-snapshot": "Po wykonaniu kopii zapasowej", + "feedback.policy.actions.after-snapshot-help": "Skrypt uruchamiany po wykonaniu kopii zapasowej", + "feedback.policy.actions.before-folder": "Przed folderem", + "feedback.policy.actions.before-folder-help": "Skrypt uruchamiany przed folderem", + "feedback.policy.actions.before-snapshot": "Przed wykonaniem kopii zapasowej", + "feedback.policy.actions.before-snapshot-help": "Skrypt uruchamiany przed wykonaniem kopii zapasowej", + "feedback.policy.actions.timeout": "Maksymalny czas działania skryptu", + "feedback.policy.command-mode-help": "Niezbędny (musi zakończyć się sukcesem; zachowanie domyślne), opcjonalny (awarie są tolerowane) lub asynchroniczny (Kopia rozpocznie akcję, ale nie będzie czekać na jej zakończenie)", + "feedback.policy.compression.compression-algorithm": "Algorytm kompresji", + "feedback.policy.compression.compression-algorithm-help": "Określ algorytm kompresji, który będzie używany podczas tworzenia kopii zapasowych plików w tym katalogu i podkatalogach", + "feedback.policy.compression.maximal-file-size": "Maksymalny rozmiar pliku", + "feedback.policy.compression.maximal-file-size-help": "Pliki, których rozmiar przekracza podaną wartość, nie zostaną skompresowane", + "feedback.policy.compression.maximal-file-size-hint": "Maksymalny rozmiar pliku w bajtach", + "feedback.policy.compression.minimal-file-size": "Minimalny rozmiar pliku", + "feedback.policy.compression.minimal-file-size-help": "Pliki mniejsze niż podana wartość nie zostaną skompresowane", + "feedback.policy.compression.minimal-file-size-hint": "minimalny rozmiar pliku w bajtach", + "feedback.policy.compression.never-compress-extensions": "Nigdy nie kompresuj rozszerzeń", + "feedback.policy.compression.never-compress-extensions-help": "Nigdy nie kompresuj następujących rozszerzeń plików (jedno rozszerzenie w linii)", + "feedback.policy.compression.never-compress-extensions-hint": "np. *.mp4", + "feedback.policy.compression.only-compress-extensions": "Kompresuj tylko rozszerzenia", + "feedback.policy.compression.only-compress-extensions-help": "Kompresuj tylko pliki z następującymi rozszerzeniami (jedno rozszerzenie w linii)", + "feedback.policy.compression.only-compress-extensions-hint": "np. *.tekst", + "feedback.policy.confirm-delete-policy": "Czy na pewno chcesz usunąć tę regułę?", + "feedback.policy.defined-by": "Określona przez", + "feedback.policy.defined-by-this-policy": "Zdefiniowane w tej regule", + "feedback.policy.error-delete-policy": "Błąd podczas usuwania reguły", + "feedback.policy.error-handling.ignore-directory-errors": "Ignoruj ​​​​błędy katalogu", + "feedback.policy.error-handling.ignore-directory-errors-help": "Traktuj błędy odczytu katalogu jako niekrytyczne.", + "feedback.policy.error-handling.ignore-file-errors": "Ignoruj ​​​​błędy plików", + "feedback.policy.error-handling.ignore-file-errors-help": "Traktuj błędy odczytu plików jako niekrytyczne.", + "feedback.policy.error-handling.ignore-unknown-directories": "Ignoruj ​​nieznane wpisy w katalogu", + "feedback.policy.error-handling.ignore-unknown-directories-help": "Traktuj nierozpoznane/nieobsługiwane wpisy katalogu jako błędy niekrytyczne.", + "feedback.policy.error-saving-policy": "Błąd podczas zapisywania zasad", + "feedback.policy.files.ignore-files": "Ignoruj ​​pliki", + "feedback.policy.files.ignore-files-help": "Lista nazw plików i katalogów do zignorowania.
Zobacz dokumentację dotyczącą ignorowania plików.", + "feedback.policy.files.ignore-files-hint": "np. /plik.txt", + "feedback.policy.files.ignore-rule-files": "Ignoruj ​​pliki reguł", + "feedback.policy.files.ignore-rule-files-from-parent-directories": "Ignoruj ​​pliki reguł z katalogów nadrzędnych", + "feedback.policy.files.ignore-rule-files-from-parent-directories-help": "Po ustawieniu, pliki określające reguły ignorowania (.kopiaignore itp.) z katalogu nadrzędnego są ignorowane", + "feedback.policy.files.ignore-rule-files-help": "Lista dodatkowych plików zawierających reguły ignorowania (każdy plik konfiguruje reguły ignorowania dla katalogu i jego podkatalogów)", + "feedback.policy.files.ignore-rule-files-hint": "np. .kopiaignore", + "feedback.policy.files.ignore-rules-from-parent-directories": "Ignoruj ​​reguły z katalogów nadrzędnych", + "feedback.policy.files.ignore-rules-from-parent-directories-help": "Po ustawieniu reguły ignorowania z katalogu nadrzędnego są ignorowane", + "feedback.policy.files.ignore-well-known-cache-directories": "Ignoruj ​​dobrze znane katalogi pamięci podręcznej", + "feedback.policy.files.ignore-well-known-cache-directories-help": "Ignoruj ​​katalogi zawierające CACHEDIR.TAG i podobne", + "feedback.policy.files.scan-only-one-filesystem": "Skanuj tylko jeden system plików", + "feedback.policy.files.scan-only-one-filesystem-help": "Podczas tworzenia kopii zapasowych nie przekraczaj granic systemu plików", + "feedback.policy.find-count": "Znaleziono {{count}} reguł spełniających kryteria", + "feedback.policy.find-count_one": "Znaleziono regułę spełniającą kryteria", + "feedback.policy.find-count_other": "Znaleziono {{count}} reguł spełniających kryteria", + "feedback.policy.find-hint": "Wejdź do katalogu, aby znaleźć lub ustawić politykę", + "feedback.policy.find-none": "Nie znaleziono reguł", + "feedback.policy.find-none-create": "Nie znaleziono reguł dla katalogu {{path}}. \nUtwórz nową regułę.", + "feedback.policy.header.actions": "działania", + "feedback.policy.header.compression": "Kompresja", + "feedback.policy.header.defined": "Zdefiniowane", + "feedback.policy.header.error-handling": "Obsługa błędów", + "feedback.policy.header.files": "Pliki", + "feedback.policy.header.folder-actions": "Akcje folderów", + "feedback.policy.header.host": "Host", + "feedback.policy.header.logging": "Logowanie", + "feedback.policy.header.other": "Inny", + "feedback.policy.header.path": "Ścieżka", + "feedback.policy.header.scheduling": "Planowanie", + "feedback.policy.header.snapshot-action": "Akcje kopii zapasowych", + "feedback.policy.header.snapshot-retention": "Przechowywanie kopii zapasowych", + "feedback.policy.header.upload": "Wgrywać", + "feedback.policy.kind.all": "Wszystkie zasady", + "feedback.policy.kind.applicable": "Obowiązujące reguły", + "feedback.policy.kind.global": "Polityka globalna", + "feedback.policy.kind.local": "Polityka lokalna", + "feedback.policy.kind.per-host-policies": "Reguły dotyczące poszczególnych hostów", + "feedback.policy.kind.per-user-policies": "Reguły dotyczące poszczególnych użytkowników", + "feedback.policy.logging.cache-hit": "Trafienie w pamięć podręczną", + "feedback.policy.logging.cache-hit-help": "Szczegółowość dziennika, gdy zamiast przesyłania pliku używana jest pamięć podręczna", + "feedback.policy.logging.cache-miss": "Brak pamięci podręcznej", + "feedback.policy.logging.cache-miss-help": "Szczegółowość dziennika, gdy nie można użyć pamięci podręcznej i plik musi zostać zaszyfrowany", + "feedback.policy.logging.directory-ignored": "Katalog zignorowany", + "feedback.policy.logging.directory-ignored-help": "Rejestruj szczegółowość, gdy katalog jest ignorowany", + "feedback.policy.logging.directory-snapshotted": "Zrzut katalogu", + "feedback.policy.logging.directory-snapshotted-help": "Szczegółowość dziennika podczas tworzenia kopii zapasowej katalogu", + "feedback.policy.logging.file-ignored": "Plik zignorowany", + "feedback.policy.logging.file-ignored-help": "Rejestruj szczegółowość, gdy plik, łącze symboliczne itp. jest ignorowane", + "feedback.policy.logging.file-snapshotted": "Zrzut pliku", + "feedback.policy.logging.file-snapshotted-help": "Rejestruj szczegółowość zapisu pliku, łącza symbolicznego itp", + "feedback.policy.other.disable-parent-policy-evaluation": "Wyłącz ocenę zasad nadrzędnych", + "feedback.policy.other.disable-parent-policy-evaluation-help": "Zapobiega wpływowi zasad nadrzędnych na ten katalog i jego podkatalogi", + "feedback.policy.other.json-representation": "Reprezentacja JSON", + "feedback.policy.other.json-representation-help": "Jest to wewnętrzna reprezentacja polityki", + "feedback.policy.policies-defined-by-path-absolute": "Zasady można definiować tylko dla ścieżek bezwzględnych.", + "feedback.policy.retention.annual-snapshot-retain": "Coroczny", + "feedback.policy.retention.annual-snapshot-retain-help": "Liczba corocznych kopii zapasowych przechowywanych dla każdego źródła. \nZachowana zostanie najnowsza kopia zapasowa z każdego roku kalendarzowego", + "feedback.policy.retention.annual-snapshot-retain-hint": "Liczba corocznych kopii zapasowych", + "feedback.policy.retention.daily-snapshot-retain": "Codziennie", + "feedback.policy.retention.daily-snapshot-retain-help": "Liczba codziennych kopii zapasowych przechowywanych dla każdego źródła. \nNajnowsza kopia zapasowa z każdego dnia zostanie zachowana", + "feedback.policy.retention.daily-snapshot-retain-hint": "Liczba codziennych kopii zapasowych", + "feedback.policy.retention.hourly-snapshot-retain": "Cogodzinne", + "feedback.policy.retention.hourly-snapshot-retain-help": "Ile godzinnych kopii zapasowych zachować na źródło. \nNajnowsza kopia zapasowa z każdej godziny zostanie zachowana", + "feedback.policy.retention.hourly-snapshot-retain-hint": "liczba godzinnych kopii zapasowych", + "feedback.policy.retention.ignore-identical-snapshots": "Ignoruj ​​identyczne kopie zapasowe", + "feedback.policy.retention.ignore-identical-snapshots-help": "NIE zapisuj kopii, jeśli żadne pliki nie zostały zmienione", + "feedback.policy.retention.keep-latest-help": "liczba najnowszych kopii zapasowych", + "feedback.policy.retention.latest-snapshot-retain": "Najnowsze kopie zapasowe", + "feedback.policy.retention.latest-snapshot-retain-help": "Liczba najnowszych kopii zapasowych do zachowania dla każdego źródła", + "feedback.policy.retention.monthly-snapshot-retain": "Comiesięczne", + "feedback.policy.retention.monthly-snapshot-retain-help": "Liczba comiesięcznych kopii zapasowych przechowywanych dla każdego źródła. \nZachowana zostanie najnowsza kopia z każdego miesiąca kalendarzowego", + "feedback.policy.retention.monthly-snapshot-retain-hint": "Liczba comiesięcznych kopii zapasowych", + "feedback.policy.retention.weekly-snapshot-retain": "Tygodniowe", + "feedback.policy.retention.weekly-snapshot-retain-help": "Liczba cotygodniowych kopii zapasowych przechowywanych dla każdego źródła. \nNajnowsza kopia z każdego tygodnia zostanie zachowana", + "feedback.policy.retention.weekly-snapshot-retain-hint": "Liczba cotygodniowych kopii zapasowych", + "feedback.policy.scheduling.cron-expressions": "Wyrażenia Crontab", + "feedback.policy.scheduling.cron-expressions-hint": "minuta godzina dzień miesiąc dzień_tygodnia", + "feedback.policy.scheduling.cron-help": "Harmonogramy zrzutów ekranu przy użyciu składni crontab UNIX (po jednym w wierszu):
Zobacz szczegóły dotyczące obsługiwanych formatów.", + "feedback.policy.scheduling.manual-snapshots-only": "Tylko ręczne kopie zapasowe", + "feedback.policy.scheduling.manual-snapshots-only-help": "Twórz kopie zapasowe tylko ręcznie (wyłącza zaplanowane zadania)", + "feedback.policy.scheduling.missed-snapshots-startup": "Uruchom pominięte kopie zapasowe podczas uruchamiania", + "feedback.policy.scheduling.missed-snapshots-startup-help": "Natychmiast uruchom wszelkie pominięte zadania kopii zapasowych po rozpoczęciu kopiowania (dotyczy tylko kopii zapasowych aktualnych)", + "feedback.policy.scheduling.no-upcoming-snapshots": "Brak nadchodzących kopii zapasowych", + "feedback.policy.scheduling.snapshot-frequency": "Częstotliwość kopii zapasowych", + "feedback.policy.scheduling.snapshot-frequency-help": "Jak często tworzyć kopie zapasowe na serwerze KopiaUI lub Kopia (nie dotyczy działania poza trybem serwera)", + "feedback.policy.scheduling.times-of-day": "Pory dnia", + "feedback.policy.scheduling.times-of-day-help": "Twórz kopie zapasowe o określonych porach dnia (format 24-godzinny)", + "feedback.policy.scheduling.times-of-day-hint": "np. 17:00", + "feedback.policy.scheduling.upcoming": "Najbliższe kopie", + "feedback.policy.scheduling.upcoming-snapshots": "Najbliższe kopie zapasowe", + "feedback.policy.scheduling.upcoming-snapshots-help": "Czasy nadchodzących kopii zapasowych obliczone na podstawie parametrów reguł", + "feedback.policy.time-of-day.invalid": "Nieprawidłowa godzina: {{tod}}", + "feedback.policy.timeout-help": "Limit czasu w sekundach, zanim Kopia zabije proces", + "feedback.policy.upload.maximum-parallel-file-reads": "Maksymalne równoległe odczyty plików", + "feedback.policy.upload.maximum-parallel-file-reads-help": "Maksymalna liczba plików, które będą odczytywane równolegle (domyślnie jest to liczba procesorów logicznych)", + "feedback.policy.upload.maximum-parallel-file-reads-hint": "maksymalna liczba równoległych odczytów plików", + "feedback.policy.upload.maximum-parallel-snapshots": "Maksymalnie równoległe kopie zapasowe", + "feedback.policy.upload.maximum-parallel-snapshots-help": "Maksymalna liczba kopii zapasowych, które można przesłać jednocześnie", + "feedback.policy.upload.maximum-parallel-snapshots-hint-set": "maksymalna liczba równoległych kopii zapasowych", + "feedback.policy.upload.maximum-parallel-snapshots-hint-unset": "należy określić przy użyciu zasad globalnych, użytkownika lub hosta", + "feedback.prodiver.gcs.paste-json-credentials": "Wklej tutaj dane uwierzytelniające JSON", + "feedback.provider.azure-blob-storage": "Magazyn obiektów Blob platformy Azure", + "feedback.provider.azure.access-key": "Klucz dostępu", + "feedback.provider.azure.azure-storage-domain": "Domena magazynu Azure", + "feedback.provider.azure.container": "Pojemnik", + "feedback.provider.azure.enter-access-key": "Wprowadź tajny klucz dostępu", + "feedback.provider.azure.enter-azure-storage-domain": "Wprowadź domenę magazynu lub pozostaw puste dla domyślnego „blob.core.windows.net”", + "feedback.provider.azure.enter-container-name": "Wpisz nazwę kontenera", + "feedback.provider.azure.enter-object-name-prefix": "Wprowadź przedrostek nazwy obiektu lub pozostaw puste", + "feedback.provider.azure.enter-sas-token": "Wprowadź tajny token SAS", + "feedback.provider.azure.enter-storage-account": "Wprowadź nazwę konta magazynu", + "feedback.provider.azure.object-name-prefix": "Przedrostek nazwy obiektu", + "feedback.provider.azure.sas-token": "Token SAS-owy", + "feedback.provider.azure.storage-account": "Konto magazynu", + "feedback.provider.b2.bucket-name": "Wiadro B2", + "feedback.provider.b2.enter-account-key": "Wprowadź tajną aplikację lub klucz konta", + "feedback.provider.b2.enter-account-key-id": "Wprowadź identyfikator klucza aplikacji lub konta", + "feedback.provider.b2.enter-bucket-name": "Wpisz nazwę zasobnika", + "feedback.provider.b2.enter-object-name-prefix": "Wprowadź przedrostek nazwy obiektu lub pozostaw puste", + "feedback.provider.b2.key": "Klucz", + "feedback.provider.b2.key-id": "Identyfikator klucza", + "feedback.provider.b2.object-name-prefix": "Przedrostek nazwy obiektu", + "feedback.provider.backblaze-b2": "Blask wsteczny B2", + "feedback.provider.filesystem.directory-path": "Ścieżka katalogu", + "feedback.provider.filesystem.enter-directory-path": "Wprowadź ścieżkę katalogu, w którym chcesz przechowywać pliki repozytorium", + "feedback.provider.gcs.bucket-name": "Wiadro GCS", + "feedback.provider.gcs.credentials-file": "Plik poświadczeń", + "feedback.provider.gcs.credentials-json": "Poświadczenia JSON", + "feedback.provider.gcs.enter-bucket-name": "Wpisz nazwę zasobnika", + "feedback.provider.gcs.enter-credentials-file-name": "Wprowadź nazwę pliku JSON poświadczeń", + "feedback.provider.gcs.enter-object-name-prefix": "Wprowadź przedrostek nazwy obiektu lub pozostaw puste", + "feedback.provider.gcs.object-name-prefix": "Przedrostek nazwy obiektu", + "feedback.provider.google-cloud-storage": "Magazyn w chmurze Google", + "feedback.provider.kopia-repository-server": "Serwer repozytorium Kopia", + "feedback.provider.local-directory-or-nas": "Katalog lokalny lub NAS", + "feedback.provider.rclone-remote": "Pilot zdalnego sterowania", + "feedback.provider.rclone.rclone-executable-path": "Ścieżka pliku wykonywalnego Rclone", + "feedback.provider.rclone.rclone-executable-path-hint": "Wprowadź ścieżkę do pliku wykonywalnego rclone", + "feedback.provider.rclone.rclone-remote-path": "Zdalna ścieżka Rclone", + "feedback.provider.rclone.rclone-remote-path-hint": "Wpisz :<ścieżka>", + "feedback.provider.repositoryserver.enter-server-certificate-fingerprint": "Wprowadź odcisk palca certyfikatu zaufanego serwera wydrukowany podczas uruchamiania serwera", + "feedback.provider.repositoryserver.enter-server-url": "Wprowadź adres URL serwera (https://:port)", + "feedback.provider.repositoryserver.server-address": "Adres serwera", + "feedback.provider.repositoryserver.server-certificate-fingerprint": "Odcisk palca certyfikatu zaufanego serwera (SHA256)", + "feedback.provider.repositorytoken.paste-token": "Wklej token połączenia", + "feedback.provider.repositorytoken.token": "Znak", + "feedback.provider.required-either-key-file": "Wymagane jest jedno z Hasło, Plik klucza lub Kluczowe dane.", + "feedback.provider.required-either-known-host-data": "Wymagany jest plik znanych hostów lub dane znanych hostów, ale nie oba.", + "feedback.provider.s3-or-compatible-storage": "Amazon S3 lub kompatybilna pamięć masowa", + "feedback.provider.s3.access-key-id": "Identyfikator klucza dostępu", + "feedback.provider.s3.access-key-id-hint": "Wprowadź identyfikator klucza dostępu", + "feedback.provider.s3.bucket-name": "Wiaderko", + "feedback.provider.s3.bucket-name-hint": "Wpisz nazwę zasobnika", + "feedback.provider.s3.enter-object-name-prefix-hint": "Wprowadź przedrostek nazwy obiektu lub pozostaw puste", + "feedback.provider.s3.object-name-prefix": "Przedrostek nazwy obiektu", + "feedback.provider.s3.override-region": "Zastąp region", + "feedback.provider.s3.override-region-hint": "Wpisz konkretny region (np. us-west-1) lub pozostaw puste", + "feedback.provider.s3.secret-access-key": "Tajny klucz dostępu", + "feedback.provider.s3.secret-access-key-hint": "Wprowadź tajny klucz dostępu", + "feedback.provider.s3.server-endpoint": "Punkt końcowy serwera", + "feedback.provider.s3.server-endpoint-hint": "Wpisz adres serwera (np. s3.amazonaws.com)", + "feedback.provider.s3.session-token": "Token sesji", + "feedback.provider.s3.session-token-hint": "Wprowadź token sesji lub pozostaw puste", + "feedback.provider.sftp-key-data": "Kluczowe dane", + "feedback.provider.sftp-key-data-hint": "Wklej zawartość pliku klucza", + "feedback.provider.sftp-server": "Serwer SFTP", + "feedback.provider.sftp.enter-password": "Wprowadź hasło", + "feedback.provider.sftp.enter-path-host-file": "Wprowadź ścieżkę do pliku znane_hosty", + "feedback.provider.sftp.enter-path-to-key-file": "Wprowadź ścieżkę do pliku klucza", + "feedback.provider.sftp.enter-remote-path": "Wprowadź zdalną ścieżkę do repozytorium, np. „/mnt/data/repository”", + "feedback.provider.sftp.enter-ssh-arguments": "Wprowadź argumenty polecenia SSH („użytkownik@host -s sftp” zostanie dodany automatycznie)", + "feedback.provider.sftp.enter-ssh-host-name": "nazwa hosta ssh (np. przykład.com)", + "feedback.provider.sftp.host": "Gospodarz", + "feedback.provider.sftp.known-host-data": "Znane dane hostów", + "feedback.provider.sftp.launch-external-ssh-command": "Uruchom zewnętrzne polecenie SSH bez hasła", + "feedback.provider.sftp.launch-external-ssh-command-hint": "Domyślnie Kopia łączy się z serwerem za pomocą wewnętrznego klienta SSH, który obsługuje ograniczone opcje. \nAlternatywnie może uruchomić zewnętrzne polecenie SSH bez hasła, które obsługuje dodatkowe opcje, ale jest generalnie mniej wydajne niż wbudowany klient.", + "feedback.provider.sftp.password": "Hasło", + "feedback.provider.sftp.paste-content-of-known-host": "Wklej zawartość pliku znane_hosty", + "feedback.provider.sftp.path": "Ścieżka", + "feedback.provider.sftp.path-host-file": "Ścieżka do pliku znane_hosty", + "feedback.provider.sftp.path-key-file": "Ścieżka do pliku klucza", + "feedback.provider.sftp.port": "Port", + "feedback.provider.sftp.port-number": "Numer portu (np. 22)", + "feedback.provider.sftp.provide-passwordless-ssh-command": "Podaj polecenie SSH bez hasła do wykonania (zwykle „ssh”)", + "feedback.provider.sftp.ssh-arguments": "Argumenty SSH", + "feedback.provider.sftp.ssh-command": "Polecenie SSH", + "feedback.provider.sftp.user": "Użytkownik", + "feedback.provider.sftp.user-name": "Nazwa użytkownika", + "feedback.provider.use-repository-token": "Użyj tokena repozytorium", + "feedback.provider.webdav-server": "Serwer WebDAV", + "feedback.provider.webdav.enter-password": "Wprowadź hasło", + "feedback.provider.webdav.enter-username": "Wpisz nazwę użytkownika", + "feedback.provider.webdav.password": "Hasło", + "feedback.provider.webdav.server-url": "Adres URL serwera WebDAV", + "feedback.provider.webdav.username": "Nazwa użytkownika", + "feedback.repository.additional-parameters-hint": "Dodatkowe parametry można ustawić podczas tworzenia repozytorium za pomocą wiersza poleceń.", + "feedback.repository.attribute.algorithm-eco": "Korekcja błędów", + "feedback.repository.attribute.algorithm-encryption": "Szyfrowanie", + "feedback.repository.attribute.algorithm-hash": "Funkcja haszująca", + "feedback.repository.attribute.algorithm-splitter": "Splitter", + "feedback.repository.attribute.config-file": "Plik konfiguracyjny", + "feedback.repository.attribute.connected-as": "Połączony jako", + "feedback.repository.attribute.internal-compression": "Wewnętrzna kompresja", + "feedback.repository.attribute.repository-eco": "Narzut na korekcję błędów", + "feedback.repository.attribute.repository-format": "Format repozytorium", + "feedback.repository.attribute.repository-provider": "Provider", + "feedback.repository.attribute.server-url": "Adres URL serwera", + "feedback.repository.configuration": "Konfiguracja pamięci", + "feedback.repository.connect-as": "Połącz jako", + "feedback.repository.connect-in-read-only-mode": "Połącz się w trybie tylko do odczytu", + "feedback.repository.connect-in-read-only-mode-hint": "Tryb tylko do odczytu zapobiega wszelkim zmianom w repozytorium.", + "feedback.repository.connect-to-repository": "Połącz się z repozytorium", + "feedback.repository.create-repository-new": "Utwórz nowe repozytorium", + "feedback.repository.create-repository-new-help": "Wprowadź silne hasło, aby utworzyć repozytorium Kopia w udostępnionym magazynie.", + "feedback.repository.eco-disabled": "Brak", + "feedback.repository.eec-warning": "[EKSPERYMENTALNE] Korekcja błędów może pomóc w ochronie przed niektórymi rodzajami uszkodzeń danych spowodowanymi spontanicznymi zamianami bitów na nośniku pamięci.", + "feedback.repository.encryption": "Szyfrowanie", + "feedback.repository.enter-repository-password": "Wprowadź hasło do repozytorium", + "feedback.repository.hostname": "Nazwa hosta", + "feedback.repository.hostname-hint": "Użyj tej opcji podczas przywracania kopii wykonanej na innym komputerze", + "feedback.repository.internal-compression-supported-no": "no", + "feedback.repository.internal-compression-supported-yes": "yes", + "feedback.repository.kopia-server-parameters": "Parametry serwera Kopia", + "feedback.repository.name-default": "Moje repozytorium", + "feedback.repository.override-hint": "Aby zastąpić, kliknij „Pokaż opcje zaawansowane”", + "feedback.repository.provider-selection": "Wybierz Typ przechowywania", + "feedback.repository.provider-selection-hint": "Aby połączyć się z repozytorium lub je utworzyć, wybierz preferowany typ magazynu:", + "feedback.repository.repository-description": "Opis repozytorium", + "feedback.repository.repository-description-help": "Pomaga rozróżnić wiele połączonych repozytoriów", + "feedback.repository.repository-description-hint": "Wprowadź opis repozytorium", + "feedback.repository.repository-description-required": "Opis jest wymagany", + "feedback.repository.repository-initializing": "Inicjalizacja w toku...", + "feedback.repository.repository-is-read-only": "Repozytorium jest w trybie tylko do odczytu", + "feedback.repository.repository-password": "Hasło do repozytorium", + "feedback.repository.repository-password-confirm": "Potwierdź hasło do repozytorium", + "feedback.repository.repository-password-confirm-again": "wprowadź ponownie hasło do repozytorium", + "feedback.repository.repository-password-help": "Służy do szyfrowania zawartości repozytorium", + "feedback.repository.repository-token-enter": "Wprowadź token repozytorium", + "feedback.repository.server-password": "Hasło serwera", + "feedback.repository.server-password-hint": "Wprowadź hasło, aby połączyć się z serwerem", + "feedback.repository.status-connected": "Podłączone repoytorium", + "feedback.repository.username": "Nazwa użytkownika", + "feedback.repository.username-hint": "Zastąp tę opcję podczas przywracania migawki wykonanej przez innego użytkownika", + "feedback.snapshot.create.enter-path-to-snapshot-hint": "Wprowadź ścieżkę do migawki", + "feedback.snapshot.create.must-specify-path": "Należy określić katalog do wykonania migawki.", + "feedback.snapshot.create.snapshot-new": "Nowa kopia zapasowa", + "feedback.snapshot.description": "Opis", + "feedback.snapshot.description.snapshot-description": "Opis kopii zapasowej", + "feedback.snapshot.directory.browsing-not-supported": "Przeglądanie katalogów nie jest obsługiwane w przeglądarce internetowej. \nUżyj interfejsu Kopia.", + "feedback.snapshot.directory.restore-all-files-help": "Możesz zamontować/przywrócić wszystkie pliki i katalogi widoczne poniżej lub przywrócić pliki pojedynczo.", + "feedback.snapshot.header.actions": "działania", + "feedback.snapshot.header.details": "Detale", + "feedback.snapshot.header.directories": "Reż", + "feedback.snapshot.header.files": "Akta", + "feedback.snapshot.header.last-snapshot": "Ostatnia kopia zapasowa", + "feedback.snapshot.header.next-snapshot": "Następna kopia zapasowa", + "feedback.snapshot.header.retention": "Przechowywanie", + "feedback.snapshot.header.root": "Źródło", + "feedback.snapshot.header.selected": "Zaznacz", + "feedback.snapshot.header.snapshot-owner": "Właściciel", + "feedback.snapshot.header.snapshot-path": "Ścieżka", + "feedback.snapshot.header.snapshot-size": "Rozmiar", + "feedback.snapshot.header.start-time": "Czas rozpoczęcia", + "feedback.snapshot.header.status": "Status", + "feedback.snapshot.history.snapshot-displaying": "Wyświetlanie", + "feedback.snapshot.history.wipe-all-snapshots": "Wyczyść wszystkie migawki i zasady dla tego źródła.", + "feedback.snapshot.restore.continue-on-errors": "Kontynuuj w przypadku błędów", + "feedback.snapshot.restore.continue-on-errors-help": "Gdy wystąpi błąd przywracania, spróbuj kontynuować zamiast szybko zakończyć.", + "feedback.snapshot.restore.destination": "Cel", + "feedback.snapshot.restore.destination-help": "Możesz również przywrócić do pliku .zip lub .tar, podając odpowiednie rozszerzenie.", + "feedback.snapshot.restore.destination-hint": "Wprowadź ścieżkę docelową", + "feedback.snapshot.restore.disable-zip-compression": "Wyłącz kompresję ZIP", + "feedback.snapshot.restore.disable-zip-compression-help": "Nie kompresuj przy przywracaniu do pliku ZIP (szybciej).", + "feedback.snapshot.restore.minimal-file-size-for-shallow-restore": "Minimalny rozmiar pliku dla płytkiego przywracania", + "feedback.snapshot.restore.overwrite-directory": "Nadpisz katalogi", + "feedback.snapshot.restore.overwrite-files": "Nadpisz pliki", + "feedback.snapshot.restore.overwrite-symbolic-links": "Nadpisz dowiązania symboliczne", + "feedback.snapshot.restore.restore-file-modification-time": "Przywróć czas modyfikacji plików", + "feedback.snapshot.restore.restore-file-ownership": "Przywróć własność plików", + "feedback.snapshot.restore.restore-file-permissions": "Przywróć uprawnienia plików", + "feedback.snapshot.restore.shallow-restore-at-depth": "Płytkie przywracanie na określonej głębokości", + "feedback.snapshot.restore.skip-previously-restored-files": "Pomiń wcześniej przywrócone pliki i dowiązania symboliczne", + "feedback.snapshot.restore.snapshot-restore": "Przywróć", + "feedback.snapshot.restore.write-files-atomically": "Zapisuj pliki atomowo", + "feedback.snapshot.restore.write-sparse-files": "Zapisuj pliki rzadkie", + "feedback.snapshot.show-individual-snapshots-count": "feedback.snapshot.show-individual-snapshots-count", + "feedback.snapshot.show-individual-snapshots-count_one": "Pokaż {{count}} indywidualną migawkę", + "feedback.snapshot.show-individual-snapshots-count_other": "Pokaż {{count}} pojedynczych kopii zapasowych", + "feedback.snapshot.start-after-previous-snapshot": "Migawka rozpocznie się po zakończeniu poprzedniej migawki", + "feedback.snapshot.status.status-overdue": "zaległy", + "feedback.snapshot.status.status-pending": "Aż do", + "feedback.tab.policies": "Reguły", + "feedback.tab.preferences": "Ustawienia", + "feedback.tab.repository": "Repozytorium", + "feedback.tab.repository-is-not-connected": "Repozytorium nie jest połączone", + "feedback.tab.snapshots": "Kopie zapasowe", + "feedback.tab.tasks": "Zadania", + "feedback.task.estimated-results": "{{description}} Bytes: {{bytes}} ({{bytes.excluded}} wyłączony) Files: {{files}} ({{files.excluded}} wyłączony) Directories: {{directories}} ({{directories.excluded}} wyłączony) Errors: {{errors}} ({{errors.ignored}} ignorowany)", + "feedback.task.header.counter": "Licznik", + "feedback.task.header.value": "Wartość", + "feedback.task.logs": "Logi", + "feedback.task.no-tasks-help": "Lista zadań pojawi się tutaj podczas tworzenia kopii zapasowych, przywracania, przeprowadzania konserwacji itp.", + "feedback.task.search-tasks-by-hint": "Przeszukuj dzienniki zadań według opisu", + "feedback.task.status.task-canceled": "Zadanie anulowane", + "feedback.task.status.task-canceled-after": "Zadanie anulowane po", + "feedback.task.status.task-canceling": "Anulowanie", + "feedback.task.status.task-error": "Błąd", + "feedback.task.status.task-failed-after": "Nie udało się po", + "feedback.task.status.task-finished": "Zakończone", + "feedback.task.status.task-finished-in": "Skończono w", + "feedback.task.status.task-running-for": "Zadanie w toku od", + "feedback.task.status.task-started": "Rozpoczęte", + "feedback.task.status.task-succeeded-after": "Zadanie zakończone po", + "feedback.task.table.header-description": "Opis", + "feedback.task.table.header-kind": "Uprzejmy", + "feedback.task.table.header-start-time": "Czas rozpoczęcia", + "feedback.task.table.header-status": "Status", + "feedback.task.tasks-total": "Całkowity", + "feedback.ui.appearance": "Wielkość tekstu", + "feedback.ui.appearance-help": "Wybierz rodzaj czcionki", + "feedback.ui.appearance-hint": "Rozmiar czcionki", + "feedback.ui.byte-representation-description": "Formatowanie rozmiarów plików", + "feedback.ui.byte-representation-help": "Określa w jaki sposób będą wyświetlane rozmiary plików", + "feedback.ui.byte-representation-select": "Wybierz sposób formatowania rozmiarów plików", + "feedback.ui.pagesize-description": "Rozmiar strony wyników", + "feedback.ui.pagesize-help": "Określa liczbę elementów na stronie wyników", + "feedback.ui.pagesize-hint": "Rozmiar strony", + "feedback.ui.theme-description": "Kolorystyka", + "feedback.ui.theme-help": "Aktywny schemat kolorów", + "feedback.ui.theme-select": "Wybierz schemat kolorów", + "feedback.validation.invalid-times-of-day": "Nieprawidłowe pory dnia", + "feedback.validation.optional.valid-number-or-empty": "Musi to być prawidłowy numer lub pusty", + "feedback.validation.passwords-dont-match": "Hasła nie pasują", + "feedback.validation.required.directory": "Pole wymagane", + "feedback.validation.required.field": "Pole wymagane", + "feedback.validation.required.valid-number-or-empty": "Musi to być prawidłowy numer lub pusty", + "value.algorithm.eco-disabled": "Wyłączony", + "value.algorithm.suffix-not-recommended": "(NIEZALECANE)", + "value.algorithm.suffix-recommended": "(ZALECANA)", + "value.log.details-0-no-output": "0 - brak wyjścia", + "value.log.details-1-minimal-details": "1 - minimalne szczegóły", + "value.log.details-10-maximum-details": "10 - maksimum szczegółów", + "value.log.details-5-normal-details": "5 - normalne szczegóły", + "value.log.details-inherit-from-parent": "(dziedzicz po rodzicu)", + "value.policy.async": "Uruchom asynchronicznie, ignoruj ​​awarie", + "value.policy.essential": "Musi się udać", + "value.policy.inherent-from-parent": "dziedziczyć od rodziców", + "value.policy.none": "nic", + "value.policy.optional": "Ignoruj ​​niepowodzenia", + "value.provider.s3.http-connection-insecure": "Użyj połączenia HTTP (niepewne)", + "value.provider.s3.no-tls-verification": "Nie weryfikuj certyfikatu TLS", + "value.repository.latest-format": "Najnowszy format", + "value.repository.legacy-format": "Starszy format zgodny z wersją 0.8", + "value.snapshot-frequency.10-minutes": "co 10 minut", + "value.snapshot-frequency.12-hours": "co 12 godzin", + "value.snapshot-frequency.15-minutes": "co 15 minut", + "value.snapshot-frequency.20-minutes": "co 20 minut", + "value.snapshot-frequency.3-hours": "co 3 godziny", + "value.snapshot-frequency.30-minutes": "co 30 minut", + "value.snapshot-frequency.6-hours": "co 6 godzin", + "value.snapshot-frequency.hour": "co godzinę", + "value.ui.appearance-large": "duża", + "value.ui.appearance-medium": "średnia", + "value.ui.appearance-small": "mała", + "value.ui.byte-representation-base10": "Base-10 (KB, MB, GB, TB)", + "value.ui.byte-representation-base2": "Base-2 (KiB, MiB, GiB, TiB)", + "value.ui.theme-dark": "ciemna", + "value.ui.theme-light": "jasna", + "value.ui.theme-ocean": "oceaniczna", + "value.ui.theme-pastel": "pastelowa", + "value.validation.optional-no": "nie", + "value.validation.optional-yes": "Tak" +} diff --git a/public/locales/ru/translation.json b/public/locales/ru/translation.json new file mode 100644 index 00000000..3f2c84a4 --- /dev/null +++ b/public/locales/ru/translation.json @@ -0,0 +1,479 @@ +{ + "common.action.back": "Назад", + "common.action.cancel": "Отмена", + "common.action.click-here-to-learn-more": "Кликните сюда, чтобы узнать больше.", + "common.action.confirm-delete": "Подтвердите удаление", + "common.action.delete": "Удалить", + "common.action.next": "Следующий", + "common.action.return": "Возврат", + "common.action.stop": "Остановить", + "common.label.loading": "Загрузка...", + "event.cli.copy-to-clipboard": "Скопировать в буфер обмена", + "event.cli.show-cli-equivalent": "Нажмите, чтобы показать эквивалент CLI", + "event.log.hide-log": "Скрыть лог", + "event.log.show-log": "Показать лог", + "event.pin.add-pin": "Добавить пин", + "event.pin.pin-snapshot": "Снимок закрепления", + "event.pin.remove-pin": "Удалить булавку", + "event.pin.update-pin": "Обновить пин-код", + "event.policy.delete": "Удалить политику", + "event.policy.edit": "Редактировать", + "event.policy.save": "Сохранить политику", + "event.policy.set-policy": "Установить политику", + "event.repository.cancel-connection": "Отменить подключение", + "event.repository.connect-to-repository": "Подключиться к репозиторию", + "event.repository.create-repository": "Создать репозиторий", + "event.repository.disconnect-from-repository": "Отключиться от репозитория", + "event.repository.hide-advanced-options": "Скрыть дополнительные параметры", + "event.repository.show-advanced-options": "Показать дополнительные параметры", + "event.repository.update-description": "Обновить описание", + "event.snapshot.browse-directory": "Просматривать", + "event.snapshot.delete-selected": "event.snapshot.delete-selected", + "event.snapshot.delete-selected_one": "Вы хотите удалить выбранный снимок {{count}}?", + "event.snapshot.delete-selected_other": "Вы хотите удалить выбранные снимки ({{count}})?", + "event.snapshot.description.enter-new-description": "Введите новое описание", + "event.snapshot.description.remove-description": "Удалить описание", + "event.snapshot.description.update-description": "Описание обновления", + "event.snapshot.estimate": "Оценивать", + "event.snapshot.fetch-snapshots": "Получить снимки", + "event.snapshot.history.delete-selected": "Удалить выбранное ({{count}})", + "event.snapshot.history.delete-snapshot-source": "Удалить источник снимка", + "event.snapshot.history.deselect-all": "Убрать выделение со всего", + "event.snapshot.history.select-all-snapshots": "Выбрать все", + "event.snapshot.history.update-snapshot-description": "{{description}} – нажмите, чтобы обновить описание снимка.", + "event.snapshot.mount-directory": "Монтировать как локальную файловую систему", + "event.snapshot.new-snapshot": "Новый снимок", + "event.snapshot.restore-file-directories": "Восстановление файлов и каталогов", + "event.snapshot.restore.begin-restore": "Начать восстановление", + "event.snapshot.restore.go-to-restore-task": "Перейти к задаче восстановления", + "event.snapshot.show-policy": "Политика", + "event.snapshot.snapshot-now": "Снимок сейчас", + "event.snapshot.synchronize": "Синхронизировать", + "event.snapshot.unmount-directory": "Размонтировать", + "event.task.action.cancel": "Отменить задачу", + "event.task.select.task-all": "Все", + "event.task.select.task-failed": "Не удалось", + "event.task.select.task-running": "Выполняются", + "feedback.directory.header.directories": "Каталоги", + "feedback.directory.header.files": "Файлы", + "feedback.directory.header.last-modification": "Последнее изменение", + "feedback.directory.header.name": "Имя", + "feedback.directory.header.size": "Размер", + "feedback.error.common": "Ошибка", + "feedback.error.connection": "Ошибка подключения:", + "feedback.header.effective": "Эффективный", + "feedback.header.username": "Имя пользователя", + "feedback.pin.add-pin-to-protect": "Добавьте булавку, чтобы защитить снимок от удаления", + "feedback.pin.do-not-delete": "не удалять", + "feedback.pin.name-of-the-pin": "Название контакта", + "feedback.policy.action.command-mode": "Командный режим", + "feedback.policy.actions.after-folder": "После папки", + "feedback.policy.actions.after-folder-help": "Скрипт для запуска после папки", + "feedback.policy.actions.after-snapshot": "После снимка", + "feedback.policy.actions.after-snapshot-help": "Скрипт для запуска после снимка", + "feedback.policy.actions.before-folder": "Перед папкой", + "feedback.policy.actions.before-folder-help": "Скрипт для запуска перед папкой", + "feedback.policy.actions.before-snapshot": "Перед снимком", + "feedback.policy.actions.before-snapshot-help": "Скрипт для запуска перед снимком", + "feedback.policy.actions.timeout": "Тайм-аут", + "feedback.policy.command-mode-help": "Необходимое (должно быть успешным; поведение по умолчанию), необязательное (сбои допускаются) или асинхронное (Kopia запускает действие, но не ждет его завершения).", + "feedback.policy.compression.compression-algorithm": "Алгоритм сжатия", + "feedback.policy.compression.compression-algorithm-help": "Укажите алгоритм сжатия, который будет использоваться при создании снимков файлов в этом каталоге и подкаталогах.", + "feedback.policy.compression.maximal-file-size": "Максимальный размер файла", + "feedback.policy.compression.maximal-file-size-help": "Файлы, размер которых превышает указанное значение, не будут сжаты.", + "feedback.policy.compression.maximal-file-size-hint": "Максимальный размер файла в байтах", + "feedback.policy.compression.minimal-file-size": "Минимальный размер файла", + "feedback.policy.compression.minimal-file-size-help": "Файлы размером меньше указанного значения не будут сжаты.", + "feedback.policy.compression.minimal-file-size-hint": "минимальный размер файла в байтах", + "feedback.policy.compression.never-compress-extensions": "Никогда не сжимайте расширения", + "feedback.policy.compression.never-compress-extensions-help": "Никогда не сжимайте следующие расширения файлов (по одному расширению в строке)", + "feedback.policy.compression.never-compress-extensions-hint": "например *.mp4", + "feedback.policy.compression.only-compress-extensions": "Сжимать только расширения", + "feedback.policy.compression.only-compress-extensions-help": "Сжимайте только файлы со следующими расширениями (по одному расширению в строке)", + "feedback.policy.compression.only-compress-extensions-hint": "например *.текст", + "feedback.policy.confirm-delete-policy": "Вы уверены, что хотите удалить эту политику?", + "feedback.policy.defined-by": "Определяется", + "feedback.policy.defined-by-this-policy": "Определено этой политикой", + "feedback.policy.error-delete-policy": "Ошибка удаления политики.", + "feedback.policy.error-handling.ignore-directory-errors": "Игнорировать ошибки каталога", + "feedback.policy.error-handling.ignore-directory-errors-help": "Считайте ошибки чтения каталога нефатальными.", + "feedback.policy.error-handling.ignore-file-errors": "Игнорировать ошибки файлов", + "feedback.policy.error-handling.ignore-file-errors-help": "Считайте ошибки чтения файлов нефатальными.", + "feedback.policy.error-handling.ignore-unknown-directories": "Игнорировать неизвестные записи каталога", + "feedback.policy.error-handling.ignore-unknown-directories-help": "Считайте нераспознанные/неподдерживаемые записи каталога нефатальными ошибками.", + "feedback.policy.error-saving-policy": "Ошибка сохранения политики.", + "feedback.policy.files.ignore-files": "Игнорировать файлы", + "feedback.policy.files.ignore-files-help": "Список имен файлов и каталогов, которые следует игнорировать.
См. документацию по игнорированию файлов.", + "feedback.policy.files.ignore-files-hint": "например /file.txt", + "feedback.policy.files.ignore-rule-files": "Игнорировать файлы правил", + "feedback.policy.files.ignore-rule-files-from-parent-directories": "Игнорировать файлы правил из родительских каталогов", + "feedback.policy.files.ignore-rule-files-from-parent-directories-help": "Если этот параметр установлен, файлы, определяющие правила игнорирования (.kopiaignore и т. д.), из родительского каталога игнорируются.", + "feedback.policy.files.ignore-rule-files-help": "Список дополнительных файлов, содержащих правила игнорирования (каждый файл настраивает правила игнорирования для каталога и его подкаталогов)", + "feedback.policy.files.ignore-rule-files-hint": "например .kopiaignore", + "feedback.policy.files.ignore-rules-from-parent-directories": "Игнорировать правила из родительских каталогов", + "feedback.policy.files.ignore-rules-from-parent-directories-help": "Если установлено, игнорируются правила из родительского каталога.", + "feedback.policy.files.ignore-well-known-cache-directories": "Игнорировать известные каталоги кэша", + "feedback.policy.files.ignore-well-known-cache-directories-help": "Игнорировать каталоги, содержащие CACHEDIR.TAG и подобные.", + "feedback.policy.files.scan-only-one-filesystem": "Сканировать только одну файловую систему", + "feedback.policy.files.scan-only-one-filesystem-help": "Не пересекайте границы файловой системы при создании моментального снимка.", + "feedback.policy.find-count": "обратная связь.policy.find-count", + "feedback.policy.find-count_one": "Найдено {{count}} политики, соответствующей критериям.", + "feedback.policy.find-count_other": "Найдено {{count}} политик, соответствующих критериям.", + "feedback.policy.find-hint": "Введите каталог, чтобы найти или установить политику", + "feedback.policy.find-none": "Политики не найдены", + "feedback.policy.find-none-create": "Политика для каталога {{path}} не найдена. \nПожалуйста, настройте новую политику.", + "feedback.policy.header.actions": "Действия", + "feedback.policy.header.compression": "Сжатие", + "feedback.policy.header.defined": "Определенный", + "feedback.policy.header.error-handling": "Обработка ошибок", + "feedback.policy.header.files": "Файлы", + "feedback.policy.header.folder-actions": "Действия с папками", + "feedback.policy.header.host": "Хозяин", + "feedback.policy.header.logging": "Ведение журнала", + "feedback.policy.header.other": "Другой", + "feedback.policy.header.path": "Путь", + "feedback.policy.header.scheduling": "Планирование", + "feedback.policy.header.snapshot-action": "Действия со снимками", + "feedback.policy.header.snapshot-retention": "Хранение моментальных снимков", + "feedback.policy.header.upload": "Загрузить", + "feedback.policy.kind.all": "Все политики", + "feedback.policy.kind.applicable": "Применимые политики", + "feedback.policy.kind.global": "Глобальная политика", + "feedback.policy.kind.local": "Местная политика", + "feedback.policy.kind.per-host-policies": "Политики для каждого хоста", + "feedback.policy.kind.per-user-policies": "Политики для каждого пользователя", + "feedback.policy.logging.cache-hit": "Попадание в кэш", + "feedback.policy.logging.cache-hit-help": "Подробность журнала, когда вместо загрузки файла используется кеш", + "feedback.policy.logging.cache-miss": "Промах в кэше", + "feedback.policy.logging.cache-miss-help": "Подробность журнала, когда кеш нельзя использовать и файл необходимо хешировать", + "feedback.policy.logging.directory-ignored": "Каталог игнорируется", + "feedback.policy.logging.directory-ignored-help": "Подробность журнала, когда каталог игнорируется", + "feedback.policy.logging.directory-snapshotted": "Снимок каталога", + "feedback.policy.logging.directory-snapshotted-help": "Подробность журнала при создании снимка каталога", + "feedback.policy.logging.file-ignored": "Файл игнорируется", + "feedback.policy.logging.file-ignored-help": "Подробность журнала, когда файл, символическая ссылка и т. д. игнорируются", + "feedback.policy.logging.file-snapshotted": "Снимок файла", + "feedback.policy.logging.file-snapshotted-help": "Подробность журнала при создании моментального снимка файла, символической ссылки и т. д.", + "feedback.policy.other.disable-parent-policy-evaluation": "Отключить оценку родительской политики", + "feedback.policy.other.disable-parent-policy-evaluation-help": "Предотвращает влияние родительских политик на этот каталог и его подкаталоги.", + "feedback.policy.other.json-representation": "JSON-представление", + "feedback.policy.other.json-representation-help": "Это внутреннее представление политики", + "feedback.policy.policies-defined-by-path-absolute": "Политики могут быть определены только для абсолютных путей.", + "feedback.policy.retention.annual-snapshot-retain": "Ежегодный", + "feedback.policy.retention.annual-snapshot-retain-help": "Сколько ежегодных снимков следует сохранять для каждого источника. \nПоследний снимок за каждый календарный год будет сохранен.", + "feedback.policy.retention.annual-snapshot-retain-hint": "Количество ежегодных снимков", + "feedback.policy.retention.daily-snapshot-retain": "Ежедневно", + "feedback.policy.retention.daily-snapshot-retain-help": "Сколько ежедневных снимков следует сохранять для каждого источника. \nПоследний снимок каждого дня будет сохранен.", + "feedback.policy.retention.daily-snapshot-retain-hint": "Количество ежедневных снимков", + "feedback.policy.retention.hourly-snapshot-retain": "Ежечасно", + "feedback.policy.retention.hourly-snapshot-retain-help": "Сколько снимков в час сохранять для каждого источника. \nПоследний снимок каждого часа будет сохранен.", + "feedback.policy.retention.hourly-snapshot-retain-hint": "количество снимков в час", + "feedback.policy.retention.ignore-identical-snapshots": "Игнорировать идентичные снимки", + "feedback.policy.retention.ignore-identical-snapshots-help": "НЕ сохраняйте снимок, если файлы не были изменены.", + "feedback.policy.retention.keep-latest-help": "количество последних снимков", + "feedback.policy.retention.latest-snapshot-retain": "Последние снимки", + "feedback.policy.retention.latest-snapshot-retain-help": "Количество последних снимков, которые необходимо сохранить, для каждого источника", + "feedback.policy.retention.monthly-snapshot-retain": "Ежемесячно", + "feedback.policy.retention.monthly-snapshot-retain-help": "Сколько ежемесячных снимков следует сохранять для каждого источника. \nПоследний снимок за каждый календарный месяц будет сохранен.", + "feedback.policy.retention.monthly-snapshot-retain-hint": "Количество ежемесячных снимков", + "feedback.policy.retention.weekly-snapshot-retain": "Еженедельно", + "feedback.policy.retention.weekly-snapshot-retain-help": "Сколько еженедельных снимков сохранять для каждого источника. \nПоследний снимок каждой недели будет сохранен.", + "feedback.policy.retention.weekly-snapshot-retain-hint": "Количество еженедельных снимков", + "feedback.policy.scheduling.cron-expressions": "Выражения Крон", + "feedback.policy.scheduling.cron-expressions-hint": "минута час день месяц будний день", + "feedback.policy.scheduling.cron-help": "Расписания моментальных снимков с использованием синтаксиса crontab UNIX (по одному на строку):
см. подробности о поддерживаемом формате.", + "feedback.policy.scheduling.manual-snapshots-only": "Только снимки вручную", + "feedback.policy.scheduling.manual-snapshots-only-help": "Создавайте снимки только вручную (отключает запланированные снимки)", + "feedback.policy.scheduling.missed-snapshots-startup": "Запуск пропущенных снимков при запуске", + "feedback.policy.scheduling.missed-snapshots-startup-help": "Немедленно запускайте все пропущенные снимки при запуске kopia (актуально только для снимков по времени).", + "feedback.policy.scheduling.no-upcoming-snapshots": "Нет предстоящих снимков", + "feedback.policy.scheduling.snapshot-frequency": "Частота снимков", + "feedback.policy.scheduling.snapshot-frequency-help": "Как часто создавать снимки на сервере KopiaUI или Kopia (не влияет вне режима сервера)", + "feedback.policy.scheduling.times-of-day": "Время суток", + "feedback.policy.scheduling.times-of-day-help": "Создание снимков в указанное время суток (24-часовой формат)", + "feedback.policy.scheduling.times-of-day-hint": "например 17:00", + "feedback.policy.scheduling.upcoming": "Предстоящие", + "feedback.policy.scheduling.upcoming-snapshots": "Предстоящие снимки", + "feedback.policy.scheduling.upcoming-snapshots-help": "Время предстоящих снимков рассчитывается на основе параметров политики.", + "feedback.policy.time-of-day.invalid": "Неверное время суток: {{tod}}", + "feedback.policy.timeout-help": "Тайм-аут в секундах, прежде чем Копия завершит процесс", + "feedback.policy.upload.maximum-parallel-file-reads": "Максимальное параллельное чтение файлов", + "feedback.policy.upload.maximum-parallel-file-reads-help": "Максимальное количество файлов, которые будут читаться параллельно (по умолчанию равно количеству логических процессоров).", + "feedback.policy.upload.maximum-parallel-file-reads-hint": "максимальное количество параллельных чтений файлов", + "feedback.policy.upload.maximum-parallel-snapshots": "Максимальное количество параллельных снимков", + "feedback.policy.upload.maximum-parallel-snapshots-help": "Максимальное количество снимков, которые можно загрузить одновременно", + "feedback.policy.upload.maximum-parallel-snapshots-hint-set": "максимальное количество параллельных снимков", + "feedback.policy.upload.maximum-parallel-snapshots-hint-unset": "должно быть указано с использованием глобальной, пользовательской или хостовой политики.", + "feedback.prodiver.gcs.paste-json-credentials": "Вставьте сюда учетные данные JSON.", + "feedback.provider.azure-blob-storage": "Хранилище BLOB-объектов Azure", + "feedback.provider.azure.access-key": "Ключ доступа", + "feedback.provider.azure.azure-storage-domain": "Домен хранилища Azure", + "feedback.provider.azure.container": "Контейнер", + "feedback.provider.azure.enter-access-key": "Введите секретный ключ доступа", + "feedback.provider.azure.enter-azure-storage-domain": "Введите домен хранения или оставьте пустым для значения по умолчанию «blob.core.windows.net».", + "feedback.provider.azure.enter-container-name": "Введите имя контейнера", + "feedback.provider.azure.enter-object-name-prefix": "Введите префикс имени объекта или оставьте пустым.", + "feedback.provider.azure.enter-sas-token": "Введите секретный токен SAS", + "feedback.provider.azure.enter-storage-account": "Введите имя учетной записи хранения", + "feedback.provider.azure.object-name-prefix": "Префикс имени объекта", + "feedback.provider.azure.sas-token": "Токен SAS", + "feedback.provider.azure.storage-account": "Учетная запись хранения", + "feedback.provider.b2.bucket-name": "Ведро Б2", + "feedback.provider.b2.enter-account-key": "Введите секретный ключ приложения или аккаунта", + "feedback.provider.b2.enter-account-key-id": "Введите идентификатор ключа приложения или учетной записи", + "feedback.provider.b2.enter-bucket-name": "Введите название сегмента", + "feedback.provider.b2.enter-object-name-prefix": "Введите префикс имени объекта или оставьте пустым.", + "feedback.provider.b2.key": "Ключ", + "feedback.provider.b2.key-id": "Идентификатор ключа", + "feedback.provider.b2.object-name-prefix": "Префикс имени объекта", + "feedback.provider.backblaze-b2": "Бэкблэйз Б2", + "feedback.provider.filesystem.directory-path": "Путь к каталогу", + "feedback.provider.filesystem.enter-directory-path": "Введите путь к каталогу, в котором вы хотите хранить файлы репозитория.", + "feedback.provider.gcs.bucket-name": "Сегмент ГКС", + "feedback.provider.gcs.credentials-file": "Файл учетных данных", + "feedback.provider.gcs.credentials-json": "Учетные данные JSON", + "feedback.provider.gcs.enter-bucket-name": "Введите название сегмента", + "feedback.provider.gcs.enter-credentials-file-name": "Введите имя файла JSON учетных данных", + "feedback.provider.gcs.enter-object-name-prefix": "Введите префикс имени объекта или оставьте пустым.", + "feedback.provider.gcs.object-name-prefix": "Префикс имени объекта", + "feedback.provider.google-cloud-storage": "Облачное хранилище Google", + "feedback.provider.kopia-repository-server": "Сервер репозитория Копиа", + "feedback.provider.local-directory-or-nas": "Локальный каталог или NAS", + "feedback.provider.rclone-remote": "Rclone удаленный", + "feedback.provider.rclone.rclone-executable-path": "Путь к исполняемому файлу Rclone", + "feedback.provider.rclone.rclone-executable-path-hint": "Введите путь к исполняемому файлу rclone", + "feedback.provider.rclone.rclone-remote-path": "Rclone удаленный путь", + "feedback.provider.rclone.rclone-remote-path-hint": "Введите <имя-удаленного клона>:<путь>", + "feedback.provider.repositoryserver.enter-server-certificate-fingerprint": "Введите отпечаток сертификата доверенного сервера, распечатанный при запуске сервера.", + "feedback.provider.repositoryserver.enter-server-url": "Введите URL-адрес сервера (https://<хост>:порт)", + "feedback.provider.repositoryserver.server-address": "Адрес сервера", + "feedback.provider.repositoryserver.server-certificate-fingerprint": "Отпечаток сертификата доверенного сервера (SHA256)", + "feedback.provider.repositorytoken.paste-token": "Вставить токен подключения", + "feedback.provider.repositorytoken.token": "Токен", + "feedback.provider.required-either-key-file": "Требуется один из Пароль, Ключевой файл или Ключевые данные.", + "feedback.provider.required-either-known-host-data": "Требуется либо Файл известных хостов, либо Данные известных хостов, но не оба одновременно.", + "feedback.provider.s3-or-compatible-storage": "Amazon S3 или совместимое хранилище", + "feedback.provider.s3.access-key-id": "Идентификатор ключа доступа", + "feedback.provider.s3.access-key-id-hint": "Введите идентификатор ключа доступа", + "feedback.provider.s3.bucket-name": "Ведро", + "feedback.provider.s3.bucket-name-hint": "Введите название сегмента", + "feedback.provider.s3.enter-object-name-prefix-hint": "Введите префикс имени объекта или оставьте пустым.", + "feedback.provider.s3.object-name-prefix": "Префикс имени объекта", + "feedback.provider.s3.override-region": "Переопределить регион", + "feedback.provider.s3.override-region-hint": "Введите конкретный регион (например, us-west-1) или оставьте пустым.", + "feedback.provider.s3.secret-access-key": "Секретный ключ доступа", + "feedback.provider.s3.secret-access-key-hint": "Введите секретный ключ доступа", + "feedback.provider.s3.server-endpoint": "Конечная точка сервера", + "feedback.provider.s3.server-endpoint-hint": "Введите адрес сервера (например, s3.amazonaws.com)", + "feedback.provider.s3.session-token": "Токен сеанса", + "feedback.provider.s3.session-token-hint": "Введите токен сеанса или оставьте пустым", + "feedback.provider.sftp-key-data": "Ключевые данные", + "feedback.provider.sftp-key-data-hint": "Вставьте содержимое ключевого файла", + "feedback.provider.sftp-server": "SFTP-сервер", + "feedback.provider.sftp.enter-password": "Введите пароль", + "feedback.provider.sftp.enter-path-host-file": "Введите путь к файлуknown_hosts", + "feedback.provider.sftp.enter-path-to-key-file": "Введите путь к файлу ключа", + "feedback.provider.sftp.enter-remote-path": "Введите удаленный путь к репозиторию, например, «/mnt/data/repository».", + "feedback.provider.sftp.enter-ssh-arguments": "Введите аргументы команды SSH (user@host -s sftp будет добавлен автоматически)", + "feedback.provider.sftp.enter-ssh-host-name": "имя хоста ssh (например, example.com)", + "feedback.provider.sftp.host": "Хозяин", + "feedback.provider.sftp.known-host-data": "Данные об известных хостах", + "feedback.provider.sftp.launch-external-ssh-command": "Запустите внешнюю SSH-команду без пароля.", + "feedback.provider.sftp.launch-external-ssh-command-hint": "По умолчанию Kopia подключается к серверу с помощью внутреннего SSH-клиента, который поддерживает ограниченные возможности. \nВ качестве альтернативы он может запустить внешнюю команду SSH без пароля, которая поддерживает дополнительные параметры, но, как правило, менее эффективна, чем встроенный клиент.", + "feedback.provider.sftp.password": "Пароль", + "feedback.provider.sftp.paste-content-of-known-host": "Вставьте содержимое файлаknown_hosts.", + "feedback.provider.sftp.path": "Путь", + "feedback.provider.sftp.path-host-file": "Путь к файлуknown_hosts", + "feedback.provider.sftp.path-key-file": "Путь к ключевому файлу", + "feedback.provider.sftp.port": "Порт", + "feedback.provider.sftp.port-number": "Номер порта (например, 22)", + "feedback.provider.sftp.provide-passwordless-ssh-command": "Предоставьте для выполнения команду SSH без пароля (обычно «ssh»).", + "feedback.provider.sftp.ssh-arguments": "SSH-аргументы", + "feedback.provider.sftp.ssh-command": "SSH-команда", + "feedback.provider.sftp.user": "Пользователь", + "feedback.provider.sftp.user-name": "Имя пользователя", + "feedback.provider.use-repository-token": "Использовать токен репозитория", + "feedback.provider.webdav-server": "ВебДАВ-сервер", + "feedback.provider.webdav.enter-password": "Введите пароль", + "feedback.provider.webdav.enter-username": "Введите имя пользователя", + "feedback.provider.webdav.password": "Пароль", + "feedback.provider.webdav.server-url": "URL-адрес сервера WebDAV", + "feedback.provider.webdav.username": "Имя пользователя", + "feedback.repository.additional-parameters-hint": "Дополнительные параметры можно задать при создании репозитория с помощью командной строки.", + "feedback.repository.attribute.algorithm-eco": "Алгоритм коррекции ошибок", + "feedback.repository.attribute.algorithm-encryption": "Алгоритм шифрования", + "feedback.repository.attribute.algorithm-hash": "Алгоритм хеширования", + "feedback.repository.attribute.algorithm-splitter": "Алгоритм разделения", + "feedback.repository.attribute.config-file": "Файл конфигурации", + "feedback.repository.attribute.connected-as": "Подключено как", + "feedback.repository.attribute.internal-compression": "Внутреннее сжатие", + "feedback.repository.attribute.repository-eco": "Коррекция ошибок", + "feedback.repository.attribute.repository-format": "Формат репозитория", + "feedback.repository.attribute.repository-provider": "Поставщик", + "feedback.repository.attribute.server-url": "URL сервера", + "feedback.repository.configuration": "Конфигурация хранилища", + "feedback.repository.connect-as": "Подключиться как", + "feedback.repository.connect-in-read-only-mode": "Подключайтесь в режиме только для чтения", + "feedback.repository.connect-in-read-only-mode-hint": "Режим только для чтения предотвращает любые изменения в репозитории.", + "feedback.repository.connect-to-repository": "Подключиться к репозиторию", + "feedback.repository.create-repository-new": "Создать новый репозиторий", + "feedback.repository.create-repository-new-help": "Введите надежный пароль, чтобы создать репозиторий Kopia в предоставленном хранилище.", + "feedback.repository.eco-disabled": "Отключено", + "feedback.repository.eec-warning": "[ЭКСПЕРИМЕНТАЛЬНАЯ ЧАСТЬ] Исправление ошибок может помочь защитить от определенных видов повреждения данных из-за самопроизвольной смены битов на носителе.", + "feedback.repository.encryption": "Шифрование", + "feedback.repository.enter-repository-password": "Введите пароль репозитория", + "feedback.repository.hostname": "Имя хоста", + "feedback.repository.hostname-hint": "Переопределите это значение при восстановлении снимка, сделанного на другом компьютере.", + "feedback.repository.internal-compression-supported-no": "нет", + "feedback.repository.internal-compression-supported-yes": "да", + "feedback.repository.kopia-server-parameters": "Параметры сервера Копия", + "feedback.repository.name-default": "Мой репозиторий", + "feedback.repository.override-hint": "Чтобы переопределить, нажмите «Показать дополнительные параметры».", + "feedback.repository.provider-selection": "Выберите тип хранилища", + "feedback.repository.provider-selection-hint": "Чтобы подключиться к репозиторию или создать его, выберите предпочитаемый тип хранилища:", + "feedback.repository.repository-description": "Описание репозитория", + "feedback.repository.repository-description-help": "Помогает различать несколько подключенных репозиториев.", + "feedback.repository.repository-description-hint": "Введите описание репозитория", + "feedback.repository.repository-description-required": "Требуется описание репозитория", + "feedback.repository.repository-initializing": "Инициализация репозитория...", + "feedback.repository.repository-is-read-only": "Репозиторий доступен только для чтения", + "feedback.repository.repository-password": "Пароль репозитория", + "feedback.repository.repository-password-confirm": "Подтвердите пароль репозитория", + "feedback.repository.repository-password-confirm-again": "введите пароль хранилища еще раз", + "feedback.repository.repository-password-help": "Используется для шифрования содержимого репозитория.", + "feedback.repository.repository-token-enter": "Введите токен репозитория", + "feedback.repository.server-password": "Пароль сервера", + "feedback.repository.server-password-hint": "Введите пароль для подключения к серверу", + "feedback.repository.status-connected": "Подключено к репозиторию", + "feedback.repository.username": "Имя пользователя", + "feedback.repository.username-hint": "Переопределите это при восстановлении снимка, сделанного другим пользователем.", + "feedback.snapshot.create.enter-path-to-snapshot-hint": "Введите путь к снимку", + "feedback.snapshot.create.must-specify-path": "Необходимо указать каталог для снимка.", + "feedback.snapshot.create.snapshot-new": "Новый снимок", + "feedback.snapshot.description": "Описание", + "feedback.snapshot.description.snapshot-description": "Описание снимка", + "feedback.snapshot.directory.browsing-not-supported": "Просмотр каталогов не поддерживается в веб-браузере. \nИспользуйте интерфейс Копиа.", + "feedback.snapshot.directory.restore-all-files-help": "Вы можете смонтировать/восстановить все файлы и каталоги, которые вы видите ниже, или восстановить файлы по отдельности.", + "feedback.snapshot.header.actions": "Действия", + "feedback.snapshot.header.details": "Подробности", + "feedback.snapshot.header.directories": "Дирс", + "feedback.snapshot.header.files": "Файлы", + "feedback.snapshot.header.last-snapshot": "Последний снимок", + "feedback.snapshot.header.next-snapshot": "Следующий снимок", + "feedback.snapshot.header.retention": "Удержание", + "feedback.snapshot.header.root": "Корень", + "feedback.snapshot.header.selected": "Выбрано", + "feedback.snapshot.header.snapshot-owner": "Владелец", + "feedback.snapshot.header.snapshot-path": "Путь", + "feedback.snapshot.header.snapshot-size": "Размер", + "feedback.snapshot.header.start-time": "Время начала", + "feedback.snapshot.header.status": "Статус", + "feedback.snapshot.history.snapshot-displaying": "Отображение", + "feedback.snapshot.history.wipe-all-snapshots": "Сотрите все снимки и политику для этого источника.", + "feedback.snapshot.restore.continue-on-errors": "Продолжить при возникновении ошибок", + "feedback.snapshot.restore.continue-on-errors-help": "При возникновении ошибки восстановления попробуйте продолжить, а не прекращать операцию.", + "feedback.snapshot.restore.destination": "Назначение", + "feedback.snapshot.restore.destination-help": "Вы также можете восстановить в файл .zip или .tar, указав соответствующее расширение.", + "feedback.snapshot.restore.destination-hint": "Введите путь назначения", + "feedback.snapshot.restore.disable-zip-compression": "Отключить сжатие ZIP", + "feedback.snapshot.restore.disable-zip-compression-help": "Не сжимать при восстановлении в файл ZIP (быстрее).", + "feedback.snapshot.restore.minimal-file-size-for-shallow-restore": "Минимальный размер файла для поверхностного восстановления", + "feedback.snapshot.restore.overwrite-directory": "Перезаписать директории", + "feedback.snapshot.restore.overwrite-files": "Перезаписать файлы", + "feedback.snapshot.restore.overwrite-symbolic-links": "Перезаписать символические ссылки", + "feedback.snapshot.restore.restore-file-modification-time": "Восстановить время изменения файлов", + "feedback.snapshot.restore.restore-file-ownership": "Восстановить владение файлами", + "feedback.snapshot.restore.restore-file-permissions": "Восстановить разрешения файлов", + "feedback.snapshot.restore.shallow-restore-at-depth": "Поверхностное восстановление на определенной глубине", + "feedback.snapshot.restore.skip-previously-restored-files": "Пропустить ранее восстановленные файлы и символические ссылки", + "feedback.snapshot.restore.snapshot-restore": "Восстановить", + "feedback.snapshot.restore.write-files-atomically": "Записывать файлы атомарно", + "feedback.snapshot.restore.write-sparse-files": "Записывать разреженные файлы", + "feedback.snapshot.show-individual-snapshots-count": "feedback.snapshot.show-individual-snapshots-count", + "feedback.snapshot.show-individual-snapshots-count_one": "Показать {{count}} отдельный снимок", + "feedback.snapshot.show-individual-snapshots-count_other": "Показать {{count}} отдельных снимков", + "feedback.snapshot.start-after-previous-snapshot": "Снимок начнется после завершения предыдущего снимка", + "feedback.snapshot.status.status-overdue": "просроченный", + "feedback.snapshot.status.status-pending": "Ожидание", + "feedback.tab.policies": "Политики", + "feedback.tab.preferences": "Настройки", + "feedback.tab.repository": "Репозиторий", + "feedback.tab.repository-is-not-connected": "Репозиторий не подключен", + "feedback.tab.snapshots": "Снимки", + "feedback.tab.tasks": "Задачи", + "feedback.task.estimated-results": "{{description}} Bytes: {{bytes}} ({{bytes.excluded}} исключено) Files: {{files}} ({{files.excluded}} исключено) Directories: {{directories}} ({{directories.excluded}} исключено) Errors: {{errors}} ({{errors.ignored}} проигнорировал)", + "feedback.task.header.counter": "Счетчик", + "feedback.task.header.value": "Значение", + "feedback.task.logs": "Логи", + "feedback.task.no-tasks-help": "Список задач появится здесь при создании снимков, восстановлении, выполнении обслуживания и т. д.", + "feedback.task.search-tasks-by-hint": "Поиск журналов задач по описанию", + "feedback.task.status.task-canceled": "Задача отменена", + "feedback.task.status.task-canceled-after": "Задача отменена после", + "feedback.task.status.task-canceling": "Отмена", + "feedback.task.status.task-error": "Ошибка задачи", + "feedback.task.status.task-failed-after": "Не удалось после", + "feedback.task.status.task-finished": "Завершено", + "feedback.task.status.task-finished-in": "Закончено через", + "feedback.task.status.task-running-for": "Задача выполняется в течение", + "feedback.task.status.task-started": "Начало", + "feedback.task.status.task-succeeded-after": "Задача успешно завершена после", + "feedback.task.table.header-description": "Описание", + "feedback.task.table.header-kind": "Тип", + "feedback.task.table.header-start-time": "Время начала", + "feedback.task.table.header-status": "Статус", + "feedback.task.tasks-total": "Общий", + "feedback.ui.appearance": "Внешний вид", + "feedback.ui.appearance-help": "Определяет внешний вид пользовательского интерфейса", + "feedback.ui.appearance-hint": "Выберите размер шрифта", + "feedback.ui.byte-representation-description": "Выберите представление байта", + "feedback.ui.byte-representation-help": "Определяет представление байтов", + "feedback.ui.byte-representation-select": "Выберите представление байта", + "feedback.ui.pagesize-description": "Размер страницы", + "feedback.ui.pagesize-help": "Определяет размер страницы в таблицах", + "feedback.ui.pagesize-hint": "Размер страницы", + "feedback.ui.theme-description": "Тема", + "feedback.ui.theme-help": "Текущая активная тема", + "feedback.ui.theme-select": "Выберите тему", + "feedback.validation.invalid-times-of-day": "Неверное время суток", + "feedback.validation.optional.valid-number-or-empty": "Должно быть действительным числом или пустым.", + "feedback.validation.passwords-dont-match": "Пароли не совпадают", + "feedback.validation.required.directory": "Обязательное поле", + "feedback.validation.required.field": "Обязательное поле", + "feedback.validation.required.valid-number-or-empty": "Должно быть действительным числом или пустым.", + "value.algorithm.eco-disabled": "Неполноценный", + "value.algorithm.suffix-not-recommended": "(НЕ РЕКОМЕНДУЕТСЯ)", + "value.algorithm.suffix-recommended": "(РЕКОМЕНДУЕМЫЕ)", + "value.log.details-0-no-output": "0 - нет вывода", + "value.log.details-1-minimal-details": "1 - минимум деталей", + "value.log.details-10-maximum-details": "10 - максимум деталей", + "value.log.details-5-normal-details": "5 - нормальные детали", + "value.log.details-inherit-from-parent": "(наследовать от родителя)", + "value.policy.async": "Запускать асинхронно, игнорировать сбои", + "value.policy.essential": "Должен добиться успеха", + "value.policy.inherent-from-parent": "наследовать от родителя", + "value.policy.none": "никто", + "value.policy.optional": "Игнорировать неудачи", + "value.provider.s3.http-connection-insecure": "Использовать HTTP-соединение (небезопасно)", + "value.provider.s3.no-tls-verification": "Не проверять сертификат TLS", + "value.repository.latest-format": "Последний формат", + "value.repository.legacy-format": "Устаревший формат, совместимый с версией 0.8.", + "value.snapshot-frequency.10-minutes": "каждые 10 минут", + "value.snapshot-frequency.12-hours": "каждые 12 часов", + "value.snapshot-frequency.15-minutes": "каждые 15 минут", + "value.snapshot-frequency.20-minutes": "каждые 20 минут", + "value.snapshot-frequency.3-hours": "каждые 3 часа", + "value.snapshot-frequency.30-minutes": "каждые 30 минут", + "value.snapshot-frequency.6-hours": "каждые 6 часов", + "value.snapshot-frequency.hour": "каждый час", + "value.ui.appearance-large": "большой", + "value.ui.appearance-medium": "средний", + "value.ui.appearance-small": "маленький", + "value.ui.byte-representation-base10": "Base-10 (КБ, МБ, ГБ, ТБ)", + "value.ui.byte-representation-base2": "Base-2 (КиБ, МиБ, ГиБ, ТиБ)", + "value.ui.theme-dark": "темная", + "value.ui.theme-light": "светлая", + "value.ui.theme-ocean": "морская", + "value.ui.theme-pastel": "пастельная", + "value.validation.optional-no": "нет", + "value.validation.optional-yes": "да" +} diff --git a/src/App.jsx b/src/App.jsx index 6669ff91..01f6cfe1 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -2,6 +2,8 @@ import 'bootstrap/dist/css/bootstrap.min.css'; import './css/Theme.css'; import './css/App.css'; import axios from 'axios'; +import i18n from './utils/i18n' +import { LanguageSelection } from './components/LanguageSelection'; import { React, Component } from 'react'; import { Navbar, Nav, Container } from 'react-bootstrap'; import { BrowserRouter as Router, NavLink, Redirect, Route, Switch } from 'react-router-dom'; @@ -36,6 +38,7 @@ export default class App extends Component { this.fetchInitialRepositoryDescription = this.fetchInitialRepositoryDescription.bind(this); const tok = document.head.querySelector('meta[name="kopia-csrf-token"]'); + if (tok && tok.content) { axios.defaults.headers.common['X-Kopia-Csrf-Token'] = tok.content; } else { @@ -98,7 +101,6 @@ export default class App extends Component { render() { const { uiPrefs, runningTaskCount, isRepositoryConnected } = this.state; - return ( @@ -108,19 +110,22 @@ export default class App extends Component { + diff --git a/src/assets/languages.json b/src/assets/languages.json new file mode 100644 index 00000000..776a91a2 --- /dev/null +++ b/src/assets/languages.json @@ -0,0 +1,42 @@ +{ + "en": { + "label": "English", + "code": "GB", + "value": "en" + }, + "de": { + "label": "Deutsch", + "code": "DE", + "value": "de" + }, + "es": { + "label": "Español", + "code": "ES", + "value": "es" + }, + "fr": { + "label": "Français", + "code": "FR", + "value": "fr" + }, + "ru": { + "label": "Русский", + "code": "RU", + "value": "ru" + }, + "jp": { + "label": "日本語", + "code": "JP", + "value": "jp" + }, + "it": { + "label": "Italiano", + "code": "IT", + "value": "it" + }, + "pl": { + "label": "Polski", + "code": "PL", + "value": "pl" + } +} \ No newline at end of file diff --git a/src/components/DirectoryItems.jsx b/src/components/DirectoryItems.jsx index fac5eea0..3fcd875c 100644 --- a/src/components/DirectoryItems.jsx +++ b/src/components/DirectoryItems.jsx @@ -1,8 +1,9 @@ import React, { Component } from 'react'; import { Link } from "react-router-dom"; -import KopiaTable from '../utils/KopiaTable'; import { objectLink, rfc3339TimestampForDisplay, sizeWithFailures } from '../utils/uiutil'; import { UIPreferencesContext } from '../contexts/UIPreferencesContext'; +import i18n from '../utils/i18n' +import KopiaTable from '../utils/KopiaTable'; function objectName(name, typeID) { if (typeID === "d") { @@ -37,30 +38,30 @@ export class DirectoryItems extends Component { const { bytesStringBase2 } = this.context; const columns = [{ id: "name", - Header: 'Name', + Header: i18n.t('feedback.directory.header.name'), width: "", accessor: x => directoryLinkOrDownload(x, this.props.historyState), }, { id: "mtime", accessor: "mtime", - Header: "Last Modification", + Header: i18n.t('feedback.directory.header.last-modification'), width: 200, Cell: x => rfc3339TimestampForDisplay(x.cell.value), }, { id: "size", accessor: x => sizeInfo(x), - Header: "Size", + Header: i18n.t('feedback.directory.header.size'), width: 100, Cell: x => sizeWithFailures(x.cell.value, x.row.original.summ, bytesStringBase2), }, { id: "files", accessor: "summ.files", - Header: "Files", + Header: i18n.t('feedback.directory.header.files'), width: 100, }, { id: "dirs", accessor: "summ.dirs", - Header: "Directories", + Header: i18n.t('feedback.directory.header.directories'), width: 100, }] diff --git a/src/components/LanguageSelection.jsx b/src/components/LanguageSelection.jsx new file mode 100644 index 00000000..faa06ab3 --- /dev/null +++ b/src/components/LanguageSelection.jsx @@ -0,0 +1,34 @@ +import React, { useContext } from 'react'; +import languages from '../assets/languages.json' +import Flags from 'country-flag-icons/react/3x2' +import Select, { components } from "react-select"; +import { UIPreferencesContext } from '../contexts/UIPreferencesContext'; + +const { Option } = components; +const LanguageOption = props => { + const Flag = Flags[props.data.code]; + return <> + + +}; + +export function LanguageSelection() { + const { language, setLanguage } = useContext(UIPreferencesContext); + const allLanguages = Object.values(languages) + return <> + + +} \ No newline at end of file diff --git a/src/components/Logs.jsx b/src/components/Logs.jsx index 72c66e69..5f78a8bd 100644 --- a/src/components/Logs.jsx +++ b/src/components/Logs.jsx @@ -3,10 +3,11 @@ import React, { Component } from 'react'; import Table from 'react-bootstrap/Table'; import { handleChange } from '../forms'; import { redirect } from '../utils/uiutil'; +import i18n from '../utils/i18n'; export class Logs extends Component { - constructor() { - super(); + constructor(props) { + super(props); this.state = { items: [], isLoading: false, @@ -15,7 +16,6 @@ export class Logs extends Component { this.handleChange = handleChange.bind(this); this.fetchLog = this.fetchLog.bind(this); - this.interval = window.setInterval(this.fetchLog, 3000); this.messagesEndRef = React.createRef(); this.scrollToBottom = this.scrollToBottom.bind(this); } @@ -25,6 +25,7 @@ export class Logs extends Component { isLoading: true, }); + this.interval = window.setInterval(this.fetchLog, 3000); this.fetchLog(); this.scrollToBottom(); } @@ -105,7 +106,7 @@ export class Logs extends Component { return

{error.message}

; } if (isLoading) { - return

Loading ...

; + return

{i18n.t('common.label.loading')}

; } if (logs) { diff --git a/src/components/SetupRepository.jsx b/src/components/SetupRepository.jsx index 485c1530..e37a6fcb 100644 --- a/src/components/SetupRepository.jsx +++ b/src/components/SetupRepository.jsx @@ -23,18 +23,22 @@ import { SetupRepositorySFTP } from './SetupRepositorySFTP'; import { SetupRepositoryToken } from './SetupRepositoryToken'; import { SetupRepositoryWebDAV } from './SetupRepositoryWebDAV'; import { toAlgorithmOption } from '../utils/uiutil'; +import i18n from '../utils/i18n'; +/** + * Descriptions will be translated when rendering the providers + */ const supportedProviders = [ - { provider: "filesystem", description: "Local Directory or NAS", component: SetupRepositoryFilesystem }, - { provider: "gcs", description: "Google Cloud Storage", component: SetupRepositoryGCS }, - { provider: "s3", description: "Amazon S3 or Compatible Storage", component: SetupRepositoryS3 }, - { provider: "b2", description: "Backblaze B2", component: SetupRepositoryB2 }, - { provider: "azureBlob", description: "Azure Blob Storage", component: SetupRepositoryAzure }, - { provider: "sftp", description: "SFTP Server", component: SetupRepositorySFTP }, - { provider: "rclone", description: "Rclone Remote", component: SetupRepositoryRclone }, - { provider: "webdav", description: "WebDAV Server", component: SetupRepositoryWebDAV }, - { provider: "_server", description: "Kopia Repository Server", component: SetupRepositoryServer }, - { provider: "_token", description: "Use Repository Token", component: SetupRepositoryToken }, + { provider: "filesystem", description: 'feedback.provider.local-directory-or-nas', component: SetupRepositoryFilesystem }, + { provider: "gcs", description: 'feedback.provider.google-cloud-storage', component: SetupRepositoryGCS }, + { provider: "s3", description: 'feedback.provider.s3-or-compatible-storage', component: SetupRepositoryS3 }, + { provider: "b2", description: 'feedback.provider.backblaze-b2', component: SetupRepositoryB2 }, + { provider: "azureBlob", description: 'feedback.provider.azure-blob-storage', component: SetupRepositoryAzure }, + { provider: "sftp", description: 'feedback.provider.sftp-server', component: SetupRepositorySFTP }, + { provider: "rclone", description: 'feedback.provider.rclone-remote', component: SetupRepositoryRclone }, + { provider: "webdav", description: 'feedback.provider.webdav-server', component: SetupRepositoryWebDAV }, + { provider: "_server", description: 'feedback.provider.kopia-repository-server', component: SetupRepositoryServer }, + { provider: "_token", description: 'feedback.provider.use-repository-token', component: SetupRepositoryToken }, ]; export class SetupRepository extends Component { @@ -47,7 +51,7 @@ export class SetupRepository extends Component { showAdvanced: false, storageVerified: false, providerSettings: {}, - description: "My Repository", + description: i18n.t('feedback.repository.name-default'), formatVersion: "2", }; @@ -106,7 +110,7 @@ export class SetupRepository extends Component { } if (valid && this.state.password !== this.state.confirmPassword) { - alert("Passwords don't match"); + alert(i18n.t('feedback.validation.passwords-dont-match')); return false; } } @@ -222,15 +226,15 @@ export class SetupRepository extends Component { renderProviderSelection() { return <> -

Select Storage Type

-

To connect to a repository or create one, select the preferred storage type:

+

{i18n.t('feedback.repository.provider-selection')}

+

{i18n.t('feedback.repository.provider-selection-hint')}

{supportedProviders.map(x => + className="providerIcon" >{i18n.t(x.description)} )} ; @@ -304,18 +308,18 @@ export class SetupRepository extends Component { } return
- {!this.state.provider.startsWith("_") &&

Storage Configuration

} - {this.state.provider === "_token" &&

Enter Repository Token

} - {this.state.provider === "_server" &&

Kopia Server Parameters

} + {!this.state.provider.startsWith("_") &&

{i18n.t('feedback.repository.configuration')}

} + {this.state.provider === "_token" &&

{i18n.t('feedback.repository.repository-token-enter')}

} + {this.state.provider === "_server" &&

{i18n.t('feedback.repository.kopia-server-parameters')}

} {this.connectionErrorInfo()}
- +   - + {this.loadingSpinner()} ; } @@ -323,14 +327,13 @@ export class SetupRepository extends Component { toggleAdvancedButton() { // Determine button icon and text based upon component state. const icon = this.state.showAdvanced ? faAngleDoubleUp : faAngleDoubleDown; - const text = this.state.showAdvanced ? "Hide Advanced Options" : "Show Advanced Options"; + const text = this.state.showAdvanced ? i18n.t('event.repository.hide-advanced-options') : i18n.t('event.repository.show-advanced-options'); return ; @@ -338,11 +341,11 @@ export class SetupRepository extends Component { renderConfirmCreate() { return
-

Create New Repository

-

Enter a strong password to create Kopia repository in the provided storage.

+

{i18n.t('feedback.repository.create-repository-new')}

+

{i18n.t('feedback.repository.create-repository-new-help')}

- {RequiredField(this, "Repository Password", "password", { autoFocus: true, type: "password", placeholder: "enter repository password" }, "Used to encrypt the repository's contents")} - {RequiredField(this, "Confirm Repository Password", "confirmPassword", { type: "password", placeholder: "enter repository password again" })} + {RequiredField(this, i18n.t('feedback.repository.repository-password'), "password", { autoFocus: true, type: "password", placeholder: i18n.t('feedback.repository.enter-repository-password') }, i18n.t('feedback.repository.repository-password-help'))} + {RequiredField(this, i18n.t('feedback.repository.repository-password-confirm'), "confirmPassword", { type: "password", placeholder: i18n.t('feedback.repository.repository-password-confirm-again') })}
{this.toggleAdvancedButton()} @@ -351,7 +354,7 @@ export class SetupRepository extends Component {
- Encryption + {i18n.t('feedback.repository.encryption')} - Hash Algorithm + {i18n.t('feedback.repository.attribute.algorithm-hash')} + name="hash" + onChange={this.handleChange} + data-testid="control-hash" + value={this.state.hash}> {this.state.algorithms.hash.map(x => toAlgorithmOption(x, this.state.defaultHash))} - Splitter + {i18n.t('feedback.repository.attribute.algorithm-splitter')} + name="splitter" + onChange={this.handleChange} + data-testid="control-splitter" + value={this.state.splitter}> {this.state.algorithms.splitter.map(x => toAlgorithmOption(x, this.state.defaultSplitter))} +
- Repository Format + {i18n.t('feedback.repository.attribute.repository-format')} - - + name="formatVersion" + onChange={this.handleChange} + data-testid="control-formatVersion" + value={this.state.formatVersion}> + + - Error Correction Overhead + {i18n.t('feedback.repository.attribute.repository-eco')} - + name="eccOverheadPercent" + onChange={this.handleChange} + data-testid="control-eccOverheadPercent" + value={this.state.eccOverheadPercent}> + @@ -408,7 +412,7 @@ export class SetupRepository extends Component { - Error Correction Algorithm + {i18n.t('feedback.repository.attribute.algorithm-eco')} - [EXPERIMENTAL] Error correction can help protect from certain - kinds of data corruption due to spontaneous bit flips in the storage - media. Click here to - learn more. + {i18n.t('feedback.repository.eec-warning')} {i18n.t('common.action.click-here-to-learn-more')}. +
{this.overrideUsernameHostnameRow()} - Additional parameters can be set when creating repository using command line. + {i18n.t('feedback.repository.additional-parameters-hint')}
+
{this.connectionErrorInfo()}
- -   - + + {' '} + {this.loadingSpinner()} ; } overrideUsernameHostnameRow() { return - {RequiredField(this, "Username", "username", {}, "Override this when restoring a snapshot taken by another user")} - {RequiredField(this, "Hostname", "hostname", {}, "Override this when restoring a snapshot taken on another machine")} + {RequiredField(this, i18n.t('feedback.repository.username'), "username", {}, i18n.t('feedback.repository.username-hint'))} + {RequiredField(this, i18n.t('feedback.repository.hostname'), "hostname", {}, i18n.t('feedback.repository.hostname-hint'))} ; } connectionErrorInfo() { return this.state.connectError && - Connect Error: {this.state.connectError} + {i18n.t('feedback.error.connection')} {this.state.connectError} ; } renderConfirmConnect() { return
-

Connect To Repository

+

{i18n.t('feedback.repository.connect-to-repository')}

- Connect As + {i18n.t('feedback.repository.connect-as')} - To override, click 'Show Advanced Options' + {i18n.t('feedback.repository.override-hint')} +
- {(this.state.provider !== "_token" && this.state.provider !== "_server") && RequiredField(this, "Repository Password", "password", { autoFocus: true, type: "password", placeholder: "enter repository password" }, "Used to encrypt the repository's contents")} - {this.state.provider === "_server" && RequiredField(this, "Server Password", "password", { autoFocus: true, type: "password", placeholder: "enter password to connect to server" })} + {(this.state.provider !== "_token" && this.state.provider !== "_server") && RequiredField(this, i18n.t('feedback.repository.repository-password'), "password", { autoFocus: true, type: "password", placeholder: i18n.t('feedback.repository.enter-repository-password') }, i18n.t('feedback.repository.repository-password-help'))} + {this.state.provider === "_server" && RequiredField(this, i18n.t('feedback.repository.server-password'), "password", { autoFocus: true, type: "password", placeholder: i18n.t('feedback.repository.server-password-hint') })} +
- {RequiredField(this, "Repository Description", "description", { autoFocus: this.state.provider === "_token", placeholder: "enter repository description" }, "Helps to distinguish between multiple connected repositories")} + {RequiredField(this, i18n.t('feedback.repository.repository-description'), "description", { autoFocus: this.state.provider === "_token", placeholder: i18n.t('feedback.repository.repository-description-hint') }, i18n.t('feedback.repository.repository-description-help') )} +
{this.toggleAdvancedButton()}
- {RequiredBoolean(this, "Connect in read-only mode", "readonly", "Read-only mode prevents any changes to the repository.")} + {RequiredBoolean(this, i18n.t('feedback.repository.connect-in-read-only-mode'), "readonly", i18n.t('feedback.repository.connect-in-read-only-mode-hint'))} {this.overrideUsernameHostnameRow()}
{this.connectionErrorInfo()}
- -   - + + {' '} + {this.loadingSpinner()}
; } @@ -523,7 +529,6 @@ export class SetupRepository extends Component { render() { return <> {this.renderInternal()} - {/*
{JSON.stringify(this.state, null, 2)}
*/} ; } } diff --git a/src/components/SetupRepositoryAzure.jsx b/src/components/SetupRepositoryAzure.jsx index b32e22c2..ceb9660d 100644 --- a/src/components/SetupRepositoryAzure.jsx +++ b/src/components/SetupRepositoryAzure.jsx @@ -3,6 +3,7 @@ import Row from 'react-bootstrap/Row'; import { handleChange, validateRequiredFields } from '../forms'; import { OptionalField } from '../forms/OptionalField'; import { RequiredField } from '../forms/RequiredField'; +import i18n from '../utils/i18n'; export class SetupRepositoryAzure extends Component { constructor(props) { @@ -21,16 +22,18 @@ export class SetupRepositoryAzure extends Component { render() { return <> - {RequiredField(this, "Container", "container", { autoFocus: true, placeholder: "enter container name" })} - {OptionalField(this, "Object Name Prefix", "prefix", { placeholder: "enter object name prefix or leave empty" })} + {RequiredField(this, i18n.t('feedback.provider.azure.container'), "container", { autoFocus: true, placeholder: i18n.t('feedback.provider.azure.enter-container-name') })} + {OptionalField(this, i18n.t('feedback.provider.azure.object-name-prefix'), "prefix", { placeholder: i18n.t('feedback.provider.azure.enter-object-name-prefix') })} +
- {RequiredField(this, "Storage Account", "storageAccount", { placeholder: "enter storage account name" })} - {OptionalField(this, "Access Key", "storageKey", { placeholder: "enter secret access key", type: "password" })} + {RequiredField(this, i18n.t('feedback.provider.azure.storage-account'), "storageAccount", { placeholder: i18n.t('feedback.provider.azure.enter-storage-account') })} + {OptionalField(this, i18n.t('feedback.provider.azure.access-key'), "storageKey", { placeholder: i18n.t('feedback.provider.azure.enter-access-key'), type: "password" })} +
- {OptionalField(this, "Azure Storage Domain", "storageDomain", { placeholder: "enter storage domain or leave empty for default 'blob.core.windows.net'" })} - {OptionalField(this, "SAS Token", "sasToken", { placeholder: "enter secret SAS Token", type: "password" })} + {OptionalField(this, i18n.t('feedback.provider.azure.azure-storage-domain'), "storageDomain", { placeholder: i18n.t('feedback.provider.azure.enter-azure-storage-domain') })} + {OptionalField(this, i18n.t('feedback.provider.azure.sas-token'), "sasToken", { placeholder: i18n.t('feedback.provider.azure.enter-sas-token'), type: "password" })} ; } diff --git a/src/components/SetupRepositoryB2.jsx b/src/components/SetupRepositoryB2.jsx index 73fffd11..626b399f 100644 --- a/src/components/SetupRepositoryB2.jsx +++ b/src/components/SetupRepositoryB2.jsx @@ -3,6 +3,7 @@ import Row from 'react-bootstrap/Row'; import { handleChange, validateRequiredFields } from '../forms'; import { RequiredField } from '../forms/RequiredField'; import { OptionalField } from '../forms/OptionalField'; +import i18n from '../utils/i18n'; export class SetupRepositoryB2 extends Component { constructor(props) { @@ -21,14 +22,16 @@ export class SetupRepositoryB2 extends Component { render() { return <> - {RequiredField(this, "B2 Bucket", "bucket", { autoFocus: true, placeholder: "enter bucket name" })} + {RequiredField(this, i18n.t('feedback.provider.b2.bucket-name'), "bucket", { autoFocus: true, placeholder: i18n.t('feedback.provider.b2.enter-bucket-name') })} +
- {RequiredField(this, "Key ID", "keyId", { placeholder: "enter application or account key ID" })} - {RequiredField(this, "Key", "key", { placeholder: "enter secret application or account key", type: "password" })} + {RequiredField(this, i18n.t('feedback.provider.b2.key-id'), "keyId", { placeholder: i18n.t('feedback.provider.b2.enter-account-key-id') })} + {RequiredField(this, i18n.t('feedback.provider.b2.key'), "key", { placeholder: i18n.t('feedback.provider.b2.enter-account-key'), type: "password" })} +
- {OptionalField(this, "Object Name Prefix", "prefix", { placeholder: "enter object name prefix or leave empty" })} + {OptionalField(this, i18n.t('feedback.provider.b2.object-name-prefix'), "prefix", { placeholder: i18n.t('feedback.provider.b2.enter-object-name-prefix') })} ; } diff --git a/src/components/SetupRepositoryFilesystem.jsx b/src/components/SetupRepositoryFilesystem.jsx index 6f3dbcd6..157b0db1 100644 --- a/src/components/SetupRepositoryFilesystem.jsx +++ b/src/components/SetupRepositoryFilesystem.jsx @@ -1,6 +1,7 @@ import React, { Component } from 'react'; import { handleChange, validateRequiredFields } from '../forms'; import { RequiredDirectory } from '../forms/RequiredDirectory'; +import i18n from '../utils/i18n'; export class SetupRepositoryFilesystem extends Component { constructor(props) { @@ -18,7 +19,7 @@ export class SetupRepositoryFilesystem extends Component { render() { return <> - {RequiredDirectory(this, "Directory Path", "path", { autoFocus: true, placeholder: "enter directory path where you want to store repository files"})} + {RequiredDirectory(this, i18n.t('feedback.provider.filesystem.directory-path'), "path", { autoFocus: true, placeholder: i18n.t('feedback.provider.filesystem.enter-directory-path')})} ; } } diff --git a/src/components/SetupRepositoryGCS.jsx b/src/components/SetupRepositoryGCS.jsx index cb303e99..e9b26194 100644 --- a/src/components/SetupRepositoryGCS.jsx +++ b/src/components/SetupRepositoryGCS.jsx @@ -3,6 +3,7 @@ import Row from 'react-bootstrap/Row'; import { handleChange, validateRequiredFields } from '../forms'; import { OptionalField } from '../forms/OptionalField'; import { RequiredField } from '../forms/RequiredField'; +import i18n from '../utils/i18n'; export class SetupRepositoryGCS extends Component { constructor(props) { @@ -21,14 +22,16 @@ export class SetupRepositoryGCS extends Component { render() { return <> - {RequiredField(this, "GCS Bucket", "bucket", { autoFocus: true, placeholder: "enter bucket name" })} - {OptionalField(this, "Object Name Prefix", "prefix", { placeholder: "enter object name prefix or leave empty", type: "password" })} + {RequiredField(this, i18n.t('feedback.provider.gcs.bucket-name'), "bucket", { autoFocus: true, placeholder: i18n.t('feedback.provider.gcs.enter-bucket-name') })} + {OptionalField(this, i18n.t('feedback.provider.gcs.object-name-prefix'), "prefix", { placeholder: i18n.t('feedback.provider.gcs.enter-object-name-prefix'), type: "password" })} +
- {OptionalField(this, "Credentials File", "credentialsFile", { placeholder: "enter name of credentials JSON file" })} + {OptionalField(this, i18n.t('feedback.provider.gcs.credentials-file'), "credentialsFile", { placeholder: i18n.t('feedback.provider.gcs.enter-credentials-file-name') })} +
- {OptionalField(this, "Credentials JSON", "credentials", { placeholder: "paste JSON credentials here", as: "textarea", rows: 5 })} + {OptionalField(this, i18n.t('feedback.provider.gcs.credentials-json'), "credentials", { placeholder: i18n.t('feedback.prodiver.gcs.paste-json-credentials'), as: "textarea", rows: 5 })} ; } diff --git a/src/components/SetupRepositoryRclone.jsx b/src/components/SetupRepositoryRclone.jsx index 5a59e43f..68796f15 100644 --- a/src/components/SetupRepositoryRclone.jsx +++ b/src/components/SetupRepositoryRclone.jsx @@ -3,6 +3,7 @@ import Row from 'react-bootstrap/Row'; import { handleChange, validateRequiredFields } from '../forms'; import { OptionalField } from '../forms/OptionalField'; import { RequiredField } from '../forms/RequiredField'; +import i18n from '../utils/i18n'; export class SetupRepositoryRclone extends Component { constructor(props) { @@ -21,10 +22,11 @@ export class SetupRepositoryRclone extends Component { render() { return <> - {RequiredField(this, "Rclone Remote Path", "remotePath", { autoFocus: true, placeholder: "enter :" })} + {RequiredField(this, i18n.t('feedback.provider.rclone.rclone-remote-path'), "remotePath", { autoFocus: true, placeholder: i18n.t('feedback.provider.rclone.rclone-remote-path-hint') })} +
- {OptionalField(this, "Rclone Executable Path", "rcloneExe", { placeholder: "enter path to rclone executable" })} + {OptionalField(this, i18n.t('feedback.provider.rclone.rclone-executable-path'), "rcloneExe", { placeholder: i18n.t('feedback.provider.rclone.rclone-executable-path-hint') })} ; } diff --git a/src/components/SetupRepositoryS3.jsx b/src/components/SetupRepositoryS3.jsx index d05da1d3..0c9c8216 100644 --- a/src/components/SetupRepositoryS3.jsx +++ b/src/components/SetupRepositoryS3.jsx @@ -4,6 +4,7 @@ import { handleChange, validateRequiredFields } from '../forms'; import { OptionalField } from '../forms/OptionalField'; import { RequiredBoolean } from '../forms/RequiredBoolean'; import { RequiredField } from '../forms/RequiredField'; +import i18n from '../utils/i18n'; export class SetupRepositoryS3 extends Component { constructor(props) { @@ -24,21 +25,24 @@ export class SetupRepositoryS3 extends Component { render() { return <> - {RequiredField(this, "Bucket", "bucket", { autoFocus: true, placeholder: "enter bucket name" })} - {RequiredField(this, "Server Endpoint", "endpoint", { placeholder: "enter server address (e.g., s3.amazonaws.com)" })} - {OptionalField(this, "Override Region", "region", { placeholder: "enter specific region (e.g., us-west-1) or leave empty" })} + {RequiredField(this, i18n.t('feedback.provider.s3.bucket-name'), "bucket", { autoFocus: true, placeholder: i18n.t('feedback.provider.s3.bucket-name-hint') })} + {RequiredField(this, i18n.t('feedback.provider.s3.server-endpoint'), "endpoint", { placeholder: i18n.t('feedback.provider.s3.server-endpoint-hint') })} + {OptionalField(this, i18n.t('feedback.provider.s3.override-region'), "region", { placeholder: i18n.t('feedback.provider.s3.override-region-hint') })} +
- {RequiredBoolean(this, "Use HTTP connection (insecure)", "doNotUseTLS")} - {RequiredBoolean(this, "Do not verify TLS certificate", "doNotVerifyTLS")} + {RequiredBoolean(this, i18n.t('value.provider.s3.http-connection-insecure'), "doNotUseTLS")} + {RequiredBoolean(this, i18n.t('value.provider.s3.no-tls-verification'), "doNotVerifyTLS")} +
- {RequiredField(this, "Access Key ID", "accessKeyID", { placeholder: "enter access key ID" })} - {RequiredField(this, "Secret Access Key", "secretAccessKey", { placeholder: "enter secret access key", type: "password" })} - {OptionalField(this, "Session Token", "sessionToken", { placeholder: "enter session token or leave empty", type: "password" })} + {RequiredField(this, i18n.t('feedback.provider.s3.access-key-id'), "accessKeyID", { placeholder: i18n.t('feedback.provider.s3.access-key-id-hint') })} + {RequiredField(this, i18n.t('feedback.provider.s3.secret-access-key'), "secretAccessKey", { placeholder: i18n.t('feedback.provider.s3.secret-access-key-hint'), type: "password" })} + {OptionalField(this, i18n.t('feedback.provider.s3.session-token'), "sessionToken", { placeholder: i18n.t('feedback.provider.s3.session-token-hint'), type: "password" })} +
- {OptionalField(this, "Object Name Prefix", "prefix", { placeholder: "enter object name prefix or leave empty" })} + {OptionalField(this, i18n.t('feedback.provider.s3.object-name-prefix'), "prefix", { placeholder: i18n.t('feedback.provider.s3.enter-object-name-prefix-hint') })} ; } diff --git a/src/components/SetupRepositorySFTP.jsx b/src/components/SetupRepositorySFTP.jsx index 3f9a58b9..6d7b39c6 100644 --- a/src/components/SetupRepositorySFTP.jsx +++ b/src/components/SetupRepositorySFTP.jsx @@ -5,6 +5,8 @@ import { OptionalField } from '../forms/OptionalField'; import { OptionalNumberField } from '../forms/OptionalNumberField'; import { RequiredBoolean } from '../forms/RequiredBoolean'; import { RequiredField } from '../forms/RequiredField'; +import i18n from '../utils/i18n'; +import { Trans } from 'react-i18next'; function hasExactlyOneOf(component, names) { let count = 0; @@ -57,41 +59,46 @@ export class SetupRepositorySFTP extends Component { render() { return <> - {RequiredField(this, "Host", "host", { autoFocus: true, placeholder: "ssh host name (e.g., example.com)" })} - {RequiredField(this, "User", "username", { placeholder: "user name" })} - {OptionalNumberField(this, "Port", "port", { placeholder: "port number (e.g., 22)" })} + {RequiredField(this, i18n.t('feedback.provider.sftp.host'), "host", { autoFocus: true, placeholder: i18n.t('feedback.provider.sftp.enter-ssh-host-name') })} + {RequiredField(this, i18n.t('feedback.provider.sftp.user'), "username", { placeholder: i18n.t('feedback.provider.sftp.user-name') })} + {OptionalNumberField(this, i18n.t('feedback.provider.sftp.port'), "port", { placeholder: i18n.t('feedback.provider.sftp.port-number') })} +
- {RequiredField(this, "Path", "path", { placeholder: "enter remote path to repository, e.g., '/mnt/data/repository'" })} + {RequiredField(this, i18n.t('feedback.provider.sftp.path'), "path", { placeholder: i18n.t('feedback.provider.sftp.enter-remote-path') })} +
{!this.state.externalSSH && <> - {OptionalField(this, "Password", "password", { type: "password", placeholder: "password" })} + {OptionalField(this, i18n.t('feedback.provider.sftp.password'), "password", { type: "password", placeholder: i18n.t('feedback.provider.sftp.enter-password') })} +
- {OptionalField(this, "Path to key file", "keyfile", { placeholder: "enter path to the key file" })} - {OptionalField(this, "Path to known_hosts File", "knownHostsFile", { placeholder: "enter path to the known_hosts file" })} + {OptionalField(this, i18n.t('feedback.provider.sftp.path-key-file'), "keyfile", { placeholder: i18n.t('feedback.provider.sftp.enter-path-to-key-file') })} + {OptionalField(this, i18n.t('feedback.provider.sftp.path-host-file'), "knownHostsFile", { placeholder: i18n.t('feedback.provider.sftp.enter-path-host-file') })} +
- {OptionalField(this, "Key Data", "keyData", { - placeholder: "paste contents of the key file", + {OptionalField(this, i18n.t('feedback.provider.sftp-key-data'), "keyData", { + placeholder: i18n.t('feedback.provider.sftp-key-data-hint'), as: "textarea", rows: 5, isInvalid: this.state.validated && !this.state.externalSSH && !hasExactlyOneOf(this, ["password", "keyfile", "keyData"]), - }, null, <>One of Password, Key File or Key Data is required.)} - {OptionalField(this, "Known Hosts Data", "knownHostsData", { - placeholder: "paste contents of the known_hosts file", + }, )} + {OptionalField(this, i18n.t('feedback.provider.sftp.known-host-data'), "knownHostsData", { + placeholder: i18n.t('feedback.provider.sftp.paste-content-of-known-host'), as: "textarea", rows: 5, isInvalid: this.state.validated && !this.state.externalSSH && !hasExactlyOneOf(this, ["knownHostsFile", "knownHostsData"]), - }, null, <>Either Known Hosts File or Known Hosts Data is required, but not both.)} + }, )} -
+
} - {RequiredBoolean(this, "Launch external password-less SSH command", "externalSSH", "By default Kopia connects to the server using internal SSH client which supports limited options. Alternatively it may launch external password-less SSH command, which supports additional options, but is generally less efficient than the built-in client.")} + {RequiredBoolean(this, i18n.t('feedback.provider.sftp.launch-external-ssh-command'), "externalSSH", i18n.t('feedback.provider.sftp.launch-external-ssh-command-hint'))} +
{this.state.externalSSH && <> - {OptionalField(this, "SSH Command", "sshCommand", { placeholder: "provide enter passwordless SSH command to execute (typically 'ssh')" })} - {OptionalField(this, "SSH Arguments", "sshArguments", { placeholder: "enter SSH command arguments ('user@host -s sftp' will be appended automatically)" })} + {OptionalField(this, i18n.t('feedback.provider.sftp.ssh-command'), "sshCommand", { placeholder: i18n.t('feedback.provider.sftp.provide-passwordless-ssh-command') })} + {OptionalField(this, i18n.t('feedback.provider.sftp.ssh-arguments'), "sshArguments", { placeholder: i18n.t('feedback.provider.sftp.enter-ssh-arguments') })} } ; diff --git a/src/components/SetupRepositoryServer.jsx b/src/components/SetupRepositoryServer.jsx index 1bf7ab7e..8aeec57f 100644 --- a/src/components/SetupRepositoryServer.jsx +++ b/src/components/SetupRepositoryServer.jsx @@ -3,6 +3,7 @@ import Row from 'react-bootstrap/Row'; import { handleChange, validateRequiredFields } from '../forms'; import { OptionalField } from '../forms/OptionalField'; import { RequiredField } from '../forms/RequiredField'; +import i18n from '../utils/i18n'; export class SetupRepositoryServer extends Component { constructor(props) { @@ -21,10 +22,11 @@ export class SetupRepositoryServer extends Component { render() { return <> - {RequiredField(this, "Server address", "url", { autoFocus: true, placeholder: "enter server URL (https://:port)" })} + {RequiredField(this, i18n.t('feedback.provider.repositoryserver.server-address'), "url", { autoFocus: true, placeholder: i18n.t('feedback.provider.repositoryserver.enter-server-url') })} +
- {OptionalField(this, "Trusted server certificate fingerprint (SHA256)", "serverCertFingerprint", { placeholder: "enter trusted server certificate fingerprint printed at server startup" })} + {OptionalField(this, i18n.t('feedback.provider.repositoryserver.server-certificate-fingerprint'), "serverCertFingerprint", { placeholder: i18n.t('feedback.provider.repositoryserver.enter-server-certificate-fingerprint') })} ; } diff --git a/src/components/SetupRepositoryToken.jsx b/src/components/SetupRepositoryToken.jsx index b767a355..25e9c064 100644 --- a/src/components/SetupRepositoryToken.jsx +++ b/src/components/SetupRepositoryToken.jsx @@ -2,6 +2,7 @@ import React, { Component } from 'react'; import Row from 'react-bootstrap/Row'; import { handleChange, validateRequiredFields } from '../forms'; import { RequiredField } from '../forms/RequiredField'; +import i18n from '../utils/i18n'; export class SetupRepositoryToken extends Component { constructor(props) { @@ -20,7 +21,7 @@ export class SetupRepositoryToken extends Component { render() { return <> - {RequiredField(this, "Token", "token", { autoFocus: true, type: "password", placeholder: "paste connection token" })} + {RequiredField(this, i18n.t('feedback.provider.repositorytoken.token'), "token", { autoFocus: true, type: "password", placeholder: i18n.t('feedback.provider.repositorytoken.paste-token') })} ; } diff --git a/src/components/SetupRepositoryWebDAV.jsx b/src/components/SetupRepositoryWebDAV.jsx index 51067630..88acd4fd 100644 --- a/src/components/SetupRepositoryWebDAV.jsx +++ b/src/components/SetupRepositoryWebDAV.jsx @@ -3,6 +3,7 @@ import Row from 'react-bootstrap/Row'; import { handleChange, validateRequiredFields } from '../forms'; import { OptionalField } from '../forms/OptionalField'; import { RequiredField } from '../forms/RequiredField'; +import i18n from '../utils/i18n'; export class SetupRepositoryWebDAV extends Component { constructor(props) { @@ -21,11 +22,12 @@ export class SetupRepositoryWebDAV extends Component { render() { return <> - {RequiredField(this, "WebDAV Server URL", "url", { autoFocus: true, placeholder: "http[s]://server:port/path" })} + {RequiredField(this, i18n.t('feedback.provider.webdav.server-url'), "url", { autoFocus: true, placeholder: "http[s]://server:port/path" })} +
- {OptionalField(this, "Username", "username", { placeholder: "enter username" })} - {OptionalField(this, "Password", "password", { placeholder: "enter password", type: "password" })} + {OptionalField(this, i18n.t('feedback.provider.webdav.username'), "username", { placeholder: i18n.t('feedback.provider.webdav.enter-username') })} + {OptionalField(this, i18n.t('feedback.provider.webdav.password'), "password", { placeholder: i18n.t('feedback.provider.webdav.enter-password'), type: "password" })} ; } diff --git a/src/components/SnapshotEstimation.jsx b/src/components/SnapshotEstimation.jsx index 86b07b74..4cd54f2a 100644 --- a/src/components/SnapshotEstimation.jsx +++ b/src/components/SnapshotEstimation.jsx @@ -9,28 +9,27 @@ import Form from 'react-bootstrap/Form'; import { Logs } from './Logs'; import { cancelTask, redirect, sizeDisplayName } from '../utils/uiutil'; import { UIPreferencesContext } from '../contexts/UIPreferencesContext'; +import i18n from '../utils/i18n'; +import { Trans } from 'react-i18next'; export class SnapshotEstimation extends Component { - constructor() { - super(); + constructor(props) { + super(props); this.state = { isLoading: true, error: null, showLog: false, }; - this.taskID = this.taskID.bind(this); this.fetchTask = this.fetchTask.bind(this); - - // poll frequently, we will stop as soon as the task ends. - this.interval = window.setInterval(() => this.fetchTask(this.props), 500); } componentDidMount() { this.setState({ isLoading: true, }); - + // poll frequently, we will stop as soon as the task ends. + this.interval = window.setInterval(() => this.fetchTask(this.props), 500); this.fetchTask(this.props); } @@ -76,7 +75,7 @@ export class SnapshotEstimation extends Component { } if (task.status === "SUCCESS") { - return "Total" + return i18n.t('feedback.task.tasks-total') } if (task.status === "CANCELED") { @@ -94,26 +93,34 @@ export class SnapshotEstimation extends Component { } if (isLoading) { - return

Loading ...

; + return

{i18n.t('common.label.loading')}

; } return <> {task.counters && - {this.taskStatusDescription(task)} Bytes: {sizeDisplayName(task.counters["Bytes"]?.value, bytesStringBase2)} ({sizeDisplayName(task.counters["Excluded Bytes"]?.value, bytesStringBase2)} excluded) - Files: {task.counters["Files"]?.value} ({task.counters["Excluded Files"]?.value} excluded) - Directories: {task.counters["Directories"]?.value} ({task.counters["Excluded Directories"]?.value} excluded) - Errors: {task.counters["Errors"]?.value} ({task.counters["Ignored Errors"]?.value} ignored) + } {task.status === "RUNNING" && <> -   + {' '} } {this.state.showLog ? <> - + - : } - - ; + : } + ; } } SnapshotEstimation.contextType = UIPreferencesContext \ No newline at end of file diff --git a/src/components/policy-editor/ActionRowMode.jsx b/src/components/policy-editor/ActionRowMode.jsx index 43600dee..3c186efb 100644 --- a/src/components/policy-editor/ActionRowMode.jsx +++ b/src/components/policy-editor/ActionRowMode.jsx @@ -5,18 +5,19 @@ import { stateProperty } from '../../forms'; import { LabelColumn } from './LabelColumn'; import { WideValueColumn } from './WideValueColumn'; import { EffectiveValue } from './EffectiveValue'; +import i18n from '../../utils/i18n' export function ActionRowMode(component, action) { return - + - - - + + + {EffectiveValue(component, action)} diff --git a/src/components/policy-editor/ActionRowTimeout.jsx b/src/components/policy-editor/ActionRowTimeout.jsx index fbbf3417..79f94751 100644 --- a/src/components/policy-editor/ActionRowTimeout.jsx +++ b/src/components/policy-editor/ActionRowTimeout.jsx @@ -4,10 +4,11 @@ import { OptionalNumberField } from '../../forms/OptionalNumberField'; import { LabelColumn } from './LabelColumn'; import { WideValueColumn } from './WideValueColumn'; import { EffectiveValue } from './EffectiveValue'; +import i18n from '../../utils/i18n'; export function ActionRowTimeout(component, action) { return - + {OptionalNumberField(component, "", "policy." + action, {})} {EffectiveValue(component, action)} ; diff --git a/src/components/policy-editor/PolicyEditor.jsx b/src/components/policy-editor/PolicyEditor.jsx index b61554ee..65ca0a4d 100644 --- a/src/components/policy-editor/PolicyEditor.jsx +++ b/src/components/policy-editor/PolicyEditor.jsx @@ -29,6 +29,8 @@ import { SectionHeaderRow } from './SectionHeaderRow'; import { ActionRowScript } from './ActionRowScript'; import { ActionRowTimeout } from './ActionRowTimeout'; import { ActionRowMode } from './ActionRowMode'; +import i18n from '../../utils/i18n'; +import { Trans } from 'react-i18next'; export class PolicyEditor extends Component { constructor() { @@ -117,10 +119,10 @@ export class PolicyEditor extends Component { } if (p.userName === this.props.userName && p.host === this.props.host && p.path === this.props.path) { - return "(Defined by this policy)"; + return i18n.t('feedback.policy.defined-by-this-policy'); } - return <>Defined by {PolicyEditorLink(p)}; + return <>{i18n.t('feedback.policy.defined-by')} {PolicyEditorLink(p)}; } getAndValidatePolicy() { @@ -146,7 +148,7 @@ export class PolicyEditor extends Component { for (const tod of l) { if (typeof (tod) !== "object") { // unparsed - throw Error("invalid time of day: '" + tod + "'") + throw Error(i18n.t('feedback.policy.time-of-day.invalid', { 'tod': tod })) } } @@ -212,7 +214,7 @@ export class PolicyEditor extends Component { this.props.close(); }).catch(error => { this.setState({ saving: false }); - errorAlert(error, 'Error saving policy'); + errorAlert(error, i18n.t('feedback.policy.error-saving-policy')); }); } catch (e) { errorAlert(e); @@ -221,14 +223,14 @@ export class PolicyEditor extends Component { } deletePolicy() { - if (window.confirm('Are you sure you want to delete this policy?')) { + if (window.confirm(i18n.t('feedback.policy.confirm-delete-policy'))) { this.setState({ saving: true }); axios.delete(this.policyURL(this.props)).then(result => { this.props.close(); }).catch(error => { this.setState({ saving: false }); - errorAlert(error, 'Error deleting policy'); + errorAlert(error, i18n.t('feedback.policy.error-delete-policy')); }); } } @@ -248,208 +250,207 @@ export class PolicyEditor extends Component { } if (isLoading) { - return

Loading ...

; + return

{i18n.t('common.label.loading')}

; } return <>
- + -  Snapshot Retention + {i18n.t('feedback.policy.header.snapshot-retention')} - - {OptionalNumberField(this, null, "policy.retention.keepLatest", { placeholder: "# of latest snapshots" })} + + {OptionalNumberField(this, null, "policy.retention.keepLatest", { placeholder: i18n.t('feedback.policy.retention.keep-latest-help') })} {EffectiveValue(this, "retention.keepLatest")} - - {OptionalNumberField(this, null, "policy.retention.keepHourly", { placeholder: "# of hourly snapshots" })} + + {OptionalNumberField(this, null, "policy.retention.keepHourly", { placeholder: i18n.t('feedback.policy.retention.hourly-snapshot-retain-hint') })} {EffectiveValue(this, "retention.keepHourly")} - - {OptionalNumberField(this, null, "policy.retention.keepDaily", { placeholder: "# of daily snapshots" })} + + {OptionalNumberField(this, null, "policy.retention.keepDaily", { placeholder: i18n.t('feedback.policy.retention.daily-snapshot-retain-hint') })} {EffectiveValue(this, "retention.keepDaily")} - - {OptionalNumberField(this, null, "policy.retention.keepWeekly", { placeholder: "# of weekly snapshots" })} + + {OptionalNumberField(this, null, "policy.retention.keepWeekly", { placeholder: i18n.t('feedback.policy.retention.weekly-snapshot-retain-hint') })} {EffectiveValue(this, "retention.keepWeekly")} - - {OptionalNumberField(this, null, "policy.retention.keepMonthly", { placeholder: "# of monthly snapshots" })} + + {OptionalNumberField(this, null, "policy.retention.keepMonthly", { placeholder: i18n.t('feedback.policy.retention.monthly-snapshot-retain-hint') })} {EffectiveValue(this, "retention.keepMonthly")} - - {OptionalNumberField(this, null, "policy.retention.keepAnnual", { placeholder: "# of annual snapshots" })} + + {OptionalNumberField(this, null, "policy.retention.keepAnnual", { placeholder: i18n.t('feedback.policy.retention.annual-snapshot-retain-hint') })} {EffectiveValue(this, "retention.keepAnnual")} - - {OptionalBoolean(this, null, "policy.retention.ignoreIdenticalSnapshots", "inherit from parent")} + + {OptionalBoolean(this, null, "policy.retention.ignoreIdenticalSnapshots", i18n.t('value.policy.inherent-from-parent'))} {EffectiveValue(this, "retention.ignoreIdenticalSnapshots")} -  Files + {i18n.t('feedback.policy.header.files')} - List of file and directory names to ignore.
(See documentation on ignoring files).} /> - {StringList(this, "policy.files.ignore", { placeholder: "e.g. /file.txt" })} + }} />} /> + {StringList(this, "policy.files.ignore", { placeholder: i18n.t('feedback.policy.files.ignore-files-hint') })} {EffectiveTextAreaValue(this, "files.ignore")}
- + {RequiredBoolean(this, "", "policy.files.noParentIgnore")} - - {StringList(this, "policy.files.ignoreDotFiles", { placeholder: "e.g. .kopiaignore" })} + + {StringList(this, "policy.files.ignoreDotFiles", { placeholder: i18n.t('feedback.policy.files.ignore-rule-files-hint') })} {EffectiveTextAreaValue(this, "files.ignoreDotFiles")} - + {RequiredBoolean(this, "", "policy.files.noParentDotFiles")} - - {OptionalBoolean(this, null, "policy.files.ignoreCacheDirs", "inherit from parent")} + + {OptionalBoolean(this, null, "policy.files.ignoreCacheDirs", i18n.t('value.policy.inherent-from-parent'))} {EffectiveBooleanValue(this, "files.ignoreCacheDirs")} - - {OptionalBoolean(this, null, "policy.files.oneFileSystem", "inherit from parent")} + + {OptionalBoolean(this, null, "policy.files.oneFileSystem", i18n.t('value.policy.inherent-from-parent'))} {EffectiveBooleanValue(this, "files.oneFileSystem")}
-  Error Handling + {i18n.t('feedback.policy.header.error-handling')} - - {OptionalBoolean(this, null, "policy.errorHandling.ignoreDirectoryErrors", "inherit from parent")} + + {OptionalBoolean(this, null, "policy.errorHandling.ignoreDirectoryErrors", i18n.t('value.policy.inherent-from-parent'))} {EffectiveBooleanValue(this, "errorHandling.ignoreDirectoryErrors")} - - {OptionalBoolean(this, null, "policy.errorHandling.ignoreFileErrors", "inherit from parent")} + + {OptionalBoolean(this, null, "policy.errorHandling.ignoreFileErrors", i18n.t('value.policy.inherent-from-parent'))} {EffectiveBooleanValue(this, "errorHandling.ignoreFileErrors")} - - {OptionalBoolean(this, null, "policy.errorHandling.ignoreUnknownTypes", "inherit from parent")} + + {OptionalBoolean(this, null, "policy.errorHandling.ignoreUnknownTypes", i18n.t('value.policy.inherent-from-parent'))} {EffectiveBooleanValue(this, "errorHandling.ignoreUnknownTypes")} -  Compression + {i18n.t('feedback.policy.header.compression')} - + - + {this.state.algorithms && this.state.algorithms.compression.map(x => toAlgorithmOption(x, ""))} {EffectiveValue(this, "compression.compressorName")} - - {OptionalNumberField(this, "", "policy.compression.minSize", { placeholder: "minimum file size in bytes" })} + + {OptionalNumberField(this, "", "policy.compression.minSize", { placeholder: i18n.t('feedback.policy.compression.minimal-file-size-hint') })} {EffectiveValue(this, "compression.minSize")} - - {OptionalNumberField(this, "", "policy.compression.maxSize", { placeholder: "maximum file size in bytes" })} + + {OptionalNumberField(this, "", "policy.compression.maxSize", { placeholder: i18n.t('feedback.policy.compression.maximal-file-size-hint') })} {EffectiveValue(this, "compression.maxSize")} - + - {StringList(this, "policy.compression.onlyCompress", { placeholder: "e.g. *.txt" })} + {StringList(this, "policy.compression.onlyCompress", { placeholder: i18n.t('feedback.policy.compression.only-compress-extensions-hint') })} {EffectiveTextAreaValue(this, "compression.onlyCompress")} - + - {StringList(this, "policy.compression.neverCompress", { placeholder: "e.g. *.mp4" })} + {StringList(this, "policy.compression.neverCompress", { placeholder: i18n.t('feedback.policy.compression.never-compress-extensions-hint') })} {EffectiveTextAreaValue(this, "compression.neverCompress")} -  Scheduling + {i18n.t('feedback.policy.header.scheduling')} - + this.handleChange(e, valueToNumber)} value={stateProperty(this, "policy.scheduling.intervalSeconds")}> - - - - - - - - + + + + + + + + {EffectiveValue(this, "scheduling.intervalSeconds")} - + - {TimesOfDayList(this, "policy.scheduling.timeOfDay", { placeholder: "e.g. 17:00" })} + {TimesOfDayList(this, "policy.scheduling.timeOfDay", { placeholder: i18n.t('feedback.policy.scheduling.times-of-day-hint') })} {EffectiveTimesOfDayValue(this, "scheduling.timeOfDay")} - Snapshot schedules using UNIX crontab syntax (one per line): -
See supported format details.} /> + }} />} /> - {StringList(this, "policy.scheduling.cron", { placeholder: "minute hour day month weekday #comment" })} + {StringList(this, "policy.scheduling.cron", { placeholder: i18n.t('feedback.policy.scheduling.cron-expressions-hint') })} {EffectiveListValue(this, "scheduling.cron")}
- + - {OptionalBoolean(this, "", "policy.scheduling.runMissed", "inherit from parent")} + {OptionalBoolean(this, "", "policy.scheduling.runMissed", i18n.t('value.policy.inherent-from-parent'))} {EffectiveBooleanValue(this, "scheduling.runMissed")} - + - {OptionalBoolean(this, "", "policy.scheduling.manual", "inherit from parent")} + {OptionalBoolean(this, "", "policy.scheduling.manual", i18n.t('value.policy.inherent-from-parent'))} {EffectiveBooleanValue(this, "scheduling.manual")} - + @@ -459,89 +460,89 @@ export class PolicyEditor extends Component {
-  Upload + {i18n.t('feedback.policy.header.upload')} - - {OptionalNumberField(this, "", "policy.upload.maxParallelSnapshots", { placeholder: !this.props.path ? "max number of parallel snapshots" : "must be specified using global, user, or host policy", disabled: !!this.props.path })} + + {OptionalNumberField(this, "", "policy.upload.maxParallelSnapshots", { placeholder: !this.props.path ? i18n.t('feedback.policy.upload.maximum-parallel-snapshots-hint-set') : i18n.t('feedback.policy.upload.maximum-parallel-snapshots-hint-unset'), disabled: !!this.props.path })} {EffectiveValue(this, "upload.maxParallelSnapshots")} - - {OptionalNumberField(this, "", "policy.upload.maxParallelFileReads", { placeholder: "max number of parallel file reads" })} + + {OptionalNumberField(this, "", "policy.upload.maxParallelFileReads", { placeholder: i18n.t('feedback.policy.upload.maximum-parallel-file-reads-hint') })} {EffectiveValue(this, "upload.maxParallelFileReads")} -  Snapshot Actions + {i18n.t('feedback.policy.header.snapshot-action')} - {ActionRowScript(this, "actions.beforeSnapshotRoot.script", "Before Snapshot", "Script to run before snapshot")} + {ActionRowScript(this, "actions.beforeSnapshotRoot.script", i18n.t('feedback.policy.actions.before-snapshot'), i18n.t('feedback.policy.actions.before-snapshot-help'))} {ActionRowTimeout(this, "actions.beforeSnapshotRoot.timeout")} {ActionRowMode(this, "actions.beforeSnapshotRoot.mode")}
- {ActionRowScript(this, "actions.afterSnapshotRoot.script", "After Snapshot", "Script to run after snapshot")} + {ActionRowScript(this, "actions.afterSnapshotRoot.script", i18n.t('feedback.policy.actions.after-snapshot'), i18n.t('feedback.policy.actions.after-snapshot-help'))} {ActionRowTimeout(this, "actions.afterSnapshotRoot.timeout")} {ActionRowMode(this, "actions.afterSnapshotRoot.mode")}
-  Folder Actions + {i18n.t('feedback.policy.header.folder-actions')} - {ActionRowScript(this, "actions.beforeFolder.script", "Before Folder", "Script to run before folder")} + {ActionRowScript(this, "actions.beforeFolder.script", i18n.t('feedback.policy.actions.before-folder'), i18n.t('feedback.policy.actions.before-folder-help'))} {ActionRowTimeout(this, "actions.beforeFolder.timeout")} {ActionRowMode(this, "actions.beforeFolder.mode")}
- {ActionRowScript(this, "actions.afterFolder.script", "After Folder", "Script to run after folder")} + {ActionRowScript(this, "actions.afterFolder.script", i18n.t('feedback.policy.actions.after-folder'), i18n.t('feedback.policy.actions.after-folder-help'))} {ActionRowTimeout(this, "actions.afterFolder.timeout")} {ActionRowMode(this, "actions.afterFolder.mode")}
-  Logging + {i18n.t('feedback.policy.header.logging')} - + {LogDetailSelector(this, "policy.logging.directories.snapshotted")} {EffectiveValue(this, "logging.directories.snapshotted")} - + {LogDetailSelector(this, "policy.logging.directories.ignored")} {EffectiveValue(this, "logging.directories.ignored")} - + {LogDetailSelector(this, "policy.logging.entries.snapshotted")} {EffectiveValue(this, "logging.entries.snapshotted")} - + {LogDetailSelector(this, "policy.logging.entries.ignored")} {EffectiveValue(this, "logging.entries.ignored")} - + {LogDetailSelector(this, "policy.logging.entries.cacheHit")} {EffectiveValue(this, "logging.entries.cacheHit")} - + {LogDetailSelector(this, "policy.logging.entries.cacheMiss")} @@ -550,16 +551,16 @@ export class PolicyEditor extends Component { -  Other + {i18n.t('feedback.policy.header.other')} - + {RequiredBoolean(this, "", "policy.noParent")} - +
{JSON.stringify(this.state.policy, null, 4)}
                                     
@@ -568,10 +569,10 @@ export class PolicyEditor extends Component {
- - {!this.props.embedded && } +
+ {!this.props.embedded && } {!this.state.isNew && !this.props.embedded && <>  - + } {this.state.saving && <>   diff --git a/src/components/policy-editor/SectionHeaderRow.jsx b/src/components/policy-editor/SectionHeaderRow.jsx index 568a14ad..500c94a4 100644 --- a/src/components/policy-editor/SectionHeaderRow.jsx +++ b/src/components/policy-editor/SectionHeaderRow.jsx @@ -3,11 +3,12 @@ import Row from 'react-bootstrap/Row'; import { LabelColumn } from './LabelColumn'; import { ValueColumn } from './ValueColumn'; import { EffectiveValueColumn } from './EffectiveValueColumn'; +import i18n from '../../utils/i18n'; export function SectionHeaderRow() { return -
Defined
-
Effective
+
{i18n.t('feedback.policy.header.defined')}
+
{i18n.t('feedback.header.effective')}
; } diff --git a/src/components/policy-editor/UpcomingSnapshotTimes.jsx b/src/components/policy-editor/UpcomingSnapshotTimes.jsx index b5285898..969ed350 100644 --- a/src/components/policy-editor/UpcomingSnapshotTimes.jsx +++ b/src/components/policy-editor/UpcomingSnapshotTimes.jsx @@ -1,6 +1,7 @@ import moment from 'moment'; import React from 'react'; import { LabelColumn } from './LabelColumn'; +import i18n from '../../utils/i18n'; export function UpcomingSnapshotTimes(resolved) { if (!resolved) { @@ -14,11 +15,11 @@ export function UpcomingSnapshotTimes(resolved) { const times = resolved.upcomingSnapshotTimes; if (!times) { - return ; + return ; } return <> - +
    {times.map(x =>
  • {moment(x).format('L LT')} ({moment(x).fromNow()})
  • )} diff --git a/src/contexts/UIPreferencesContext.tsx b/src/contexts/UIPreferencesContext.tsx index 5bf31674..edc18a60 100644 --- a/src/contexts/UIPreferencesContext.tsx +++ b/src/contexts/UIPreferencesContext.tsx @@ -1,11 +1,13 @@ -import React, { ReactNode, useCallback, useEffect, useState } from 'react'; +import { ReactNode, createContext, useCallback, useEffect, useState } from 'react'; import axios from 'axios'; +import i18next from 'i18next'; + +const PREFERENCES_URL = '/api/v1/ui-preferences'; export const PAGE_SIZES = [10, 20, 30, 40, 50, 100]; -export const UIPreferencesContext = React.createContext({} as UIPreferences); +export const UIPreferencesContext = createContext({} as UIPreferences); -const DEFAULT_PREFERENCES = { pageSize: PAGE_SIZES[0], bytesStringBase2: false, defaultSnapshotViewAll: false, theme: getDefaultTheme(), preferWebDav: false, fontSize: "fs-6" } as SerializedUIPreferences; -const PREFERENCES_URL = '/api/v1/ui-preferences'; +const DEFAULT_PREFERENCES = { pageSize: PAGE_SIZES[0], bytesStringBase2: false, defaultSnapshotViewAll: false, theme: getDefaultTheme(), fontSize: "fs-6", language: "en" } as SerializedUIPreferences; export type Theme = "light" | "dark" | "pastel" | "ocean"; export type PageSize = 10 | 20 | 30 | 40 | 50 | 100; @@ -17,11 +19,14 @@ export interface UIPreferences { get bytesStringBase2(): boolean get defaultSnapshotViewAll(): boolean get fontSize(): FontSize + get language(): string + setTheme: (theme: Theme) => void setPageSize: (pageSize: number) => void setByteStringBase: (bytesStringBase2: String) => void setDefaultSnapshotViewAll: (defaultSnapshotView: boolean) => void setFontSize: (size: String) => void + setLanguage: (lang: string) => void } interface SerializedUIPreferences { @@ -30,6 +35,7 @@ interface SerializedUIPreferences { defaultSnapshotView?: boolean theme: Theme fontSize: FontSize + language: string } export interface UIPreferenceProviderProps { @@ -66,7 +72,7 @@ function normalizePageSize(pageSize: number): PageSize { export function UIPreferenceProvider(props: UIPreferenceProviderProps) { const [preferences, setPreferences] = useState(DEFAULT_PREFERENCES); - + const setTheme = useCallback((theme: Theme) => setPreferences(oldPreferences => { syncTheme(theme, oldPreferences.fontSize); return { ...oldPreferences, theme }; @@ -90,6 +96,11 @@ export function UIPreferenceProvider(props: UIPreferenceProviderProps) { return { ...oldPreferences, fontSize }; }), []); + const setLanguage = useCallback((language: string) => setPreferences(oldPreferences => { + i18next.changeLanguage(language); + return { ...oldPreferences, language }; + }), []); + useEffect(() => { axios.get(PREFERENCES_URL).then(result => { let storedPreferences = result.data as SerializedUIPreferences; @@ -99,17 +110,21 @@ export function UIPreferenceProvider(props: UIPreferenceProviderProps) { if (!storedPreferences.fontSize || (storedPreferences.fontSize as string) === "") { storedPreferences.fontSize = DEFAULT_PREFERENCES.fontSize } + if (!storedPreferences.language || storedPreferences.language === "") { + storedPreferences.language = DEFAULT_PREFERENCES.language + } if (!storedPreferences.pageSize || storedPreferences.pageSize === 0) { storedPreferences.pageSize = DEFAULT_PREFERENCES.pageSize; } else { storedPreferences.pageSize = normalizePageSize(storedPreferences.pageSize); } setTheme(storedPreferences.theme); + setLanguage(storedPreferences.language); setFontSize(storedPreferences.fontSize); setPreferences(storedPreferences); }).catch(err => console.error(err)); - }, [setTheme, setFontSize]); + }, [setTheme, setFontSize, setLanguage]); useEffect(() => { if (!preferences) { @@ -134,9 +149,10 @@ export function UIPreferenceProvider(props: UIPreferenceProviderProps) { doc.classList.add(theme, fontSize) } - const providedValue = { ...preferences, setTheme, setPageSize, setByteStringBase, setDefaultSnapshotViewAll, setFontSize } as UIPreferences; + const providedValue = { ...preferences, setTheme, setPageSize, setByteStringBase, setDefaultSnapshotViewAll, setFontSize, setLanguage } as UIPreferences; return {props.children} ; } + diff --git a/src/css/App.css b/src/css/App.css index d75bd892..65b1f0ea 100644 --- a/src/css/App.css +++ b/src/css/App.css @@ -11,8 +11,13 @@ body { color: var(--color-text-body); } +#select-language { + width: 10em; + font-size: 90%; +} + #kopia .options-select { - overflow: ellipsis + overflow: ellipsis; } #kopia .btn-close { @@ -153,9 +158,10 @@ body { } #kopia .text-muted.form-text, +#kopia .text-muted, #kopia .form-text, #kopia .form-control::placeholder { - color: var(--color-text-form-help) !important + color: var(--color-text-form-help) !important; } #kopia .accordion-body, @@ -189,6 +195,13 @@ body { border: 1px solid rgba(0,0,0,.125); } +#kopia .policy-icon { + margin-left: 0; + margin-right:0.5em; + height: 1.25em; + width: 1.25em; +} + .popover { max-width: 1000px; } @@ -464,3 +477,47 @@ div.tab-body { #kopia li.page-item:disabled { background-color: var(--background-color) } + +#kopia .loader-container{ + position: absolute; + top: 50%; + left: 50%; + margin-top: -50px; + margin-left: -50px; + width: 100px; + height: 100px; +}​ + +#kopia .loader { + width: 48px; + height: 48px; + border-radius: 50%; + position: relative; + animation: rotate 1s linear infinite +} +#kopia .loader::before , .loader::after { + content: ""; + box-sizing: border-box; + position: absolute; + inset: 0px; + border-radius: 50%; + border: 5px solid #FFF; + animation: prixClipFix 2s linear infinite ; +} +#kopia .loader::after{ + inset: 8px; + transform: rotate3d(90, 90, 0, 180deg ); + border-color: #FF3D00; +} + +@keyframes rotate { + 0% {transform: rotate(0deg)} + 100% {transform: rotate(360deg)} +} + +@keyframes prixClipFix { + 0% {clip-path:polygon(50% 50%,0 0,0 0,0 0,0 0,0 0)} + 50% {clip-path:polygon(50% 50%,0 0,100% 0,100% 0,100% 0,100% 0)} + 75%, 100% {clip-path:polygon(50% 50%,0 0,100% 0,100% 100%,100% 100%,100% 100%)} +} + diff --git a/src/forms/LogDetailSelector.jsx b/src/forms/LogDetailSelector.jsx index 6f1b8bdf..79aa42c7 100644 --- a/src/forms/LogDetailSelector.jsx +++ b/src/forms/LogDetailSelector.jsx @@ -1,23 +1,24 @@ import React from 'react'; import Form from 'react-bootstrap/Form'; import { valueToNumber, stateProperty } from '.'; +import i18n from '../utils/i18n'; export function LogDetailSelector(component, name) { return component.handleChange(e, valueToNumber)} value={stateProperty(component, name)}> - - - + + + - + - + ; } diff --git a/src/forms/OptionalBoolean.jsx b/src/forms/OptionalBoolean.jsx index 6efb1320..9d91c9b9 100644 --- a/src/forms/OptionalBoolean.jsx +++ b/src/forms/OptionalBoolean.jsx @@ -1,6 +1,7 @@ import React from 'react'; import Form from 'react-bootstrap/Form'; import Col from 'react-bootstrap/Col'; +import i18n from '../utils/i18n'; import { stateProperty } from '.'; @@ -25,8 +26,8 @@ export function OptionalBoolean(component, label, name, defaultLabel) { onChange={e => component.handleChange(e, optionalBooleanValue)} as="select"> - - + + ; } diff --git a/src/forms/OptionalNumberField.jsx b/src/forms/OptionalNumberField.jsx index a81bb5c0..451ea617 100644 --- a/src/forms/OptionalNumberField.jsx +++ b/src/forms/OptionalNumberField.jsx @@ -2,6 +2,7 @@ import React from 'react'; import Form from 'react-bootstrap/Form'; import Col from 'react-bootstrap/Col'; import { isInvalidNumber, stateProperty, valueToNumber } from '.'; +import i18n from '../utils/i18n'; export function OptionalNumberField(component, label, name, props = {}) { return @@ -14,6 +15,6 @@ export function OptionalNumberField(component, label, name, props = {}) { onChange={e => component.handleChange(e, valueToNumber)} data-testid={'control-' + name} {...props} /> - Must be a valid number or empty + {i18n.t('feedback.validation.optional.valid-number-or-empty')} ; } diff --git a/src/forms/RequiredDirectory.jsx b/src/forms/RequiredDirectory.jsx index ecb40c3c..95a6ff97 100644 --- a/src/forms/RequiredDirectory.jsx +++ b/src/forms/RequiredDirectory.jsx @@ -6,6 +6,7 @@ import { faFolderOpen } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { stateProperty } from '.'; import { setDeepStateProperty } from '../utils/deepstate'; +import i18n from '../utils/i18n' /** * This functions returns a directory selector that allows the user to select a directory. @@ -46,7 +47,7 @@ export function RequiredDirectory(component, label, name, props = {}) { } - Required field + {i18n.t('feedback.validation.required.directory')} } \ No newline at end of file diff --git a/src/forms/RequiredField.jsx b/src/forms/RequiredField.jsx index b274bc59..b8472227 100644 --- a/src/forms/RequiredField.jsx +++ b/src/forms/RequiredField.jsx @@ -2,6 +2,7 @@ import React from 'react'; import Form from 'react-bootstrap/Form'; import Col from 'react-bootstrap/Col'; import { stateProperty } from '.'; +import i18n from '../utils/i18n' export function RequiredField(component, label, name, props = {}, helpText = null) { return @@ -15,6 +16,6 @@ export function RequiredField(component, label, name, props = {}, helpText = nul onChange={component.handleChange} {...props} /> {helpText && {helpText}} - Required field + {i18n.t('feedback.validation.required.field')} ; } diff --git a/src/forms/RequiredNumberField.jsx b/src/forms/RequiredNumberField.jsx index ba9e4e13..a895b5f8 100644 --- a/src/forms/RequiredNumberField.jsx +++ b/src/forms/RequiredNumberField.jsx @@ -2,6 +2,7 @@ import React from 'react'; import Form from 'react-bootstrap/Form'; import Col from 'react-bootstrap/Col'; import { stateProperty, isInvalidNumber, valueToNumber } from '.'; +import i18n from '../utils/i18n' export function RequiredNumberField(component, label, name, props = {}) { return @@ -14,6 +15,6 @@ export function RequiredNumberField(component, label, name, props = {}) { onChange={e => component.handleChange(e, valueToNumber)} data-testid={'control-' + name} {...props} /> - Must be a valid number or empty + {i18n.t('feedback.validation.required.valid-number-or-empty')} ; } diff --git a/src/forms/TimesOfDayList.jsx b/src/forms/TimesOfDayList.jsx index 061c5a0e..f4e583ea 100644 --- a/src/forms/TimesOfDayList.jsx +++ b/src/forms/TimesOfDayList.jsx @@ -2,6 +2,7 @@ import React from 'react'; import Form from 'react-bootstrap/Form'; import FormGroup from 'react-bootstrap/FormGroup'; import { stateProperty } from '.'; +import i18n from '../utils/i18n' export function TimesOfDayList(component, name, props = {}) { function parseTimeOfDay(v) { @@ -68,6 +69,6 @@ export function TimesOfDayList(component, name, props = {}) { rows="5" {...props}> - Invalid Times of Day + {i18n.t('feedback.validation.invalid-times-of-day')} ; } diff --git a/src/index.jsx b/src/index.jsx index 3057d233..2b6c8739 100644 --- a/src/index.jsx +++ b/src/index.jsx @@ -1,7 +1,19 @@ -import React from 'react'; -import { createRoot } from 'react-dom/client'; -import App from './App'; +import './utils/i18n'; import './css/index.css'; +import { createRoot } from 'react-dom/client'; +import React, { lazy, Suspense } from 'react'; +const App = lazy(() => import('./App')) const root = createRoot(document.getElementById('root')) -root.render(); +const loadingScreen = ( +
    + +
    +) + +root.render( + + + + , + ); \ No newline at end of file diff --git a/src/pages/Policies.jsx b/src/pages/Policies.jsx index 56676d56..46c2124f 100644 --- a/src/pages/Policies.jsx +++ b/src/pages/Policies.jsx @@ -13,6 +13,7 @@ import { handleChange } from '../forms'; import { OptionalDirectory } from '../forms/OptionalDirectory' import KopiaTable from '../utils/KopiaTable'; import { CLIEquivalent, compare, isAbsolutePath, ownerName, policyEditorURL, redirect } from '../utils/uiutil'; +import i18n from '../utils/i18n' const applicablePolicies = "Applicable Policies" const localPolicies = "Local Path Policies" @@ -104,7 +105,7 @@ export class Policies extends Component { } if (!isAbsolutePath(this.state.policyPath)) { - alert("Policies can only be defined for absolute paths."); + alert(i18n.t('feedback.policy.policies-defined-by-path-absolute')); return; } @@ -174,7 +175,7 @@ export class Policies extends Component { return

    {error.message}

    ; } if (isLoading) { - return

    Loading ...

    ; + return

    {i18n.t('common.label.loading')}

    ; } let uniqueOwners = sources.reduce((a, d) => { @@ -230,24 +231,24 @@ export class Policies extends Component { const columns = [{ - Header: 'Username', + Header: i18n.t('feedback.header.username'), width: 100, accessor: x => x.target.userName || "*", }, { - Header: 'Host', + Header: i18n.t('feedback.policy.header.host'), width: 100, accessor: x => x.target.host || "*", }, { - Header: 'Path', + Header: i18n.t('feedback.policy.header.path'), accessor: x => x.target.path || "*", }, { - Header: 'Defined', + Header: i18n.t('feedback.policy.header.defined'), accessor: x => this.policySummary(x), }, { id: 'edit', - Header: 'Actions', + Header: i18n.t('feedback.policy.header.actions'), width: 50, - Cell: x => + Cell: x => }] return <> @@ -257,17 +258,17 @@ export class Policies extends Component { -  {this.state.selectedOwner} + {' '}{this.state.selectedOwner} - this.selectOwner(applicablePolicies)}>{applicablePolicies} - this.selectOwner(localPolicies)}>{localPolicies} - this.selectOwner(allPolicies)}>{allPolicies} + this.selectOwner(applicablePolicies)}>{i18n.t('feedback.policy.kind.applicable')} + this.selectOwner(localPolicies)}>{i18n.t('feedback.policy.kind.local')} + this.selectOwner(allPolicies)}>{i18n.t('feedback.policy.kind.all')} - this.selectOwner(globalPolicy)}>{globalPolicy} - this.selectOwner(perUserPolicies)}>{perUserPolicies} - this.selectOwner(perHostPolicies)}>{perHostPolicies} + this.selectOwner(globalPolicy)}>{i18n.t('feedback.policy.kind.global')} + this.selectOwner(perUserPolicies)}>{i18n.t('feedback.policy.kind.per-user-policies')} + this.selectOwner(perHostPolicies)}>{i18n.t('feedback.policy.kind.per-host-policies')} {uniqueOwners.map(v => this.selectOwner(v)}>{v})} @@ -275,10 +276,10 @@ export class Policies extends Component { {(this.state.selectedOwner === localPolicies || this.state.selectedOwner === this.state.localSourceName || this.state.selectedOwner === applicablePolicies) ? <> - {OptionalDirectory(this, null, "policyPath", { autoFocus: true, placeholder: "enter directory to find or set policy" })} + {OptionalDirectory(this, null, "policyPath", { autoFocus: true, placeholder: i18n.t('feedback.policy.find-hint') })} - + : } @@ -286,11 +287,11 @@ export class Policies extends Component {
} {policies.length > 0 ?
-

Found {policies.length} policies matching criteria.

+

{i18n.t('feedback.policy.find-count', { count: policies.length })}.

: ((this.state.selectedOwner === localPolicies && this.state.policyPath) ?

- No policy found for directory {this.state.policyPath}. Click Set Policy to define it. -

:

No policies found.

)} + {i18n.t('feedback.policy.find-none-create', { path: this.state.policyPath })} +

:

{i18n.t('feedback.policy.find-none')}.

)} ; } diff --git a/src/pages/Policy.jsx b/src/pages/Policy.jsx index e759e786..27ef359d 100644 --- a/src/pages/Policy.jsx +++ b/src/pages/Policy.jsx @@ -1,31 +1,24 @@ -import React, { Component, createRef } from 'react'; +import { useRef } from 'react'; import Col from 'react-bootstrap/esm/Col'; import Row from 'react-bootstrap/esm/Row'; import { PolicyEditor } from '../components/policy-editor/PolicyEditor'; import { CLIEquivalent, GoBackButton, parseQuery, PolicyTypeName } from '../utils/uiutil'; -export class Policy extends Component { - constructor() { - super(); +export function Policy({ location, history }) { + const source = parseQuery(location.search); + const { userName, host, path } = source; + const editorRef = useRef(); - this.editorRef = createRef(); - } - - render() { - const source = parseQuery(this.props.location.search); - const { userName, host, path } = source; - - return <> -

- -   {PolicyTypeName(source)}

- -   - - - - - - ; - } + return <> +

+ + {' '}{PolicyTypeName(source)}

+ +
+ + + + + + ; } diff --git a/src/pages/Preferences.jsx b/src/pages/Preferences.jsx index f831d6cb..0fd0c53b 100644 --- a/src/pages/Preferences.jsx +++ b/src/pages/Preferences.jsx @@ -1,52 +1,51 @@ -import { Component } from 'react'; +import { useContext } from 'react'; +import { useTranslation } from "react-i18next"; import { UIPreferencesContext } from '../contexts/UIPreferencesContext'; /** * Class that exports preferences */ -export class Preferences extends Component { - render() { - const { pageSize, theme, bytesStringBase2, fontSize, setByteStringBase, setTheme, setFontSize} = this.context; - return <> - -
- - - The current active theme -
-
-
- - - Specifies the representation of bytes -
-
-
- - - Specifies the appearance of the user interface -
-
-
- - - Specifies the pagination size in tables -
- - - } -} -Preferences.contextType = UIPreferencesContext +export function Preferences() { + const { t } = useTranslation(); + const { pageSize, theme, bytesStringBase2, fontSize, setFontSize, setByteStringBase, setTheme } = useContext(UIPreferencesContext); + return <> +
+
+ + + {t('feedback.ui.theme-help')} +
+
+
+ + + {t('feedback.ui.byte-representation-help')} +
+
+
+ + + {t('feedback.ui.appearance-help')} +
+
+
+ + + {t('feedback.ui.pagesize-help')} +
+
+ +} \ No newline at end of file diff --git a/src/pages/Repository.jsx b/src/pages/Repository.jsx index 5e646cb3..740d7993 100644 --- a/src/pages/Repository.jsx +++ b/src/pages/Repository.jsx @@ -14,6 +14,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faCheck, faChevronCircleDown, faChevronCircleUp, faWindowClose } from '@fortawesome/free-solid-svg-icons'; import { Logs } from '../components/Logs'; import { AppContext } from '../contexts/AppContext'; +import i18n from '../utils/i18n' export class Repository extends Component { constructor() { @@ -127,13 +128,13 @@ export class Repository extends Component { } if (this.state.status.initTaskID) { - return <>

 Initializing Repository...

+ return <>

{' '}{i18n.t('feedback.repository.repository-initializing')}

{this.state.showLog ? <> - + - : } + : }
- + ; } @@ -141,7 +142,7 @@ export class Repository extends Component { return <>

- Connected To Repository + {i18n.t('feedback.repository.status-connected')}

@@ -155,13 +156,13 @@ export class Repository extends Component { onChange={this.handleChange} size="sm" />   - + - Description Is Required + {i18n.t('feedback.repository.repository-description-required')} {this.state.status.readonly && - Repository is read-only + {i18n.t('feedback.repository.repository-is-read-only')} }

@@ -169,68 +170,71 @@ export class Repository extends Component { {this.state.status.apiServerURL ? <> - Server URL + {i18n.t('feedback.repository.attribute.server-url')}: : <> - Config File + {i18n.t('feedback.repository.attribute.config-file')}: +
- Provider + {i18n.t('feedback.repository.attribute.repository-provider')}: - Encryption Algorithm + {i18n.t('feedback.repository.attribute.algorithm-encryption')}: - Hash Algorithm + {i18n.t('feedback.repository.attribute.algorithm-hash')}: - Splitter Algorithm + {i18n.t('feedback.repository.attribute.algorithm-splitter')}: +
- Repository Format + {i18n.t('feedback.repository.attribute.repository-format')}: - Error Correction Overhead - 0 ? this.state.status.eccOverheadPercent + "%" : "Disabled"} /> + {i18n.t('feedback.repository.attribute.repository-eco')}: + 0 ? this.state.status.eccOverheadPercent + "%" : i18n.t('feedback.repository.eco-disabled')} /> - Error Correction Algorithm + {i18n.t('feedback.repository.attribute.algorithm-eco')}: - Internal Compression - + {i18n.t('feedback.repository.attribute.internal-compression')}: + } +
- Connected as: + {i18n.t('feedback.repository.attribute.connected-as')}: -   +
- + -   +
@@ -238,7 +242,6 @@ export class Repository extends Component { ; } - return ; } } diff --git a/src/pages/SnapshotCreate.jsx b/src/pages/SnapshotCreate.jsx index 0bc663a6..966490d8 100644 --- a/src/pages/SnapshotCreate.jsx +++ b/src/pages/SnapshotCreate.jsx @@ -9,6 +9,7 @@ import { PolicyEditor } from '../components/policy-editor/PolicyEditor'; import { SnapshotEstimation } from '../components/SnapshotEstimation'; import { RequiredDirectory } from '../forms/RequiredDirectory'; import { CLIEquivalent, errorAlert, GoBackButton, redirect } from '../utils/uiutil'; +import i18n from '../utils/i18n' export class SnapshotCreate extends Component { constructor() { @@ -117,7 +118,7 @@ export class SnapshotCreate extends Component { e.preventDefault(); if (!this.state.resolvedSource.path) { - alert('Must specify directory to snapshot.'); + alert(i18n.t('feedback.snapshot.create.must-specify-path')); return } @@ -152,27 +153,27 @@ export class SnapshotCreate extends Component {
-

New Snapshot

+

{i18n.t('feedback.snapshot.create.snapshot-new')}


- {RequiredDirectory(this, null, "path", { autoFocus: true, placeholder: "enter path to snapshot" })} + {RequiredDirectory(this, null, "path", { autoFocus: true, placeholder: i18n.t('feedback.snapshot.create.enter-path-to-snapshot-hint')})} + onClick={this.estimate}>{i18n.t('event.snapshot.estimate')} + onClick={this.snapshotNow}>{i18n.t('event.snapshot.snapshot-now')} {this.state.estimateTaskID && this.state.estimateTaskVisible && diff --git a/src/pages/SnapshotDirectory.jsx b/src/pages/SnapshotDirectory.jsx index bbadb8d6..2a6e4244 100644 --- a/src/pages/SnapshotDirectory.jsx +++ b/src/pages/SnapshotDirectory.jsx @@ -10,6 +10,7 @@ import { DirectoryItems } from "../components/DirectoryItems"; import { CLIEquivalent } from '../utils/uiutil'; import { DirectoryBreadcrumbs } from "../components/DirectoryBreadcrumbs"; import { UIPreferencesContext } from '../contexts/UIPreferencesContext'; +import i18n from '../utils/i18n'; export class SnapshotDirectory extends Component { constructor() { @@ -69,7 +70,7 @@ export class SnapshotDirectory extends Component { } mount() { - axios.post('/api/v1/mounts', { "root": this.state.oid} ).then(result => { + axios.post('/api/v1/mounts', { "root": this.state.oid }).then(result => { this.setState({ mountInfo: result.data, }); @@ -91,7 +92,7 @@ export class SnapshotDirectory extends Component { browseMounted() { if (!window.kopiaUI) { - alert('Directory browsing is not supported in a web browser. Use Kopia UI.'); + alert(i18n.t('feedback.snapshot.directory.browsing-not-supported')); return; } @@ -110,6 +111,10 @@ export class SnapshotDirectory extends Component { document.execCommand("copy"); } + navigateTo(path) { + this.props.history.push(path); + } + render() { let { items, isLoading, error } = this.state; if (error) { @@ -124,27 +129,22 @@ export class SnapshotDirectory extends Component { {this.state.mountInfo.path ? <> - + {window.kopiaUI && <> - + } : <> - + } -   - -   + - You can mount/restore all the files & directories that you see below or restore files individually. - - -   + {i18n.t('feedback.snapshot.directory.restore-all-files-help')} +
diff --git a/src/pages/SnapshotHistory.jsx b/src/pages/SnapshotHistory.jsx index cf6324f4..ccd6b789 100644 --- a/src/pages/SnapshotHistory.jsx +++ b/src/pages/SnapshotHistory.jsx @@ -14,6 +14,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import Modal from 'react-bootstrap/Modal'; import { faFileAlt } from '@fortawesome/free-regular-svg-icons'; import { UIPreferencesContext } from '../contexts/UIPreferencesContext'; +import i18n from '../utils/i18n' function pillVariant(tag) { if (tag.startsWith("latest-")) { @@ -249,7 +250,7 @@ export class SnapshotHistory extends Component { originalSnapshotDescription: x.description, }) }} - title={x.description + " - Click to update snapshot description."} + title={i18n.t('event.snapshot.history.update-snapshot-description', {description: x.description})} className={x.description ? "snapshot-description-set" : "snapshot-description"}>; } @@ -260,10 +261,10 @@ export class SnapshotHistory extends Component { this.setState({ editPinFor: [x.id], originalPinName: "", - newPinName: "do-not-delete", + newPinName: i18n.t('feedback.pin.do-not-delete'), }); } - } title="Add a pin to protect snapshot from deletion">; + } title={i18n.t('feedback.pin.add-pin-to-protect')}>; } editPin(snap, pin) { @@ -331,13 +332,13 @@ export class SnapshotHistory extends Component { const columns = [{ id: 'selected', - Header: 'Selected', + Header: i18n.t('feedback.snapshot.header.selected'), width: 20, align: "center", Cell: x =>
this.toggleSelected(x.row.original)} />
, }, { id: 'startTime', - Header: 'Start time', + Header: i18n.t('feedback.snapshot.header.start-time'), width: 200, accessor: x => { let timestamp = rfc3339TimestampForDisplay(x.startTime); @@ -345,38 +346,38 @@ export class SnapshotHistory extends Component { }, }, { id: 'description', - Header: '', + Header: i18n.t('feedback.snapshot.description'), width: 20, Cell: x => this.descriptionFor(x.row.original), }, { id: 'rootID', - Header: 'Root', + Header: i18n.t('feedback.snapshot.header.root'), width: "", accessor: x => x.rootID, Cell: x => <>{x.cell.value} {x.row.original.description &&
{x.row.original.description}
}, }, { - Header: 'Retention', + Header: i18n.t('feedback.snapshot.header.retention'), accessor: 'retention', width: "", Cell: x => {x.cell.value.map(l => {l}{' '})} {x.row.original.pins.map(l => - this.editPin(x.row.original, l)}> {l}{' '} + this.editPin(x.row.original, l)}>{l}{' '} )} {this.newPinFor(x.row.original)} }, { - Header: 'Size', + Header: i18n.t('feedback.snapshot.header.snapshot-size'), accessor: 'summary.size', width: 100, Cell: x => sizeWithFailures(x.cell.value, x.row.original.summary, bytesStringBase2), }, { - Header: 'Files', + Header: i18n.t('feedback.snapshot.header.files'), accessor: 'summary.files', width: 100, }, { - Header: 'Dirs', + Header: i18n.t('feedback.snapshot.header.directories'), accessor: 'summary.dirs', width: 100, }] @@ -387,30 +388,30 @@ export class SnapshotHistory extends Component { -   + {' '} {snapshots.length > 0 && (selectedElements.length < snapshots.length ? - : - )} -   - {selectedElements.length > 0 && <>  - + : + )} + {' '} + {selectedElements.length > 0 && <>{' '} + } - {snapshots.length === 0 && <>  - + {snapshots.length === 0 && <>{' '} + }
- Displaying {snapshots.length !== unfilteredCount ? snapshots.length + ' out of ' + unfilteredCount : snapshots.length} snapshots of {this.state.userName}@{this.state.host}:{this.state.path} + {i18n.t('feedback.snapshot.history.snapshot-displaying')} {snapshots.length !== unfilteredCount ? snapshots.length + ' out of ' + unfilteredCount : snapshots.length} snapshots of{' '}{this.state.userName}@{this.state.host}:{this.state.path}
@@ -421,7 +422,7 @@ export class SnapshotHistory extends Component { @@ -437,17 +438,15 @@ export class SnapshotHistory extends Component { - Confirm Delete + {i18n.t('common.action.confirm-delete')} <> - {selectedElements.length > 1 ? -

Do you want to delete the selected {selectedElements.length} snapshots?

: -

Do you want to delete the selected snapshot?

} +

{i18n.t('event.snapshot.delete-selected',{count: selectedElements.length})}

{selectedElements.length === snapshots.length && this.setState({ alsoDeleteSource: !this.state.alsoDeleteSource })} @@ -457,19 +456,19 @@ export class SnapshotHistory extends Component {
- - + +
- Snapshot Description + {i18n.t('feedback.snapshot.description.snapshot-description')} - Enter new description + {i18n.t('event.snapshot.description.enter-new-description')} {this.state.savingSnapshot && } - - {this.state.originalSnapshotDescription && } - + + {this.state.originalSnapshotDescription && } + - Pin Snapshot + {i18n.t('event.pin.pin-snapshot')} - Name of the pin + {i18n.t('feedback.pin.name-of-the-pin')} {this.state.savingSnapshot && } - - {this.state.originalPinName && } - + + {this.state.originalPinName && } + ; diff --git a/src/pages/SnapshotRestore.jsx b/src/pages/SnapshotRestore.jsx index 1041fea0..fa8fa578 100644 --- a/src/pages/SnapshotRestore.jsx +++ b/src/pages/SnapshotRestore.jsx @@ -10,6 +10,7 @@ import { RequiredBoolean } from '../forms/RequiredBoolean'; import { RequiredField } from '../forms/RequiredField'; import { RequiredNumberField } from '../forms/RequiredNumberField'; import { errorAlert, GoBackButton } from '../utils/uiutil'; +import i18n from '../utils/i18n' export class SnapshotRestore extends Component { constructor(props) { @@ -91,70 +92,71 @@ export class SnapshotRestore extends Component { if (this.state.restoreTask) { return

- Go To Restore Task. + {i18n.t('event.snapshot.restore.go-to-restore-task')}.

; } return
-  Restore -
+ {' '}{i18n.t('feedback.snapshot.restore.snapshot-restore')} +
- {RequiredField(this, "Destination", "destination", { - autoFocus: true, - placeholder: "enter destination path", - }, - "You can also restore to a .zip or .tar file by providing the appropriate extension.")} + {RequiredField(this, i18n.t('feedback.snapshot.restore.destination'), "destination", + { + autoFocus: true, + placeholder: i18n.t('feedback.snapshot.restore.destination-hint'), + }, i18n.t('feedback.snapshot.restore.destination-help'))} +
- {RequiredBoolean(this, "Skip previously restored files and symlinks", "incremental")} + {RequiredBoolean(this, i18n.t('feedback.snapshot.restore.skip-previously-restored-files'), "incremental")} - {RequiredBoolean(this, "Continue on Errors", "continueOnErrors", "When a restore error occurs, attempt to continue instead of failing fast.")} + {RequiredBoolean(this, i18n.t('feedback.snapshot.restore.continue-on-errors'), "continueOnErrors", i18n.t('feedback.snapshot.restore.continue-on-errors-help'))} - {RequiredBoolean(this, "Restore File Ownership", "restoreOwnership")} + {RequiredBoolean(this, i18n.t('feedback.snapshot.restore.restore-file-ownership'), "restoreOwnership")} - {RequiredBoolean(this, "Restore File Permissions", "restorePermissions")} + {RequiredBoolean(this, i18n.t('feedback.snapshot.restore.restore-file-permissions'), "restorePermissions")} - {RequiredBoolean(this, "Restore File Modification Time", "restoreModTimes")} + {RequiredBoolean(this, i18n.t('feedback.snapshot.restore.restore-file-modification-time'), "restoreModTimes")} - {RequiredBoolean(this, "Overwrite Files", "overwriteFiles")} + {RequiredBoolean(this, i18n.t('feedback.snapshot.restore.overwrite-files'), "overwriteFiles")} - {RequiredBoolean(this, "Overwrite Directories", "overwriteDirectories")} + {RequiredBoolean(this, i18n.t('feedback.snapshot.restore.overwrite-directory'), "overwriteDirectories")} - {RequiredBoolean(this, "Overwrite Symbolic Links", "overwriteSymlinks")} + {RequiredBoolean(this, i18n.t('feedback.snapshot.restore.overwrite-symbolic-links'), "overwriteSymlinks")} - {RequiredBoolean(this, "Write files atomically", "writeFilesAtomically")} + {RequiredBoolean(this, i18n.t('feedback.snapshot.restore.write-files-atomically'), "writeFilesAtomically")} - {RequiredBoolean(this, "Write Sparse Files", "writeSparseFiles")} + {RequiredBoolean(this, i18n.t('feedback.snapshot.restore.write-sparse-files'), "writeSparseFiles")} -
+
- {RequiredNumberField(this, "Shallow Restore At Depth", "restoreDirEntryAtDepth")} - {RequiredNumberField(this, "Minimal File Size For Shallow Restore", "minSizeForPlaceholder")} + {RequiredNumberField(this, i18n.t('feedback.snapshot.restore.shallow-restore-at-depth'), "restoreDirEntryAtDepth")} + {RequiredNumberField(this, i18n.t('feedback.snapshot.restore.minimal-file-size-for-shallow-restore'), "minSizeForPlaceholder")} -
+
- {RequiredBoolean(this, "Disable ZIP compression", "uncompressedZip", "Do not compress when restoring to a ZIP file (faster).")} + {RequiredBoolean(this, i18n.t('feedback.snapshot.restore.disable-zip-compression'), "uncompressedZip", i18n.t('feedback.snapshot.restore.disable-zip-compression-help'))} -
+
- +
diff --git a/src/pages/Snapshots.jsx b/src/pages/Snapshots.jsx index ffabeaab..0b2861cf 100644 --- a/src/pages/Snapshots.jsx +++ b/src/pages/Snapshots.jsx @@ -14,6 +14,7 @@ import { handleChange } from '../forms'; import KopiaTable from '../utils/KopiaTable'; import { CLIEquivalent, compare, errorAlert, ownerName, policyEditorURL, redirect, sizeDisplayName, sizeWithFailures, sourceQueryStringParams } from '../utils/uiutil'; import { UIPreferencesContext } from '../contexts/UIPreferencesContext'; +import i18n from '../utils/i18n'; const localSnapshots = "Local Snapshots" const allSnapshots = "All Snapshots" @@ -111,10 +112,10 @@ export class Snapshots extends Component { switch (x.cell.value) { case "IDLE": case "PAUSED": - return x.cell.column.Header = "Actions" + return x.cell.column.Header = i18n.t('feedback.snapshot.header.actions'); case "PENDING": case "UPLOADING": - return x.cell.column.Header = "Status" + return x.cell.column.Header = i18n.t('feedback.snapshot.header.status'); default: return x.cell.column.Header = "" } @@ -131,17 +132,17 @@ export class Snapshots extends Component { case "IDLE": case "PAUSED": return <> - + ; case "PENDING": return <> - -  Pending + + {' '}{i18n.t('feedback.snapshot.status.status-pending')} ; case "UPLOADING": @@ -152,13 +153,10 @@ export class Snapshots extends Component { title = " hashed " + u.hashedFiles + " files (" + sizeDisplayName(u.hashedBytes, bytesStringBase2) + ")\n" + " cached " + u.cachedFiles + " files (" + sizeDisplayName(u.cachedBytes, bytesStringBase2) + ")\n" + " dir " + u.directory; - const totalBytes = u.hashedBytes + u.cachedBytes; - totals = sizeDisplayName(totalBytes, bytesStringBase2); if (u.estimatedBytes) { totals += "/" + sizeDisplayName(u.estimatedBytes, bytesStringBase2); - const percent = Math.round(totalBytes * 1000.0 / u.estimatedBytes) / 10.0; if (percent <= 100) { totals += " " + percent + "%"; @@ -169,7 +167,7 @@ export class Snapshots extends Component { return <>  {totals}   - {x.row.original.currentTask && Details} + {x.row.original.currentTask && {i18n.t('feedback.snapshot.header.details')}} ; default: @@ -198,7 +196,6 @@ export class Snapshots extends Component { if (x.row.original.status === "PAUSED") { return "paused"; } - return ""; } @@ -209,11 +206,16 @@ export class Snapshots extends Component { return

{moment(x.cell.value).fromNow()} {moment(x.cell.value).isBefore(moment()) && <>   - overdue + {i18n.t('feedback.snapshot.status.status-overdue')} }

; } + navigateTo(path) { + this.props.history.push(path); + } + + render() { let { sources, isLoading, error } = this.state; const { bytesStringBase2 } = this.context @@ -221,7 +223,9 @@ export class Snapshots extends Component { return

{error.message}

; } if (isLoading) { - return ; + return (
+ +
); } let uniqueOwners = sources.reduce((a, d) => { const owner = ownerName(d.source); @@ -248,26 +252,25 @@ export class Snapshots extends Component { const columns = [{ id: 'path', - Header: 'Path', + Header: i18n.t('feedback.snapshot.header.snapshot-path'), accessor: x => x.source, sortType: (a, b) => { const v = compare(a.original.source.path, b.original.source.path); if (v !== 0) { return v; } - return compare(ownerName(a.original.source), ownerName(b.original.source)); }, width: "", Cell: x => {x.cell.value.path}, }, { id: 'owner', - Header: 'Owner', + Header: i18n.t('feedback.snapshot.header.snapshot-owner'), accessor: x => x.source.userName + '@' + x.source.host, width: 250, }, { id: 'lastSnapshotSize', - Header: 'Size', + Header: i18n.t('feedback.snapshot.header.snapshot-size'), width: 120, accessor: x => x.lastSnapshot ? x.lastSnapshot.stats.totalSize : 0, Cell: x => sizeWithFailures( @@ -275,13 +278,13 @@ export class Snapshots extends Component { x.row.original.lastSnapshot && x.row.original.lastSnapshot.rootEntry ? x.row.original.lastSnapshot.rootEntry.summ : null, bytesStringBase2), }, { id: 'lastSnapshotTime', - Header: 'Last Snapshot', + Header: i18n.t('feedback.snapshot.header.last-snapshot'), width: 160, accessor: x => x.lastSnapshot ? x.lastSnapshot.startTime : null, Cell: x => x.cell.value ?

{moment(x.cell.value).fromNow()}

: '', }, { id: 'nextSnapshotTime', - Header: 'Next Snapshot', + Header: i18n.t('feedback.snapshot.header.next-snapshot'), width: 160, accessor: x => x.nextSnapshotTime, Cell: x => this.nextSnapshotTimeCell(x, this), @@ -299,7 +302,7 @@ export class Snapshots extends Component { {this.state.multiUser && <> -  {this.state.selectedOwner} + {' '}{this.state.selectedOwner} @@ -311,12 +314,12 @@ export class Snapshots extends Component { } - + - diff --git a/src/pages/Task.jsx b/src/pages/Task.jsx index df4bbf90..605843cb 100644 --- a/src/pages/Task.jsx +++ b/src/pages/Task.jsx @@ -13,10 +13,11 @@ import Spinner from 'react-bootstrap/Spinner'; import { Logs } from '../components/Logs'; import { cancelTask, formatDuration, GoBackButton, redirect, sizeDisplayName } from '../utils/uiutil'; import { UIPreferencesContext } from '../contexts/UIPreferencesContext'; +import i18n from '../utils/i18n' export class Task extends Component { - constructor() { - super(); + constructor(props) { + super(props); this.state = { items: [], isLoading: true, @@ -26,9 +27,6 @@ export class Task extends Component { this.taskID = this.taskID.bind(this); this.fetchTask = this.fetchTask.bind(this); - - // poll frequently, we will stop as soon as the task ends. - this.interval = window.setInterval(() => this.fetchTask(), 500); } componentDidMount() { @@ -36,6 +34,8 @@ export class Task extends Component { isLoading: true, }); + // poll frequently, we will stop as soon as the task ends. + this.interval = window.setInterval(() => this.fetchTask(), 500); this.fetchTask(); } @@ -81,21 +81,21 @@ export class Task extends Component { switch (task.status) { case "SUCCESS": - return Task succeeded after {dur}.; + return {i18n.t('feedback.task.status.task-succeeded-after')} {dur}.; case "FAILED": - return Error: {task.errorMessage}.; + return {i18n.t('feedback.task.status.task-error')}: {task.errorMessage}.; case "CANCELED": - return Task canceled.; + return {i18n.t('feedback.task.status.task-canceled')}.; case "CANCELING": return - Canceling {dur}: {task.progressInfo}.; + {i18n.t('feedback.task.status.task-canceling')} {dur}: {task.progressInfo}.; default: return - Running for {dur}: {task.progressInfo}.; + {i18n.t('feedback.task.status.task-running-for')} {dur}: {task.progressInfo}.; } } @@ -164,7 +164,7 @@ export class Task extends Component { } if (isLoading) { - return

Loading ...

; + return

{i18n.t('common.label.loading')}

; } return
@@ -174,7 +174,7 @@ export class Task extends Component {

{task.status === "RUNNING" && <> -   +   }  {task.kind}: {task.description}

@@ -189,8 +189,8 @@ export class Task extends Component { - - + + @@ -202,25 +202,25 @@ export class Task extends Component { - Started + {i18n.t('feedback.task.status.task-started')} - Finished + {i18n.t('feedback.task.status.task-finished')} +
- Logs + {i18n.t('feedback.task.logs')} - ; } } Task.contextType = UIPreferencesContext \ No newline at end of file diff --git a/src/pages/Tasks.jsx b/src/pages/Tasks.jsx index 427df65a..3cac691e 100644 --- a/src/pages/Tasks.jsx +++ b/src/pages/Tasks.jsx @@ -3,47 +3,48 @@ import { faInfoCircle } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import axios from 'axios'; import moment from 'moment'; -import React, { Component } from 'react'; +import React from 'react'; import Alert from 'react-bootstrap/Alert'; import Col from 'react-bootstrap/Col'; import Dropdown from 'react-bootstrap/Dropdown'; import Form from 'react-bootstrap/Form'; import Row from 'react-bootstrap/Row'; -import { Link } from 'react-router-dom'; -import { handleChange } from '../forms'; import KopiaTable from '../utils/KopiaTable'; +import { Link } from 'react-router-dom'; import { redirect, taskStatusSymbol } from '../utils/uiutil'; - -export class Tasks extends Component { - constructor() { - super(); - this.state = { - items: [], - isLoading: false, - error: null, - showKind: "All", - showStatus: "All", - uniqueKinds: [], - }; - - this.handleChange = handleChange.bind(this); - this.fetchTasks = this.fetchTasks.bind(this); - this.interval = window.setInterval(this.fetchTasks, 3000); - } - - componentDidMount() { - this.setState({ - isLoading: true, +import { useTranslation } from "react-i18next"; +import { useState, useLayoutEffect, useCallback } from 'react'; + +export function Tasks() { + const [isLoading, setIsLoading] = useState(false); + const [searchDescription, setDescription] = useState("") + const [response, setResponse] = useState({ items: [], kinds: [] }); + const [kind, setKind] = useState("All"); + const [status, setStatus] = useState("All"); + const [error, setError] = useState(); + const { t } = useTranslation(); + + const fetchTasks = useCallback(() => { + axios.get('/api/v1/tasks').then(result => { + setIsLoading(false); + setResponse({ items: result.data.tasks, kinds: getUniqueKinds(result.data.tasks) }); + }).catch(error => { + redirect(error); + setError(error); + setIsLoading(false); }); + }, []) + + useLayoutEffect(() => { + setIsLoading(true) + fetchTasks() + let interval = setInterval(fetchTasks, 5000) + return () => { + window.clearInterval(interval); + }; + }, [fetchTasks]); - this.fetchTasks(); - } - - componentWillUnmount() { - window.clearInterval(this.interval); - } - - getUniqueKinds(tasks) { + function getUniqueKinds(tasks) { let o = {}; for (const tsk of tasks) { @@ -58,112 +59,97 @@ export class Tasks extends Component { return result; } - fetchTasks() { - axios.get('/api/v1/tasks').then(result => { - this.setState({ - items: result.data.tasks, - uniqueKinds: this.getUniqueKinds(result.data.tasks), - isLoading: false, - }); - }).catch(error => { - redirect(error); - this.setState({ - error, - isLoading: false - }); - }); + function handleDescription(desc) { + setDescription(desc.target.value) } - taskMatches(t) { - if (this.state.showKind !== "All" && t.kind !== this.state.showKind) { + function taskMatches(t) { + if (kind !== "All" && t.kind !== kind) { return false; } - if (this.state.showStatus !== "All" && t.status.toLowerCase() !== this.state.showStatus.toLowerCase()) { + if (status !== "All" && t.status.toLowerCase() !== status.toLowerCase()) { return false; } - if (this.state.searchDescription && t.description.indexOf(this.state.searchDescription) < 0) { + if (searchDescription && t.description.indexOf(searchDescription) < 0) { return false; } return true } - filterItems(items) { - return items.filter(c => this.taskMatches(c)) + function filterItems(items) { + return items.filter(c => taskMatches(c)) } - render() { - const { items, isLoading, error } = this.state; - if (error) { - return

{error.message}

; - } - if (isLoading) { - return

Loading ...

; - } + if (error) { + return

{error.message}

; + } + if (isLoading) { + return

{t('common.label.loading')}

; + } - const columns = [{ - Header: 'Start Time', - width: 160, - accessor: x => - {moment(x.startTime).fromNow()} - - }, { - Header: 'Status', - width: 240, - accessor: x => taskStatusSymbol(x), - }, { - Header: 'Kind', - width: "", - accessor: x =>

{x.kind}

, - }, { - Header: 'Description', - width: "", - accessor: x =>

{x.description}

, - }] - - const filteredItems = this.filterItems(items) - - return <> + const columns = [{ + Header: t('feedback.task.table.header-start-time'), + width: 160, + accessor: x => + {moment(x.startTime).fromNow()} + + }, { + Header: t('feedback.task.table.header-status'), + width: 240, + accessor: x => taskStatusSymbol(x), + }, { + Header: t('feedback.task.table.header-kind'), + width: "", + accessor: x =>

{x.kind}

, + }, { + Header: t('feedback.task.table.header-description'), + width: "", + accessor: x =>

{x.description}

, + }] + + const filteredItems = filterItems(response.items) + return ( + <>
- Status: {this.state.showStatus} + {t('feedback.task.table.header-status')}: {status} - this.setState({ showStatus: "All" })}>All + setStatus("All")}>{t('event.task.select.task-all')} - this.setState({ showStatus: "Running" })}>Running - this.setState({ showStatus: "Failed" })}>Failed + setStatus("Running")}>{t('event.task.select.task-running')} + setStatus("Failed")}>{t('event.task.select.task-failed')} - Kind: {this.state.showKind} + {t('feedback.task.table.header-kind')}: {kind} - this.setState({ showKind: "All" })}>All + setKind("All")}>{t('event.task.select.task-all')} - {this.state.uniqueKinds.map(k => this.setState({ showKind: k })}>{k})} + {response.kinds.map(kind => setKind(kind)}>{kind})} - + - {!items.length ? + {!response.items.length ? - A list of tasks will appear here when you create snapshots, restore, run maintenance, etc. + {t('feedback.task.no-tasks-help')} : } - ; - } + ); } diff --git a/src/tests/Language.test.jsx b/src/tests/Language.test.jsx new file mode 100644 index 00000000..e9fa0cce --- /dev/null +++ b/src/tests/Language.test.jsx @@ -0,0 +1,68 @@ +import { expect, test } from '@jest/globals'; +const { sync: globSync } = require('glob'); + +const localesPaths = globSync('./public/locales/*/*.json', { realpath: true }); +const srcPaths = globSync('./src/**/*.+(tsx|ts|jsx)', { realpath: true }); + +function computeIntersection(dataA, dataB) { + return dataA.filter(element => dataB.includes(element)); +} + +/** + * + */ +describe('Check for unused translations', () => { + test('Translations should be declared and used', () => { + }) +}) + +/** + * This test checks for empty strings within each translation file. + * If an empty string exists, the test will fail. + */ +describe('Check for empty translations', () => { + test('Translations should not be emtpy. Check translations files for empty values!', async () => { + for (const localeFile in localesPaths) { + let locale = localesPaths[localeFile] + let data = require(locale); + expect(data).not.toBeNull() + + for (const key in data) { + expect(data[key]).toBeTruthy(); + } + } + }) +}) + +/** + * The test checks whether the intersection of two json sets is equal + * to the length of the primary json key set. + * + * Each file is checked against the others. + */ +describe('Check that translations are in sync', () => { + test.each(localesPaths)('All translations should be in sync with each other', l1 => { + for (const localeF2 in localesPaths) { + let l2 = localesPaths[localeF2] + // We do not have to check the file with itself + if (l1 == l2) { + break; + } + + let msg = `${l1} should be in sync with ${l2}` + let dataA = require(l1) + let dataB = require(l2) + expect(dataA).not.toBeNull() + expect(dataB).not.toBeNull() + + let keysA = Object.keys(dataA) + let keysB = Object.keys(dataB) + expect(keysA.length).toBeGreaterThan(0) + expect(keysB.length).toBeGreaterThan(0) + + let intersection = computeIntersection(keysA, keysB) + expect({ msg, result: intersection.length }).toEqual({ msg, result: keysA.length }) + } + }) +}) + diff --git a/src/tests/PolicyEditor.test.jsx b/src/tests/PolicyEditor.test.jsx index c27e4614..9ceedb27 100644 --- a/src/tests/PolicyEditor.test.jsx +++ b/src/tests/PolicyEditor.test.jsx @@ -5,6 +5,7 @@ import { MemoryRouter } from 'react-router-dom'; import { setupAPIMock } from '../tests/api_mocks'; import moment from 'moment'; import { changeControlValue, simulateClick } from '../tests/testutils'; +import i18n from '../utils/i18n'; // Mockup for the server let serverMock; @@ -144,7 +145,7 @@ it('e2e', async () => { // this will trigger resolve and will update effective field: "(Defined by this policy)" await waitFor(() => expect(getByTestId("effective-retention.keepLatest").value).toBe("44")); - await waitFor(() => expect(getByTestId("definition-retention.keepLatest").innerHTML).toEqual("(Defined by this policy)")); + await waitFor(() => expect(getByTestId("definition-retention.keepLatest").innerHTML).toEqual(i18n.t('feedback.policy.defined-by-this-policy'))); simulateClick(getByTestId('button-save')); await waitFor(() => expect(serverMock.history.put.length).toEqual(1)); diff --git a/src/tests/Preferences.test.js b/src/tests/Preferences.test.jsx similarity index 65% rename from src/tests/Preferences.test.js rename to src/tests/Preferences.test.jsx index 2660571d..09ea26d4 100644 --- a/src/tests/Preferences.test.js +++ b/src/tests/Preferences.test.jsx @@ -2,7 +2,10 @@ import { render, screen } from '@testing-library/react' import { expect, test } from '@jest/globals'; import userEvent from "@testing-library/user-event"; import { Preferences } from '../pages/Preferences'; -const { setTheme } = jest.requireActual('../pages/Preferences'); + +import { configure } from '@testing-library/dom' +configure({ testIdAttribute: 'id' }) + // Wrapper let wrapper; @@ -28,11 +31,10 @@ describe('Calling the preference page', () => { describe('Select the light theme', () => { test('Should select light theme', () => { userEvent.selectOptions( - screen.getByRole('combobox', { name: "Theme" }), - screen.getByRole('option', { name: 'light' })); - - expect(screen.getByRole('option', { name: 'light' }).selected).toBe(true) + screen.getByTestId('themeSelector'), + screen.getByRole('option', { name: "value.ui.theme-light" })); + expect(screen.getByRole('option', { name: "value.ui.theme-light" }).selected).toBe(true) expect(wrapper).toMatchSnapshot(); }) }) @@ -42,8 +44,8 @@ describe('Select the light theme', () => { */ describe('Test number of themes', () => { test('Should have four themes', () => { - let theme = screen.getByRole('combobox', { name: "Theme" }); - expect(theme).toHaveLength(4); + let selector = screen.getByTestId('themeSelector'); + expect(selector).toHaveLength(4); expect(wrapper).toMatchSnapshot(); }) }) @@ -53,8 +55,8 @@ describe('Test number of themes', () => { */ describe('Test byte representation', () => { test('Should have two options', () => { - let theme = screen.getByRole('combobox', { name: "Byte representation" }); - expect(theme).toHaveLength(2); + let selector = screen.getByTestId('bytesBaseInput'); + expect(selector).toHaveLength(2); expect(wrapper).toMatchSnapshot(); }) }) \ No newline at end of file diff --git a/src/tests/__snapshots__/Preferences.test.js.snap b/src/tests/__snapshots__/Preferences.test.jsx.snap similarity index 77% rename from src/tests/__snapshots__/Preferences.test.js.snap rename to src/tests/__snapshots__/Preferences.test.jsx.snap index 09741206..d3b4ef38 100644 --- a/src/tests/__snapshots__/Preferences.test.js.snap +++ b/src/tests/__snapshots__/Preferences.test.jsx.snap @@ -14,32 +14,32 @@ Object { for="themeSelector" id="themeLabel" > - Theme + feedback.ui.theme-description - The current active theme + feedback.ui.theme-help
@@ -58,22 +58,22 @@ Object { class="label-description" for="bytesBaseInput" > - Byte representation + feedback.ui.byte-representation-description - Specifies the representation of bytes + feedback.ui.byte-representation-help
@@ -91,35 +91,35 @@ Object { - Specifies the appearance of the user interface + feedback.ui.appearance-help
@@ -129,13 +129,13 @@ Object { @@ -144,7 +144,7 @@ Object { hmtlfor="pageSizeInput" id="pageSizeHelp" > - Specifies the pagination size in tables + feedback.ui.pagesize-help @@ -160,32 +160,32 @@ Object { for="themeSelector" id="themeLabel" > - Theme + feedback.ui.theme-description - The current active theme + feedback.ui.theme-help
@@ -204,22 +204,22 @@ Object { class="label-description" for="bytesBaseInput" > - Byte representation + feedback.ui.byte-representation-description - Specifies the representation of bytes + feedback.ui.byte-representation-help
@@ -237,35 +237,35 @@ Object { - Specifies the appearance of the user interface + feedback.ui.appearance-help
@@ -275,13 +275,13 @@ Object { @@ -290,7 +290,7 @@ Object { hmtlfor="pageSizeInput" id="pageSizeHelp" > - Specifies the pagination size in tables + feedback.ui.pagesize-help @@ -363,32 +363,32 @@ Object { for="themeSelector" id="themeLabel" > - Theme + feedback.ui.theme-description - The current active theme + feedback.ui.theme-help
@@ -407,22 +407,22 @@ Object { class="label-description" for="bytesBaseInput" > - Byte representation + feedback.ui.byte-representation-description - Specifies the representation of bytes + feedback.ui.byte-representation-help
@@ -440,35 +440,35 @@ Object { - Specifies the appearance of the user interface + feedback.ui.appearance-help
@@ -478,13 +478,13 @@ Object { @@ -493,7 +493,7 @@ Object { hmtlfor="pageSizeInput" id="pageSizeHelp" > - Specifies the pagination size in tables + feedback.ui.pagesize-help @@ -509,32 +509,32 @@ Object { for="themeSelector" id="themeLabel" > - Theme + feedback.ui.theme-description - The current active theme + feedback.ui.theme-help
@@ -553,22 +553,22 @@ Object { class="label-description" for="bytesBaseInput" > - Byte representation + feedback.ui.byte-representation-description - Specifies the representation of bytes + feedback.ui.byte-representation-help
@@ -586,35 +586,35 @@ Object { - Specifies the appearance of the user interface + feedback.ui.appearance-help
@@ -624,13 +624,13 @@ Object { @@ -639,7 +639,7 @@ Object { hmtlfor="pageSizeInput" id="pageSizeHelp" > - Specifies the pagination size in tables + feedback.ui.pagesize-help @@ -712,32 +712,32 @@ Object { for="themeSelector" id="themeLabel" > - Theme + feedback.ui.theme-description - The current active theme + feedback.ui.theme-help
@@ -756,22 +756,22 @@ Object { class="label-description" for="bytesBaseInput" > - Byte representation + feedback.ui.byte-representation-description - Specifies the representation of bytes + feedback.ui.byte-representation-help
@@ -789,35 +789,35 @@ Object { - Specifies the appearance of the user interface + feedback.ui.appearance-help
@@ -827,13 +827,13 @@ Object { @@ -842,7 +842,7 @@ Object { hmtlfor="pageSizeInput" id="pageSizeHelp" > - Specifies the pagination size in tables + feedback.ui.pagesize-help @@ -858,32 +858,32 @@ Object { for="themeSelector" id="themeLabel" > - Theme + feedback.ui.theme-description - The current active theme + feedback.ui.theme-help
@@ -902,22 +902,22 @@ Object { class="label-description" for="bytesBaseInput" > - Byte representation + feedback.ui.byte-representation-description - Specifies the representation of bytes + feedback.ui.byte-representation-help
@@ -935,35 +935,35 @@ Object { - Specifies the appearance of the user interface + feedback.ui.appearance-help
@@ -973,13 +973,13 @@ Object { @@ -988,7 +988,7 @@ Object { hmtlfor="pageSizeInput" id="pageSizeHelp" > - Specifies the pagination size in tables + feedback.ui.pagesize-help @@ -1061,32 +1061,32 @@ Object { for="themeSelector" id="themeLabel" > - Theme + feedback.ui.theme-description - The current active theme + feedback.ui.theme-help
@@ -1105,22 +1105,22 @@ Object { class="label-description" for="bytesBaseInput" > - Byte representation + feedback.ui.byte-representation-description - Specifies the representation of bytes + feedback.ui.byte-representation-help
@@ -1138,35 +1138,35 @@ Object { - Specifies the appearance of the user interface + feedback.ui.appearance-help
@@ -1176,13 +1176,13 @@ Object { @@ -1191,7 +1191,7 @@ Object { hmtlfor="pageSizeInput" id="pageSizeHelp" > - Specifies the pagination size in tables + feedback.ui.pagesize-help @@ -1207,32 +1207,32 @@ Object { for="themeSelector" id="themeLabel" > - Theme + feedback.ui.theme-description - The current active theme + feedback.ui.theme-help
@@ -1251,22 +1251,22 @@ Object { class="label-description" for="bytesBaseInput" > - Byte representation + feedback.ui.byte-representation-description - Specifies the representation of bytes + feedback.ui.byte-representation-help
@@ -1284,35 +1284,35 @@ Object { - Specifies the appearance of the user interface + feedback.ui.appearance-help
@@ -1322,13 +1322,13 @@ Object { @@ -1337,7 +1337,7 @@ Object { hmtlfor="pageSizeInput" id="pageSizeHelp" > - Specifies the pagination size in tables + feedback.ui.pagesize-help diff --git a/src/utils/i18n.js b/src/utils/i18n.js new file mode 100644 index 00000000..a0002f04 --- /dev/null +++ b/src/utils/i18n.js @@ -0,0 +1,24 @@ +import i18n from "i18next"; +import { initReactI18next } from "react-i18next"; +import detector from 'i18next-browser-languagedetector'; +import backend from "i18next-http-backend" + +i18n + .use(backend) + .use(detector) + .use(initReactI18next) + .init({ + lng: "en", + fallbackLng: "en", + ns: ["translation"], + defaultNS: "translation", + interpolation: { + escapeValue: false, + }, + react: + { + useSuspense: true + }, + }); + +export default i18n; \ No newline at end of file diff --git a/src/utils/uiutil.jsx b/src/utils/uiutil.jsx index 0f230498..dd9bdd9e 100644 --- a/src/utils/uiutil.jsx +++ b/src/utils/uiutil.jsx @@ -7,6 +7,7 @@ import FormControl from 'react-bootstrap/FormControl'; import InputGroup from 'react-bootstrap/InputGroup'; import Spinner from 'react-bootstrap/Spinner'; import { Link } from 'react-router-dom'; +import i18n from './i18n' // locale to use for number formatting (undefined would use default locale, but we stick to EN for now) const locale = "en-US" @@ -272,19 +273,19 @@ export function taskStatusSymbol(task) { switch (st) { case "RUNNING": return <> - Running for {dur} + {i18n.t('feedback.task.status.task-running-for')} {dur} case "SUCCESS": - return

Finished in {dur}

; + return

{i18n.t('feedback.task.status.task-finished-in')} {dur}

; case "FAILED": - return

Failed after {dur}

; + return

{i18n.t('feedback.task.status.task-failed-after')} {dur}

; case "CANCELED": - return

Canceled after {dur}

; + return

{i18n.t('feedback.task.status.task-canceled-after')} {dur}

; default: return st; @@ -298,7 +299,7 @@ export function cancelTask(tid) { } export function GoBackButton(props) { - return ; + return ; } export function PolicyTypeName(s) { @@ -352,7 +353,7 @@ export function isAbsolutePath(p) { export function errorAlert(err, prefix) { if (!prefix) { - prefix = "Error" + prefix = i18n.t('feedback.error.common') } prefix += ": "; @@ -392,8 +393,8 @@ export function CLIEquivalent(props) { return <> - - {visible && } + + {visible && } {visible && } ; @@ -403,11 +404,11 @@ export function toAlgorithmOption(x, defaultID) { let text = x.id; if (x.id === defaultID) { - text = x.id + " (RECOMMENDED)"; + text = x.id + i18n.t('value.algorithm.suffix-recommended'); } if (x.deprecated) { - text = x.id + " (NOT RECOMMENDED)"; + text = x.id + i18n.t('value.algorithm.suffix-not-recommended'); } return ;
CounterValue{i18n.t('feedback.task.header.counter')}{i18n.t('feedback.task.header.value')}