diff --git a/.gitignore b/.gitignore index b622b5cb..3c4efe20 100644 --- a/.gitignore +++ b/.gitignore @@ -258,7 +258,4 @@ paket-files/ # Python Tools for Visual Studio (PTVS) __pycache__/ -*.pyc - -# Visual Studio Code config directory -.vscode/ \ No newline at end of file +*.pyc \ No newline at end of file diff --git a/.vscode/i18n-ally-custom-framework.yml b/.vscode/i18n-ally-custom-framework.yml new file mode 100644 index 00000000..2690f6a2 --- /dev/null +++ b/.vscode/i18n-ally-custom-framework.yml @@ -0,0 +1,8 @@ +languageIds: + - jade + - javascript + - vue + +usageMatchRegex: "\\$t\\(['\"`]({key})['\"`]" + +monoonly: true \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..17dee1bc --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "i18n-ally.localesPaths": ["html/src/localization/strings"], + "i18n-ally.keystyle": "nested", + "i18n-ally.sourceLanguage": "en" +} diff --git a/AppApi.cs b/AppApi.cs index 69f226a1..2036e111 100644 --- a/AppApi.cs +++ b/AppApi.cs @@ -5,26 +5,26 @@ // For a copy, see . using CefSharp; -using Microsoft.Win32; -using System; -using System.Diagnostics; -using System.Linq; -using System.Management; -using System.Text.RegularExpressions; -using System.Windows.Forms; -using System.IO; -using System.Security.Cryptography; -using System.Net; -using Windows.UI.Notifications; -using Windows.Data.Xml.Dom; using librsync.net; -using System.Net.Sockets; -using System.Text; -using System.Collections.Generic; -using System.Threading; -using System.IO.Pipes; +using Microsoft.Win32; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.IO.Pipes; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Windows.Forms; +using Windows.Data.Xml.Dom; +using Windows.UI.Notifications; namespace VRCX { @@ -410,7 +410,12 @@ namespace VRCX public string CurrentCulture() { - return System.Globalization.CultureInfo.CurrentCulture.ToString(); + return CultureInfo.CurrentCulture.ToString(); + } + + public string CurrentLanguage() + { + return CultureInfo.InstalledUICulture.Name; } public string GetVersion() diff --git a/html/.eslintrc.json b/html/.eslintrc.json index 1174f237..ff2151de 100644 --- a/html/.eslintrc.json +++ b/html/.eslintrc.json @@ -1,83 +1,91 @@ { - "root": true, - "extends": ["eslint:all", "prettier"], - "env": { - "browser": true, - "commonjs": true, - "es2021": true - }, - "parserOptions": { - "ecmaVersion": "latest", - "sourceType": "module", - "ecmaFeatures": { - "impliedStrict": true, - "jsx": true + "root": true, + "extends": ["eslint:all", "prettier"], + "env": { + "browser": true, + "commonjs": true, + "es2021": true + }, + "parser": "@babel/eslint-parser", + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module", + "ecmaFeatures": { + "impliedStrict": true, + "jsx": true + }, + "requireConfigFile": false, + "babelOptions": { + "presets": ["@babel/preset-env"], + "parserOpts": { + "plugins": ["importAssertions"] + } + } + }, + "globals": { + "CefSharp": "readonly", + "VRCX": "readonly", + "VRCXStorage": "readonly", + "SQLite": "readonly", + "LogWatcher": "readonly", + "Discord": "readonly", + "AppApi": "readonly", + "SharedVariable": "readonly", + "WebApi": "readonly", + "AssetBundleCacher": "readonly" + }, + "rules": { + "arrow-body-style": 0, + "block-scoped-var": 0, + "camelcase": 0, + "capitalized-comments": 0, + "class-methods-use-this": 0, + "complexity": 0, + "default-case": 0, + "func-names": 0, + "func-style": 0, + "guard-for-in": 0, + "id-length": 0, + "line-comment-position": 0, + "max-depth": 0, + "max-lines": 0, + "max-lines-per-function": 0, + "max-params": 0, + "max-statements": 0, + "multiline-comment-style": 0, + "new-cap": 0, + "no-await-in-loop": 0, + "no-console": 0, + "no-continue": 0, + "no-control-regex": 0, + "no-empty": [ + "error", + { + "allowEmptyCatch": true + } + ], + "no-inline-comments": 0, + "no-invalid-this": 0, + "no-magic-numbers": 0, + "no-negated-condition": 0, + "no-plusplus": 0, + "no-redeclare": 0, + "no-ternary": 0, + "no-throw-literal": 0, + "no-underscore-dangle": 0, + "no-var": 0, + "no-void": 0, + "no-warning-comments": 0, + "one-var": 0, + "prefer-arrow-callback": 0, + "prefer-const": 0, + "prefer-destructuring": 0, + "prefer-named-capture-group": 0, + "require-unicode-regexp": 0, + "sort-imports": 0, + "sort-keys": 0, + "sort-vars": 0, + "strict": 0, + "vars-on-top": 0 } - }, - "globals": { - "CefSharp": "readonly", - "VRCX": "readonly", - "VRCXStorage": "readonly", - "SQLite": "readonly", - "LogWatcher": "readonly", - "Discord": "readonly", - "AppApi": "readonly", - "SharedVariable": "readonly", - "WebApi": "readonly", - "AssetBundleCacher": "readonly" - }, - "rules": { - "arrow-body-style": 0, - "block-scoped-var": 0, - "camelcase": 0, - "capitalized-comments": 0, - "class-methods-use-this": 0, - "complexity": 0, - "default-case": 0, - "func-names": 0, - "func-style": 0, - "guard-for-in": 0, - "id-length": 0, - "line-comment-position": 0, - "max-depth": 0, - "max-lines": 0, - "max-lines-per-function": 0, - "max-params": 0, - "max-statements": 0, - "multiline-comment-style": 0, - "new-cap": 0, - "no-await-in-loop": 0, - "no-console": 0, - "no-continue": 0, - "no-control-regex": 0, - "no-empty": [ - "error", - { - "allowEmptyCatch": true - } - ], - "no-inline-comments": 0, - "no-invalid-this": 0, - "no-magic-numbers": 0, - "no-negated-condition": 0, - "no-plusplus": 0, - "no-redeclare": 0, - "no-ternary": 0, - "no-throw-literal": 0, - "no-underscore-dangle": 0, - "no-var": 0, - "no-void": 0, - "no-warning-comments": 0, - "one-var": 0, - "prefer-arrow-callback": 0, - "prefer-const": 0, - "prefer-destructuring": 0, - "prefer-named-capture-group": 0, - "require-unicode-regexp": 0, - "sort-imports": 0, - "sort-keys": 0, - "sort-vars": 0, - "strict": 0, - "vars-on-top": 0 - } } diff --git a/html/package-lock.json b/html/package-lock.json index 2af891f0..01255d61 100644 --- a/html/package-lock.json +++ b/html/package-lock.json @@ -6,6 +6,9 @@ "": { "license": "MIT", "devDependencies": { + "@babel/eslint-parser": "^7.19.1", + "@babel/plugin-syntax-import-assertions": "^7.20.0", + "@babel/preset-env": "^7.20.2", "@fontsource/noto-sans-jp": "^4.5.12", "@fontsource/noto-sans-kr": "^4.5.12", "animate.css": "^4.1.1", @@ -28,6 +31,7 @@ "uuid": "^9.0.0", "vue": "^2.6.14", "vue-data-tables": "^3.4.5", + "vue-i18n": "^8.28.2", "vue-lazyload": "^1.3.4", "vue-marquee-text-component": "^1.2.0", "webpack": "^5.75.0", @@ -35,6 +39,471 @@ "worker-timers": "^7.0.60" } }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@ampproject/remapping/node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.20.10", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.10.tgz", + "integrity": "sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.7.tgz", + "integrity": "sha512-t1ZjCluspe5DW24bn2Rr1CDb2v9rn/hROtg9a2tmd0+QYf4bsloYfLQzjG4qHPNMhWtKdGC33R5AxGR2Af2cBw==", + "dev": true, + "peer": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-module-transforms": "^7.20.7", + "@babel/helpers": "^7.20.7", + "@babel/parser": "^7.20.7", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.7", + "@babel/types": "^7.20.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/json5": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.2.tgz", + "integrity": "sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ==", + "dev": true, + "peer": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/eslint-parser": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz", + "integrity": "sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==", + "dev": true, + "dependencies": { + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.11.0", + "eslint": "^7.5.0 || ^8.0.0" + } + }, + "node_modules/@babel/eslint-parser/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@babel/eslint-parser/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz", + "integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", + "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", + "dev": true, + "dependencies": { + "@babel/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", + "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.7.tgz", + "integrity": "sha512-LtoWbDXOaidEf50hmdDqn9g8VEzsorMexoWMQdQODbvmqYmaF23pBP5VNPAGIFHsFQCIeKokDiz3CH5Y2jlY6w==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-member-expression-to-functions": "^7.20.7", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.20.7", + "@babel/helper-split-export-declaration": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.20.5.tgz", + "integrity": "sha512-m68B1lkg3XDGX5yCvGO0kPx3v9WIYLnzjKfPcQiwntEQa5ZeRkPmo2X/ISJc8qxWGfwUr+kvZAeEzAwLec2r2w==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.2.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0-0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-explode-assignable-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", + "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "dev": true, + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.20.7.tgz", + "integrity": "sha512-9J0CxJLq315fEdi4s7xK5TQaNYjZw+nDVpVqr1axNGKzdrdwYBD5b4uKv3n75aABG0rCCTK8Im8Ww7eYfMrZgw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", + "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.20.2", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.10", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz", + "integrity": "sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.20.7", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.7", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", + "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", + "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-string-parser": { "version": "7.19.4", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", @@ -53,10 +522,134 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/parser": { + "node_modules/@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz", + "integrity": "sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.19.0", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.5", + "@babel/types": "^7.20.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.7.tgz", + "integrity": "sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.7", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "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" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "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", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "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" + } + }, + "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 + }, + "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" + } + }, + "node_modules/@babel/highlight/node_modules/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, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/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, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz", + "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -65,6 +658,1109 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", + "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.20.7.tgz", + "integrity": "sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-proposal-optional-chaining": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", + "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-remap-async-to-generator": "^7.18.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-static-block": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.20.7.tgz", + "integrity": "sha512-AveGOoi9DAjUYYuUAG//Ig69GlazLnoyzMw68VCDux+c1tsnnH/OkYcpz/5xzMkEFC6UxjR5Gw1c+iY2wOGVeQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-proposal-dynamic-import": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", + "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-export-namespace-from": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-json-strings": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", + "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", + "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", + "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-catch-binding": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", + "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.20.7.tgz", + "integrity": "sha512-T+A7b1kfjtRM51ssoOfS1+wbyCVqorfyZhT99TvxxLMirPShD8CzKMRepMlCBGM5RpHMbn8s+5MMHnPstJH6mQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.20.5.tgz", + "integrity": "sha512-Vq7b9dUA12ByzB4EjQTPo25sFhY+08pQDBSZRtUAkj7lb7jahaHR5igera16QZ+3my1nYR4dKsNdYj5IjPHilQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.20.5", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-unicode-property-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz", + "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz", + "integrity": "sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz", + "integrity": "sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-remap-async-to-generator": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", + "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.11.tgz", + "integrity": "sha512-tA4N427a7fjf1P0/2I4ScsHGc5jcHPbb30xMbaTke2gxDuWpUfXDuX1FEymJwKk4tuGUvGcejAR6HdZVqmmPyw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.20.7.tgz", + "integrity": "sha512-LWYbsiXTPKl+oBlXUGlwNlJZetXD5Am+CyBdqhPsDVjM9Jc8jwBJFrKhHf900Kfk2eZG1y9MAG3UNajol7A4VQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-replace-supers": "^7.20.7", + "@babel/helper-split-export-declaration": "^7.18.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz", + "integrity": "sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/template": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.7.tgz", + "integrity": "sha512-Xwg403sRrZb81IVB79ZPqNQME23yhugYVqgTxAhT99h485F4f+GMELFhhOsscDUB7HCswepKeCKLn/GZvUKoBA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", + "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", + "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", + "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz", + "integrity": "sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.20.11.tgz", + "integrity": "sha512-S8e1f7WQ7cimJQ51JkAaDrEtohVEitXjgCGAS2N8S31Y42E+kWwfSz83LYz57QdBm7q9diARVqanIaH2oVgQnw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-simple-access": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz", + "integrity": "sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-validator-identifier": "^7.19.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", + "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz", + "integrity": "sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.20.5", + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", + "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", + "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.7.tgz", + "integrity": "sha512-WiWBIkeHKVOSYPO0pWkxGPfKeWrCJyD3NJ53+Lrp/QMSZbsVPovrVl2aWZ19D/LTVnaDv5Ap7GJ/B2CTOZdrfA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", + "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz", + "integrity": "sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "regenerator-transform": "^0.15.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", + "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", + "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz", + "integrity": "sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", + "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", + "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", + "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.20.2.tgz", + "integrity": "sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.20.1", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.20.1", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.20.2", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.20.0", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.20.2", + "@babel/plugin-transform-classes": "^7.20.2", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.20.2", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.19.6", + "@babel/plugin-transform-modules-commonjs": "^7.19.6", + "@babel/plugin-transform-modules-systemjs": "^7.19.6", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.20.1", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.19.0", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", + "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.20.2", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "core-js-compat": "^3.25.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/runtime": { "version": "7.20.6", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.6.tgz", @@ -83,10 +1779,54 @@ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", "dev": true }, + "node_modules/@babel/template": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", + "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.20.10", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.10.tgz", + "integrity": "sha512-oSf1juCgymrSez8NI4A2sr4+uB/mFd9MXplYGPEBnfAuWmmyeVcHa6xLPiaRBcXkcb/28bgxmQLTVwFKE1yfsg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.19.4", @@ -232,6 +1972,37 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dev": true, + "dependencies": { + "eslint-scope": "5.1.1" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -694,6 +2465,54 @@ "integrity": "sha512-gsLiKK7Qrb7zYJNgiXKpXblxbV5ffSwR0f5whkPAaBAR4fhi6bwRZxX9wBlIc5M/v8CCkXUbXZL4N/nSE97cqg==", "dev": true }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", + "semver": "^6.1.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", + "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.3", + "core-js-compat": "^3.25.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/babel-runtime": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", @@ -998,6 +2817,13 @@ "@babel/types": "^7.6.1" } }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true, + "peer": true + }, "node_modules/copy-webpack-plugin": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", @@ -1030,6 +2856,19 @@ "dev": true, "hasInstallScript": true }, + "node_modules/core-js-compat": { + "version": "3.27.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.27.0.tgz", + "integrity": "sha512-spN2H4E/wocMML7XtbKuqttHHM+zbF3bAdl9mT4/iyFaF33bowQGjxiWNWyvUJGH9F+hTgnhWziiLtwu3oC/Qg==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -1698,6 +3537,16 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/get-intrinsic": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", @@ -2191,6 +4040,12 @@ "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==", "dev": true }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -2203,6 +4058,18 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, "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", @@ -2318,6 +4185,12 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -3157,12 +5030,39 @@ "node": ">= 10.13.0" } }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", "dev": true }, + "node_modules/regenerator-transform": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", + "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -3175,6 +5075,50 @@ "url": "https://github.com/sponsors/mysticatea" } }, + "node_modules/regexpu-core": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.2.tgz", + "integrity": "sha512-T0+1Zp2wjF/juXMrMxHxidqGYn8U4R+zleSJhX9tQ1PUsS8a9UtYfbsF9LdiVgNX3kiX8RNaKM42nfSgvFJjmw==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsgen": "^0.7.1", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", + "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==", + "dev": true + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, "node_modules/relateurl": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", @@ -3737,6 +5681,46 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/update-browserslist-db": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", @@ -3827,6 +5811,12 @@ "npm": ">= 3.0.0" } }, + "node_modules/vue-i18n": { + "version": "8.28.2", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.28.2.tgz", + "integrity": "sha512-C5GZjs1tYlAqjwymaaCPDjCyGo10ajUphiwA922jKt9n7KPpqR7oM1PCwYzhB/E7+nT3wfdG3oRre5raIT1rKA==", + "dev": true + }, "node_modules/vue-lazyload": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/vue-lazyload/-/vue-lazyload-1.3.4.tgz", @@ -4135,6 +6125,359 @@ } }, "dependencies": { + "@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "peer": true, + "requires": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "peer": true, + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + } + } + }, + "@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/compat-data": { + "version": "7.20.10", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.10.tgz", + "integrity": "sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==", + "dev": true + }, + "@babel/core": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.7.tgz", + "integrity": "sha512-t1ZjCluspe5DW24bn2Rr1CDb2v9rn/hROtg9a2tmd0+QYf4bsloYfLQzjG4qHPNMhWtKdGC33R5AxGR2Af2cBw==", + "dev": true, + "peer": true, + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-module-transforms": "^7.20.7", + "@babel/helpers": "^7.20.7", + "@babel/parser": "^7.20.7", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.7", + "@babel/types": "^7.20.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "dependencies": { + "json5": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.2.tgz", + "integrity": "sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ==", + "dev": true, + "peer": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "peer": true + } + } + }, + "@babel/eslint-parser": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz", + "integrity": "sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==", + "dev": true, + "requires": { + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz", + "integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==", + "dev": true, + "requires": { + "@babel/types": "^7.20.7", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", + "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", + "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", + "semver": "^6.3.0" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.7.tgz", + "integrity": "sha512-LtoWbDXOaidEf50hmdDqn9g8VEzsorMexoWMQdQODbvmqYmaF23pBP5VNPAGIFHsFQCIeKokDiz3CH5Y2jlY6w==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-member-expression-to-functions": "^7.20.7", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.20.7", + "@babel/helper-split-export-declaration": "^7.18.6" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.20.5.tgz", + "integrity": "sha512-m68B1lkg3XDGX5yCvGO0kPx3v9WIYLnzjKfPcQiwntEQa5ZeRkPmo2X/ISJc8qxWGfwUr+kvZAeEzAwLec2r2w==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.2.1" + } + }, + "@babel/helper-define-polyfill-provider": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "dev": true + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", + "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "dev": true, + "requires": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.20.7.tgz", + "integrity": "sha512-9J0CxJLq315fEdi4s7xK5TQaNYjZw+nDVpVqr1axNGKzdrdwYBD5b4uKv3n75aABG0rCCTK8Im8Ww7eYfMrZgw==", + "dev": true, + "requires": { + "@babel/types": "^7.20.7" + } + }, + "@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-module-transforms": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", + "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.20.2", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.10", + "@babel/types": "^7.20.7" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", + "dev": true + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-replace-supers": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz", + "integrity": "sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.20.7", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.7", + "@babel/types": "^7.20.7" + } + }, + "@babel/helper-simple-access": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", + "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", + "dev": true, + "requires": { + "@babel/types": "^7.20.2" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", + "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", + "dev": true, + "requires": { + "@babel/types": "^7.20.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, "@babel/helper-string-parser": { "version": "7.19.4", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", @@ -4147,12 +6490,852 @@ "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", "dev": true }, - "@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", + "@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", "dev": true }, + "@babel/helper-wrap-function": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz", + "integrity": "sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.19.0", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.5", + "@babel/types": "^7.20.5" + } + }, + "@babel/helpers": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.7.tgz", + "integrity": "sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA==", + "dev": true, + "peer": true, + "requires": { + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.7", + "@babel/types": "^7.20.7" + } + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "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" + } + }, + "chalk": { + "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", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "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" + } + }, + "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 + }, + "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 + }, + "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 + }, + "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" + } + } + } + }, + "@babel/parser": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz", + "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==", + "dev": true + }, + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", + "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.20.7.tgz", + "integrity": "sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-proposal-optional-chaining": "^7.20.7" + } + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", + "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-remap-async-to-generator": "^7.18.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-proposal-class-static-block": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.20.7.tgz", + "integrity": "sha512-AveGOoi9DAjUYYuUAG//Ig69GlazLnoyzMw68VCDux+c1tsnnH/OkYcpz/5xzMkEFC6UxjR5Gw1c+iY2wOGVeQ==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", + "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + } + }, + "@babel/plugin-proposal-export-namespace-from": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", + "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3" + } + }, + "@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", + "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", + "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.20.7" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", + "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.20.7.tgz", + "integrity": "sha512-T+A7b1kfjtRM51ssoOfS1+wbyCVqorfyZhT99TvxxLMirPShD8CzKMRepMlCBGM5RpHMbn8s+5MMHnPstJH6mQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.20.5.tgz", + "integrity": "sha512-Vq7b9dUA12ByzB4EjQTPo25sFhY+08pQDBSZRtUAkj7lb7jahaHR5igera16QZ+3my1nYR4dKsNdYj5IjPHilQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.20.5", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-import-assertions": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz", + "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.19.0" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz", + "integrity": "sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz", + "integrity": "sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-remap-async-to-generator": "^7.18.9" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", + "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.11.tgz", + "integrity": "sha512-tA4N427a7fjf1P0/2I4ScsHGc5jcHPbb30xMbaTke2gxDuWpUfXDuX1FEymJwKk4tuGUvGcejAR6HdZVqmmPyw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.20.7.tgz", + "integrity": "sha512-LWYbsiXTPKl+oBlXUGlwNlJZetXD5Am+CyBdqhPsDVjM9Jc8jwBJFrKhHf900Kfk2eZG1y9MAG3UNajol7A4VQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-replace-supers": "^7.20.7", + "@babel/helper-split-export-declaration": "^7.18.6", + "globals": "^11.1.0" + }, + "dependencies": { + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + } + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz", + "integrity": "sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/template": "^7.20.7" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.7.tgz", + "integrity": "sha512-Xwg403sRrZb81IVB79ZPqNQME23yhugYVqgTxAhT99h485F4f+GMELFhhOsscDUB7HCswepKeCKLn/GZvUKoBA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", + "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", + "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", + "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz", + "integrity": "sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helper-plugin-utils": "^7.20.2" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.20.11.tgz", + "integrity": "sha512-S8e1f7WQ7cimJQ51JkAaDrEtohVEitXjgCGAS2N8S31Y42E+kWwfSz83LYz57QdBm7q9diARVqanIaH2oVgQnw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-simple-access": "^7.20.2" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz", + "integrity": "sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-validator-identifier": "^7.19.1" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", + "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz", + "integrity": "sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.20.5", + "@babel/helper-plugin-utils": "^7.20.2" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", + "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", + "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.7.tgz", + "integrity": "sha512-WiWBIkeHKVOSYPO0pWkxGPfKeWrCJyD3NJ53+Lrp/QMSZbsVPovrVl2aWZ19D/LTVnaDv5Ap7GJ/B2CTOZdrfA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", + "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz", + "integrity": "sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2", + "regenerator-transform": "^0.15.1" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", + "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", + "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz", + "integrity": "sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", + "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", + "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", + "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/preset-env": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.20.2.tgz", + "integrity": "sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.20.1", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.20.1", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.20.2", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.20.0", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.20.2", + "@babel/plugin-transform-classes": "^7.20.2", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.20.2", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.19.6", + "@babel/plugin-transform-modules-commonjs": "^7.19.6", + "@babel/plugin-transform-modules-systemjs": "^7.19.6", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.20.1", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.19.0", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", + "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.20.2", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "core-js-compat": "^3.25.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/preset-modules": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, "@babel/runtime": { "version": "7.20.6", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.6.tgz", @@ -4170,10 +7353,47 @@ } } }, + "@babel/template": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", + "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" + } + }, + "@babel/traverse": { + "version": "7.20.10", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.10.tgz", + "integrity": "sha512-oSf1juCgymrSez8NI4A2sr4+uB/mFd9MXplYGPEBnfAuWmmyeVcHa6xLPiaRBcXkcb/28bgxmQLTVwFKE1yfsg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "dependencies": { + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + } + } + }, "@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", "dev": true, "requires": { "@babel/helper-string-parser": "^7.19.4", @@ -4288,6 +7508,33 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, + "@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dev": true, + "requires": { + "eslint-scope": "5.1.1" + }, + "dependencies": { + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -4680,6 +7927,44 @@ "integrity": "sha512-gsLiKK7Qrb7zYJNgiXKpXblxbV5ffSwR0f5whkPAaBAR4fhi6bwRZxX9wBlIc5M/v8CCkXUbXZL4N/nSE97cqg==", "dev": true }, + "babel-plugin-polyfill-corejs2": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", + "semver": "^6.1.1" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", + "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.3", + "core-js-compat": "^3.25.1" + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.3" + } + }, "babel-runtime": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", @@ -4907,6 +8192,13 @@ "@babel/types": "^7.6.1" } }, + "convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true, + "peer": true + }, "copy-webpack-plugin": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", @@ -4927,6 +8219,15 @@ "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", "dev": true }, + "core-js-compat": { + "version": "3.27.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.27.0.tgz", + "integrity": "sha512-spN2H4E/wocMML7XtbKuqttHHM+zbF3bAdl9mT4/iyFaF33bowQGjxiWNWyvUJGH9F+hTgnhWziiLtwu3oC/Qg==", + "dev": true, + "requires": { + "browserslist": "^4.21.4" + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -5422,6 +8723,13 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "peer": true + }, "get-intrinsic": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", @@ -5773,6 +9081,12 @@ "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==", "dev": true }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -5782,6 +9096,12 @@ "argparse": "^2.0.1" } }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, "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", @@ -5873,6 +9193,12 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -6509,18 +9835,79 @@ "resolve": "^1.20.0" } }, + "regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", + "dev": true, + "requires": { + "regenerate": "^1.4.2" + } + }, "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", "dev": true }, + "regenerator-transform": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", + "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.4" + } + }, "regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, + "regexpu-core": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.2.tgz", + "integrity": "sha512-T0+1Zp2wjF/juXMrMxHxidqGYn8U4R+zleSJhX9tQ1PUsS8a9UtYfbsF9LdiVgNX3kiX8RNaKM42nfSgvFJjmw==", + "dev": true, + "requires": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsgen": "^0.7.1", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + } + }, + "regjsgen": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", + "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==", + "dev": true + }, + "regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true + } + } + }, "relateurl": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", @@ -6884,6 +10271,34 @@ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true }, + "unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true + }, "update-browserslist-db": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", @@ -6948,6 +10363,12 @@ "vue": "^2.5.16" } }, + "vue-i18n": { + "version": "8.28.2", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.28.2.tgz", + "integrity": "sha512-C5GZjs1tYlAqjwymaaCPDjCyGo10ajUphiwA922jKt9n7KPpqR7oM1PCwYzhB/E7+nT3wfdG3oRre5raIT1rKA==", + "dev": true + }, "vue-lazyload": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/vue-lazyload/-/vue-lazyload-1.3.4.tgz", diff --git a/html/package.json b/html/package.json index c7b4d57a..216e7c56 100644 --- a/html/package.json +++ b/html/package.json @@ -22,6 +22,9 @@ }, "homepage": "https://github.com/pypy-vrc/VRCX#readme", "devDependencies": { + "@babel/eslint-parser": "^7.19.1", + "@babel/plugin-syntax-import-assertions": "^7.20.0", + "@babel/preset-env": "^7.20.2", "@fontsource/noto-sans-jp": "^4.5.12", "@fontsource/noto-sans-kr": "^4.5.12", "animate.css": "^4.1.1", @@ -44,6 +47,7 @@ "uuid": "^9.0.0", "vue": "^2.6.14", "vue-data-tables": "^3.4.5", + "vue-i18n": "^8.28.2", "vue-lazyload": "^1.3.4", "vue-marquee-text-component": "^1.2.0", "webpack": "^5.75.0", diff --git a/html/src/app.js b/html/src/app.js index 53fd612a..0c35bece 100644 --- a/html/src/app.js +++ b/html/src/app.js @@ -9,9 +9,9 @@ import '@fontsource/noto-sans-jp'; import Noty from 'noty'; import Vue from 'vue'; import VueLazyload from 'vue-lazyload'; +import VueI18n from 'vue-i18n'; import {DataTables} from 'vue-data-tables'; import ElementUI from 'element-ui'; -import locale from 'element-ui/lib/locale/lang/en'; import {v4 as uuidv4} from 'uuid'; import * as workerTimers from 'worker-timers'; import 'default-passive-events'; @@ -21,6 +21,7 @@ import webApiService from './service/webapi.js'; import gameLogService from './service/gamelog.js'; import security from './security.js'; import database from './repository/database.js'; +import * as localizedStrings from './localization/localizedStrings.js'; speechSynthesis.getVoices(); @@ -125,8 +126,18 @@ speechSynthesis.getVoices(); timeout: 6000 }); + Vue.use(VueI18n); + + var i18n = new VueI18n({ + locale: 'en', + fallbackLocale: 'en', + messages: localizedStrings + }); + + var $t = i18n.t.bind(i18n); + Vue.use(ElementUI, { - locale + i18n: (key, value) => i18n.t(key, value) }); var removeFromArray = function (array, item) { @@ -4657,6 +4668,7 @@ speechSynthesis.getVoices(); exportFriendsListDialog: false, exportFriendsListContent: '' }, + i18n, computed: {}, methods: {}, watch: {}, @@ -6405,80 +6417,72 @@ speechSynthesis.getVoices(); }; $app.methods.promptTOTP = function () { - this.$prompt( - 'Enter a numeric code from your authenticator app', - 'Two-factor Authentication', - { - distinguishCancelAndClose: true, - cancelButtonText: 'Use OTP', - confirmButtonText: 'Verify', - inputPlaceholder: 'Code', - inputPattern: /^[0-9]{6}$/, - inputErrorMessage: 'Invalid Code', - callback: (action, instance) => { - if (action === 'confirm') { - API.verifyTOTP({ - code: instance.inputValue.trim() + this.$prompt($t('prompt.totp.description'), $t('prompt.totp.header'), { + distinguishCancelAndClose: true, + cancelButtonText: $t('prompt.totp.use_otp'), + confirmButtonText: $t('prompt.totp.verify'), + inputPlaceholder: $t('prompt.totp.input_placeholder'), + inputPattern: /^[0-9]{6}$/, + inputErrorMessage: $t('prompt.totp.input_error'), + callback: (action, instance) => { + if (action === 'confirm') { + API.verifyTOTP({ + code: instance.inputValue.trim() + }) + .catch((err) => { + this.promptTOTP(); + throw err; }) - .catch((err) => { - this.promptTOTP(); - throw err; - }) - .then((args) => { - API.getCurrentUser(); - return args; - }); - } else if (action === 'cancel') { - this.promptOTP(); - } + .then((args) => { + API.getCurrentUser(); + return args; + }); + } else if (action === 'cancel') { + this.promptOTP(); } } - ); + }); }; $app.methods.promptOTP = function () { - this.$prompt( - 'Enter one of your saved recovery codes', - 'Two-factor Authentication', - { - distinguishCancelAndClose: true, - cancelButtonText: 'Use TOTP', - confirmButtonText: 'Verify', - inputPlaceholder: 'Code', - inputPattern: /^[a-z0-9]{4}-[a-z0-9]{4}$/, - inputErrorMessage: 'Invalid Code', - callback: (action, instance) => { - if (action === 'confirm') { - API.verifyOTP({ - code: instance.inputValue.trim() + this.$prompt($t('prompt.otp.description'), $t('prompt.otp.header'), { + distinguishCancelAndClose: true, + cancelButtonText: $t('prompt.otp.use_otp'), + confirmButtonText: $t('prompt.otp.verify'), + inputPlaceholder: $t('prompt.otp.input_placeholder'), + inputPattern: /^[a-z0-9]{4}-[a-z0-9]{4}$/, + inputErrorMessage: $t('prompt.otp.input_error'), + callback: (action, instance) => { + if (action === 'confirm') { + API.verifyOTP({ + code: instance.inputValue.trim() + }) + .catch((err) => { + this.promptOTP(); + throw err; }) - .catch((err) => { - this.promptOTP(); - throw err; - }) - .then((args) => { - API.getCurrentUser(); - return args; - }); - } else if (action === 'cancel') { - this.promptTOTP(); - } + .then((args) => { + API.getCurrentUser(); + return args; + }); + } else if (action === 'cancel') { + this.promptTOTP(); } } - ); + }); }; $app.methods.promptEmailOTP = function () { this.$prompt( - 'Enter a numeric code that was sent to your email', - 'Email Two-factor Authentication', + $t('prompt.email_otp.description'), + $t('prompt.email_otp.header'), { distinguishCancelAndClose: true, - cancelButtonText: 'Cancel', - confirmButtonText: 'Verify', - inputPlaceholder: 'Code', + cancelButtonText: $t('prompt.email_otp.cancel'), + confirmButtonText: $t('prompt.email_otp.verify'), + inputPlaceholder: $t('prompt.email_otp.input_placeholder'), inputPattern: /^[0-9]{6}$/, - inputErrorMessage: 'Invalid Code', + inputErrorMessage: $t('prompt.email_otp.input_error'), callback: (action, instance) => { if (action === 'confirm') { API.verifyEmailOTP({ @@ -6614,8 +6618,8 @@ speechSynthesis.getVoices(); resolve(args.password); } $app.$prompt( - 'Please enter your Primary Password.', - 'Primary Password Required', + $t('prompt.primary_password.description'), + $t('prompt.primary_password.header'), { inputType: 'password', inputPattern: /[\s\S]{1,32}/ @@ -6650,8 +6654,8 @@ speechSynthesis.getVoices(); this.enablePrimaryPasswordDialog.visible = true; } else { this.$prompt( - 'Please enter your Primary Password.', - 'Primary Password Required', + $t('prompt.primary_password.description'), + $t('prompt.primary_password.header'), { inputType: 'password', inputPattern: /[\s\S]{1,32}/ @@ -6905,8 +6909,8 @@ speechSynthesis.getVoices(); this.enablePrimaryPassword ) { $app.$prompt( - 'Please enter your Primary Password.', - 'Primary Password Required', + $t('prompt.primary_password.description'), + $t('prompt.primary_password.header'), { inputType: 'password', inputPattern: /[\s\S]{1,32}/ @@ -11780,30 +11784,44 @@ speechSynthesis.getVoices(); }; $app.methods.changeFavoriteGroupName = function (ctx) { - this.$prompt('Enter a new name', 'Change Group Name', { - distinguishCancelAndClose: true, - cancelButtonText: 'Cancel', - confirmButtonText: 'Change', - inputPlaceholder: 'Name', - inputValue: ctx.displayName, - inputPattern: /\S+/, - inputErrorMessage: 'Name is required', - callback: (action, instance) => { - if (action === 'confirm') { - API.saveFavoriteGroup({ - type: ctx.type, - group: ctx.name, - displayName: instance.inputValue - }).then((args) => { - this.$message({ - message: 'Group renamed', - type: 'success' + this.$prompt( + $t('prompt.change_favorite_group_name.description'), + $t('prompt.change_favorite_group_name.header'), + { + distinguishCancelAndClose: true, + cancelButtonText: $t( + 'prompt.change_favorite_group_name.cancel' + ), + confirmButtonText: $t( + 'prompt.change_favorite_group_name.change' + ), + inputPlaceholder: $t( + 'prompt.change_favorite_group_name.input_placeholder' + ), + inputValue: ctx.displayName, + inputPattern: /\S+/, + inputErrorMessage: $t( + 'prompt.change_favorite_group_name.input_error' + ), + callback: (action, instance) => { + if (action === 'confirm') { + API.saveFavoriteGroup({ + type: ctx.type, + group: ctx.name, + displayName: instance.inputValue + }).then((args) => { + this.$message({ + message: $t( + 'prompt.change_favorite_group_name.message.success' + ), + type: 'success' + }); + return args; }); - return args; - }); + } } } - }); + ); }; $app.methods.clearFavoriteGroup = function (ctx) { @@ -13259,7 +13277,8 @@ speechSynthesis.getVoices(); notificationTheme, backgroundEnabled: this.vrBackgroundEnabled, dtHour12: this.dtHour12, - pcUptimeOnFeed: this.pcUptimeOnFeed + pcUptimeOnFeed: this.pcUptimeOnFeed, + appLanguage: this.appLanguage }; var json = JSON.stringify(VRConfigVars); AppApi.ExecuteVrFeedFunction('configUpdate', json); @@ -13452,112 +13471,146 @@ speechSynthesis.getVoices(); }; $app.methods.promptUserIdDialog = function () { - this.$prompt('Enter a User URL or ID (UUID)', 'Direct Access', { - distinguishCancelAndClose: true, - confirmButtonText: 'OK', - cancelButtonText: 'Cancel', - inputPattern: /\S+/, - inputErrorMessage: 'User URL/ID is required', - callback: (action, instance) => { - if (action === 'confirm' && instance.inputValue) { - var testUrl = instance.inputValue.substring(0, 15); - if (testUrl === 'https://vrchat.') { - var userId = this.parseUserUrl(instance.inputValue); - if (userId) { - this.showUserDialog(userId); + this.$prompt( + $t('prompt.direct_access_user_id.description'), + $t('prompt.direct_access_user_id.header'), + { + distinguishCancelAndClose: true, + confirmButtonText: $t('prompt.direct_access_user_id.ok'), + cancelButtonText: $t('prompt.direct_access_user_id.cancel'), + inputPattern: /\S+/, + inputErrorMessage: $t( + 'prompt.direct_access_user_id.input_error' + ), + callback: (action, instance) => { + if (action === 'confirm' && instance.inputValue) { + var testUrl = instance.inputValue.substring(0, 15); + if (testUrl === 'https://vrchat.') { + var userId = this.parseUserUrl(instance.inputValue); + if (userId) { + this.showUserDialog(userId); + } else { + this.$message({ + message: $t( + 'prompt.direct_access_user_id.message.error' + ), + type: 'error' + }); + } } else { - this.$message({ - message: 'Invalid URL', - type: 'error' - }); + this.showUserDialog(instance.inputValue); } - } else { - this.showUserDialog(instance.inputValue); } } } - }); + ); }; $app.methods.promptUsernameDialog = function () { - this.$prompt('Enter a Username', 'Direct Access', { - distinguishCancelAndClose: true, - confirmButtonText: 'OK', - cancelButtonText: 'Cancel', - inputPattern: /\S+/, - inputErrorMessage: 'Username is required', - callback: (action, instance) => { - if (action === 'confirm' && instance.inputValue) { - this.lookupUser({displayName: instance.inputValue}); + this.$prompt( + $t('prompt.direct_access_username.description'), + $t('prompt.direct_access_username.header'), + { + distinguishCancelAndClose: true, + confirmButtonText: $t('prompt.direct_access_username.ok'), + cancelButtonText: $t('prompt.direct_access_username.cancel'), + inputPattern: /\S+/, + inputErrorMessage: $t( + 'prompt.direct_access_username.input_error' + ), + callback: (action, instance) => { + if (action === 'confirm' && instance.inputValue) { + this.lookupUser({displayName: instance.inputValue}); + } } } - }); + ); }; $app.methods.promptWorldDialog = function () { - this.$prompt('Enter a World URL or ID (UUID)', 'Direct Access', { - distinguishCancelAndClose: true, - confirmButtonText: 'OK', - cancelButtonText: 'Cancel', - inputPattern: /\S+/, - inputErrorMessage: 'World URL/ID is required', - callback: (action, instance) => { - if (action === 'confirm' && instance.inputValue) { - if (!this.directAccessWorld(instance.inputValue)) { - this.$message({ - message: 'Invalid URL/id', - type: 'error' - }); - } - } - } - }); - }; - - $app.methods.promptAvatarDialog = function () { - this.$prompt('Enter a Avatar URL or ID (UUID)', 'Direct Access', { - distinguishCancelAndClose: true, - confirmButtonText: 'OK', - cancelButtonText: 'Cancel', - inputPattern: /\S+/, - inputErrorMessage: 'Avatar URL/ID is required', - callback: (action, instance) => { - if (action === 'confirm' && instance.inputValue) { - var testUrl = instance.inputValue.substring(0, 15); - if (testUrl === 'https://vrchat.') { - var avatarId = this.parseAvatarUrl(instance.inputValue); - if (avatarId) { - this.showAvatarDialog(avatarId); - } else { + this.$prompt( + $t('prompt.direct_access_world_id.description'), + $t('prompt.direct_access_world_id.header'), + { + distinguishCancelAndClose: true, + confirmButtonText: $t('prompt.direct_access_world_id.ok'), + cancelButtonText: $t('prompt.direct_access_world_id.cancel'), + inputPattern: /\S+/, + inputErrorMessage: $t( + 'prompt.direct_access_world_id.input_error' + ), + callback: (action, instance) => { + if (action === 'confirm' && instance.inputValue) { + if (!this.directAccessWorld(instance.inputValue)) { this.$message({ - message: 'Invalid URL', + message: $t( + 'prompt.direct_access_world_id.message.error' + ), type: 'error' }); } - } else { - this.showAvatarDialog(instance.inputValue); } } } - }); + ); + }; + + $app.methods.promptAvatarDialog = function () { + this.$prompt( + $t('prompt.direct_access_avatar_id.description'), + $t('prompt.direct_access_avatar_id.header'), + { + distinguishCancelAndClose: true, + confirmButtonText: $t('prompt.direct_access_avatar_id.ok'), + cancelButtonText: $t('prompt.direct_access_avatar_id.cancel'), + inputPattern: /\S+/, + inputErrorMessage: $t( + 'prompt.direct_access_avatar_id.input_error' + ), + callback: (action, instance) => { + if (action === 'confirm' && instance.inputValue) { + var testUrl = instance.inputValue.substring(0, 15); + if (testUrl === 'https://vrchat.') { + var avatarId = this.parseAvatarUrl( + instance.inputValue + ); + if (avatarId) { + this.showAvatarDialog(avatarId); + } else { + this.$message({ + message: $t( + 'prompt.direct_access_avatar_id.message.error' + ), + type: 'error' + }); + } + } else { + this.showAvatarDialog(instance.inputValue); + } + } + } + } + ); }; $app.methods.promptOmniDirectDialog = function () { this.$prompt( - 'Enter a User/World/Instance/Avatar/Group URL or ID (UUID)', - 'Direct Access', + $t('prompt.direct_access_omni.description'), + $t('prompt.direct_access_omni.header'), { distinguishCancelAndClose: true, - confirmButtonText: 'OK', - cancelButtonText: 'Cancel', + confirmButtonText: $t('prompt.direct_access_omni.ok'), + cancelButtonText: $t('prompt.direct_access_omni.cancel'), inputPattern: /\S+/, - inputErrorMessage: 'URL/ID is required', + inputErrorMessage: $t('prompt.direct_access_omni.input_error'), callback: (action, instance) => { if (action === 'confirm' && instance.inputValue) { var input = instance.inputValue; if (!this.directAccessParse(input)) { this.$message({ - message: 'Invalid URL/ID', + message: $t( + 'prompt.direct_access_omni.message.error' + ), type: 'error' }); } @@ -13689,233 +13742,94 @@ speechSynthesis.getVoices(); }; $app.methods.promptNotificationTimeout = function () { - this.$prompt('Enter amount of seconds', 'Notification Timeout', { - distinguishCancelAndClose: true, - confirmButtonText: 'OK', - cancelButtonText: 'Cancel', - inputValue: this.notificationTimeout / 1000, - inputPattern: /\d+$/, - inputErrorMessage: 'Valid number is required', - callback: (action, instance) => { - if ( - action === 'confirm' && - instance.inputValue && - !isNaN(instance.inputValue) - ) { - this.notificationTimeout = Math.trunc( - Number(instance.inputValue) * 1000 - ); - configRepository.setString( - 'VRCX_notificationTimeout', - this.notificationTimeout - ); - this.updateVRConfigVars(); + this.$prompt( + $t('prompt.notification_timeout.description'), + $t('prompt.notification_timeout.header'), + { + distinguishCancelAndClose: true, + confirmButtonText: $t('prompt.notification_timeout.ok'), + cancelButtonText: $t('prompt.notification_timeout.cancel'), + inputValue: this.notificationTimeout / 1000, + inputPattern: /\d+$/, + inputErrorMessage: $t( + 'prompt.notification_timeout.input_error' + ), + callback: (action, instance) => { + if ( + action === 'confirm' && + instance.inputValue && + !isNaN(instance.inputValue) + ) { + this.notificationTimeout = Math.trunc( + Number(instance.inputValue) * 1000 + ); + configRepository.setString( + 'VRCX_notificationTimeout', + this.notificationTimeout + ); + this.updateVRConfigVars(); + } } } - }); + ); }; $app.methods.promptPhotonOverlayMessageTimeout = function () { - this.$prompt('Enter amount of seconds', 'Overlay Message Timeout', { - distinguishCancelAndClose: true, - confirmButtonText: 'OK', - cancelButtonText: 'Cancel', - inputValue: this.photonOverlayMessageTimeout / 1000, - inputPattern: /\d+$/, - inputErrorMessage: 'Valid number is required', - callback: (action, instance) => { - if ( - action === 'confirm' && - instance.inputValue && - !isNaN(instance.inputValue) - ) { - this.photonOverlayMessageTimeout = Math.trunc( - Number(instance.inputValue) * 1000 - ); - configRepository.setString( - 'VRCX_photonOverlayMessageTimeout', - this.photonOverlayMessageTimeout - ); - this.updateVRConfigVars(); + this.$prompt( + $t('prompt.overlay_message_timeout.description'), + $t('prompt.overlay_message_timeout.header'), + { + distinguishCancelAndClose: true, + confirmButtonText: $t('prompt.overlay_message_timeout.ok'), + cancelButtonText: $t('prompt.overlay_message_timeout.cancel'), + inputValue: this.photonOverlayMessageTimeout / 1000, + inputPattern: /\d+$/, + inputErrorMessage: $t( + 'prompt.overlay_message_timeout.input_error' + ), + callback: (action, instance) => { + if ( + action === 'confirm' && + instance.inputValue && + !isNaN(instance.inputValue) + ) { + this.photonOverlayMessageTimeout = Math.trunc( + Number(instance.inputValue) * 1000 + ); + configRepository.setString( + 'VRCX_photonOverlayMessageTimeout', + this.photonOverlayMessageTimeout + ); + this.updateVRConfigVars(); + } } } - }); + ); }; $app.methods.promptRenameAvatar = function (avatar) { - this.$prompt('Enter avatar name', 'Rename Avatar', { - distinguishCancelAndClose: true, - confirmButtonText: 'OK', - cancelButtonText: 'Cancel', - inputValue: avatar.ref.name, - inputErrorMessage: 'Valid name is required', - callback: (action, instance) => { - if ( - action === 'confirm' && - instance.inputValue !== avatar.ref.name - ) { - API.saveAvatar({ - id: avatar.id, - name: instance.inputValue - }).then((args) => { - this.$message({ - message: 'Avatar renamed', - type: 'success' - }); - return args; - }); - } - } - }); - }; - - $app.methods.promptChangeAvatarDescription = function (avatar) { - this.$prompt('Enter avatar description', 'Change Description', { - distinguishCancelAndClose: true, - confirmButtonText: 'OK', - cancelButtonText: 'Cancel', - inputValue: avatar.ref.description, - inputErrorMessage: 'Valid description is required', - callback: (action, instance) => { - if ( - action === 'confirm' && - instance.inputValue !== avatar.ref.description - ) { - API.saveAvatar({ - id: avatar.id, - description: instance.inputValue - }).then((args) => { - this.$message({ - message: 'Avatar description changed', - type: 'success' - }); - return args; - }); - } - } - }); - }; - - $app.methods.promptRenameWorld = function (world) { - this.$prompt('Enter world name', 'Rename World', { - distinguishCancelAndClose: true, - confirmButtonText: 'OK', - cancelButtonText: 'Cancel', - inputValue: world.ref.name, - inputErrorMessage: 'Valid name is required', - callback: (action, instance) => { - if ( - action === 'confirm' && - instance.inputValue !== world.ref.name - ) { - API.saveWorld({ - id: world.id, - name: instance.inputValue - }).then((args) => { - this.$message({ - message: 'World renamed', - type: 'success' - }); - return args; - }); - } - } - }); - }; - - $app.methods.promptChangeWorldDescription = function (world) { - this.$prompt('Enter world description', 'Change Description', { - distinguishCancelAndClose: true, - confirmButtonText: 'OK', - cancelButtonText: 'Cancel', - inputValue: world.ref.description, - inputErrorMessage: 'Valid description is required', - callback: (action, instance) => { - if ( - action === 'confirm' && - instance.inputValue !== world.ref.description - ) { - API.saveWorld({ - id: world.id, - description: instance.inputValue - }).then((args) => { - this.$message({ - message: 'World description changed', - type: 'success' - }); - return args; - }); - } - } - }); - }; - - $app.methods.promptChangeWorldCapacity = function (world) { - this.$prompt('Enter world capacity, Max: 40', 'Change Capacity', { - distinguishCancelAndClose: true, - confirmButtonText: 'OK', - cancelButtonText: 'Cancel', - inputValue: world.ref.capacity, - inputPattern: /\d+$/, - inputErrorMessage: 'Valid number is required', - callback: (action, instance) => { - if ( - action === 'confirm' && - instance.inputValue !== world.ref.capacity - ) { - API.saveWorld({ - id: world.id, - capacity: instance.inputValue - }).then((args) => { - this.$message({ - message: 'World capacity changed', - type: 'success' - }); - return args; - }); - } - } - }); - }; - - $app.methods.promptChangeWorldYouTubePreview = function (world) { - this.$prompt('Enter world YouTube preview', 'Change YouTube Preview', { - distinguishCancelAndClose: true, - confirmButtonText: 'OK', - cancelButtonText: 'Cancel', - inputValue: world.ref.previewYoutubeId, - inputErrorMessage: 'Valid YouTube URL is required', - callback: (action, instance) => { - if ( - action === 'confirm' && - instance.inputValue !== world.ref.previewYoutubeId - ) { - if (instance.inputValue.length > 11) { - try { - var url = new URL(instance.inputValue); - var id1 = url.pathname; - var id2 = url.searchParams.get('v'); - if (id1 && id1.length === 12) { - instance.inputValue = id1.substring(1, 12); - } - if (id2 && id2.length === 11) { - instance.inputValue = id2; - } - } catch { - this.$message({ - message: 'Invalid YouTube URL', - type: 'error' - }); - return; - } - } - if (instance.inputValue !== world.ref.previewYoutubeId) { - API.saveWorld({ - id: world.id, - previewYoutubeId: instance.inputValue + this.$prompt( + $t('prompt.rename_avatar.description'), + $t('prompt.rename_avatar.header'), + { + distinguishCancelAndClose: true, + confirmButtonText: $t('prompt.rename_avatar.ok'), + cancelButtonText: $t('prompt.rename_avatar.cancel'), + inputValue: avatar.ref.name, + inputErrorMessage: $t('prompt.rename_avatar.input_error'), + callback: (action, instance) => { + if ( + action === 'confirm' && + instance.inputValue !== avatar.ref.name + ) { + API.saveAvatar({ + id: avatar.id, + name: instance.inputValue }).then((args) => { this.$message({ - message: 'World YouTube preview changed', + message: $t( + 'prompt.rename_avatar.message.success' + ), type: 'success' }); return args; @@ -13923,20 +13837,219 @@ speechSynthesis.getVoices(); } } } - }); + ); + }; + + $app.methods.promptChangeAvatarDescription = function (avatar) { + this.$prompt( + $t('prompt.change_avatar_description.description'), + $t('prompt.change_avatar_description.header'), + { + distinguishCancelAndClose: true, + confirmButtonText: $t('prompt.change_avatar_description.ok'), + cancelButtonText: $t('prompt.change_avatar_description.cancel'), + inputValue: avatar.ref.description, + inputErrorMessage: $t( + 'prompt.change_avatar_description.input_error' + ), + callback: (action, instance) => { + if ( + action === 'confirm' && + instance.inputValue !== avatar.ref.description + ) { + API.saveAvatar({ + id: avatar.id, + description: instance.inputValue + }).then((args) => { + this.$message({ + message: $t( + 'prompt.change_avatar_description.message.success' + ), + type: 'success' + }); + return args; + }); + } + } + } + ); + }; + + $app.methods.promptRenameWorld = function (world) { + this.$prompt( + $t('prompt.rename_world.description'), + $t('prompt.rename_world.header'), + { + distinguishCancelAndClose: true, + confirmButtonText: $t('prompt.rename_world.ok'), + cancelButtonText: $t('prompt.rename_world.cancel'), + inputValue: world.ref.name, + inputErrorMessage: $t('prompt.rename_world.input_error'), + callback: (action, instance) => { + if ( + action === 'confirm' && + instance.inputValue !== world.ref.name + ) { + API.saveWorld({ + id: world.id, + name: instance.inputValue + }).then((args) => { + this.$message({ + message: $t( + 'prompt.rename_world.message.success' + ), + type: 'success' + }); + return args; + }); + } + } + } + ); + }; + + $app.methods.promptChangeWorldDescription = function (world) { + this.$prompt( + $t('prompt.change_world_description.description'), + $t('prompt.change_world_description.header'), + { + distinguishCancelAndClose: true, + confirmButtonText: $t('prompt.change_world_description.ok'), + cancelButtonText: $t('prompt.change_world_description.cancel'), + inputValue: world.ref.description, + inputErrorMessage: $t( + 'prompt.change_world_description.input_error' + ), + callback: (action, instance) => { + if ( + action === 'confirm' && + instance.inputValue !== world.ref.description + ) { + API.saveWorld({ + id: world.id, + description: instance.inputValue + }).then((args) => { + this.$message({ + message: $t( + 'prompt.change_world_description.message.success' + ), + type: 'success' + }); + return args; + }); + } + } + } + ); + }; + + $app.methods.promptChangeWorldCapacity = function (world) { + this.$prompt( + $t('prompt.change_world_capacity.description'), + $t('prompt.change_world_capacity.header'), + { + distinguishCancelAndClose: true, + confirmButtonText: $t('prompt.change_world_capacity.ok'), + cancelButtonText: $t('prompt.change_world_capacity.cancel'), + inputValue: world.ref.capacity, + inputPattern: /\d+$/, + inputErrorMessage: $t( + 'prompt.change_world_capacity.input_error' + ), + callback: (action, instance) => { + if ( + action === 'confirm' && + instance.inputValue !== world.ref.capacity + ) { + API.saveWorld({ + id: world.id, + capacity: instance.inputValue + }).then((args) => { + this.$message({ + message: $t( + 'prompt.change_world_capacity.message.success' + ), + type: 'success' + }); + return args; + }); + } + } + } + ); + }; + + $app.methods.promptChangeWorldYouTubePreview = function (world) { + this.$prompt( + $t('prompt.change_world_preview.description'), + $t('prompt.change_world_preview.header'), + { + distinguishCancelAndClose: true, + confirmButtonText: $t('prompt.change_world_preview.ok'), + cancelButtonText: $t('prompt.change_world_preview.cancel'), + inputValue: world.ref.previewYoutubeId, + inputErrorMessage: $t( + 'prompt.change_world_preview.input_error' + ), + callback: (action, instance) => { + if ( + action === 'confirm' && + instance.inputValue !== world.ref.previewYoutubeId + ) { + if (instance.inputValue.length > 11) { + try { + var url = new URL(instance.inputValue); + var id1 = url.pathname; + var id2 = url.searchParams.get('v'); + if (id1 && id1.length === 12) { + instance.inputValue = id1.substring(1, 12); + } + if (id2 && id2.length === 11) { + instance.inputValue = id2; + } + } catch { + this.$message({ + message: $t( + 'prompt.change_world_preview.message.error' + ), + type: 'error' + }); + return; + } + } + if ( + instance.inputValue !== world.ref.previewYoutubeId + ) { + API.saveWorld({ + id: world.id, + previewYoutubeId: instance.inputValue + }).then((args) => { + this.$message({ + message: $t( + 'prompt.change_world_preview.message.success' + ), + type: 'success' + }); + return args; + }); + } + } + } + } + ); }; $app.methods.promptMaxTableSizeDialog = function () { this.$prompt( - 'Larger table sizes may impact RAM usage and performance (default: 1000)', - 'Max Table Size', + $t('prompt.change_table_size.description'), + $t('prompt.change_table_size.header'), { distinguishCancelAndClose: true, - confirmButtonText: 'Save', - cancelButtonText: 'Cancel', + confirmButtonText: $t('prompt.change_table_size.save'), + cancelButtonText: $t('prompt.change_table_size.cancel'), inputValue: this.maxTableSize, inputPattern: /\d+$/, - inputErrorMessage: 'Valid number is required', + inputErrorMessage: $t('prompt.change_table_size.input_error'), callback: (action, instance) => { if (action === 'confirm' && instance.inputValue) { this.maxTableSize = instance.inputValue; @@ -13965,15 +14078,17 @@ speechSynthesis.getVoices(); $app.methods.promptPhotonLobbyTimeoutThreshold = function () { this.$prompt( - 'Enter amount of seconds (default: 3)', - 'User Timeout Threshold', + $t('prompt.photon_lobby_timeout.description'), + $t('prompt.photon_lobby_timeout.header'), { distinguishCancelAndClose: true, - confirmButtonText: 'OK', - cancelButtonText: 'Cancel', + confirmButtonText: $t('prompt.photon_lobby_timeout.ok'), + cancelButtonText: $t('prompt.photon_lobby_timeout.cancel'), inputValue: this.photonLobbyTimeoutThreshold / 1000, inputPattern: /\d+$/, - inputErrorMessage: 'Valid number is required', + inputErrorMessage: $t( + 'prompt.photon_lobby_timeout.input_error' + ), callback: (action, instance) => { if ( action === 'confirm' && @@ -13995,15 +14110,15 @@ speechSynthesis.getVoices(); $app.methods.promptAutoClearVRCXCacheFrequency = function () { this.$prompt( - 'Enter amount of hours, larger values may impact RAM usage and performance (default: 24, disabled: 0)', - 'Clear VRCX Cache Timer', + $t('prompt.auto_clear_cache.description'), + $t('prompt.auto_clear_cache.header'), { distinguishCancelAndClose: true, - confirmButtonText: 'OK', - cancelButtonText: 'Cancel', + confirmButtonText: $t('prompt.auto_clear_cache.ok'), + cancelButtonText: $t('prompt.auto_clear_cache.cancel'), inputValue: this.clearVRCXCacheFrequency / 3600 / 2, inputPattern: /\d+$/, - inputErrorMessage: 'Valid number is required', + inputErrorMessage: $t('prompt.auto_clear_cache.input_error'), callback: (action, instance) => { if ( action === 'confirm' && @@ -19560,45 +19675,7 @@ speechSynthesis.getVoices(); // VRChat Config JSON $app.data.VRChatConfigFile = {}; - - $app.data.VRChatConfigList = { - cache_size: { - name: 'Max Cache Size [GB] (min 20)', - default: '20', - type: 'number', - min: 20 - }, - cache_expiry_delay: { - name: 'Cache Expiry [Days] (30 - 150)', - default: '30', - type: 'number', - min: 30, - max: 150 - }, - cache_directory: { - name: 'Custom Cache Folder Location', - default: '%AppData%\\..\\LocalLow\\VRChat\\vrchat' - }, - dynamic_bone_max_affected_transform_count: { - name: 'Dynamic Bones Limit Max Transforms (0 disable all transforms)', - default: '32', - type: 'number', - min: 0 - }, - dynamic_bone_max_collider_check_count: { - name: 'Dynamic Bones Limit Max Collider Collisions (0 disable all colliders)', - default: '8', - type: 'number', - min: 0 - }, - fpv_steadycam_fov: { - name: 'First-Person Steadycam FOV', - default: '50', - type: 'number', - min: 30, - max: 110 - } - }; + $app.data.VRChatConfigList = {}; $app.methods.readVRChatConfigFile = async function () { this.VRChatConfigFile = {}; @@ -19630,6 +19707,44 @@ speechSynthesis.getVoices(); }); $app.methods.showVRChatConfig = async function () { + this.VRChatConfigList = { + cache_size: { + name: $t('dialog.config_json.max_cache_size'), + default: '20', + type: 'number', + min: 20 + }, + cache_expiry_delay: { + name: $t('dialog.config_json.cache_expiry_delay'), + default: '30', + type: 'number', + min: 30, + max: 150 + }, + cache_directory: { + name: $t('dialog.config_json.cache_directory'), + default: '%AppData%\\..\\LocalLow\\VRChat\\vrchat' + }, + // dynamic_bone_max_affected_transform_count: { + // name: 'Dynamic Bones Limit Max Transforms (0 disable all transforms)', + // default: '32', + // type: 'number', + // min: 0 + // }, + // dynamic_bone_max_collider_check_count: { + // name: 'Dynamic Bones Limit Max Collider Collisions (0 disable all colliders)', + // default: '8', + // type: 'number', + // min: 0 + // }, + fpv_steadycam_fov: { + name: $t('dialog.config_json.fpv_steadycam_fov'), + default: '50', + type: 'number', + min: 30, + max: 110 + } + }; await this.readVRChatConfigFile(); this.$nextTick(() => adjustDialogZ(this.$refs.VRChatConfigDialog.$el)); this.VRChatConfigDialog.visible = true; @@ -22662,24 +22777,32 @@ speechSynthesis.getVoices(); }; $app.methods.promptNewLocalWorldFavoriteGroup = function () { - this.$prompt('Enter a world favorite group name', 'New Group', { - distinguishCancelAndClose: true, - confirmButtonText: 'OK', - cancelButtonText: 'Cancel', - inputPattern: /\S+/, - inputErrorMessage: 'Name is required', - callback: (action, instance) => { - if (action === 'confirm' && instance.inputValue) { - this.newLocalWorldFavoriteGroup(instance.inputValue); + this.$prompt( + $t('prompt.new_local_favorite_group.description'), + $t('prompt.new_local_favorite_group.header'), + { + distinguishCancelAndClose: true, + confirmButtonText: $t('prompt.new_local_favorite_group.ok'), + cancelButtonText: $t('prompt.new_local_favorite_group.cancel'), + inputPattern: /\S+/, + inputErrorMessage: $t( + 'prompt.new_local_favorite_group.input_error' + ), + callback: (action, instance) => { + if (action === 'confirm' && instance.inputValue) { + this.newLocalWorldFavoriteGroup(instance.inputValue); + } } } - }); + ); }; $app.methods.newLocalWorldFavoriteGroup = function (group) { if (this.localWorldFavoriteGroups.includes(group)) { $app.$message({ - message: `Group already exists with the name ${group}`, + message: $t('prompt.new_local_favorite_group.message.error', { + name: group + }), type: 'error' }); return; @@ -22694,28 +22817,41 @@ speechSynthesis.getVoices(); }; $app.methods.promptLocalWorldFavoriteGroupRename = function (group) { - this.$prompt('Enter a world favorite group name', 'Rename Group', { - distinguishCancelAndClose: true, - confirmButtonText: 'Save', - cancelButtonText: 'Cancel', - inputPattern: /\S+/, - inputErrorMessage: 'Name is required', - inputValue: group, - callback: (action, instance) => { - if (action === 'confirm' && instance.inputValue) { - this.renameLocalWorldFavoriteGroup( - instance.inputValue, - group - ); + this.$prompt( + $t('prompt.local_favorite_group_rename.description'), + $t('prompt.local_favorite_group_rename.header'), + { + distinguishCancelAndClose: true, + confirmButtonText: $t( + 'prompt.local_favorite_group_rename.save' + ), + cancelButtonText: $t( + 'prompt.local_favorite_group_rename.cancel' + ), + inputPattern: /\S+/, + inputErrorMessage: $t( + 'prompt.local_favorite_group_rename.input_error' + ), + inputValue: group, + callback: (action, instance) => { + if (action === 'confirm' && instance.inputValue) { + this.renameLocalWorldFavoriteGroup( + instance.inputValue, + group + ); + } } } - }); + ); }; $app.methods.renameLocalWorldFavoriteGroup = function (newName, group) { if (this.localWorldFavoriteGroups.includes(newName)) { $app.$message({ - message: `Group already exists with the name ${newName}`, + message: $t( + 'prompt.local_favorite_group_rename.message.error', + {name: newName} + ), type: 'error' }); return; @@ -22805,15 +22941,17 @@ speechSynthesis.getVoices(); $app.methods.promptSetPendingOffline = function () { this.$prompt( - 'Set pending offline delay in seconds (default: 110)', - 'Pending Offline', + $t('prompt.pending_offline_delay.description'), + $t('prompt.pending_offline_delay.header'), { distinguishCancelAndClose: true, - confirmButtonText: 'Save', - cancelButtonText: 'Cancel', + confirmButtonText: $t('prompt.pending_offline_delay.save'), + cancelButtonText: $t('prompt.pending_offline_delay.cancel'), inputValue: this.pendingOfflineDelay / 1000, inputPattern: /\d+$/, - inputErrorMessage: 'Valid number is required', + inputErrorMessage: $t( + 'prompt.pending_offline_delay.input_error' + ), callback: (action, instance) => { if ( action === 'confirm' && @@ -24102,6 +24240,37 @@ speechSynthesis.getVoices(); ); }; + // App: Language + + $app.data.appLanguage = 'en'; + if (configRepository.getString('VRCX_appLanguage')) { + $app.data.appLanguage = configRepository.getString('VRCX_appLanguage'); + i18n.locale = $app.data.appLanguage; + } else { + AppApi.CurrentLanguage().then((result) => { + if (!result) { + console.error('Failed to get current language'); + $app.changeAppLanguage('en'); + return; + } + var lang = result.split('-')[0]; + i18n.availableLocales.forEach((ref) => { + var refLang = ref.split('_')[0]; + if (refLang === lang) { + $app.changeAppLanguage(ref); + } + }); + }); + } + + $app.methods.changeAppLanguage = function (language) { + console.log('Language changed:', language); + this.appLanguage = language; + i18n.locale = language; + configRepository.setString('VRCX_appLanguage', language); + this.updateVRConfigVars(); + }; + $app = new Vue($app); window.$app = $app; })(); diff --git a/html/src/index.pug b/html/src/index.pug index 11d1be82..217c48c9 100644 --- a/html/src/index.pug +++ b/html/src/index.pug @@ -18,7 +18,7 @@ html el-button(type="default" @click="showVRCXUpdateDialog" size="mini" icon="el-icon-download" circle) div(style="width:300px;margin:auto") div(style="margin:15px" v-if="Object.keys(loginForm.savedCredentials).length !== 0") - h2(style="font-weight:bold;text-align:center;margin:0") Saved Accounts + h2(style="font-weight:bold;text-align:center;margin:0") {{ $t("view.login.savedAccounts") }} .x-friend-list(style="margin-top:10px") .x-friend-item(v-for="user in loginForm.savedCredentials" :key="user.user.id") .x-friend-item(@click="relogin(user)" style="width:202px;padding:0") @@ -30,27 +30,27 @@ html span.extra(v-text="user.loginParmas.endpoint") el-button(type="default" @click="deleteSavedLogin(user.user.username)" size="mini" icon="el-icon-delete" circle) div(style="margin:15px") - h2(style="font-weight:bold;text-align:center;margin:0") Login + h2(style="font-weight:bold;text-align:center;margin:0") {{ $t("view.login.login") }} el-form(ref="loginForm" :model="loginForm" :rules="loginForm.rules" @submit.native.prevent="login()") - el-form-item(label="Username or Email" prop="username" required) - el-input(v-model="loginForm.username" name="username" placeholder="Username or Email" clearable) - el-form-item(label="Password" prop="password" required style="margin-top:10px") - el-input(type="password" v-model="loginForm.password" name="password" placeholder="Password" clearable show-password) - el-checkbox(v-model="loginForm.saveCredentials" style="margin-top:15px") Save Credentials - el-checkbox(v-model="enableCustomEndpoint" @change="toggleCustomEndpoint" style="margin-top:10px") Dev Endpoint - el-form-item(v-if="enableCustomEndpoint" label="Endpont" prop="endpoint" style="margin-top:10px") + el-form-item(:label="$t('view.login.field.username')" prop="username" required) + el-input(v-model="loginForm.username" name="username" :placeholder="$t('view.login.field.username')" clearable) + el-form-item(:label="$t('view.login.field.password')" prop="password" required style="margin-top:10px") + el-input(type="password" v-model="loginForm.password" name="password" :placeholder="$t('view.login.field.password')" clearable show-password) + el-checkbox(v-model="loginForm.saveCredentials" style="margin-top:15px") {{ $t("view.login.field.saveCredentials") }} + el-checkbox(v-model="enableCustomEndpoint" @change="toggleCustomEndpoint" style="margin-top:10px") {{ $t("view.login.field.devEndpoint") }} + el-form-item(v-if="enableCustomEndpoint" :label="$t('view.login.field.endpoint')" prop="endpoint" style="margin-top:10px") el-input(v-model="loginForm.endpoint" name="endpoint" :placeholder="API.endpointDomainVrchat" clearable) - el-form-item(v-if="enableCustomEndpoint" label="WebSocket" prop="endpoint" style="margin-top:10px") + el-form-item(v-if="enableCustomEndpoint" :label="$t('view.login.field.websocket')" prop="endpoint" style="margin-top:10px") el-input(v-model="loginForm.websocket" name="websocket" :placeholder="API.websocketDomainVrchat" clearable) el-form-item(style="margin-top:15px") - el-button(native-type="submit" type="primary" :loading="loginForm.loading" style="width:100%") Login - el-button(type="primary" @click="openExternalLink('https://vrchat.com/register')" :loading="loginForm.loading" style="width:100%") Register + el-button(native-type="submit" type="primary" :loading="loginForm.loading" style="width:100%") {{ $t("view.login.login") }} + el-button(type="primary" @click="openExternalLink('https://vrchat.com/register')" :loading="loginForm.loading" style="width:100%") {{ $t("view.login.register") }} div(style="text-align:center;font-size:12px") - p #[a(@click="openExternalLink('https://vrchat.com/home/password')") Forgot password?] + p #[a(@click="openExternalLink('https://vrchat.com/home/password')") {{ $t("view.login.forgotPassword") }}] p © 2019-2022 #[a(@click="openExternalLink('https://github.com/pypy-vrc')") pypy] (mina#5656) & #[a(@click="openExternalLink('https://github.com/Natsumi-sama')") Natsumi] - p VRCX is an assistant application for provide information about manage friendship. this application uses unofficial VRChat API (VRCSDK). - p VRCX isn't endorsed by VRChat and doesn't reflect the views or opinions of VRChat or anyone officially involved in producing or managing VRChat. VRChat is trademark of VRChat Inc. VRChat © VRChat Inc. - p pypy or Natsumi aren't responsible for any problems caused by VRCX. Use at your own risk! + p {{ $t("view.settings.general.legal_notice.info") }} + p {{ $t("view.settings.general.legal_notice.disclaimer1") }} + p {{ $t("view.settings.general.legal_notice.disclaimer2") }} //- menu .x-menu-container @@ -64,17 +64,17 @@ html i(class=icon) template(#title) span= name - +menuitem('feed', 'Feed', 'el-icon-news') - +menuitem('gameLog', 'Game Log', 'el-icon-s-data') - +menuitem('playerList', 'Player List', 'el-icon-tickets') - +menuitem('search', 'Search', 'el-icon-search') - +menuitem('favorite', 'Favorites', 'el-icon-star-off') - +menuitem('friendLog', 'Friend Log', 'el-icon-notebook-2') - +menuitem('moderation', 'Moderation', 'el-icon-finished') - +menuitem('notification', 'Notification', 'el-icon-bell') - +menuitem('friendsList', 'Friends List', 'el-icon-s-management') - +menuitem('profile', 'Profile', 'el-icon-user') - +menuitem('settings', 'Settings', 'el-icon-s-tools') + +menuitem('feed', "{{ $t('nav_tooltip.feed') }}", 'el-icon-news') + +menuitem('gameLog', "{{ $t('nav_tooltip.game_log') }}", 'el-icon-s-data') + +menuitem('playerList', "{{ $t('nav_tooltip.player_list') }}", 'el-icon-tickets') + +menuitem('search', "{{ $t('nav_tooltip.search') }}", 'el-icon-search') + +menuitem('favorite', "{{ $t('nav_tooltip.favorites') }}", 'el-icon-star-off') + +menuitem('friendLog', "{{ $t('nav_tooltip.friend_log') }}", 'el-icon-notebook-2') + +menuitem('moderation', "{{ $t('nav_tooltip.moderation') }}", 'el-icon-finished') + +menuitem('notification', "{{ $t('nav_tooltip.notification') }}", 'el-icon-bell') + +menuitem('friendsList', "{{ $t('nav_tooltip.friend_list') }}", 'el-icon-s-management') + +menuitem('profile', "{{ $t('nav_tooltip.profile') }}", 'el-icon-user') + +menuitem('settings', "{{ $t('nav_tooltip.settings') }}", 'el-icon-s-tools') //- playerList .x-container(v-show="$refs.menu && $refs.menu.activeIndex === 'playerList'") @@ -90,15 +90,15 @@ html div span.x-link(v-text="currentInstanceWorld.ref.authorName" @click="showUserDialog(currentInstanceWorld.ref.authorId)" style="color:#909399;font-family:monospace") div(style="margin-top:5px") - el-tag(v-if="currentInstanceWorld.ref.$isLabs" type="primary" effect="plain" size="mini" style="margin-right:5px") Labs - el-tag(v-else-if="currentInstanceWorld.ref.releaseStatus === 'public'" type="success" effect="plain" size="mini" style="margin-right:5px") Public - el-tag(v-else-if="currentInstanceWorld.ref.releaseStatus === 'private'" type="danger" effect="plain" size="mini" style="margin-right:5px") Private + el-tag(v-if="currentInstanceWorld.ref.$isLabs" type="primary" effect="plain" size="mini" style="margin-right:5px") {{ $t('dialog.world.tags.labs') }} + el-tag(v-else-if="currentInstanceWorld.ref.releaseStatus === 'public'" type="success" effect="plain" size="mini" style="margin-right:5px") {{ $t('dialog.world.tags.public') }} + el-tag(v-else-if="currentInstanceWorld.ref.releaseStatus === 'private'" type="danger" effect="plain" size="mini" style="margin-right:5px") {{ $t('dialog.world.tags.private') }} el-tag.x-tag-platform-pc(v-if="currentInstanceWorld.isPC" type="info" effect="plain" size="mini" style="margin-right:5px") PC el-tag.x-tag-platform-quest(v-if="currentInstanceWorld.isQuest" type="info" effect="plain" size="mini" style="margin-right:5px") Quest el-tag(type="info" effect="plain" size="mini" v-text="currentInstanceWorld.fileSize" style="margin-right:5px") el-tag(v-if="currentInstanceWorld.inCache" type="info" effect="plain" size="mini" style="margin-right:5px") span(v-text="currentInstanceWorld.cacheSize") - | Cache + | {{ $t('dialog.world.tags.cache') }} br location-world(:locationobject="currentInstanceLocation" :currentuserid="API.currentUser.id") span(v-if="lastLocation.playerList.size > 0" style="margin-left:5px") @@ -110,59 +110,59 @@ html div(style="display:flex;flex-direction:column;margin-left:20px") .x-friend-item(style="cursor:default") .detail - span.name Capacity + span.name {{ $t('dialog.world.info.capacity') }} span.extra {{ currentInstanceWorld.ref.capacity | commaNumber }} ({{ currentInstanceWorld.ref.capacity * 2 | commaNumber }}) .x-friend-item(style="cursor:default") .detail - span.name Last Updated + span.name {{ $t('dialog.world.info.last_updated') }} span.extra {{ currentInstanceWorld.fileCreatedAt | formatDate('long') }} .x-friend-item(style="cursor:default") .detail - span.name Created + span.name {{ $t('dialog.world.info.created_at') }} span.extra {{ currentInstanceWorld.ref.created_at | formatDate('long') }} div.photon-event-table(v-if="photonLoggingEnabled") div(style="position:absolute;width:600px;margin-left:195px;z-index:1") - el-select(v-model="photonEventTableTypeFilter" @change="photonEventTableFilterChange" multiple clearable collapse-tags style="flex:1;width:220px" placeholder="Filter") + el-select(v-model="photonEventTableTypeFilter" @change="photonEventTableFilterChange" multiple clearable collapse-tags style="flex:1;width:220px" :placeholder="$t('view.player_list.photon.filter_placeholder')") el-option(v-once v-for="type in photonEventTableTypeFilterList" :key="type" :label="type" :value="type") - el-input(v-model="photonEventTableFilter" @input="photonEventTableFilterChange" placeholder="Search" clearable style="width:150px;margin-left:10px") - el-button(@click="showChatboxBlacklistDialog" style="margin-left:10px") Chatbox Blacklist - el-tooltip(placement="bottom" content="VRCX Companion Status" :disabled="hideTooltips") + el-input(v-model="photonEventTableFilter" @input="photonEventTableFilterChange" :placeholder="$t('view.player_list.photon.search_placeholder')" clearable style="width:150px;margin-left:10px") + el-button(@click="showChatboxBlacklistDialog" style="margin-left:10px") {{ $t('view.player_list.photon.chatbox_blacklist') }} + el-tooltip(placement="bottom" :content="$t('view.player_list.photon.status_tooltip')" :disabled="hideTooltips") div(style="display:inline-block;margin-left:15px;font-size:14px;vertical-align:text-top;margin-top:1px") span(v-if="ipcEnabled && !photonEventIcon") 🟢 span(v-else-if="ipcEnabled") ⚪ span(v-else) 🔴 el-tabs(type="card") - el-tab-pane(label="Current") + el-tab-pane(:label="$t('view.player_list.photon.current')") data-tables(v-bind="photonEventTable" style="margin-bottom:10px") - el-table-column(label="Date" prop="created_at" width="120") + el-table-column(:label="$t('table.playerList.date')" prop="created_at" width="120") template(v-once #default="scope") el-tooltip(placement="right") template(#content) span {{ scope.row.created_at | formatDate('long') }} span {{ scope.row.created_at | formatDate('short') }} - el-table-column(label="User" prop="photonId" width="160") + el-table-column(:label="$t('table.playerList.user')" prop="photonId" width="160") template(v-once #default="scope") span.x-link(v-text="scope.row.displayName" @click="showUserFromPhotonId(scope.row.photonId)" style="padding-right:10px") - el-table-column(label="Type" prop="type" width="140") - el-table-column(label="Details" prop="text") + el-table-column(:label="$t('table.playerList.type')" prop="type" width="140") + el-table-column(:label="$t('table.playerList.detail')" prop="text") template(v-once #default="scope") template(v-if="scope.row.type === 'ChangeAvatar'") span.x-link(v-text="scope.row.avatar.name" @click="showAvatarDialog(scope.row.avatar.id)") |   span(v-if="!scope.row.inCache" style="color:#aaa") #[i.el-icon-download]  - span.avatar-info-public(v-if="scope.row.avatar.releaseStatus === 'public'") (Public) - span.avatar-info-own(v-else-if="scope.row.avatar.releaseStatus === 'private'") (Private) + span.avatar-info-public(v-if="scope.row.avatar.releaseStatus === 'public'") {{ $t('dialog.avatar.labels.public') }} + span.avatar-info-own(v-else-if="scope.row.avatar.releaseStatus === 'private'") {{ $t('dialog.avatar.labels.private') }} template(v-if="scope.row.avatar.description && scope.row.avatar.name !== scope.row.avatar.description") | - {{ scope.row.avatar.description }} template(v-else-if="scope.row.type === 'ChangeStatus'") template(v-if="scope.row.status !== scope.row.previousStatus") el-tooltip(placement="top") template(#content) - span(v-if="scope.row.previousStatus === 'active'") Active - span(v-else-if="scope.row.previousStatus === 'join me'") Join Me - span(v-else-if="scope.row.previousStatus === 'ask me'") Ask Me - span(v-else-if="scope.row.previousStatus === 'busy'") Do Not Disturb - span(v-else) Offline + span(v-if="scope.row.previousStatus === 'active'") {{ $t('dialog.user.status.active') }} + span(v-else-if="scope.row.previousStatus === 'join me'") {{ $t('dialog.user.status.join_me') }} + span(v-else-if="scope.row.previousStatus === 'ask me'") {{ $t('dialog.user.status.ask_me') }} + span(v-else-if="scope.row.previousStatus === 'busy'") {{ $t('dialog.user.status.busy') }} + span(v-else) {{ $t('dialog.user.status.offline') }} i.x-user-status(:class="statusClass(scope.row.previousStatus)") span i.el-icon-right @@ -182,23 +182,23 @@ html span.x-link(v-text="scope.row.avatar.name" @click="showAvatarDialog(scope.row.avatar.id)") |   span(v-if="!scope.row.inCache" style="color:#aaa") #[i.el-icon-download]  - span.avatar-info-public(v-if="scope.row.avatar.releaseStatus === 'public'") (Public) - span.avatar-info-own(v-else-if="scope.row.avatar.releaseStatus === 'private'") (Private) + span.avatar-info-public(v-if="scope.row.avatar.releaseStatus === 'public'") {{ $t('dialog.avatar.labels.public') }} + span.avatar-info-own(v-else-if="scope.row.avatar.releaseStatus === 'private'") {{ $t('dialog.avatar.labels.private') }} span(v-else-if="scope.row.color === 'yellow'" v-text="scope.row.text" style="color:yellow") span(v-else v-text="scope.row.text") - el-tab-pane(label="Previous") + el-tab-pane(:label="$t('view.player_list.photon.previous')") data-tables(v-bind="photonEventTablePrevious" style="margin-bottom:10px") - el-table-column(label="Date" prop="created_at" width="120") + el-table-column(:label="$t('table.playerList.date')" prop="created_at" width="120") template(v-once #default="scope") el-tooltip(placement="right") template(#content) span {{ scope.row.created_at | formatDate('long') }} span {{ scope.row.created_at | formatDate('short') }} - el-table-column(label="User" prop="photonId" width="160") + el-table-column(:label="$t('table.playerList.user')" prop="photonId" width="160") template(v-once #default="scope") span.x-link(v-text="scope.row.displayName" @click="lookupUser(scope.row)" style="padding-right:10px") - el-table-column(label="Type" prop="type" width="140") - el-table-column(label="Details" prop="text") + el-table-column(:label="$t('table.playerList.type')" prop="type" width="140") + el-table-column(:label="$t('table.playerList.detail')" prop="text") template(v-once #default="scope") template(v-if="scope.row.type === 'ChangeAvatar'") span.x-link(v-text="scope.row.avatar.name" @click="showAvatarDialog(scope.row.avatar.id)") @@ -212,21 +212,21 @@ html template(v-if="scope.row.status !== scope.row.previousStatus") el-tooltip(placement="top") template(#content) - span(v-if="scope.row.previousStatus === 'active'") Active - span(v-else-if="scope.row.previousStatus === 'join me'") Join Me - span(v-else-if="scope.row.previousStatus === 'ask me'") Ask Me - span(v-else-if="scope.row.previousStatus === 'busy'") Do Not Disturb - span(v-else) Offline + span(v-if="scope.row.previousStatus === 'active'") {{ $t('dialog.user.status.active') }} + span(v-else-if="scope.row.previousStatus === 'join me'") {{ $t('dialog.user.status.join_me') }} + span(v-else-if="scope.row.previousStatus === 'ask me'") {{ $t('dialog.user.status.ask_me') }} + span(v-else-if="scope.row.previousStatus === 'busy'") {{ $t('dialog.user.status.busy') }} + span(v-else) {{ $t('dialog.user.status.offline') }} i.x-user-status(:class="statusClass(scope.row.previousStatus)") span i.el-icon-right el-tooltip(placement="top") template(#content) - span(v-if="scope.row.status === 'active'") Active - span(v-else-if="scope.row.status === 'join me'") Join Me - span(v-else-if="scope.row.status === 'ask me'") Ask Me - span(v-else-if="scope.row.status === 'busy'") Do Not Disturb - span(v-else) Offline + span(v-if="scope.row.status === 'active'") {{ $t('dialog.user.status.active') }} + span(v-else-if="scope.row.status === 'join me'") {{ $t('dialog.user.status.join_me') }} + span(v-else-if="scope.row.status === 'ask me'") {{ $t('dialog.user.status.ask_me') }} + span(v-else-if="scope.row.status === 'busy'") {{ $t('dialog.user.status.busy') }} + span(v-else) {{ $t('dialog.user.status.offline') }} i.x-user-status(:class="statusClass(scope.row.status)") span(v-if="scope.row.statusDescription !== scope.row.previousStatusDescription" v-text="scope.row.statusDescription" style="margin-left:5px") span.x-link(v-else-if="scope.row.type === 'PortalSpawn'" @click="showWorldDialog(scope.row.location, scope.row.shortName)") @@ -242,16 +242,16 @@ html span(v-else v-text="scope.row.text") div.current-instance-table data-tables(v-bind="currentInstanceUserList" @row-click="selectCurrentInstanceRow" style="margin-top:10px;cursor:pointer") - el-table-column(label="Avatar" width="70" prop="photo") + el-table-column(:label="$t('table.playerList.avatar')" width="70" prop="photo") template(v-once #default="scope") template(v-if="userImage(scope.row.ref)") el-popover(placement="right" height="500px" trigger="hover") img.friends-list-avatar(slot="reference" v-lazy="userImage(scope.row.ref)") img.friends-list-avatar(v-lazy="userImageFull(scope.row.ref)" style="height:500px;cursor:pointer" @click="downloadAndSaveImage(userImageFull(scope.row.ref))") - el-table-column(label="Timer" width="90" prop="timer" sortable) + el-table-column(:label="$t('table.playerList.timer')" width="90" prop="timer" sortable) template(v-once #default="scope") timer(:epoch="scope.row.timer") - el-table-column(v-if="photonLoggingEnabled" label="Photon Id" width="110" prop="photonId" sortable) + el-table-column(v-if="photonLoggingEnabled" :label="$t('table.playerList.photonId')" width="110" prop="photonId" sortable) template(v-once #default="scope") template(v-if="chatboxUserBlacklist.has(scope.row.ref.id)") el-tooltip(placement="left" content="Unblock chatbox messages") @@ -260,7 +260,7 @@ html el-tooltip(placement="left" content="Block chatbox messages") el-button(type="text" icon="el-icon-microphone" size="mini" style="margin-right:5px" @click.stop="addChatboxUserBlacklist(scope.row.ref)") span(v-text="scope.row.photonId") - el-table-column(label="Icons" prop="isMaster" width="100") + el-table-column(:label="$t('table.playerList.icon')" prop="isMaster" width="100") template(v-once #default="scope") el-tooltip(v-if="scope.row.isMaster" placement="left" content="Instance Master") span 👑 @@ -268,7 +268,7 @@ html span 💚 el-tooltip(v-if="scope.row.timeoutTime" placement="left" content="Timeout") span(style="color:red") 🔴{{ scope.row.timeoutTime }}s - el-table-column(label="Platform" prop="inVRMode" width="80") + el-table-column(:label="$t('table.playerList.platform')" prop="inVRMode" width="80") template(v-once #default="scope") template(v-if="scope.row.ref.last_platform") span(v-if="scope.row.ref.last_platform === 'standalonewindows'" style="color:#409eff") PC @@ -277,11 +277,11 @@ html template(v-if="scope.row.inVRMode !== null") span(v-if="scope.row.inVRMode") VR span(v-else) D - el-table-column(label="Display Name" min-width="140" prop="ref.displayName") + el-table-column(:label="$t('table.playerList.displayName')" min-width="140" prop="ref.displayName") template(v-once #default="scope") span(v-if="randomUserColours" v-text="scope.row.ref.displayName" :style="{'color':scope.row.ref.$userColour}") span(v-else v-text="scope.row.ref.displayName") - el-table-column(label="Status" min-width="180" prop="ref.status") + el-table-column(:label="$t('table.playerList.status')" min-width="180" prop="ref.status") template(v-once #default="scope") template(v-if="scope.row.ref.status") i.x-user-status(:class="statusClass(scope.row.ref.status)") @@ -290,16 +290,16 @@ html //- el-table-column(label="Group" min-width="180" prop="groupOnNameplate" sortable) //- template(v-once #default="scope") //- span(v-text="scope.row.groupOnNameplate") - el-table-column(label="Rank" width="110" prop="$trustSortNum" sortable="custom") + el-table-column(:label="$t('table.playerList.rank')" width="110" prop="$trustSortNum" sortable="custom") template(v-once #default="scope") span.name(v-text="scope.row.ref.$trustLevel" :class="scope.row.ref.$trustClass") - el-table-column(label="Language" width="100" prop="ref.$languages") + el-table-column(:label="$t('table.playerList.language')" width="100" prop="ref.$languages") template(v-once #default="scope") el-tooltip(v-for="item in scope.row.ref.$languages" :key="item.key" placement="top") template(#content) span {{ item.value }} ({{ item.key }}) span.flags(:class="languageClass(item.key)" style="display:inline-block;margin-left:5px") - el-table-column(label="Bio Links" width="100" prop="ref.bioLinks") + el-table-column(:label="$t('table.playerList.bioLink')" width="100" prop="ref.bioLinks") template(v-once #default="scope") el-tooltip(v-if="link" v-for="(link, index) in scope.row.ref.bioLinks" :key="index") template(#content) @@ -312,11 +312,11 @@ html template(#tool) div(style="margin:0 0 10px;display:flex;align-items:center") div(style="flex:none;margin-right:10px") - el-tooltip(placement="bottom" content="Filter VIP only" :disabled="hideTooltips") + el-tooltip(placement="bottom" :content="$t('view.feed.favorites_only_tooltip')" :disabled="hideTooltips") el-switch(v-model="feedTable.vip" @change="feedTableLookup" active-color="#13ce66") - el-select(v-model="feedTable.filter" @change="feedTableLookup" multiple clearable collapse-tags style="flex:1" placeholder="Filter") + el-select(v-model="feedTable.filter" @change="feedTableLookup" multiple clearable collapse-tags style="flex:1" :placeholder="$t('view.feed.filter_placeholder')") el-option(v-once v-for="type in ['GPS', 'Online', 'Offline', 'Status', 'Avatar', 'Bio']" :key="type" :label="type" :value="type") - el-input(v-model="feedTable.search" placeholder="Search" @keyup.native.13="feedTableLookup" @change="feedTableLookup" clearable style="flex:none;width:150px;margin:0 10px") + el-input(v-model="feedTable.search" :placeholder="$t('view.feed.search_placeholder')" @keyup.native.13="feedTableLookup" @change="feedTableLookup" clearable style="flex:none;width:150px;margin:0 10px") //- el-tooltip(placement="bottom" content="Clear feed" :disabled="hideTooltips") //- el-button(type="default" @click="clearFeed()" icon="el-icon-delete" circle style="flex:none") el-table-column(type="expand" width="20") @@ -347,11 +347,11 @@ html template(v-else-if="scope.row.type === 'Status'") el-tooltip(placement="top") template(#content) - span(v-if="scope.row.previousStatus === 'active'") Active - span(v-else-if="scope.row.previousStatus === 'join me'") Join Me - span(v-else-if="scope.row.previousStatus === 'ask me'") Ask Me - span(v-else-if="scope.row.previousStatus === 'busy'") Do Not Disturb - span(v-else) Offline + span(v-if="scope.row.previousStatus === 'active'") {{ $t('dialog.user.status.active') }} + span(v-else-if="scope.row.previousStatus === 'join me'") {{ $t('dialog.user.status.join_me') }} + span(v-else-if="scope.row.previousStatus === 'ask me'") {{ $t('dialog.user.status.ask_me') }} + span(v-else-if="scope.row.previousStatus === 'busy'") {{ $t('dialog.user.status.busy') }} + span(v-else) {{ $t('dialog.user.status.offline') }} i.x-user-status(:class="statusClass(scope.row.previousStatus)") span(v-text="scope.row.previousStatusDescription") br @@ -359,11 +359,11 @@ html i.el-icon-right el-tooltip(placement="top") template(#content) - span(v-if="scope.row.status === 'active'") Active - span(v-else-if="scope.row.status === 'join me'") Join Me - span(v-else-if="scope.row.status === 'ask me'") Ask Me - span(v-else-if="scope.row.status === 'busy'") Do Not Disturb - span(v-else) Offline + span(v-if="scope.row.status === 'active'") {{ $t('dialog.user.status.active') }} + span(v-else-if="scope.row.status === 'join me'") {{ $t('dialog.user.status.join_me') }} + span(v-else-if="scope.row.status === 'ask me'") {{ $t('dialog.user.status.ask_me') }} + span(v-else-if="scope.row.status === 'busy'") {{ $t('dialog.user.status.busy') }} + span(v-else) {{ $t('dialog.user.status.offline') }} i.x-user-status(:class="statusClass(scope.row.status)") span(v-text="scope.row.statusDescription") template(v-else-if="scope.row.type === 'Bio'") @@ -371,17 +371,17 @@ html span i.el-icon-right pre(v-text="scope.row.bio" style="font-family:inherit;font-size:12px;white-space:pre-wrap;margin:0 0.5em 0 0") - el-table-column(label="Date" prop="created_at" sortable="custom" width="120") + el-table-column(:label="$t('table.feed.date')" prop="created_at" sortable="custom" width="120") template(v-once #default="scope") el-tooltip(placement="right") template(#content) span {{ scope.row.created_at | formatDate('long') }} span {{ scope.row.created_at | formatDate('short') }} - el-table-column(label="Type" prop="type" width="70") - el-table-column(label="User" prop="displayName" width="180") + el-table-column(:label="$t('table.feed.type')" prop="type" width="70") + el-table-column(:label="$t('table.feed.user')" prop="displayName" width="180") template(v-once #default="scope") span.x-link(v-text="scope.row.displayName" @click="showUserDialog(scope.row.userId)") - el-table-column(label="Detail") + el-table-column(:label="$t('table.feed.detail')") template(v-once #default="scope") template(v-if="scope.row.type === 'GPS'") location(v-if="scope.row.location" :location="scope.row.location" :hint="scope.row.worldName" :grouphint="scope.row.groupName") @@ -391,30 +391,30 @@ html template(v-if="scope.row.statusDescription === scope.row.previousStatusDescription") el-tooltip(placement="top") template(#content) - span(v-if="scope.row.previousStatus === 'active'") Active - span(v-else-if="scope.row.previousStatus === 'join me'") Join Me - span(v-else-if="scope.row.previousStatus === 'ask me'") Ask Me - span(v-else-if="scope.row.previousStatus === 'busy'") Do Not Disturb - span(v-else) Offline + span(v-if="scope.row.previousStatus === 'active'") {{ $t('dialog.user.status.active') }} + span(v-else-if="scope.row.previousStatus === 'join me'") {{ $t('dialog.user.status.join_me') }} + span(v-else-if="scope.row.previousStatus === 'ask me'") {{ $t('dialog.user.status.ask_me') }} + span(v-else-if="scope.row.previousStatus === 'busy'") {{ $t('dialog.user.status.busy') }} + span(v-else) {{ $t('dialog.user.status.offline') }} i.x-user-status(:class="statusClass(scope.row.previousStatus)") span i.el-icon-right el-tooltip(placement="top") template(#content) - span(v-if="scope.row.status === 'active'") Active - span(v-else-if="scope.row.status === 'join me'") Join Me - span(v-else-if="scope.row.status === 'ask me'") Ask Me - span(v-else-if="scope.row.status === 'busy'") Do Not Disturb - span(v-else) Offline + span(v-if="scope.row.status === 'active'") {{ $t('dialog.user.status.active') }} + span(v-else-if="scope.row.status === 'join me'") {{ $t('dialog.user.status.join_me') }} + span(v-else-if="scope.row.status === 'ask me'") {{ $t('dialog.user.status.ask_me') }} + span(v-else-if="scope.row.status === 'busy'") {{ $t('dialog.user.status.busy') }} + span(v-else) {{ $t('dialog.user.status.offline') }} i.x-user-status(:class="statusClass(scope.row.status)") template(v-else) el-tooltip(placement="top") template(#content) - span(v-if="scope.row.status === 'active'") Online - span(v-else-if="scope.row.status === 'join me'") Join Me - span(v-else-if="scope.row.status === 'ask me'") Ask Me - span(v-else-if="scope.row.status === 'busy'") Do Not Disturb - span(v-else) Offline + span(v-if="scope.row.status === 'active'") {{ $t('dialog.user.status.active') }} + span(v-else-if="scope.row.status === 'join me'") {{ $t('dialog.user.status.join_me') }} + span(v-else-if="scope.row.status === 'ask me'") {{ $t('dialog.user.status.ask_me') }} + span(v-else-if="scope.row.status === 'busy'") {{ $t('dialog.user.status.busy') }} + span(v-else) {{ $t('dialog.user.status.offline') }} i.x-user-status(:class="statusClass(scope.row.status)") span ‎ span(v-text="scope.row.statusDescription") @@ -428,32 +428,32 @@ html data-tables(v-bind="gameLogTable" v-loading="gameLogTable.loading") template(#tool) div(style="margin:0 0 10px;display:flex;align-items:center") - el-select(v-model="gameLogTable.filter" @change="gameLogTableLookup" multiple clearable collapse-tags style="flex:1" placeholder="Filter") + el-select(v-model="gameLogTable.filter" @change="gameLogTableLookup" multiple clearable collapse-tags style="flex:1" :placeholder="$t('view.game_log.filter_placeholder')") el-option(v-once v-for="type in ['Location', 'OnPlayerJoined', 'OnPlayerLeft', 'PortalSpawn', 'Event', 'VideoPlay']" :key="type" :label="type" :value="type") - el-input(v-model="gameLogTable.search" placeholder="Search" @keyup.native.13="gameLogTableLookup" @change="gameLogTableLookup" clearable style="flex:none;width:150px;margin:0 10px") + el-input(v-model="gameLogTable.search" :placeholder="$t('view.game_log.search_placeholder')" @keyup.native.13="gameLogTableLookup" @change="gameLogTableLookup" clearable style="flex:none;width:150px;margin:0 10px") //- el-tooltip(placement="bottom" content="Reload game log" :disabled="hideTooltips") //- el-button(type="default" @click="resetGameLog" icon="el-icon-refresh" circle style="flex:none") - el-table-column(label="Date" prop="created_at" sortable="custom" width="120") + el-table-column(:label="$t('table.gameLog.date')" prop="created_at" sortable="custom" width="120") template(v-once #default="scope") el-tooltip(placement="right") template(#content) span {{ scope.row.created_at | formatDate('long') }} span {{ scope.row.created_at | formatDate('short') }} - el-table-column(label="Type" prop="type" width="120") + el-table-column(:label="$t('table.gameLog.type')" prop="type" width="120") template(v-once #default="scope") span.x-link(v-if="scope.row.location && scope.row.type !== 'Location'" v-text="scope.row.type" @click="showWorldDialog(scope.row.location)") span(v-else v-text="scope.row.type") - el-table-column(label="User" prop="displayName" width="180") + el-table-column(:label="$t('table.gameLog.user')" prop="displayName" width="180") template(v-once #default="scope") span.x-link(v-if="scope.row.displayName" v-text="scope.row.displayName" @click="lookupUser(scope.row)" style="padding-right:10px") - el-table-column(label="Detail" prop="data") + el-table-column(:label="$t('table.gameLog.detail')" prop="data") template(v-once #default="scope") location(v-if="scope.row.type === 'Location'" :location="scope.row.location" :hint="scope.row.worldName" :grouphint="scope.row.groupName") location(v-else-if="scope.row.type === 'PortalSpawn'" :location="scope.row.instanceId" :hint="scope.row.worldName" :grouphint="scope.row.groupName") template(v-else-if="scope.row.type === 'Event'") span(v-text="scope.row.data") template(v-else-if="scope.row.type === 'VideoPlay'") - span(v-if="scope.row.videoId") {{ scope.row.videoId }}: + span(v-if="scope.row.videoId") {{ scope.row.videoId }}: span(v-if="scope.row.videoId === 'LSMedia'" v-text="scope.row.videoName") span.x-link(v-else-if="scope.row.videoName" @click="openExternalLink(scope.row.videoUrl)" v-text="scope.row.videoName") span.x-link(v-else @click="openExternalLink(scope.row.videoUrl)" v-text="scope.row.videoUrl") @@ -463,11 +463,11 @@ html //- search .x-container(v-show="$refs.menu && $refs.menu.activeIndex === 'search'") div(style="margin:0 0 10px;display:flex;align-items:center") - el-input(v-model="searchText" placeholder="Search" @keyup.native.13="search()" style="flex:1") - el-tooltip(placement="bottom" content="Clear search results" :disabled="hideTooltips") + el-input(v-model="searchText" :placeholder="$t('view.search.search_placeholder')" @keyup.native.13="search()" style="flex:1") + el-tooltip(placement="bottom" :content="$t('view.search.clear_results_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="clearSearch()" icon="el-icon-delete" circle style="flex:none;margin-left:10px") el-tabs(ref="searchTab" type="card" style="margin-top:15px") - el-tab-pane(label="User" v-loading="isSearchUserLoading" style="min-height:60px") + el-tab-pane(:label="$t('view.search.user.header')" v-loading="isSearchUserLoading" style="min-height:60px") .x-friend-list .x-friend-item(v-for="user in searchUserResults" :key="user.id" @click="showUserDialog(user.id)") template(v-once) @@ -478,14 +478,14 @@ html span.extra(v-if="randomUserColours" v-text="user.$trustLevel" :class="user.$trustClass") span.extra(v-else v-text="user.$trustLevel" :style="{'color':user.$userColour}") el-button-group(style="margin-top:15px") - el-button(v-if="searchUserParams.offset" @click="moreSearchUser(-1)" icon="el-icon-back" size="small") Prev - el-button(v-if="searchUserResults.length" @click="moreSearchUser(1)" icon="el-icon-right" size="small") Next - el-tab-pane(label="World" v-loading="isSearchWorldLoading" style="min-height:60px") + el-button(v-if="searchUserParams.offset" @click="moreSearchUser(-1)" icon="el-icon-back" size="small") {{ $t('view.search.prev_page') }} + el-button(v-if="searchUserResults.length" @click="moreSearchUser(1)" icon="el-icon-right" size="small") {{ $t('view.search.next_page') }} + el-tab-pane(:label="$t('view.search.world.header')" v-loading="isSearchWorldLoading" style="min-height:60px") el-dropdown(@command="(row) => searchWorld(row)" size="small" trigger="click" style="margin-bottom:15px") - el-button(size="small") Search by Category #[i.el-icon-arrow-down.el-icon--right] + el-button(size="small") {{ $t('view.search.world.category') }} #[i.el-icon-arrow-down.el-icon--right] el-dropdown-menu(#default="dropdown") el-dropdown-item(v-for="row in API.cachedConfig.dynamicWorldRows" :key="row.index" v-text="row.name" :command="row") - el-checkbox(v-model="searchWorldLabs" style="margin-left:10px") Include community labs + el-checkbox(v-model="searchWorldLabs" style="margin-left:10px") {{ $t('view.search.world.community_lab') }} .x-friend-list .x-friend-item(v-for="world in searchWorldResults" :key="world.id" @click="showWorldDialog(world.id)") template(v-once) @@ -496,28 +496,28 @@ html span.extra(v-if="world.occupants") {{ world.authorName }} ({{ world.occupants }}) span.extra(v-else v-text="world.authorName") el-button-group(style="margin-top:15px") - el-button(v-if="searchWorldParams.offset" @click="moreSearchWorld(-1)" icon="el-icon-back" size="small") Prev - el-button(v-if="searchWorldResults.length >= 10" @click="moreSearchWorld(1)" icon="el-icon-right" size="small") Next - el-tab-pane(label="Avatar" v-loading="isSearchAvatarLoading" style="min-height:60px") + el-button(v-if="searchWorldParams.offset" @click="moreSearchWorld(-1)" icon="el-icon-back" size="small") {{ $t('view.search.prev_page') }} + el-button(v-if="searchWorldResults.length >= 10" @click="moreSearchWorld(1)" icon="el-icon-right" size="small") {{ $t('view.search.next_page') }} + el-tab-pane(:label="$t('view.search.avatar.header')" v-loading="isSearchAvatarLoading" style="min-height:60px") el-dropdown(v-if="avatarRemoteDatabaseProviderList.length > 1" trigger="click" @click.native.stop size="mini" style="margin-right:5px") - el-button(size="small") Search Provider #[i.el-icon-arrow-down.el-icon--right] + el-button(size="small") {{ $t('view.search.avatar.search_provider') }} #[i.el-icon-arrow-down.el-icon--right] el-dropdown-menu(#default="dropdown") el-dropdown-item(v-for="provider in avatarRemoteDatabaseProviderList" :key="provider" @click.native="setAvatarProvider(provider)") #[i.el-icon-check.el-icon--left(v-if="provider === avatarRemoteDatabaseProvider")] {{ provider }} - el-tooltip(placement="bottom" content="Refresh own avatars" :disabled="hideTooltips") + el-tooltip(placement="bottom" :content="$t('view.search.avatar.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" :loading="userDialog.isAvatarsLoading" @click="refreshUserDialogAvatars()" size="mini" icon="el-icon-refresh" circle) - span(style="font-size:14px;margin-left:5px;margin-right:5px") Results {{ searchAvatarResults.length }} + span(style="font-size:14px;margin-left:5px;margin-right:5px") {{ $t("view.search.avatar.result_count", { count: searchAvatarResults.length }) }} el-radio-group(v-model="searchAvatarFilter" size="mini" style="margin:5px;display:block" @change="searchAvatar") - el-radio(label="all") all - el-radio(label="public") public - el-radio(label="private") private + el-radio(label="all") {{ $t('view.search.avatar.all') }} + el-radio(label="public") {{ $t('view.search.avatar.public') }} + el-radio(label="private") {{ $t('view.search.avatar.private') }} el-radio-group(v-model="searchAvatarFilterRemote" size="mini" style="margin:5px;display:block" @change="searchAvatar") - el-radio(label="all") all - el-radio(label="local") local - el-radio(label="remote" :disabled="!avatarRemoteDatabase") remote + el-radio(label="all") {{ $t('view.search.avatar.all') }} + el-radio(label="local") {{ $t('view.search.avatar.local') }} + el-radio(label="remote" :disabled="!avatarRemoteDatabase") {{ $t('view.search.avatar.remote') }} el-radio-group(:disabled="searchAvatarFilterRemote !== 'local'" v-model="searchAvatarSort" size="mini" style="margin:5px;display:block" @change="searchAvatar") - el-radio(label="name") by name - el-radio(label="update") by update - el-radio(label="created") by created + el-radio(label="name") {{ $t('view.search.avatar.sort_name') }} + el-radio(label="update") {{ $t('view.search.avatar.sort_update') }} + el-radio(label="created") {{ $t('view.search.avatar.sort_created') }} .x-friend-list(style="margin-top:20px") .x-friend-item(v-for="avatar in searchAvatarPage" :key="avatar.id" @click="showAvatarDialog(avatar.id)") template(v-once) @@ -531,25 +531,25 @@ html span.extra(v-text="avatar.releaseStatus" v-else) span.extra(v-text="avatar.authorName") el-button-group(style="margin-top:15px") - el-button(v-if="searchAvatarPageNum" @click="moreSearchAvatar(-1)" icon="el-icon-back" size="small") Prev - el-button(v-if="searchAvatarResults.length > 10 && (searchAvatarPageNum + 1) * 10 < searchAvatarResults.length" @click="moreSearchAvatar(1)" icon="el-icon-right" size="small") Next + el-button(v-if="searchAvatarPageNum" @click="moreSearchAvatar(-1)" icon="el-icon-back" size="small") {{ $t('view.search.prev_page') }} + el-button(v-if="searchAvatarResults.length > 10 && (searchAvatarPageNum + 1) * 10 < searchAvatarResults.length" @click="moreSearchAvatar(1)" icon="el-icon-right" size="small") {{ $t('view.search.next_page') }} //- favorite .x-container(v-show="$refs.menu && $refs.menu.activeIndex === 'favorite'") - el-tooltip(placement="bottom" content="Refresh all favorites" :disabled="hideTooltips") + el-tooltip(placement="bottom" :content="$t('view.favorite.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" :loading="API.isFavoriteLoading" @click="API.refreshFavorites(); getLocalWorldFavorites()" size="small" icon="el-icon-refresh" circle style="position:relative;float:right;z-index:1") el-tabs(ref="favoriteTabRef" type="card" v-loading="API.isFavoriteLoading") - el-tab-pane(label="Friends") + el-tab-pane(:label="$t('view.favorite.friends.header')") el-collapse(v-if="$refs.menu && $refs.menu.activeIndex === 'favorite' && $refs.favoriteTabRef && $refs.favoriteTabRef.currentName === '0'" style="border:0") - el-button(size="small" @click="showFriendExportDialog") Export - el-button(size="small" @click="showFriendImportDialog") Import + el-button(size="small" @click="showFriendExportDialog") {{ $t('view.favorite.export') }} + el-button(size="small" @click="showFriendImportDialog") {{ $t('view.favorite.import') }} el-collapse-item(v-for="group in API.favoriteFriendGroups" :key="group.name") template(slot="title") span(v-text="group.displayName" style="font-weight:bold;font-size:14px;margin-left:10px") span(style="color:#909399;font-size:12px;margin-left:10px") {{ group.count }}/{{ group.capacity }} - el-tooltip(placement="top" content="Rename" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.favorite.rename_tooltip')" :disabled="hideTooltips") el-button(@click.stop="changeFavoriteGroupName(group)" size="mini" icon="el-icon-edit" circle style="margin-left:10px") - el-tooltip(placement="right" content="Clear" :disabled="hideTooltips") + el-tooltip(placement="right" :content="$t('view.favorite.clear_tooltip')" :disabled="hideTooltips") el-button(@click.stop="clearFavoriteGroup(group)" size="mini" icon="el-icon-delete" circle style="margin-left:5px") .x-friend-list(v-if="group.count" style="margin-top:10px") div(style="display:inline-block;width:300px;margin-right:15px" v-for="favorite in favoriteFriends" v-if="favorite.groupKey === group.key" :key="favorite.id" @click="showUserDialog(favorite.id)") @@ -561,35 +561,35 @@ html span.name(v-text="favorite.ref.displayName" :style="{'color':favorite.ref.$userColour}") location.extra(v-if="favorite.ref.location !== 'offline'" :location="favorite.ref.location" :traveling="favorite.ref.travelingToLocation" :link="false") span(v-else v-text="favorite.ref.statusDescription") - el-tooltip(placement="left" content="Move" :disabled="hideTooltips") + el-tooltip(placement="left" :content="$t('view.favorite.move_tooltip')" :disabled="hideTooltips") el-dropdown(trigger="click" @click.native.stop size="mini" style="margin-left:5px") el-button(type="default" icon="el-icon-back" size="mini" circle) el-dropdown-menu(#default="dropdown") template(v-if="groupAPI.name !== group.name" v-for="groupAPI in API.favoriteFriendGroups" :key="groupAPI.name") el-dropdown-item(style="display:block;margin:10px 0" @click.native="moveFavorite(favorite.ref, groupAPI, 'friend')" :disabled="groupAPI.count >= groupAPI.capacity") {{ groupAPI.displayName }} ({{ groupAPI.count }} / {{ groupAPI.capacity }}) - el-tooltip(placement="right" content="Unfavorite" :disabled="hideTooltips") + el-tooltip(placement="right" :content="$t('view.favorite.unfavorite_tooltip')" :disabled="hideTooltips") el-button(@click.stop="deleteFavorite(favorite.id)" size="mini" icon="el-icon-delete" circle style="margin-left:5px") template(v-else) span(v-text="favorite.name || favorite.id") el-button(type="text" icon="el-icon-close" size="mini" @click.stop="deleteFavorite(favorite.id)" style="margin-left:5px") - el-tab-pane(label="Worlds") + el-tab-pane(:label="$t('view.favorite.worlds.header')") el-collapse(v-if="$refs.menu && $refs.menu.activeIndex === 'favorite' && $refs.favoriteTabRef && $refs.favoriteTabRef.currentName === '1'" style="border:0") - el-button(size="small" @click="showWorldExportDialog") Export - el-button(size="small" @click="showWorldImportDialog") Import - span(style="display:block;margin-top:20px") VRChat Favorites + el-button(size="small" @click="showWorldExportDialog") {{ $t('view.favorite.export') }} + el-button(size="small" @click="showWorldImportDialog") {{ $t('view.favorite.import') }} + span(style="display:block;margin-top:20px") {{ $t('view.favorite.worlds.vrchat_favorites') }} el-collapse-item(v-for="group in API.favoriteWorldGroups" :key="group.name") template(slot="title") span(v-text="group.displayName" style="font-weight:bold;font-size:14px;margin-left:10px") i.x-user-status(style="margin-left:5px" :class="userFavoriteWorldsStatus(group.visibility)") span(style="color:#909399;font-size:12px;margin-left:10px") {{ group.count }}/{{ group.capacity }} - el-tooltip(placement="top" content="Change visibility" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.favorite.visibility_tooltip')" :disabled="hideTooltips") el-dropdown(trigger="click" @click.native.stop size="mini" style="margin-left:10px") el-button(type="default" icon="el-icon-view" size="mini" circle) el-dropdown-menu(#default="dropdown") el-dropdown-item(v-if="group.visibility !== visibility" v-for="visibility in worldGroupVisibilityOptions" :key="visibility" style="display:block;margin:10px 0" v-text="visibility" @click.native="changeWorldGroupVisibility(group.name, visibility)") - el-tooltip(placement="top" content="Rename" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.favorite.rename_tooltip')" :disabled="hideTooltips") el-button(@click.stop="changeFavoriteGroupName(group)" size="mini" icon="el-icon-edit" circle style="margin-left:5px") - el-tooltip(placement="right" content="Clear" :disabled="hideTooltips") + el-tooltip(placement="right" :content="$t('view.favorite.clear_tooltip')" :disabled="hideTooltips") el-button(@click.stop="clearFavoriteGroup(group)" size="mini" icon="el-icon-delete" circle style="margin-left:5px") .x-friend-list(v-if="group.count" style="margin-top:10px") div(style="display:inline-block;width:300px;margin-right:15px" v-for="favorite in favoriteWorlds" v-if="favorite.groupKey === group.key" :key="favorite.id" @click="showWorldDialog(favorite.id)") @@ -601,26 +601,26 @@ html span.name(v-text="favorite.ref.name") span.extra(v-if="favorite.ref.occupants") {{ favorite.ref.authorName }} ({{ favorite.ref.occupants }}) span.extra(v-else v-text="favorite.ref.authorName") - el-tooltip(placement="left" content="Move" :disabled="hideTooltips") + el-tooltip(placement="left" :content="$t('view.favorite.move_tooltip')" :disabled="hideTooltips") el-dropdown(trigger="click" @click.native.stop size="mini" style="margin-left:5px") el-button(type="default" icon="el-icon-back" size="mini" circle) el-dropdown-menu(#default="dropdown") template(v-if="groupAPI.name !== group.name" v-for="groupAPI in API.favoriteWorldGroups" :key="groupAPI.name") el-dropdown-item(style="display:block;margin:10px 0" @click.native="moveFavorite(favorite.ref, groupAPI, 'world')" :disabled="groupAPI.count >= groupAPI.capacity") {{ groupAPI.displayName }} ({{ groupAPI.count }} / {{ groupAPI.capacity }}) - el-tooltip(placement="right" content="Unfavorite" :disabled="hideTooltips") + el-tooltip(placement="right" :content="$t('view.favorite.unfavorite_tooltip')" :disabled="hideTooltips") el-button(@click.stop="deleteFavorite(favorite.id)" size="mini" icon="el-icon-delete" circle style="margin-left:5px") template(v-else) span(v-text="favorite.name || favorite.id") el-button(type="text" icon="el-icon-close" size="mini" @click.stop="deleteFavorite(favorite.id)" style="margin-left:5px") - span(style="display:block;margin-top:20px") Local Favorites - el-button(size="small" @click="promptNewLocalWorldFavoriteGroup" style="display:block;margin-top:10px") New Group + span(style="display:block;margin-top:20px") {{ $t('view.favorite.worlds.local_favorites') }} + el-button(size="small" @click="promptNewLocalWorldFavoriteGroup" style="display:block;margin-top:10px") {{ $t('view.favorite.worlds.new_group') }} el-collapse-item(v-for="group in localWorldFavoriteGroups" v-if="localWorldFavorites[group]" :key="group") template(slot="title") span(v-text="group" style="font-weight:bold;font-size:14px;margin-left:10px") span(style="color:#909399;font-size:12px;margin-left:10px") {{ getLocalWorldFavoriteGroupLength(group) }} - el-tooltip(placement="top" content="Rename" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.favorite.rename_tooltip')" :disabled="hideTooltips") el-button(@click.stop="promptLocalWorldFavoriteGroupRename(group)" size="mini" icon="el-icon-edit" circle style="margin-left:10px") - el-tooltip(placement="right" content="Delete" :disabled="hideTooltips") + el-tooltip(placement="right" :content="$t('view.favorite.delete_tooltip')" :disabled="hideTooltips") el-button(@click.stop="promptLocalWorldFavoriteGroupDelete(group)" size="mini" icon="el-icon-delete" circle style="margin-left:5px") .x-friend-list(style="margin-top:10px") div(style="display:inline-block;width:300px;margin-right:15px" v-for="favorite in localWorldFavorites[group]" :key="favorite.id" @click="showWorldDialog(favorite.id)") @@ -632,22 +632,22 @@ html span.name(v-text="favorite.name") span.extra(v-if="favorite.occupants") {{ favorite.authorName }} ({{ favorite.occupants }}) span.extra(v-else v-text="favorite.authorName") - el-tooltip(placement="right" content="Unfavorite" :disabled="hideTooltips") + el-tooltip(placement="right" :content="$t('view.favorite.unfavorite_tooltip')" :disabled="hideTooltips") el-button(@click.stop="removeLocalWorldFavorite(favorite.id, group)" size="mini" icon="el-icon-delete" circle style="margin-left:5px") template(v-else) span(v-text="favorite.id") el-button(type="text" icon="el-icon-close" size="mini" @click.stop="removeLocalWorldFavorite(favorite.id, group)" style="margin-left:5px") - el-tab-pane(label="Avatars") + el-tab-pane(:label="$t('view.favorite.avatars.header')") el-collapse(v-if="$refs.menu && $refs.menu.activeIndex === 'favorite' && $refs.favoriteTabRef && $refs.favoriteTabRef.currentName === '2'" style="border:0") - el-button(size="small" @click="showAvatarExportDialog") Export - el-button(size="small" @click="showAvatarImportDialog") Import + el-button(size="small" @click="showAvatarExportDialog") {{ $t('view.favorite.export') }} + el-button(size="small" @click="showAvatarImportDialog") {{ $t('view.favorite.import') }} el-collapse-item(v-for="group in API.favoriteAvatarGroups" :key="group.name") template(slot="title") span(v-text="group.displayName" style="font-weight:bold;font-size:14px;margin-left:10px") span(style="color:#909399;font-size:12px;margin-left:10px") {{ group.count }}/{{ group.capacity }} - el-tooltip(placement="top" content="Rename" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.favorite.rename_tooltip')" :disabled="hideTooltips") el-button(@click.stop="changeFavoriteGroupName(group)" size="mini" icon="el-icon-edit" circle style="margin-left:10px") - el-tooltip(placement="right" content="Clear" :disabled="hideTooltips") + el-tooltip(placement="right" :content="$t('view.favorite.clear_tooltip')" :disabled="hideTooltips") el-button(@click.stop="clearFavoriteGroup(group)" size="mini" icon="el-icon-delete" circle style="margin-left:5px") .x-friend-list(v-if="group.count" style="margin-top:10px") div(style="display:inline-block;width:300px;margin-right:15px" v-for="favorite in favoriteAvatars" v-if="favorite.groupKey === group.key" :key="favorite.id" @click="showAvatarDialog(favorite.id)") @@ -658,13 +658,13 @@ html .detail span.name(v-text="favorite.ref.name") span.extra(v-text="favorite.ref.authorName") - el-tooltip(placement="left" content="Move" :disabled="hideTooltips") + el-tooltip(placement="left" :content="$t('view.favorite.move_tooltip')" :disabled="hideTooltips") el-dropdown(trigger="click" @click.native.stop size="mini" style="margin-left:5px") el-button(type="default" icon="el-icon-back" size="mini" circle) el-dropdown-menu(#default="dropdown") template(v-if="groupAPI.name !== group.name" v-for="groupAPI in API.favoriteAvatarGroups" :key="groupAPI.name") el-dropdown-item(style="display:block;margin:10px 0" @click.native="moveFavorite(favorite.ref, groupAPI, 'avatar')" :disabled="groupAPI.count >= groupAPI.capacity") {{ groupAPI.displayName }} ({{ groupAPI.count }} / {{ groupAPI.capacity }}) - el-tooltip(placement="right" content="Unfavorite" :disabled="hideTooltips") + el-tooltip(placement="right" :content="$t('view.favorite.unfavorite_tooltip')" :disabled="hideTooltips") el-button(@click.stop="deleteFavorite(favorite.id)" size="mini" icon="el-icon-delete" circle style="margin-left:5px") template(v-else) .detail @@ -696,23 +696,23 @@ html data-tables(v-bind="friendLogTable") template(#tool) div(style="margin:0 0 10px;display:flex;align-items:center") - el-select(v-model="friendLogTable.filters[0].value" @change="saveTableFilters" multiple clearable collapse-tags style="flex:1" placeholder="Filter") + el-select(v-model="friendLogTable.filters[0].value" @change="saveTableFilters" multiple clearable collapse-tags style="flex:1" :placeholder="$t('view.friend_log.filter_placeholder')") el-option(v-once v-for="type in ['Friend', 'Unfriend', 'FriendRequest', 'CancelFriendRequest', 'DisplayName', 'TrustLevel']" :key="type" :label="type" :value="type") - el-input(v-model="friendLogTable.filters[1].value" placeholder="Search" style="flex:none;width:150px;margin-left:10px") - el-table-column(label="Date" prop="created_at" sortable="custom" width="120") + el-input(v-model="friendLogTable.filters[1].value" :placeholder="$t('view.friend_log.search_placeholder')" style="flex:none;width:150px;margin-left:10px") + el-table-column(:label="$t('table.friendLog.date')" prop="created_at" sortable="custom" width="120") template(v-once #default="scope") el-tooltip(placement="right") template(#content) span {{ scope.row.created_at | formatDate('long') }} span {{ scope.row.created_at | formatDate('short') }} - el-table-column(label="Type" prop="type" width="150") - el-table-column(label="User" prop="displayName") + el-table-column(:label="$t('table.friendLog.type')" prop="type" width="150") + el-table-column(:label="$t('table.friendLog.user')" prop="displayName") template(v-once #default="scope") - span(v-if="scope.row.type === 'DisplayName'") {{ scope.row.previousDisplayName }} #[i.el-icon-right] + span(v-if="scope.row.type === 'DisplayName'") {{ scope.row.previousDisplayName }} #[i.el-icon-right] span.x-link(v-text="scope.row.displayName || scope.row.userId" @click="showUserDialog(scope.row.userId)") template(v-if="scope.row.type === 'TrustLevel'") span ({{ scope.row.previousTrustLevel }} #[i.el-icon-right] {{ scope.row.trustLevel }}) - el-table-column(label="Action" width="80" align="right") + el-table-column(:label="$t('table.friendLog.action')" width="80" align="right") template(v-once #default="scope") el-button(type="text" icon="el-icon-close" size="mini" @click="deleteFriendLog(scope.row)") @@ -721,25 +721,25 @@ html data-tables(v-bind="playerModerationTable" v-loading="API.isPlayerModerationsLoading") template(#tool) div(style="margin:0 0 10px;display:flex;align-items:center") - el-select(v-model="playerModerationTable.filters[0].value" @change="saveTableFilters" multiple clearable collapse-tags style="flex:1" placeholder="Filter") + el-select(v-model="playerModerationTable.filters[0].value" @change="saveTableFilters" multiple clearable collapse-tags style="flex:1" :placeholder="$t('view.moderation.filter_placeholder')") el-option(v-once v-for="type in ['block', 'unblock', 'mute', 'unmute', 'interactOn', 'interactOff']" :key="type" :label="type" :value="type") - el-input(v-model="playerModerationTable.filters[1].value" placeholder="Search" style="flex:none;width:150px;margin:0 10px") - el-tooltip(placement="bottom" content="Refresh" :disabled="hideTooltips") + el-input(v-model="playerModerationTable.filters[1].value" :placeholder="$t('view.moderation.search_placeholder')" style="flex:none;width:150px;margin:0 10px") + el-tooltip(placement="bottom" :content="$t('view.moderation.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" :loading="API.isPlayerModerationsLoading" @click="API.refreshPlayerModerations()" icon="el-icon-refresh" circle style="flex:none") - el-table-column(label="Date" prop="created" sortable="custom" width="120") + el-table-column(:label="$t('table.moderation.date')" prop="created" sortable="custom" width="120") template(v-once #default="scope") el-tooltip(placement="right") template(#content) span {{ scope.row.created | formatDate('long') }} span {{ scope.row.created | formatDate('short') }} - el-table-column(label="Type" prop="type" width="100") - el-table-column(label="Source" prop="sourceDisplayName") + el-table-column(:label="$t('table.moderation.type')" prop="type" width="100") + el-table-column(:label="$t('table.moderation.source')" prop="sourceDisplayName") template(v-once #default="scope") span.x-link(v-text="scope.row.sourceDisplayName" @click="showUserDialog(scope.row.sourceUserId)") - el-table-column(label="Target" prop="targetDisplayName") + el-table-column(:label="$t('table.moderation.target')" prop="targetDisplayName") template(v-once #default="scope") span.x-link(v-text="scope.row.targetDisplayName" @click="showUserDialog(scope.row.targetUserId)") - el-table-column(label="Action" width="80" align="right") + el-table-column(:label="$t('table.moderation.action')" width="80" align="right") template(v-once #default="scope") el-button(v-if="scope.row.sourceUserId === API.currentUser.id" type="text" icon="el-icon-close" size="mini" @click="deletePlayerModeration(scope.row)") @@ -748,18 +748,18 @@ html data-tables(v-bind="notificationTable") template(#tool) div(style="margin:0 0 10px;display:flex;align-items:center") - el-select(v-model="notificationTable.filters[0].value" @change="saveTableFilters" multiple clearable collapse-tags style="flex:1" placeholder="Filter") + el-select(v-model="notificationTable.filters[0].value" @change="saveTableFilters" multiple clearable collapse-tags style="flex:1" :placeholder="$t('view.notification.filter_placeholder')") el-option(v-once v-for="type in ['requestInvite', 'invite', 'requestInviteResponse', 'inviteResponse', 'friendRequest', 'hiddenFriendRequest', 'message', 'group.announcement', 'group.informative', 'group.invite', 'group.joinRequest', 'moderation.warning.group']" :key="type" :label="type" :value="type") - el-input(v-model="notificationTable.filters[1].value" placeholder="Search" style="flex:none;width:150px;margin:0 10px") - el-tooltip(placement="bottom" content="Refresh" :disabled="hideTooltips") + el-input(v-model="notificationTable.filters[1].value" :placeholder="$t('view.notification.search_placeholder')" style="flex:none;width:150px;margin:0 10px") + el-tooltip(placement="bottom" :content="$t('view.notification.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" :loading="API.isNotificationsLoading" @click="API.refreshNotifications()" icon="el-icon-refresh" circle style="flex:none") - el-table-column(label="Date" prop="created_at" sortable="custom" width="120") + el-table-column(:label="$t('table.notification.date')" prop="created_at" sortable="custom" width="120") template(v-once #default="scope") el-tooltip(placement="right") template(#content) span {{ scope.row.created_at | formatDate('long') }} span {{ scope.row.created_at | formatDate('short') }} - el-table-column(label="Type" prop="type" width="160") + el-table-column(:label="$t('table.notification.type')" prop="type" width="160") template(v-once #default="scope") el-tooltip(v-if="scope.row.type === 'invite'" placement="top") template(#content) @@ -769,10 +769,10 @@ html el-tooltip(placement="top" :content="scope.row.linkText" :disabled="hideTooltips") span.x-link(v-text="scope.row.type" @click="openNotificationLink(scope.row.link)") span(v-else v-text="scope.row.type") - el-table-column(label="User" prop="senderUsername" width="150") + el-table-column(:label="$t('table.notification.user')" prop="senderUsername" width="150") template(v-once #default="scope") span.x-link(v-text="scope.row.senderUsername" @click="showUserDialog(scope.row.senderUserId)") - el-table-column(label="Photo" width="100" prop="photo") + el-table-column(:label="$t('table.notification.photo')" width="100" prop="photo") template(v-once #default="scope") template(v-if="scope.row.details && scope.row.details.imageUrl") el-popover(placement="right" width="500px" trigger="click") @@ -782,14 +782,14 @@ html el-popover(placement="right" width="500px" trigger="click") img.x-link(slot="reference" v-lazy="scope.row.imageUrl" style="flex:none;width:90px;border-radius:4px") img.x-link(v-lazy="scope.row.imageUrl" style="width:500px" @click="downloadAndSaveImage(scope.row.imageUrl)") - el-table-column(label="Message" prop="message") + el-table-column(:label="$t('table.notification.message')" prop="message") template(v-once #default="scope") span(v-if="scope.row.title") {{ scope.row.title }}, {{ scope.row.message }} span(v-else-if="scope.row.message" v-text="scope.row.message") span(v-else-if='scope.row.details && scope.row.details.inviteMessage' v-text="scope.row.details.inviteMessage") span(v-else-if='scope.row.details && scope.row.details.requestMessage' v-text="scope.row.details.requestMessage") span(v-else-if='scope.row.details && scope.row.details.responseMessage' v-text="scope.row.details.responseMessage") - el-table-column(label="Action" width="100" align="right") + el-table-column(:label="$t('table.notification.action')" width="100" align="right") template(v-once #default="scope") template(v-if="scope.row.senderUserId !== API.currentUser.id && !scope.row.$isExpired") template(v-if="scope.row.type === 'friendRequest'") @@ -836,7 +836,7 @@ html //- profile .x-container(v-show="$refs.menu && $refs.menu.activeIndex === 'profile'") div.options-container(style="margin-top:0") - span.header Profile + span.header {{ $t('view.profile.profile.header') }} .x-friend-list(style="margin-top:10px") .x-friend-item(@click="showUserDialog(API.currentUser.id)") .avatar @@ -846,29 +846,29 @@ html span.extra(v-text="API.currentUser.username") .x-friend-item(style="cursor:default") .detail - span.name Last Activity + span.name {{ $t('view.profile.profile.last_activity') }} span.extra {{ API.currentUser.last_activity | formatDate('long') }} .x-friend-item(style="cursor:default") .detail - span.name Two-Factor Auth (2FA) - span.extra {{ API.currentUser.twoFactorAuthEnabled ? 'Enabled' : 'Disabled' }} + span.name {{ $t('view.profile.profile.two_factor') }} + span.extra {{ API.currentUser.twoFactorAuthEnabled ? $t('view.profile.profile.two_factor_enabled') : $t('view.profile.profile.two_factor_disabled') }} div - el-button(size="small" icon="el-icon-switch-button" @click="logout()" style="margin-left:0;margin-right:5px;margin-top:10px") Logout - el-button(size="small" icon="el-icon-printer" @click="showExportFriendsListDialog()" style="margin-left:0;margin-right:5px;margin-top:10px") Export Friends List - el-button(size="small" icon="el-icon-user" @click="showExportAvatarsListDialog()" style="margin-left:0;margin-right:5px;margin-top:10px") Export Own Avatars - el-button(size="small" icon="el-icon-chat-dot-round" @click="showDiscordNamesDialog()" style="margin-left:0;margin-right:5px;margin-top:10px") Discord Names - el-button(size="small" icon="el-icon-document-copy" @click="showNoteExportDialog()" style="margin-left:0;margin-right:5px;margin-top:10px") Export Notes + el-button(size="small" icon="el-icon-switch-button" @click="logout()" style="margin-left:0;margin-right:5px;margin-top:10px") {{ $t('view.profile.profile.logout') }} + el-button(size="small" icon="el-icon-printer" @click="showExportFriendsListDialog()" style="margin-left:0;margin-right:5px;margin-top:10px") {{ $t('view.profile.profile.export_friend_list') }} + el-button(size="small" icon="el-icon-user" @click="showExportAvatarsListDialog()" style="margin-left:0;margin-right:5px;margin-top:10px") {{ $t('view.profile.profile.export_own_avatars') }} + el-button(size="small" icon="el-icon-chat-dot-round" @click="showDiscordNamesDialog()" style="margin-left:0;margin-right:5px;margin-top:10px") {{ $t('view.profile.profile.discord_names') }} + el-button(size="small" icon="el-icon-document-copy" @click="showNoteExportDialog()" style="margin-left:0;margin-right:5px;margin-top:10px") {{ $t('view.profile.profile.export_notes') }} div.options-container - span.header Game Info + span.header {{ $t('view.profile.game_info.header') }} .x-friend-list(style="margin-top:10px") .x-friend-item .detail(@click="API.getVisits()") - span.name Online Users - span.extra(v-if="visits") {{visits}} users online. - span.extra(v-else) Click to refresh + span.name {{ $t('view.profile.game_info.online_users') }} + span.extra(v-if="visits") {{ $t('view.profile.game_info.user_online', { count: visits }) }} + span.extra(v-else) {{ $t('view.profile.game_info.refresh') }} div.options-container - span.header VRC SDK Downloads - el-tooltip(placement="top" content="Refresh" :disabled="hideTooltips") + span.header {{ $t('view.profile.vrc_sdk_downloads.header') }} + el-tooltip(placement="top" :content="$t('view.profile.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="API.getConfig()" size="mini" icon="el-icon-refresh" circle style="margin-left:5px") .x-friend-list(style="margin-top:10px") .x-friend-item(v-for="(link, item) in API.cachedConfig.downloadUrls" :key="item" placement="top") @@ -876,18 +876,18 @@ html span.name(v-text="item") span.extra(v-text="link") div.options-container - span.header Direct Access + span.header {{ $t('view.profile.direct_access.header') }} div(style="margin-top:10px") el-button-group - el-button(size="small" @click="promptUsernameDialog()") Username - el-button(size="small" @click="promptUserIdDialog()") User ID - el-button(size="small" @click="promptWorldDialog()") World/Instance - el-button(size="small" @click="promptAvatarDialog()") Avatar + el-button(size="small" @click="promptUsernameDialog()") {{ $t('view.profile.direct_access.username') }} + el-button(size="small" @click="promptUserIdDialog()") {{ $t('view.profile.direct_access.user_id') }} + el-button(size="small" @click="promptWorldDialog()") {{ $t('view.profile.direct_access.world_instance') }} + el-button(size="small" @click="promptAvatarDialog()") {{ $t('view.profile.direct_access.avatar') }} div.options-container - span.header Invite Messages - el-tooltip(placement="top" content="Refresh" :disabled="hideTooltips") + span.header {{ $t('view.profile.invite_messages') }} + el-tooltip(placement="top" :content="$t('view.profile.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="inviteMessageTable.visible = true; refreshInviteMessageTable('message')" size="mini" icon="el-icon-refresh" circle style="margin-left:5px") - el-tooltip(placement="top" content="Clear results" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.profile.clear_results_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="inviteMessageTable.visible = false" size="mini" icon="el-icon-delete" circle style="margin-left:5px") data-tables(v-if="inviteMessageTable.visible" v-bind="inviteMessageTable" style="margin-top:10px") el-table-column(label="Slot" prop="slot" sortable="custom" width="70") @@ -899,10 +899,10 @@ html template(v-once #default="scope") el-button(type="text" icon="el-icon-edit" size="mini" @click="showEditInviteMessageDialog('message', scope.row)") div.options-container - span.header Invite Response Messages - el-tooltip(placement="top" content="Refresh" :disabled="hideTooltips") + span.header {{ $t('view.profile.invite_response_messages') }} + el-tooltip(placement="top" :content="$t('view.profile.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="inviteResponseMessageTable.visible = true; refreshInviteMessageTable('response')" size="mini" icon="el-icon-refresh" circle style="margin-left:5px") - el-tooltip(placement="top" content="Clear results" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.profile.clear_results_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="inviteResponseMessageTable.visible = false" size="mini" icon="el-icon-delete" circle style="margin-left:5px") data-tables(v-if="inviteResponseMessageTable.visible" v-bind="inviteResponseMessageTable" style="margin-top:10px") el-table-column(label="Slot" prop="slot" sortable="custom" width="70") @@ -914,10 +914,10 @@ html template(v-once #default="scope") el-button(type="text" icon="el-icon-edit" size="mini" @click="showEditInviteMessageDialog('response', scope.row)") div.options-container - span.header Invite Request Messages - el-tooltip(placement="top" content="Refresh" :disabled="hideTooltips") + span.header {{ $t('view.profile.invite_request_messages') }} + el-tooltip(placement="top" :content="$t('view.profile.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="inviteRequestMessageTable.visible = true; refreshInviteMessageTable('request')" size="mini" icon="el-icon-refresh" circle style="margin-left:5px") - el-tooltip(placement="top" content="Clear results" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.profile.clear_results_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="inviteRequestMessageTable.visible = false" size="mini" icon="el-icon-delete" circle style="margin-left:5px") data-tables(v-if="inviteRequestMessageTable.visible" v-bind="inviteRequestMessageTable" style="margin-top:10px") el-table-column(label="Slot" prop="slot" sortable="custom" width="70") @@ -929,10 +929,10 @@ html template(v-once #default="scope") el-button(type="text" icon="el-icon-edit" size="mini" @click="showEditInviteMessageDialog('request', scope.row)") div.options-container - span.header Invite Request Response Messages - el-tooltip(placement="top" content="Refresh" :disabled="hideTooltips") + span.header {{ $t('view.profile.invite__request_response_messages') }} + el-tooltip(placement="top" :content="$t('view.profile.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="inviteRequestResponseMessageTable.visible = true; refreshInviteMessageTable('requestResponse')" size="mini" icon="el-icon-refresh" circle style="margin-left:5px") - el-tooltip(placement="top" content="Clear results" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.profile.clear_results_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="inviteRequestResponseMessageTable.visible = false" size="mini" icon="el-icon-delete" circle style="margin-left:5px") data-tables(v-if="inviteRequestResponseMessageTable.visible" v-bind="inviteRequestResponseMessageTable" style="margin-top:10px") el-table-column(label="Slot" prop="slot" sortable="custom" width="70") @@ -944,17 +944,17 @@ html template(v-once #default="scope") el-button(type="text" icon="el-icon-edit" size="mini" @click="showEditInviteMessageDialog('requestResponse', scope.row)") div.options-container - span.header Past Display Names + span.header {{ $t('view.profile.past_display_names') }} data-tables(v-bind="pastDisplayNameTable" style="margin-top:10px") el-table-column(label="Date" prop="updated_at" sortable="custom") template(v-once #default="scope") span {{ scope.row.updated_at | formatDate('long') }} el-table-column(label="Name" prop="displayName") div.options-container - span.header Config JSON - el-tooltip(placement="top" content="Refresh" :disabled="hideTooltips") + span.header {{ $t('view.profile.config_json') }} + el-tooltip(placement="top" :content="$t('view.profile.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="refreshConfigTreeData()" size="mini" icon="el-icon-refresh" circle style="margin-left:5px") - el-tooltip(placement="top" content="Clear results" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.profile.clear_results_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="configTreeData = []" size="mini" icon="el-icon-delete" circle style="margin-left:5px") el-tree(v-if="configTreeData.length > 0" :data="configTreeData" style="margin-top:10px;font-size:12px") template(#default="scope") @@ -962,10 +962,10 @@ html span(v-text="scope.data.key" style="font-weight:bold;margin-right:5px") span(v-if="!scope.data.children" v-text="scope.data.value") div.options-container - span.header Current User JSON - el-tooltip(placement="top" content="Refresh" :disabled="hideTooltips") + span.header {{ $t('view.profile.current_user_json') }} + el-tooltip(placement="top" :content="$t('view.profile.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="refreshCurrentUserTreeData()" size="mini" icon="el-icon-refresh" circle style="margin-left:5px") - el-tooltip(placement="top" content="Clear results" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.profile.clear_results_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="currentUserTreeData = []" size="mini" icon="el-icon-delete" circle style="margin-left:5px") el-tree(v-if="currentUserTreeData.length > 0" :data="currentUserTreeData" style="margin-top:10px;font-size:12px") template(#default="scope") @@ -976,230 +976,237 @@ html //- friends list .x-container(v-show="$refs.menu && $refs.menu.activeIndex === 'friendsList'" v-if="$refs.menu && $refs.menu.activeIndex === 'friendsList'") div.options-container(style="margin-top:0") - span.header Friends List + span.header {{ $t('view.friend_list.header') }} div(style="float:right;font-size:13px") div(v-if="friendsListBulkUnfriendMode" style="display:inline-block;margin-right:10px") - el-button(size="small" @click="showBulkUnfriendSelectionConfirm") Bulk Unfriend Selection + el-button(size="small" @click="showBulkUnfriendSelectionConfirm") {{ $t('view.friend_list.bulk_unfriend_selection') }} //- el-button(size="small" @click="showBulkUnfriendAllConfirm" style="margin-right:5px") Bulk Unfriend All div(style="display:inline-block;margin-right:10px") - span.name Bulk Unfriend Mode + span.name {{ $t('view.friend_list.bulk_unfriend') }} el-switch(v-model="friendsListBulkUnfriendMode" style="margin-left:5px") - span Load missing entries - el-tooltip(placement="top" style="margin-left:5px" content="This takes a lot of API requests so use it sparingly") + span {{ $t('view.friend_list.load') }} + el-tooltip(placement="top" style="margin-left:5px" :content="$t('view.friend_list.load_notice')") i.el-icon-warning template(v-if="friendsListLoading") span(v-text="friendsListLoadingProgress" style="margin-left:5px") - el-tooltip(placement="top" content="Cancel" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.friend_list.cancel_tooltip')" :disabled="hideTooltips") el-button(@click="friendsListLoading = false" size="mini" icon="el-icon-loading" circle style="margin-left:5px") template(v-else) - el-tooltip(placement="top" content="Load" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.friend_list.load_tooltip')" :disabled="hideTooltips") el-button(@click="friendsListLoadUsers" size="mini" icon="el-icon-refresh-left" circle style="margin-left:5px") div(style="margin:10px 0 0 10px;display:flex;align-items:center") div(style="flex:none;margin-right:10px") - el-tooltip(placement="bottom" content="Filter VIP only" :disabled="hideTooltips") + el-tooltip(placement="bottom" :content="$t('view.friend_list.favorites_only_tooltip')" :disabled="hideTooltips") el-switch(v-model="friendsListSearchFilterVIP" @change="friendsListSearchChange" active-color="#13ce66") - el-input(v-model="friendsListSearch" placeholder="Search" @change="friendsListSearchChange" clearable style="flex:1") - el-select(v-model="friendsListSearchFilters" multiple clearable collapse-tags style="flex:none;width:200px;margin:0 10px" @change="friendsListSearchChange" placeholder="Filter") + el-input(v-model="friendsListSearch" :placeholder="$t('view.friend_list.search_placeholder')" @change="friendsListSearchChange" clearable style="flex:1") + el-select(v-model="friendsListSearchFilters" multiple clearable collapse-tags style="flex:none;width:200px;margin:0 10px" @change="friendsListSearchChange" :placeholder="$t('view.friend_list.filter_placeholder')") el-option(v-once v-for="type in ['Display Name', 'User Name', 'Rank', 'Status', 'Bio', 'Memo']" :key="type" :label="type" :value="type") - el-tooltip(placement="top" content="Refresh" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.friend_list.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="friendsListSearchChange" icon="el-icon-refresh" circle style="flex:none") - el-tooltip(placement="top" content="Clear results" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.friend_list.clear_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="friendsListTable.data = []" icon="el-icon-delete" circle style="flex:none;margin-left:5px") data-tables(v-bind="friendsListTable" @row-click="selectFriendsListRow" style="margin-top:10px;cursor:pointer") el-table-column(v-if="friendsListBulkUnfriendMode" width="55" prop="$selected") template(v-once #default="scope") el-button(type="text" size="mini" @click.stop) el-checkbox(v-model="scope.row.$selected") - el-table-column(label="No." width="70" prop="$friendNum" sortable="custom") - el-table-column(label="Avatar" width="70" prop="photo") + el-table-column(:label="$t('table.friendList.no')" width="70" prop="$friendNum" sortable="custom") + el-table-column(:label="$t('table.friendList.avatar')" width="70" prop="photo") template(v-once #default="scope") el-popover(placement="right" height="500px" trigger="hover") img.friends-list-avatar(slot="reference" v-lazy="userImage(scope.row)") img.friends-list-avatar(v-lazy="userImageFull(scope.row)" style="height:500px;cursor:pointer" @click="downloadAndSaveImage(userImageFull(scope.row))") - el-table-column(label="Display Name" min-width="140" prop="displayName" sortable :sort-method="(a, b) => sortAlphabetically(a, b, 'displayName')") + el-table-column(:label="$t('table.friendList.displayName')" min-width="140" prop="displayName" sortable :sort-method="(a, b) => sortAlphabetically(a, b, 'displayName')") template(v-once #default="scope") span.name(v-if="randomUserColours" v-text="scope.row.displayName" :style="{'color':scope.row.$userColour}") span.name(v-else v-text="scope.row.displayName") - el-table-column(label="Rank" width="110" prop="$trustSortNum" sortable="custom") + el-table-column(:label="$t('table.friendList.rank')" width="110" prop="$trustSortNum" sortable="custom") template(v-once #default="scope") span.name(v-if="randomUserColours" v-text="scope.row.$trustLevel" :class="scope.row.$trustClass") span.name(v-else v-text="scope.row.$trustLevel" :style="{'color':scope.row.$userColour}") - el-table-column(label="Status" min-width="180" prop="status" sortable :sort-method="(a, b) => sortStatus(a.status, b.status)") + el-table-column(:label="$t('table.friendList.status')" min-width="180" prop="status" sortable :sort-method="(a, b) => sortStatus(a.status, b.status)") template(v-once #default="scope") i.x-user-status(v-if="scope.row.status !== 'offline'" :class="statusClass(scope.row.status)") span ‎ span(v-text="scope.row.statusDescription") - el-table-column(label="Language" width="110" prop="$languages" sortable :sort-method="(a, b) => sortLanguages(a, b)") + el-table-column(:label="$t('table.friendList.language')" width="110" prop="$languages" sortable :sort-method="(a, b) => sortLanguages(a, b)") template(v-once #default="scope") el-tooltip(v-for="item in scope.row.$languages" :key="item.key" placement="top") template(#content) span {{ item.value }} ({{ item.key }}) span.flags(:class="languageClass(item.key)" style="display:inline-block;margin-left:5px") - el-table-column(label="Bio Links" width="100" prop="bioLinks") + el-table-column(:label="$t('table.friendList.bioLink')" width="100" prop="bioLinks") template(v-once #default="scope") el-tooltip(v-if="link" v-for="(link, index) in scope.row.bioLinks" :key="index") template(#content) span(v-text="link") img(:src="getFaviconUrl(link)" style="width:16px;height:16px;vertical-align:middle;margin-right:5px;cursor:pointer" @click.stop="openExternalLink(link)") - el-table-column(label="Join Count" width="120" prop="$joinCount" sortable) - el-table-column(label="Time Together" width="140" prop="$timeSpent" sortable) + el-table-column(:label="$t('table.friendList.joinCount')" width="120" prop="$joinCount" sortable) + el-table-column(:label="$t('table.friendList.timeTogether')" width="140" prop="$timeSpent" sortable) template(v-once #default="scope") span(v-if="scope.row.$timeSpent") {{ scope.row.$timeSpent | timeToText }} - el-table-column(label="Last Seen" width="170" prop="$lastSeen" sortable :sort-method="(a, b) => sortAlphabetically(a, b, '$lastSeen')") + el-table-column(:label="$t('table.friendList.lastSeen')" width="170" prop="$lastSeen" sortable :sort-method="(a, b) => sortAlphabetically(a, b, '$lastSeen')") template(v-once #default="scope") span {{ scope.row.$lastSeen | formatDate('long') }} - el-table-column(label="Last Activity" width="170" prop="last_activity" sortable :sort-method="(a, b) => sortAlphabetically(a, b, 'last_activity')") + el-table-column(:label="$t('table.friendList.lastActivity')" width="170" prop="last_activity" sortable :sort-method="(a, b) => sortAlphabetically(a, b, 'last_activity')") template(v-once #default="scope") span {{ scope.row.last_activity | formatDate('long') }} - el-table-column(label="Last Login" width="170" prop="last_login" sortable :sort-method="(a, b) => sortAlphabetically(a, b, 'last_login')") + el-table-column(:label="$t('table.friendList.lastLogin')" width="170" prop="last_login" sortable :sort-method="(a, b) => sortAlphabetically(a, b, 'last_login')") template(v-once #default="scope") span {{ scope.row.last_login | formatDate('long') }} - el-table-column(label="Date Joined" width="120" prop="date_joined" sortable :sort-method="(a, b) => sortAlphabetically(a, b, 'date_joined')") - el-table-column(label="Unfriend" width="80") + el-table-column(:label="$t('table.friendList.dateJoined')" width="120" prop="date_joined" sortable :sort-method="(a, b) => sortAlphabetically(a, b, 'date_joined')") + el-table-column(:label="$t('table.friendList.unfriend')" width="80") template(v-once #default="scope") el-button(type="text" icon="el-icon-close" size="mini" @click.stop="confirmDeleteFriend(scope.row.id)") //- settings .x-container(v-show="$refs.menu && $refs.menu.activeIndex === 'settings'") - div.options-container(style="margin-top:0") - span.header Settings + div.options-container(style="margin-top:0") + span.header {{ $t("view.settings.header") }} el-tabs(type="card" style="margin-top:10px") - el-tab-pane(label="General") + el-tab-pane(:label="$t('view.settings.category.general')") div.options-container(style="margin-top:0") - span.header General + span.header {{ $t("view.settings.general.general.header") }} .x-friend-list(style="margin-top:10px") .x-friend-item(style="cursor:default") .detail - span.name Version + span.name {{ $t("view.settings.general.general.version") }} span.extra(v-text="appVersion") .x-friend-item(@click="checkForVRCXUpdate") .detail - span.name Latest Version + span.name {{ $t("view.settings.general.general.latest_app_version") }} span.extra(v-if="latestAppVersion" v-text="latestAppVersion") - span.extra(v-else) Click to refresh + span.extra(v-else) {{ $t("view.settings.general.general.latest_app_version_refresh") }} .x-friend-item(@click="openExternalLink('https://github.com/pypy-vrc/VRCX')") .detail - span.name Repository URL + span.name {{ $t("view.settings.general.general.repository_url") }} span.extra https://github.com/pypy-vrc/VRCX .x-friend-item(@click="openExternalLink('https://vrcx.pypy.moe/discord')") .detail - span.name Support + span.name {{ $t("view.settings.general.general.support") }} span.extra https://vrcx.pypy.moe/discord div.options-container - span.header VRCX Updater + span.header {{ $t("view.settings.general.vrcx_updater.header") }} div.options-container-item - el-button(size="small" icon="el-icon-upload" @click="showVRCXUpdateDialog()") Change build + el-button(size="small" icon="el-icon-upload" @click="showVRCXUpdateDialog()") {{ $t("view.settings.general.vrcx_updater.change_build") }} div.options-container-item - span.name Auto update: + span.name {{ $t("view.settings.general.vrcx_updater.auto_update") }} br el-radio-group(v-model="autoUpdateVRCX" @change="saveAutoUpdateVRCX" size="mini") - el-radio-button(label="Off") - el-radio-button(label="Notify") - el-radio-button(label="Auto Download") - el-radio-button(label="Auto Install") + el-radio-button(label="Off") {{ $t("view.settings.general.vrcx_updater.auto_update_off") }} + el-radio-button(label="Notify") {{ $t("view.settings.general.vrcx_updater.auto_update_notify") }} + el-radio-button(label="Auto Download") {{ $t("view.settings.general.vrcx_updater.auto_update_download") }} + el-radio-button(label="Auto Install") {{ $t("view.settings.general.vrcx_updater.auto_update_install") }} div.options-container - span.header Application + span.header {{ $t("view.settings.general.application.header") }} div.options-container-item - span.name Start at Windows startup + span.name {{ $t("view.settings.general.application.startup") }} el-switch(v-model="isStartAtWindowsStartup") div.options-container-item - span.name Start as minimized state + span.name {{ $t("view.settings.general.application.minimized") }} el-switch(v-model="isStartAsMinimizedState") div.options-container-item - span.name Close to tray + span.name {{ $t("view.settings.general.application.tray") }} el-switch(v-model="isCloseToTray") div.options-container div.options-container(style="margin-top:45px;border-top:1px solid #eee;padding-top:30px") - span.header Legal Notice + span.header {{ $t("view.settings.general.legal_notice.header" )}} div.options-container-item p © 2019-2022 #[a(@click="openExternalLink('https://github.com/pypy-vrc')") pypy] (mina#5656) & #[a(@click="openExternalLink('https://github.com/Natsumi-sama')") Natsumi] - p VRCX is an assistant application for provide information about manage friendship. this application uses unofficial VRChat API (VRCSDK). - p VRCX isn't endorsed by VRChat and doesn't reflect the views or opinions of VRChat or anyone officially involved in producing or managing VRChat. VRChat is trademark of VRChat Inc. VRChat © VRChat Inc. - p pypy or Natsumi aren't responsible for any problems caused by VRCX. Use at your own risk! + p {{ $t("view.settings.general.legal_notice.info" )}} + p {{ $t("view.settings.general.legal_notice.disclaimer1" )}} + p {{ $t("view.settings.general.legal_notice.disclaimer2" )}} div.options-container-item - el-button(@click="ossDialog = true" size="small") Open Source Software Notice - el-tab-pane(label="Appearance") + el-button(@click="ossDialog = true" size="small") {{ $t("view.settings.general.legal_notice.open_source_software_notice" )}} + el-tab-pane(:label="$t('view.settings.category.appearance')") div.options-container(style="margin-top:0") - span.header Appearance + span.header {{ $t("view.settings.appearance.appearance.header") }} div.options-container-item - span.name Theme mode + span.name {{ $t('view.settings.appearance.appearance.language') }} + el-dropdown(@click.native.stop trigger="click" size="small") + el-button(size="mini") + span {{ $i18n.messages[appLanguage]?.language }} #[i.el-icon-arrow-down.el-icon--right] + el-dropdown-menu(#default="dropdown") + el-dropdown-item(v-for="(obj, language) in $i18n.messages" v-text="obj.language" @click.native="changeAppLanguage(language)") + div.options-container-item + span.name {{ $t('view.settings.appearance.appearance.theme_mode') }} el-radio-group(v-model="themeMode" size="mini") - el-radio-button(label="system") System - el-radio-button(label="light") Light - el-radio-button(label="dark") Dark + el-radio-button(label="system") {{ $t('view.settings.appearance.appearance.theme_mode_system') }} + el-radio-button(label="light") {{ $t('view.settings.appearance.appearance.theme_mode_light') }} + el-radio-button(label="dark") {{ $t('view.settings.appearance.appearance.theme_mode_dark') }} div.options-container-item - span.name VRCPlus Profile Icons + span.name {{ $t('view.settings.appearance.appearance.vrcplus_profile_icons') }} el-switch(v-model="displayVRCPlusIconsAsAvatar" @change="saveOpenVROption") div.options-container-item - span.name Disable Tooltips + span.name {{ $t('view.settings.appearance.appearance.disable_tooltips') }} el-switch(v-model="hideTooltips" @change="saveOpenVROption") div.options-container-item - span.name Sort Favorites By - el-switch(v-model="sortFavorites" inactive-text="name" active-text="date" @change="saveSortFavoritesOption") + span.name {{ $t('view.settings.appearance.appearance.sort_favorite_by') }} + el-switch(v-model="sortFavorites" :inactive-text="$t('view.settings.appearance.appearance.sort_favorite_by_name')" :active-text="$t('view.settings.appearance.appearance.sort_favorite_by_date')" @change="saveSortFavoritesOption") div.options-container-item - span.name Sort Instance Users By - el-switch(v-model="instanceUsersSortAlphabetical" inactive-text="time" active-text="alphabetical" @change="saveOpenVROption") + span.name {{ $t('view.settings.appearance.appearance.sort_instance_users_by') }} + el-switch(v-model="instanceUsersSortAlphabetical" :inactive-text="$t('view.settings.appearance.appearance.sort_instance_users_by_time')" :active-text="$t('view.settings.appearance.appearance.sort_instance_users_by_alphabet')" @change="saveOpenVROption") div.options-container-item - el-button(size="small" icon="el-icon-notebook-1" @click="promptMaxTableSizeDialog") Table Max Size + el-button(size="small" icon="el-icon-notebook-1" @click="promptMaxTableSizeDialog") {{ $t('view.settings.appearance.appearance.table_max_size') }} div.options-container-item el-dropdown(@click.native.stop trigger="click" size="small") el-button(size="mini") - span Page Size: {{ tablePageSize }} #[i.el-icon-arrow-down.el-icon--right] + span {{ $t('view.settings.appearance.appearance.page_size') }} {{ tablePageSize }} #[i.el-icon-arrow-down.el-icon--right] el-dropdown-menu(#default="dropdown") el-dropdown-item(v-for="(number) in [10, 15, 25, 50, 100]" v-text="number" @click.native="setTablePageSize(number)") div.options-container - span.header Timedate + span.header {{ $t('view.settings.appearance.timedate.header') }} div.options-container-item - span.name Time Format - el-switch(v-model="dtHour12" @change="setDatetimeFormat" inactive-text="24 Hour" active-text="12 Hour") + span.name {{ $t('view.settings.appearance.timedate.time_format') }} + el-switch(v-model="dtHour12" @change="setDatetimeFormat" :inactive-text="$t('view.settings.appearance.timedate.time_format_24')" :active-text="$t('view.settings.appearance.timedate.time_format_12')") div.options-container-item - span.name Force ISO date format + span.name {{ $t('view.settings.appearance.timedate.force_iso_date_format') }} el-switch(v-model="dtIsoFormat" @change="setDatetimeFormat") div.options-container - span.header Side Panel + span.header {{ $t('view.settings.appearance.side_panel.header') }} br - span.sub-header Sorting + span.sub-header {{ $t('view.settings.appearance.side_panel.sorting.header') }} div.options-container-item - span.name Sort Private to bottom + span.name {{ $t('view.settings.appearance.side_panel.sorting.sort_private_to_bottom') }} el-switch(v-model="orderFriendsGroupPrivate" @change="saveOrderFriendGroup") div.options-container-item - span.name Sort by status + span.name {{ $t('view.settings.appearance.side_panel.sorting.sort_by_status') }} el-switch(v-model="orderFriendsGroupStatus" @change="saveOrderFriendGroup") div.options-container-item - span.name Sort GPS to top + span.name {{ $t('view.settings.appearance.side_panel.sorting.sort_gps_to_top') }} el-switch(v-model="orderFriendsGroupGPS" @change="saveOrderFriendGroup") - span.name(style="margin-left:5px") (online for only) + span.name(style="margin-left:5px") {{ $t('view.settings.appearance.side_panel.sorting.sort_gps_to_top_notice') }} div.options-container-item - span.name VIP - el-switch(v-model="orderFriendsGroup0" inactive-text="alphabetical" active-text="online for" @change="saveOrderFriendGroup") + span.name {{ $t('view.settings.appearance.side_panel.sorting.sort_favorite_by') }} + el-switch(v-model="orderFriendsGroup0" :inactive-text="$t('view.settings.appearance.side_panel.sorting.sort_favorite_by_alphabet')" :active-text="$t('view.settings.appearance.side_panel.sorting.sort_favorite_by_online_time')" @change="saveOrderFriendGroup") div.options-container-item - span.name Online - el-switch(v-model="orderFriendsGroup1" inactive-text="alphabetical" active-text="online for" @change="saveOrderFriendGroup") + span.name {{ $t('view.settings.appearance.side_panel.sorting.sort_online_by') }} + el-switch(v-model="orderFriendsGroup1" :inactive-text="$t('view.settings.appearance.side_panel.sorting.sort_online_by_alphabet')" :active-text="$t('view.settings.appearance.side_panel.sorting.sort_online_by_online_time')" @change="saveOrderFriendGroup") div.options-container-item - span.name Active - el-switch(v-model="orderFriendsGroup2" inactive-text="alphabetical" active-text="online for" @change="saveOrderFriendGroup") + span.name {{ $t('view.settings.appearance.side_panel.sorting.sort_active_by') }} + el-switch(v-model="orderFriendsGroup2" :inactive-text="$t('view.settings.appearance.side_panel.sorting.sort_active_by_alphabet')" :active-text="$t('view.settings.appearance.side_panel.sorting.sort_active_by_online_time')" @change="saveOrderFriendGroup") div.options-container-item - span.name Offline - el-switch(v-model="orderFriendsGroup3" inactive-text="alphabetical" active-text="offline for" @change="saveOrderFriendGroup") - span.sub-header Width + span.name {{ $t('view.settings.appearance.side_panel.sorting.sort_offline_by') }} + el-switch(v-model="orderFriendsGroup3" :inactive-text="$t('view.settings.appearance.side_panel.sorting.sort_offline_by_alphabet')" :active-text="$t('view.settings.appearance.side_panel.sorting.sort_offline_by_offline_time')" @change="saveOrderFriendGroup") + span.sub-header {{ $t('view.settings.appearance.side_panel.width') }} div.options-container-item el-slider(v-model="asideWidth" @input="setAsideWidth" :show-tooltip="false" :marks="{236: ''}" :min="141" :max="500" style="width:300px") div.options-container - span.header User Dialog + span.header {{ $t('view.settings.appearance.user_dialog.header') }} div.options-container-item - span.name Hide VRChat Notes + span.name {{ $t('view.settings.appearance.user_dialog.hide_vrchat_notes') }} el-switch(v-model="hideUserNotes" @change="saveUserDialogOption") div.options-container-item - span.name Hide VRCX Memos + span.name {{ $t('view.settings.appearance.user_dialog.hide_vrcx_memos') }} el-switch(v-model="hideUserMemos" @change="saveUserDialogOption") div.options-container-item - span.name Export VRCX memos into VRChat notes + span.name {{ $t('view.settings.appearance.user_dialog.export_vrcx_memos_into_vrchat_notes') }} br - el-button(size="small" icon="el-icon-document-copy" @click="showNoteExportDialog") Export Notes + el-button(size="small" icon="el-icon-document-copy" @click="showNoteExportDialog") {{ $t('view.settings.appearance.user_dialog.export_notes') }} div.options-container - span.header User Colours + span.header {{ $t('view.settings.appearance.user_colors.header') }} div.options-container-item - span.name Random colours from user ID + span.name {{ $t('view.settings.appearance.user_colors.random_colors_from_user_id') }} el-switch(v-model="randomUserColours" @change="updatetrustColor") div.options-container-item div @@ -1223,288 +1230,288 @@ html div el-color-picker(v-model="trustColor.troll" @change="updatetrustColor" size="mini" :predefine="['#782f2f']") span.color-picker(slot="trigger" class="x-tag-troll") Nuisance - el-tab-pane(label="Notifications") + el-tab-pane(:label="$t('view.settings.category.notifications')") div.options-container(style="margin-top:0") - span.header Notifications + span.header {{ $t('view.settings.notifications.notifications.header') }} div.options-container-item - el-button(size="small" icon="el-icon-chat-square" @click="showNotyFeedFiltersDialog") Notification Filters - span.sub-header SteamVR Notifications + el-button(size="small" icon="el-icon-chat-square" @click="showNotyFeedFiltersDialog") {{ $t('view.settings.notifications.notifications.notification_filter') }} + span.sub-header {{ $t('view.settings.notifications.notifications.steamvr_notifications.header') }} div.options-container-item - span.name SteamVR Overlay + span.name {{ $t('view.settings.notifications.notifications.steamvr_notifications.steamvr_overlay') }} el-switch(v-model="openVR" @change="saveOpenVROption") div.options-container-item - span.name Overlay Notifications + span.name {{ $t('view.settings.notifications.notifications.steamvr_notifications.overlay_notifications') }} el-switch(v-model="overlayNotifications" @change="saveOpenVROption" :disabled="!openVR") div.options-container-item - el-button(size="small" icon="el-icon-rank" @click="showNotificationPositionDialog" :disabled="!overlayNotifications || !openVR") Notification Position + el-button(size="small" icon="el-icon-rank" @click="showNotificationPositionDialog" :disabled="!overlayNotifications || !openVR") {{ $t('view.settings.notifications.notifications.steamvr_notifications.notification_position') }} div.options-container-item - span.name XSOverlay Notifications + span.name {{ $t('view.settings.notifications.notifications.steamvr_notifications.xsoverlay_notifications') }} el-switch(v-model="xsNotifications" @change="saveOpenVROption") div.options-container-item - span.name User images (slower) + span.name {{ $t('view.settings.notifications.notifications.steamvr_notifications.user_images') }} el-switch(v-model="imageNotifications" @change="saveOpenVROption") div.options-container-item - el-button(size="small" icon="el-icon-time" @click="promptNotificationTimeout" :disabled="(!overlayNotifications || !openVR) && !xsNotifications") Notification Timeout - span.sub-header Desktop Notifications + el-button(size="small" icon="el-icon-time" @click="promptNotificationTimeout" :disabled="(!overlayNotifications || !openVR) && !xsNotifications") {{ $t('view.settings.notifications.notifications.steamvr_notifications.notification_timeout') }} + span.sub-header {{ $t('view.settings.notifications.notifications.desktop_notifications.header') }} div.options-container-item - span.name When to display: + span.name {{ $t('view.settings.notifications.notifications.desktop_notifications.when_to_display') }} br el-radio-group(v-model="desktopToast" @change="saveOpenVROption" size="mini") - el-radio-button(label="Never") - el-radio-button(label="Desktop Mode") - el-radio-button(label="Inside VR") - el-radio-button(label="Outside VR") - el-radio-button(label="Game Closed") - el-radio-button(label="Game Running") - el-radio-button(label="Always") + el-radio-button(label="Never") {{ $t('view.settings.notifications.notifications.desktop_notifications.when_to_display_never') }} + el-radio-button(label="Desktop Mode") {{ $t('view.settings.notifications.notifications.desktop_notifications.when_to_display_desktop') }} + el-radio-button(label="Inside VR") {{ $t('view.settings.notifications.notifications.desktop_notifications.when_to_display_inside_vr') }} + el-radio-button(label="Outside VR") {{ $t('view.settings.notifications.notifications.desktop_notifications.when_to_display_outside_vr') }} + el-radio-button(label="Game Closed") {{ $t('view.settings.notifications.notifications.desktop_notifications.when_to_display_game_closed') }} + el-radio-button(label="Game Running") {{ $t('view.settings.notifications.notifications.desktop_notifications.when_to_display_game_running') }} + el-radio-button(label="Always") {{ $t('view.settings.notifications.notifications.desktop_notifications.when_to_display_always') }} br - span.sub-header Text-To-Speech Options + span.sub-header {{ $t('view.settings.notifications.notifications.text_to_speech.header') }} div.options-container-item - span.name Notification TTS, When to play: + span.name {{ $t('view.settings.notifications.notifications.text_to_speech.when_to_play') }} br el-radio-group(v-model="notificationTTS" @change="saveNotificationTTS" size="mini") - el-radio-button(label="Never") - el-radio-button(label="Inside VR") - el-radio-button(label="Game Closed") - el-radio-button(label="Game Running") - el-radio-button(label="Always") + el-radio-button(label="Never") {{ $t('view.settings.notifications.notifications.text_to_speech.when_to_play_never') }} + el-radio-button(label="Inside VR") {{ $t('view.settings.notifications.notifications.text_to_speech.when_to_play_inside_vr') }} + el-radio-button(label="Game Closed") {{ $t('view.settings.notifications.notifications.text_to_speech.when_to_play_game_closed') }} + el-radio-button(label="Game Running") {{ $t('view.settings.notifications.notifications.text_to_speech.when_to_play_game_running') }} + el-radio-button(label="Always") {{ $t('view.settings.notifications.notifications.text_to_speech.when_to_play_always') }} div.options-container-item - span.name TTS Voice + span.name {{ $t('view.settings.notifications.notifications.text_to_speech.tts_voice') }} el-dropdown(@command="(voice) => changeTTSVoice(voice)" trigger="click" size="small") el-button(size="mini" :disabled="notificationTTS === 'Never'") span {{ getTTSVoiceName() }} #[i.el-icon-arrow-down.el-icon--right] el-dropdown-menu(#default="dropdown") el-dropdown-item(v-if="voice" v-for="(voice, index) in TTSvoices" :key="index" v-text="voice.name" :command="index") - el-tab-pane(label="Wrist Overlay") + el-tab-pane(:label="$t('view.settings.category.wrist_overlay')") div.options-container(style="margin-top:0") - span.header SteamVR Wrist Overlay + span.header {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.header') }} div.options-container-item - span * It runs automatically when VRChat is running. + span {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.description') }} br br - span Grip: Vive or Other Controllers Grab, Oculus X/A Buttons + span {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.grip') }} br - span Menu: Vive Menu, Index B, Oculus Y/B Buttons + span {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.menu') }} br div.options-container-item - span.name SteamVR Overlay + span.name {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.steamvr_overlay') }} el-switch(v-model="openVR" @change="saveOpenVROption") div.options-container-item - span.name Wrist Feed Overlay + span.name {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.wrist_feed_overlay') }} el-switch(v-model="overlayWrist" @change="saveOpenVROption" :disabled="!openVR") div.options-container-item - span.name Hide Private Worlds + span.name {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.hide_private_worlds') }} el-switch(v-model="hidePrivateFromFeed" @change="saveOpenVROption") div.options-container-item(style="min-width:118px") - span.name Start Overlay With + span.name {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.start_overlay_with') }} el-switch(v-model="openVRAlways" @change="saveOpenVROption" inactive-text="VRChat" active-text="SteamVR" :disabled="!openVR") div.options-container-item - span.name Overlay Button - el-switch(v-model="overlaybutton" @change="saveOpenVROption" inactive-text="Grip" active-text="Menu" :disabled="!openVR || !overlayWrist") + span.name {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.overlay_button') }} + el-switch(v-model="overlaybutton" @change="saveOpenVROption" :inactive-text="$t('view.settings.wrist_overlay.steamvr_wrist_overlay.overlay_button_grip')" :active-text="$t('view.settings.wrist_overlay.steamvr_wrist_overlay.overlay_button_menu')" :disabled="!openVR || !overlayWrist") div.options-container-item - span.name Display Overlay On + span.name {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.display_overlay_on') }} el-radio-group(v-model="overlayHand" @change="saveOpenVROption" size="mini") - el-radio-button(label="1") Left Hand - el-radio-button(label="2") Right Hand - el-radio-button(label="0") Both Hands + el-radio-button(label="1") {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.display_overlay_on_left') }} + el-radio-button(label="2") {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.display_overlay_on_right') }} + el-radio-button(label="0") {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.display_overlay_on_both') }} div.options-container-item - span.name Background Colour + span.name {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.background_color') }} el-switch(v-model="vrBackgroundEnabled" @change="saveOpenVROption" :disabled="!openVR || !overlayWrist") div.options-container-item - span.name Minimal Feed Icons + span.name {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.minimal_feed_icons') }} el-switch(v-model="minimalFeed" @change="saveOpenVROption" :disabled="!openVR || !overlayWrist") div.options-container-item - span.name Hide VR Devices + span.name {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.hide_vr_devices') }} el-switch(v-model="hideDevicesFromFeed" @change="saveOpenVROption" :disabled="!openVR || !overlayWrist") div.options-container-item - span.name Hide CPU Usage + span.name {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.hide_cpu_usage') }} el-switch(v-model="hideCpuUsageFromFeed" @change="saveOpenVROption" :disabled="!openVR || !overlayWrist") div.options-container-item - span.name Hide Game Uptime + span.name {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.hide_game_uptime') }} el-switch(v-model="hideUptimeFromFeed" @change="saveOpenVROption" :disabled="!openVR || !overlayWrist") div.options-container-item - span.name Show PC Uptime + span.name {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.show_pc_uptime') }} el-switch(v-model="pcUptimeOnFeed" @change="saveOpenVROption" :disabled="!openVR || !overlayWrist") div.options-container-item - el-button(size="small" icon="el-icon-notebook-2" @click="showWristFeedFiltersDialog" :disabled="!openVR || !overlayWrist") Wrist Feed Filters - el-tab-pane(label="Discord Presence") + el-button(size="small" icon="el-icon-notebook-2" @click="showWristFeedFiltersDialog" :disabled="!openVR || !overlayWrist") {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.wrist_feed_filters') }} + el-tab-pane(:label="$t('view.settings.category.discord_presence')") div.options-container(style="margin-top:0") - span.header Discord Presence + span.header {{ $t('view.settings.discord_presence.discord_presence.header') }} div.options-container-item - span * Only works when VRChat is running. + span {{ $t('view.settings.discord_presence.discord_presence.description') }} div.options-container-item - span.name Enable - el-tooltip(placement="top" style="margin-left:5px" content="Recommended to disable Rich Presence in VRChat config.json to stop it from conflicting") + span.name {{ $t('view.settings.discord_presence.discord_presence.enable') }} + el-tooltip(placement="top" style="margin-left:5px" :content="$t('view.settings.discord_presence.discord_presence.enable_tooltip')") i.el-icon-warning(style="cursor:pointer" @click="showVRChatConfig") el-switch(v-model="discordActive" @change="saveDiscordOption") div.options-container-item - span.name Instance type/player count + span.name {{ $t('view.settings.discord_presence.discord_presence.instance_type_player_count') }} el-switch(v-model="discordInstance" @change="saveDiscordOption" :disabled="!discordActive") div.options-container-item - span.name Join button (public only) + span.name {{ $t('view.settings.discord_presence.discord_presence.join_button') }} el-switch(v-model="discordJoinButton" @change="saveDiscordOption" :disabled="!discordActive") div.options-container-item - span.name Hide world details in private + span.name {{ $t('view.settings.discord_presence.discord_presence.hide_details_in_private') }} el-switch(v-model="discordHideInvite" @change="saveDiscordOption" :disabled="!discordActive") div.options-container-item - span.name Hide world images + span.name {{ $t('view.settings.discord_presence.discord_presence.hide_images') }} el-switch(v-model="discordHideImage" @change="saveDiscordOption" :disabled="!discordActive") - el-tab-pane(label="Advanced") + el-tab-pane(:label="$t('view.settings.category.advanced')") div.options-container(style="margin-top:0") - span.header Advanced + span.header {{ $t('view.settings.advanced.advanced.header') }} div.options-container-item el-button-group el-button(size="small" icon="el-icon-s-operation" @click="showVRChatConfig()") VRChat config.json - el-button(size="small" icon="el-icon-s-operation" @click="showLaunchOptions()") Launch Options + el-button(size="small" icon="el-icon-s-operation" @click="showLaunchOptions()") {{ $t('view.settings.advanced.advanced.launch_options') }} div.options-container - span.sub-header Pending Offline + span.sub-header {{ $t('view.settings.advanced.advanced.pending_offline.header') }} div.options-container-item - span.name Delay before marking user as offline (fixes false positives) + span.name {{ $t('view.settings.advanced.advanced.pending_offline.description') }} el-button-group(style="display:block") - el-button(size="small" icon="el-icon-s-operation" @click="promptSetPendingOffline") Set Delay - span.sub-header Primary password + el-button(size="small" icon="el-icon-s-operation" @click="promptSetPendingOffline") {{ $t('view.settings.advanced.advanced.pending_offline.set_delay') }} + span.sub-header {{ $t('view.settings.advanced.advanced.primary_password.header') }} div.options-container-item - span.name(style="min-width:300px") Encrypt password (disables auto login) + span.name(style="min-width:300px") {{ $t('view.settings.advanced.advanced.primary_password.description') }} el-switch(v-model="enablePrimaryPassword" @change="enablePrimaryPasswordChange" :disabled="!loginForm.savedCredentials[API.currentUser.username]") - span.sub-header VRChat Quit Fix + span.sub-header {{ $t('view.settings.advanced.advanced.vrchat_quit_fix.header') }} div.options-container-item - span.name(style="min-width:300px") Kill VRChat after exiting game + span.name(style="min-width:300px") {{ $t('view.settings.advanced.advanced.vrchat_quit_fix.description') }} el-switch(v-model="vrcQuitFix" @change="saveOpenVROption") - span.sub-header Automatically Manage Cache When Closing VRChat + span.sub-header {{ $t('view.settings.advanced.advanced.auto_cache_management.header') }} div.options-container-item - span.name(style="min-width:300px") Auto delete old versions from cache + span.name(style="min-width:300px") {{ $t('view.settings.advanced.advanced.auto_cache_management.description') }} el-switch(v-model="autoSweepVRChatCache" @change="saveOpenVROption") div.options-container - span.header Remote Avatar Database + span.header {{ $t('view.settings.advanced.advanced.remote_database.header') }} div.options-container-item - span.name Enable + span.name {{ $t('view.settings.advanced.advanced.remote_database.enable') }} el-switch(v-model="avatarRemoteDatabase" @change="saveOpenVROption") div.options-container-item - el-button(size="small" icon="el-icon-user-solid" @click="showAvatarProviderDialog") Avatar Database Provider + el-button(size="small" icon="el-icon-user-solid" @click="showAvatarProviderDialog") {{ $t('view.settings.advanced.advanced.remote_database.avatar_database_provider') }} div.options-container - span.header YouTube API + span.header {{ $t('view.settings.advanced.advanced.youtube_api.header') }} div.options-container-item - span.name Enabled + span.name {{ $t('view.settings.advanced.advanced.youtube_api.enable') }} el-switch(v-model="youTubeApi" @change="changeYouTubeApi") div.options-container-item - el-button(size="small" icon="el-icon-caret-right" @click="showYouTubeApiDialog") YouTube API Key - span.header Progress pie overlay for videos + el-button(size="small" icon="el-icon-caret-right" @click="showYouTubeApiDialog") {{ $t('view.settings.advanced.advanced.youtube_api.youtube_api_key') }} + span.header {{ $t('view.settings.advanced.advanced.video_progress_pie.header') }} div.options-container-item - span.name Enable - el-tooltip(placement="top" style="margin-left:5px" content="Requires SteamVR overlay to be enabled") + span.name {{ $t('view.settings.advanced.advanced.video_progress_pie.enable') }} + el-tooltip(placement="top" style="margin-left:5px" :content="$t('view.settings.advanced.advanced.video_progress_pie.enable_tooltip')") i.el-icon-warning el-switch(v-model="progressPie" @change="changeYouTubeApi" :disabled="!openVR") div.options-container-item - span.name Dance worlds only + span.name {{ $t('view.settings.advanced.advanced.video_progress_pie.dance_world_only') }} el-switch(v-model="progressPieFilter" @change="changeYouTubeApi" :disabled="!openVR") div.options-container(v-if="photonLoggingEnabled") - span.header Photon Logging Overlay + span.header {{ $t('view.settings.advanced.photon.header') }} div.options-container-item - span.sub-header Photon Event HUD + span.sub-header {{ $t('view.settings.advanced.photon.event_hud.header') }} div.options-container-item - span.name Enable - el-tooltip(placement="top" style="margin-left:5px" content="Requires SteamVR overlay to be enabled") + span.name {{ $t('view.settings.advanced.photon.event_hud.enable') }} + el-tooltip(placement="top" style="margin-left:5px" :content="$t('view.settings.advanced.photon.event_hud.enable_tooltip')") i.el-icon-warning el-switch(v-model="photonEventOverlay" @change="saveEventOverlay" :disabled="!openVR") div.options-container-item - span.name Filter + span.name {{ $t('view.settings.advanced.photon.event_hud.filter') }} el-radio-group(v-model="photonEventOverlayFilter" @change="saveEventOverlay" size="mini" :disabled="!openVR || !photonEventOverlay") - el-radio-button(label="VIP") - el-radio-button(label="Friends") - el-radio-button(label="Everyone") + el-radio-button(label="VIP") {{ $t('view.settings.advanced.photon.event_hud.filter_favorites') }} + el-radio-button(label="Friends") {{ $t('view.settings.advanced.photon.event_hud.filter_friends') }} + el-radio-button(label="Everyone") {{ $t('view.settings.advanced.photon.event_hud.filter_everyone') }} div.options-container-item - el-button(size="small" icon="el-icon-time" @click="promptPhotonOverlayMessageTimeout" :disabled="!openVR") Message Timeout + el-button(size="small" icon="el-icon-time" @click="promptPhotonOverlayMessageTimeout" :disabled="!openVR") {{ $t('view.settings.advanced.photon.event_hud.message_timeout') }} div.options-container-item el-select(v-model="photonEventTableTypeOverlayFilter" @change="photonEventTableFilterChange" multiple clearable collapse-tags style="flex:1" placeholder="Filter") el-option(v-once v-for="type in photonEventTableTypeFilterList" :key="type" :label="type" :value="type") br - span.sub-header User timeout HUD + span.sub-header {{ $t('view.settings.advanced.photon.timeout_hud.header') }} div.options-container-item - span.name Enable - el-tooltip(placement="top" style="margin-left:5px" content="Requires SteamVR overlay to be enabled") + span.name {{ $t('view.settings.advanced.photon.timeout_hud.enable') }} + el-tooltip(placement="top" style="margin-left:5px" :content="$t('view.settings.advanced.photon.timeout_hud.enable_tooltip')") i.el-icon-warning el-switch(v-model="timeoutHudOverlay" @change="saveEventOverlay" :disabled="!openVR") div.options-container-item - span.name Filter + span.name {{ $t('view.settings.advanced.photon.timeout_hud.filter') }} el-radio-group(v-model="timeoutHudOverlayFilter" @change="saveEventOverlay" size="mini" :disabled="!openVR || !timeoutHudOverlay") - el-radio-button(label="VIP") - el-radio-button(label="Friends") - el-radio-button(label="Everyone") + el-radio-button(label="VIP") {{ $t('view.settings.advanced.photon.timeout_hud.filter_favorites') }} + el-radio-button(label="Friends") {{ $t('view.settings.advanced.photon.timeout_hud.filter_friends') }} + el-radio-button(label="Everyone") {{ $t('view.settings.advanced.photon.timeout_hud.filter_everyone') }} div.options-container-item - el-button(size="small" icon="el-icon-time" @click="promptPhotonLobbyTimeoutThreshold" :disabled="!openVR") Timeout Threshold + el-button(size="small" icon="el-icon-time" @click="promptPhotonLobbyTimeoutThreshold" :disabled="!openVR") {{ $t('view.settings.advanced.photon.timeout_hud.timeout_threshold') }} div.options-container - span.header VRCX Instance Cache/Debug + span.header {{ $t('view.settings.advanced.advanced.cache_debug.header') }} div.options-container-item - span.name Disable GameLog + span.name {{ $t('view.settings.advanced.advanced.cache_debug.disable_gamelog') }} el-switch(v-model="gameLogDisabled" @change="disableGameLogDialog") - span.name(style="margin-left:15px") (will likely break things) + span.name(style="margin-left:15px") {{ $t('view.settings.advanced.advanced.cache_debug.disable_gamelog_notice') }} div.options-container-item - span.name User cache: #[span(v-text="API.cachedUsers.size")] + span.name {{ $t('view.settings.advanced.advanced.cache_debug.user_cache') }} #[span(v-text="API.cachedUsers.size")] div.options-container-item - span.name World cache: #[span(v-text="API.cachedWorlds.size")] + span.name {{ $t('view.settings.advanced.advanced.cache_debug.world_cache') }} #[span(v-text="API.cachedWorlds.size")] div.options-container-item - span.name Avatar cache: #[span(v-text="API.cachedAvatars.size")] + span.name {{ $t('view.settings.advanced.advanced.cache_debug.avatar_cache') }} #[span(v-text="API.cachedAvatars.size")] div.options-container-item - span.name Avatar Name cache: #[span(v-text="API.cachedAvatarNames.size")] + span.name {{ $t('view.settings.advanced.advanced.cache_debug.avatar_name_cache') }} #[span(v-text="API.cachedAvatarNames.size")] div.options-container-item - el-button(size="small" icon="el-icon-delete-solid" @click="clearVRCXCache") Clear Cache - el-button(size="small" icon="el-icon-time" @click="promptAutoClearVRCXCacheFrequency") Auto Clear Cache + el-button(size="small" icon="el-icon-delete-solid" @click="clearVRCXCache") {{ $t('view.settings.advanced.advanced.cache_debug.clear_cache') }} + el-button(size="small" icon="el-icon-time" @click="promptAutoClearVRCXCacheFrequency") {{ $t('view.settings.advanced.advanced.cache_debug.auto_clear_cache') }} div.options-container-item - el-button(size="small" icon="el-icon-download" @click="showDownloadDialog") Download History - el-button(size="small" icon="el-icon-tickets" @click="showConsole") Show Console + el-button(size="small" icon="el-icon-download" @click="showDownloadDialog") {{ $t('view.settings.advanced.advanced.cache_debug.download_history') }} + el-button(size="small" icon="el-icon-tickets" @click="showConsole") {{ $t('view.settings.advanced.advanced.cache_debug.show_console') }} div.options-container - span.sub-header SQLite Table Size + span.sub-header {{ $t('view.settings.advanced.advanced.sqlite_table_size.header') }} div.options-container-item - el-button(size="small" icon="el-icon-refresh" @click="getSqliteTableSizes") Refresh + el-button(size="small" icon="el-icon-refresh" @click="getSqliteTableSizes") {{ $t('view.settings.advanced.advanced.sqlite_table_size.refresh') }} div.options-container-item - span.name GPS: #[span(v-text="sqliteTableSizes.gps")] + span.name {{ $t('view.settings.advanced.advanced.sqlite_table_size.gps') }} #[span(v-text="sqliteTableSizes.gps")] div.options-container-item - span.name Status: #[span(v-text="sqliteTableSizes.status")] + span.name {{ $t('view.settings.advanced.advanced.sqlite_table_size.status') }} #[span(v-text="sqliteTableSizes.status")] div.options-container-item - span.name Bio: #[span(v-text="sqliteTableSizes.bio")] + span.name {{ $t('view.settings.advanced.advanced.sqlite_table_size.bio') }} #[span(v-text="sqliteTableSizes.bio")] div.options-container-item - span.name Avatar: #[span(v-text="sqliteTableSizes.avatar")] + span.name {{ $t('view.settings.advanced.advanced.sqlite_table_size.avatar') }} #[span(v-text="sqliteTableSizes.avatar")] div.options-container-item - span.name Online/Offline: #[span(v-text="sqliteTableSizes.onlineOffline")] + span.name {{ $t('view.settings.advanced.advanced.sqlite_table_size.online_offline') }} #[span(v-text="sqliteTableSizes.onlineOffline")] div.options-container-item - span.name Friend Log History: #[span(v-text="sqliteTableSizes.friendLogHistory")] + span.name {{ $t('view.settings.advanced.advanced.sqlite_table_size.friend_log_history') }} #[span(v-text="sqliteTableSizes.friendLogHistory")] div.options-container-item - span.name Notifications: #[span(v-text="sqliteTableSizes.notification")] + span.name {{ $t('view.settings.advanced.advanced.sqlite_table_size.notification') }} #[span(v-text="sqliteTableSizes.notification")] div.options-container-item - span.name Location: #[span(v-text="sqliteTableSizes.location")] + span.name {{ $t('view.settings.advanced.advanced.sqlite_table_size.location') }} #[span(v-text="sqliteTableSizes.location")] div.options-container-item - span.name Join/Leave: #[span(v-text="sqliteTableSizes.joinLeave")] + span.name {{ $t('view.settings.advanced.advanced.sqlite_table_size.join_leave') }} #[span(v-text="sqliteTableSizes.joinLeave")] div.options-container-item - span.name Portal Spawn: #[span(v-text="sqliteTableSizes.portalSpawn")] + span.name {{ $t('view.settings.advanced.advanced.sqlite_table_size.portal_spawn') }} #[span(v-text="sqliteTableSizes.portalSpawn")] div.options-container-item - span.name Video Play: #[span(v-text="sqliteTableSizes.videoPlay")] + span.name {{ $t('view.settings.advanced.advanced.sqlite_table_size.video_play') }} #[span(v-text="sqliteTableSizes.videoPlay")] div.options-container-item - span.name Event: #[span(v-text="sqliteTableSizes.event")] + span.name {{ $t('view.settings.advanced.advanced.sqlite_table_size.event') }} #[span(v-text="sqliteTableSizes.event")] //- friends - .x-aside-container(v-show="$refs.menu && $refs.menu.activeIndex !== 'friendsList'" id="aside") + .x-aside-container(v-show="$refs.menu && $refs.menu.activeIndex !== 'friendsList'" id="aside") div(style="display:flex;align-items:baseline") - el-select(v-model="quickSearch" clearable placeholder="Search" filterable remote :remote-method="quickSearchRemoteMethod" popper-class="x-quick-search" @change="quickSearchChange" @visible-change="quickSearchVisibleChange" style="flex:1;padding:10px") + el-select(v-model="quickSearch" clearable :placeholder="$t('side_panel.search_placeholder')" filterable remote :remote-method="quickSearchRemoteMethod" popper-class="x-quick-search" @change="quickSearchChange" @visible-change="quickSearchVisibleChange" style="flex:1;padding:10px") el-option(v-for="item in quickSearchItems" :key="item.value" :value="item.value" :label="item.label") .x-friend-item template(v-if="item.ref") .detail span.name(v-text="item.ref.displayName" :style="{'color':item.ref.$userColour}") - span.extra(v-if="item.ref.state === 'offline'") Offline - span.extra(v-else-if="item.ref.state === 'active'") Active + span.extra(v-if="item.ref.state === 'offline'") {{ $t('side_panel.search_result_offline') }} + span.extra(v-else-if="item.ref.state === 'active'") {{ $t('side_panel.search_result_active') }} location.extra(v-else :location="item.ref.location" :traveling="item.ref.travelingToLocation" :link="false") img.avatar(v-lazy="userImage(item.ref)") - span(v-else) Search More: #[span(v-text="item.label" style="font-weight:bold")] - el-tooltip(placement="bottom" content="Direct access ID/URL from clipboard" :disabled="hideTooltips") + span(v-else) {{ $t('side_panel.search_result_more') }} #[span(v-text="item.label" style="font-weight:bold")] + el-tooltip(placement="bottom" :content="$t('side_panel.direct_access_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="directAccessPaste" size="mini" icon="el-icon-discover" circle) - el-tooltip(placement="bottom" content="Refresh friends" :disabled="hideTooltips") + el-tooltip(placement="bottom" :content="$t('side_panel.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="API.closeWebSocket(); API.getCurrentUser(); API.refreshFriends()" :loading="API.isRefreshFriendsLoading" size="mini" icon="el-icon-refresh" circle style="margin-right:10px") .x-friend-list(style="padding-bottom:10px") .x-friend-group(style="padding:5px 0 0") - span FRIENDS―{{ onlineFriendCount }}/{{ friends.size }} + span {{ $t('side_panel.friends') }} ― {{ onlineFriendCount }}/{{ friends.size }} .x-friend-group(style="padding:10px 0 5px") i.el-icon-arrow-right(:class="{ rotate: isFriendsGroupMe }") - span.x-link(@click="isFriendsGroupMe = !isFriendsGroupMe" style="margin-left:5px") ME + span.x-link(@click="isFriendsGroupMe = !isFriendsGroupMe" style="margin-left:5px") {{ $t('side_panel.me') }} div(v-show="isFriendsGroupMe") .x-friend-item(:key="API.currentUser.id" @click="showUserDialog(API.currentUser.id)") .avatar(:class="userStatusClass(API.currentUser)") @@ -1515,7 +1522,7 @@ html span.extra(v-else v-text="API.currentUser.statusDescription" :link="false") .x-friend-group(v-show="friendsGroup0.length") i.el-icon-arrow-right(:class="{ rotate: isFriendsGroup0 }") - span.x-link(@click="isFriendsGroup0 = !isFriendsGroup0" style="margin-left:5px") VIP―{{ friendsGroup0.length }} + span.x-link(@click="isFriendsGroup0 = !isFriendsGroup0" style="margin-left:5px") {{ $t('side_panel.favorite') }} ― {{ friendsGroup0.length }} div(v-show="isFriendsGroup0") .x-friend-item(v-for="friend in friendsGroup0" :key="friend.id" @click="showUserDialog(friend.id)") template(v-if="friend.ref") @@ -1524,14 +1531,14 @@ html .detail span.name(v-if="!hideUserMemos && friend.$nickName" :style="{'color':friend.ref.$userColour}") {{ friend.ref.displayName }} ({{ friend.$nickName }}) span.name(v-else v-text="friend.ref.displayName" :style="{'color':friend.ref.$userColour}") - span.extra(v-if="friend.pendingOffline") #[i.el-icon-warning-outline] Pending Offline + span.extra(v-if="friend.pendingOffline") #[i.el-icon-warning-outline] {{ $t('side_panel.penfing_offline') }} location.extra(v-else :location="friend.ref.location" :traveling="friend.ref.travelingToLocation" :link="false") template(v-else) span(v-text="friend.name || friend.id") el-button(type="text" icon="el-icon-close" size="mini" @click.stop="confirmDeleteFriend(friend.id)" style="margin-left:5px") .x-friend-group(v-show="friendsGroup1.length") i.el-icon-arrow-right(:class="{ rotate: isFriendsGroup1 }") - span.x-link(@click="isFriendsGroup1 = !isFriendsGroup1" style="margin-left:5px") ONLINE―{{ friendsGroup1.length }} + span.x-link(@click="isFriendsGroup1 = !isFriendsGroup1" style="margin-left:5px") {{ $t('side_panel.online') }} ― {{ friendsGroup1.length }} div(v-show="isFriendsGroup1") .x-friend-item(v-for="friend in friendsGroup1" :key="friend.id" @click="showUserDialog(friend.id)") template(v-if="friend.ref") @@ -1540,14 +1547,14 @@ html .detail span.name(v-if="!hideUserMemos && friend.$nickName" :style="{'color':friend.ref.$userColour}") {{ friend.ref.displayName }} ({{ friend.$nickName }}) span.name(v-else v-text="friend.ref.displayName" :style="{'color':friend.ref.$userColour}") - span.extra(v-if="friend.pendingOffline") #[i.el-icon-warning-outline] Pending Offline + span.extra(v-if="friend.pendingOffline") #[i.el-icon-warning-outline] {{ $t('side_panel.penfing_offline') }} location.extra(v-else :location="friend.ref.location" :traveling="friend.ref.travelingToLocation" :link="false") template(v-else) span(v-text="friend.name || friend.id") el-button(type="text" icon="el-icon-close" size="mini" @click.stop="confirmDeleteFriend(friend.id)" style="margin-left:5px") .x-friend-group(v-show="friendsGroup2.length") i.el-icon-arrow-right(:class="{ rotate: isFriendsGroup2 }") - span.x-link(@click="isFriendsGroup2 = !isFriendsGroup2" style="margin-left:5px") ACTIVE―{{ friendsGroup2.length }} + span.x-link(@click="isFriendsGroup2 = !isFriendsGroup2" style="margin-left:5px") {{ $t('side_panel.active') }} ― {{ friendsGroup2.length }} div(v-show="isFriendsGroup2") .x-friend-item(v-for="friend in friendsGroup2" :key="friend.id" @click="showUserDialog(friend.id)") template(v-if="friend.ref") @@ -1562,7 +1569,7 @@ html el-button(type="text" icon="el-icon-close" size="mini" @click.stop="confirmDeleteFriend(friend.id)" style="margin-left:5px") .x-friend-group(v-show="friendsGroup3.length") i.el-icon-arrow-right(:class="{ rotate: isFriendsGroup3 }") - span.x-link(@click="isFriendsGroup3 = !isFriendsGroup3" style="margin-left:5px") OFFLINE―{{ friendsGroup3.length }} + span.x-link(@click="isFriendsGroup3 = !isFriendsGroup3" style="margin-left:5px") {{ $t('side_panel.offline') }} ― {{ friendsGroup3.length }} div(v-show="isFriendsGroup3") .x-friend-item(v-for="friend in friendsGroup3" :key="friend.id" @click="showUserDialog(friend.id)") template(v-if="friend.ref") @@ -1591,18 +1598,18 @@ html div el-tooltip(v-if="userDialog.ref.status" placement="top") template(#content) - span(v-if="userDialog.ref.state === 'active'") Active - span(v-else-if="userDialog.ref.location === 'offline'") Offline - span(v-else-if="userDialog.ref.status === 'active'") Online - span(v-else-if="userDialog.ref.status === 'join me'") Join Me - span(v-else-if="userDialog.ref.status === 'ask me'") Ask Me - span(v-else-if="userDialog.ref.status === 'busy'") Do Not Disturb - span(v-else) Offline + span(v-if="userDialog.ref.state === 'active'") {{ $t('dialog.user.status.active') }} + span(v-else-if="userDialog.ref.location === 'offline'") {{ $t('dialog.user.status.offline') }} + span(v-else-if="userDialog.ref.status === 'active'") {{ $t('dialog.user.status.online') }} + span(v-else-if="userDialog.ref.status === 'join me'") {{ $t('dialog.user.status.join_me') }} + span(v-else-if="userDialog.ref.status === 'ask me'") {{ $t('dialog.user.status.ask_me') }} + span(v-else-if="userDialog.ref.status === 'busy'") {{ $t('dialog.user.status.busy') }} + span(v-else) {{ $t('dialog.user.status.offline') }} i.x-user-status(:class="userStatusClass(userDialog.ref)") template(v-if="userDialog.previousDisplayNames.length > 0") el-tooltip(placement="bottom") template(#content) - span Previous Display Names: + span {{ $t('dialog.user.previous_display_names') }} div(v-for="displayName in userDialog.previousDisplayNames" placement="top") span(v-text="displayName") i.el-icon-caret-bottom @@ -1617,9 +1624,9 @@ html span.flags(:class="languageClass(item.key)" style="display:inline-block;margin-right:5px") div el-tag.name(type="info" effect="plain" size="mini" :class="userDialog.ref.$trustClass" v-text="userDialog.ref.$trustLevel" style="margin-right:5px;margin-top:5px") - el-tag.x-tag-friend(v-if="userDialog.isFriend && userDialog.friend" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Friend No.{{userDialog.friend.no}} + el-tag.x-tag-friend(v-if="userDialog.isFriend && userDialog.friend" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.user.tags.friend_no', { number: userDialog.friend.no }) }} el-tag.x-tag-troll(v-if="userDialog.ref.$isTroll" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Nuisance - el-tag.x-tag-vip(v-if="userDialog.ref.$isModerator" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") VRChat Team + el-tag.x-tag-vip(v-if="userDialog.ref.$isModerator" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.user.tags.vrchat_team') }} el-tag.x-tag-vrcplus(v-if="userDialog.ref.$isVRCPlus" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") VRC+ el-tag.x-tag-platform-pc(v-if="userDialog.ref.last_platform === 'standalonewindows'" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") PC el-tag.x-tag-platform-quest(v-else-if="userDialog.ref.last_platform === 'android'" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Quest @@ -1631,62 +1638,62 @@ html img.x-link(v-lazy="userDialog.ref.userIcon" style="height:500px" @click="downloadAndSaveImage(userDialog.ref.userIcon)") div(style="flex:none") template(v-if="(API.currentUser.id !== userDialog.ref.id && userDialog.isFriend) || userDialog.isFavorite") - el-tooltip(v-if="userDialog.isFavorite" placement="top" content="Remove from favorites" :disabled="hideTooltips") + el-tooltip(v-if="userDialog.isFavorite" placement="top" :content="$t('dialog.user.actions.unfavorite_tooltip')" :disabled="hideTooltips") el-button(@click="userDialogCommand('Delete Favorite')" type="warning" icon="el-icon-star-on" circle) - el-tooltip(v-else placement="top" content="Add to favorites" :disabled="hideTooltips") + el-tooltip(v-else placement="top" :content="$t('dialog.user.actions.favorite_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="userDialogCommand('Add Favorite')" icon="el-icon-star-off" circle) el-dropdown(trigger="click" @command="userDialogCommand" size="small") el-button(:type="(userDialog.incomingRequest || userDialog.outgoingRequest || userDialog.isShowAvatar) ? 'success' : (userDialog.isBlock || userDialog.isMute || userDialog.isHideAvatar) ? 'danger' : 'default'" icon="el-icon-more" circle style="margin-left:5px") el-dropdown-menu(#default="dropdown") - el-dropdown-item(icon="el-icon-refresh" command="Refresh") Refresh - el-dropdown-item(icon="el-icon-s-order" command="Copy User") Copy User URL + el-dropdown-item(icon="el-icon-refresh" command="Refresh") {{ $t('dialog.user.actions.refresh') }} + el-dropdown-item(icon="el-icon-s-order" command="Copy User") {{ $t('dialog.user.actions.copy_url') }} template(v-if="userDialog.ref.id === API.currentUser.id") - el-dropdown-item(icon="el-icon-picture-outline" command="Manage Gallery" divided) Manage Gallery/Icons - el-dropdown-item(icon="el-icon-s-custom" command="Show Avatar Author") Show Avatar Author - el-dropdown-item(icon="el-icon-s-custom" command="Show Fallback Avatar Details") Show Fallback Avatar Details - el-dropdown-item(icon="el-icon-edit" command="Edit Social Status" divided) Social Status - el-dropdown-item(icon="el-icon-edit" command="Edit Language") Language - el-dropdown-item(icon="el-icon-edit" command="Edit Bio") Bio - el-dropdown-item(icon="el-icon-switch-button" command="Logout" divided) Logout + el-dropdown-item(icon="el-icon-picture-outline" command="Manage Gallery" divided) {{ $t('dialog.user.actions.manage_gallery_icon') }} + el-dropdown-item(icon="el-icon-s-custom" command="Show Avatar Author") {{ $t('dialog.user.actions.show_avatar_author') }} + el-dropdown-item(icon="el-icon-s-custom" command="Show Fallback Avatar Details") {{ $t('dialog.user.actions.show_fallback_avatar') }} + el-dropdown-item(icon="el-icon-edit" command="Edit Social Status" divided) {{ $t('dialog.user.actions.edit_status') }} + el-dropdown-item(icon="el-icon-edit" command="Edit Language") {{ $t('dialog.user.actions.edit_language') }} + el-dropdown-item(icon="el-icon-edit" command="Edit Bio") {{ $t('dialog.user.actions.edit_bio') }} + el-dropdown-item(icon="el-icon-switch-button" command="Logout" divided) {{ $t('dialog.user.actions.logout') }} template(v-else) template(v-if="userDialog.isFriend") - el-dropdown-item(icon="el-icon-postcard" command="Request Invite" divided) Request Invite - el-dropdown-item(icon="el-icon-postcard" command="Request Invite Message") Request Invite With Message + el-dropdown-item(icon="el-icon-postcard" command="Request Invite" divided) {{ $t('dialog.user.actions.request_invite') }} + el-dropdown-item(icon="el-icon-postcard" command="Request Invite Message") {{ $t('dialog.user.actions.request_invite_with_message') }} template(v-if="lastLocation.location && isGameRunning && checkCanInvite(lastLocation.location)") - el-dropdown-item(icon="el-icon-message" command="Invite") Invite - el-dropdown-item(icon="el-icon-message" command="Invite Message") Invite With Message + el-dropdown-item(icon="el-icon-message" command="Invite") {{ $t('dialog.user.actions.invite') }} + el-dropdown-item(icon="el-icon-message" command="Invite Message") {{ $t('dialog.user.actions.invite_with_message') }} template(v-else-if="userDialog.incomingRequest") - el-dropdown-item(icon="el-icon-check" command="Accept Friend Request") Accept Friend Request - el-dropdown-item(icon="el-icon-close" command="Decline Friend Request") Decline Friend Request - el-dropdown-item(v-else-if="userDialog.outgoingRequest" icon="el-icon-close" command="Cancel Friend Request") Cancel Friend Request - el-dropdown-item(v-else icon="el-icon-plus" command="Send Friend Request") Send Friend Request - el-dropdown-item(icon="el-icon-message" command="Invite To Group") Invite To Group - el-dropdown-item(icon="el-icon-s-custom" command="Show Avatar Author" divided) Show Avatar Author - el-dropdown-item(icon="el-icon-s-custom" command="Show Fallback Avatar Details") Show Fallback Avatar Details - el-dropdown-item(icon="el-icon-tickets" command="Previous Instances") Show Previous Instances - el-dropdown-item(v-if="userDialog.ref.currentAvatarImageUrl" icon="el-icon-picture-outline" command="Previous Images") Show Avatar Previous Images - el-dropdown-item(v-if="userDialog.isBlock" icon="el-icon-circle-check" command="Unblock" divided style="color:#F56C6C") Unblock - el-dropdown-item(v-else icon="el-icon-circle-close" command="Block" divided :disabled="userDialog.ref.$isModerator") Block - el-dropdown-item(v-if="userDialog.isMute" icon="el-icon-microphone" command="Unmute" style="color:#F56C6C") Unmute - el-dropdown-item(v-else icon="el-icon-turn-off-microphone" command="Mute" :disabled="userDialog.ref.$isModerator") Mute - el-dropdown-item(icon="el-icon-user-solid" command="Show Avatar") #[i.el-icon-check.el-icon--left(v-if="userDialog.isShowAvatar")]Show Avatar - el-dropdown-item(icon="el-icon-user" command="Hide Avatar") #[i.el-icon-check.el-icon--left(v-if="userDialog.isHideAvatar")]Hide Avatar - el-dropdown-item(v-if="userDialog.isInteractOff" icon="el-icon-thumb" command="Enable Avatar Interaction" style="color:#F56C6C") Enable Avatar Interaction - el-dropdown-item(v-else icon="el-icon-circle-close" command="Disable Avatar Interaction") Disable Avatar Interaction + el-dropdown-item(icon="el-icon-check" command="Accept Friend Request") {{ $t('dialog.user.actions.accept_friend_request') }} + el-dropdown-item(icon="el-icon-close" command="Decline Friend Request") {{ $t('dialog.user.actions.decline_friend_request') }} + el-dropdown-item(v-else-if="userDialog.outgoingRequest" icon="el-icon-close" command="Cancel Friend Request") {{ $t('dialog.user.actions.cancel_friend_request') }} + el-dropdown-item(v-else icon="el-icon-plus" command="Send Friend Request") {{ $t('dialog.user.actions.send_friend_request') }} + el-dropdown-item(icon="el-icon-message" command="Invite To Group") {{ $t('dialog.user.actions.invite_to_group') }} + el-dropdown-item(icon="el-icon-s-custom" command="Show Avatar Author" divided) {{ $t('dialog.user.actions.show_avatar_author') }} + el-dropdown-item(icon="el-icon-s-custom" command="Show Fallback Avatar Details") {{ $t('dialog.user.actions.show_fallback_avatar') }} + el-dropdown-item(icon="el-icon-tickets" command="Previous Instances") {{ $t('dialog.user.actions.show_previous_instances') }} + el-dropdown-item(v-if="userDialog.ref.currentAvatarImageUrl" icon="el-icon-picture-outline" command="Previous Images") {{ $t('dialog.user.actions.show_previous_images') }} + el-dropdown-item(v-if="userDialog.isBlock" icon="el-icon-circle-check" command="Unblock" divided style="color:#F56C6C") {{ $t('dialog.user.actions.moderation_unblock') }} + el-dropdown-item(v-else icon="el-icon-circle-close" command="Block" divided :disabled="userDialog.ref.$isModerator") {{ $t('dialog.user.actions.moderation_block') }} + el-dropdown-item(v-if="userDialog.isMute" icon="el-icon-microphone" command="Unmute" style="color:#F56C6C") {{ $t('dialog.user.actions.moderation_unmute') }} + el-dropdown-item(v-else icon="el-icon-turn-off-microphone" command="Mute" :disabled="userDialog.ref.$isModerator") {{ $t('dialog.user.actions.moderation_mute') }} + el-dropdown-item(icon="el-icon-user-solid" command="Show Avatar") #[i.el-icon-check.el-icon--left(v-if="userDialog.isShowAvatar")] {{ $t('dialog.user.actions.moderation_show_avatar') }} + el-dropdown-item(icon="el-icon-user" command="Hide Avatar") #[i.el-icon-check.el-icon--left(v-if="userDialog.isHideAvatar")] {{ $t('dialog.user.actions.moderation_hide_avatar') }} + el-dropdown-item(v-if="userDialog.isInteractOff" icon="el-icon-thumb" command="Enable Avatar Interaction" style="color:#F56C6C") {{ $t('dialog.user.actions.moderation_enable_avatar_interaction') }} + el-dropdown-item(v-else icon="el-icon-circle-close" command="Disable Avatar Interaction") {{ $t('dialog.user.actions.moderation_disable_avatar_interaction') }} template(v-if="userDialog.isFriend") - el-dropdown-item(icon="el-icon-delete" command="Unfriend" divided style="color:#F56C6C") Unfriend + el-dropdown-item(icon="el-icon-delete" command="Unfriend" divided style="color:#F56C6C") {{ $t('dialog.user.actions.unfriend') }} el-tabs(ref="userDialogTabs" @tab-click="userDialogTabClick") - el-tab-pane(label="Info") + el-tab-pane(:label="$t('dialog.user.info.header')") template(v-if="isFriendOnline(userDialog.friend) || API.currentUser.id === userDialog.id") div(v-if="userDialog.ref.location" style="display:flex;flex-direction:column;margin-bottom:10px;padding-bottom:10px;border-bottom:1px solid #e4e7ed14") div(style="flex:none") location(:location="userDialog.ref.location" :traveling="userDialog.ref.travelingToLocation") template(v-if="isRealInstance(userDialog.$location.tag)") - el-tooltip(placement="top" content="Launch/Invite" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('dialog.user.info.launch_invite_tooltip')" :disabled="hideTooltips") launch(:location="userDialog.$location.tag" style="margin-left:5px") - el-tooltip(placement="top" content="Invite yourself" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('dialog.user.info.self_invite_tooltip')" :disabled="hideTooltips") invite-yourself(:location="userDialog.$location.tag" :shortname="userDialog.$location.shortName" style="margin-left:5px") - el-tooltip(placement="top" content="Refresh player count" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('dialog.user.info.refresh_user_count_tooltip')" :disabled="hideTooltips") el-button(v-if="userDialog.$location.tag !== lastLocation.location" @click="refreshInstancePlayerCount(userDialog.$location.tag)" size="mini" icon="el-icon-refresh" style="margin-left:5px" circle) span(v-if="userDialog.instance.occupants" style="margin-left:5px") {{ userDialog.instance.occupants }} #[template(v-if="userDialog.instance.friendCount > 0") ({{ userDialog.instance.friendCount }})] .x-friend-list(style="flex:1;margin-top:10px;max-height:150px") @@ -1696,7 +1703,7 @@ html img(v-lazy="userImage(userDialog.$location.user)") .detail span.name(v-text="userDialog.$location.user.displayName" :style="{'color':userDialog.$location.user.$userColour}") - span.extra Instance Creator + span.extra {{ $t('dialog.user.info.instance_creator') }} span(v-else v-text="userDialog.$location.userId") .x-friend-item(v-for="user in userDialog.users" :key="user.id" @click="showUserDialog(user.id)" class="x-friend-item-border") .avatar(:class="userStatusClass(user)") @@ -1711,25 +1718,25 @@ html .x-friend-list(style="max-height:none") .x-friend-item(v-if="!hideUserNotes" style="width:100%;cursor:default") .detail - span.name Note - el-input(v-model="userDialog.note" type="textarea" maxlength="256" show-word-limit :rows="2" :autosize="{ minRows: 1, maxRows: 20 }" @change="checkNote(userDialog.ref, userDialog.note)" @input="cleanNote(userDialog.note)" placeholder="Click to add a note" size="mini" resize="none") + span.name {{ $t('dialog.user.info.note') }} + el-input(v-model="userDialog.note" type="textarea" maxlength="256" show-word-limit :rows="2" :autosize="{ minRows: 1, maxRows: 20 }" @change="checkNote(userDialog.ref, userDialog.note)" @input="cleanNote(userDialog.note)" :placeholder="$t('dialog.user.info.note_placeholder')" size="mini" resize="none") div(style="float:right") i.el-icon-loading(v-if="userDialog.noteSaving" style="margin-left:5px") i.el-icon-more-outline(v-else-if="userDialog.note !== userDialog.ref.note" style="margin-left:5px") el-button(v-if="userDialog.note" type="text" icon="el-icon-delete" size="mini" @click="deleteNote(userDialog.id)" style="margin-left:5px") .x-friend-item(v-if="!hideUserMemos" style="width:100%;cursor:default") .detail - span.name Memo - el-input.extra(v-model="userDialog.memo" type="textarea" :rows="2" :autosize="{ minRows: 1, maxRows: 20 }" placeholder="Click to add a memo" size="mini" resize="none") + span.name {{ $t('dialog.user.info.memo') }} + el-input.extra(v-model="userDialog.memo" type="textarea" :rows="2" :autosize="{ minRows: 1, maxRows: 20 }" :placeholder="$t('dialog.user.info.memo_placeholder')" size="mini" resize="none") .x-friend-item(style="width:100%;cursor:default") .detail - span.name(v-if="userDialog.id !== API.currentUser.id && userDialog.ref.profilePicOverride && userDialog.ref.currentAvatarImageUrl") Avatar Info Last Seen - span.name(v-else) Avatar Info + span.name(v-if="userDialog.id !== API.currentUser.id && userDialog.ref.profilePicOverride && userDialog.ref.currentAvatarImageUrl") {{ $t('dialog.user.info.avatar_info_last_seen') }} + span.name(v-else) {{ $t('dialog.user.info.avatar_info') }} .extra avatar-info(:imageurl="userDialog.ref.currentAvatarImageUrl" :userid="userDialog.id") .x-friend-item(style="width:100%;cursor:default") .detail - span.name Represented Group + span.name {{ $t('dialog.user.info.represented_group') }} .extra(v-if="userDialog.representedGroup.isRepresenting") div(style="display:inline-block;flex:none;margin-right:5px") el-popover(placement="right" width="500px" trigger="click") @@ -1742,7 +1749,7 @@ html .extra(v-else) - .x-friend-item(style="width:100%;cursor:default") .detail - span.name Bio + span.name {{ $t('dialog.user.info.bio') }} pre.extra(style="font-family:inherit;font-size:12px;white-space:pre-wrap;margin:0 0.5em 0 0") {{ userDialog.ref.bio || '-' }} div(v-if="userDialog.id === API.currentUser.id" style="float:right") el-button(type="text" icon="el-icon-edit" size="mini" @click="showBioDialog" style="margin-left:5px") @@ -1754,21 +1761,21 @@ html template(v-if="API.currentUser.id !== userDialog.id") .x-friend-item(style="cursor:default") .detail - span.name Last Seen - el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" content="Info from local database may not be accurate") + span.name {{ $t('dialog.user.info.last_seen') }} + el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" :content="$t('dialog.user.info.accuracy_notice')") i.el-icon-warning span.extra {{ userDialog.lastSeen | formatDate('long') }} .x-friend-item(@click="showPreviousInstancesUserDialog(userDialog.ref)") .detail - span.name Join Count - el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" content="Info from local database may not be accurate") + span.name {{ $t('dialog.user.info.join_count') }} + el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" :content="$t('dialog.user.info.accuracy_notice')") i.el-icon-warning span.extra(v-if="userDialog.joinCount === 0") - span.extra(v-else v-text="userDialog.joinCount") .x-friend-item(style="cursor:default") .detail - span.name Time Together - el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" content="Info from local database may not be accurate") + span.name {{ $t('dialog.user.info.time_together') }} + el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" :content="$t('dialog.user.info.accuracy_notice')") i.el-icon-warning span.extra(v-if="userDialog.timeSpent === 0") - span.extra(v-else) {{ userDialog.timeSpent | timeToText }} @@ -1777,57 +1784,57 @@ html template(#content) span {{ userOnlineForTimestamp(userDialog) | formatDate('short') }} .detail - span.name(v-if="userDialog.ref.state === 'online' && userDialog.ref.$online_for") Online For - el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" content="Info from local database may not be accurate") + span.name(v-if="userDialog.ref.state === 'online' && userDialog.ref.$online_for") {{ $t('dialog.user.info.online_for') }} + el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" :content="$t('dialog.user.info.accuracy_notice')") i.el-icon-warning - span.name(v-else) Offline For - el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" content="Info from local database may not be accurate") + span.name(v-else) {{ $t('dialog.user.info.offline_for') }} + el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" :content="$t('dialog.user.info.accuracy_notice')") i.el-icon-warning span.extra {{ userOnlineFor(userDialog) | timeToText }} .x-friend-item(style="cursor:default") el-tooltip(placement="top") template(#content) - span Last Login {{ userDialog.ref.last_login | formatDate('short') }} + span {{ $t('dialog.user.info.last_login') }} {{ userDialog.ref.last_login | formatDate('short') }} .detail - span.name Last Activity + span.name {{ $t('dialog.user.info.last_activity') }} span.extra {{ userDialog.ref.last_activity | formatDate('long') }} .x-friend-item(style="cursor:default") .detail - span.name Date Joined + span.name {{ $t('dialog.user.info.date_joined') }} span.extra(v-text="userDialog.ref.date_joined") .x-friend-item(v-if="API.currentUser.id !== userDialog.id" style="cursor:default") .detail - span.name(v-if="userDialog.unFriended") Unfriended - el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" content="Info from local database may not be accurate") + span.name(v-if="userDialog.unFriended") {{ $t('dialog.user.info.unfriended') }} + el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" :content="$t('dialog.user.info.accuracy_notice')") i.el-icon-warning - span.name(v-else) Friended - el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" content="Info from local database may not be accurate") + span.name(v-else) {{ $t('dialog.user.info.friended') }} + el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" :content="$t('dialog.user.info.accuracy_notice')") i.el-icon-warning span.extra {{ userDialog.dateFriended | formatDate('long') }} template(v-if="API.currentUser.id === userDialog.id") .x-friend-item(@click="toggleAvatarCopying") .detail - span.name Avatar Cloning - span.extra(v-if="userDialog.ref.allowAvatarCopying" style="color:#67C23A") Allow - span.extra(v-else style="color:#F56C6C") Deny + span.name {{ $t('dialog.user.info.avatar_cloning') }} + span.extra(v-if="userDialog.ref.allowAvatarCopying" style="color:#67C23A") {{ $t('dialog.user.info.avatar_cloning_allow') }} + span.extra(v-else style="color:#F56C6C") {{ $t('dialog.user.info.avatar_cloning_deny') }} template(v-else) .x-friend-item(style="cursor:default") .detail - span.name Avatar Cloning - span.extra(v-if="userDialog.ref.allowAvatarCopying" style="color:#67C23A") Allow - span.extra(v-else style="color:#F56C6C") Deny + span.name {{ $t('dialog.user.info.avatar_cloning') }} + span.extra(v-if="userDialog.ref.allowAvatarCopying" style="color:#67C23A") {{ $t('dialog.user.info.avatar_cloning_allow') }} + span.extra(v-else style="color:#F56C6C") {{ $t('dialog.user.info.avatar_cloning_deny') }} .x-friend-item(v-if="userDialog.ref.id === API.currentUser.id && API.currentUser.homeLocation" @click="showWorldDialog(API.currentUser.homeLocation)" style="width:100%") .detail - span.name Home Location + span.name {{ $t('dialog.user.info.home_location') }} span.extra span(v-text="userDialog.$homeLocationName") el-button(@click.stop="resetHome()" size="mini" icon="el-icon-delete" circle style="margin-left:5px") - el-tab-pane(label="Groups") + el-tab-pane(:label="$t('dialog.user.groups.header')") el-button(type="default" :loading="userDialog.isGroupsLoading" @click="getUserGroups(userDialog.id)" size="mini" icon="el-icon-refresh" circle) - span(style="margin-left:5px") Total {{ userGroups.groups.length }} + span(style="margin-left:5px") {{ $t('dialog.user.groups.total_count', { count: userGroups.groups.length }) }} div(v-loading="userDialog.isGroupsLoading" style="margin-top:10px") template(v-if="userGroups.ownGroups.length > 0") - span(style="font-weight:bold;font-size:16px") Own Groups + span(style="font-weight:bold;font-size:16px") {{ $t('dialog.user.groups.own_groups') }} span(style="color:#909399;font-size:12px;margin-left:5px") {{ userGroups.ownGroups.length }} .x-friend-list(style="margin-top:10px;margin-bottom:15px;min-height:60px") .x-friend-item(v-for="group in userGroups.ownGroups" :key="group.id" @click="showGroupDialog(group.id)" class="x-friend-item-border") @@ -1837,7 +1844,7 @@ html span.name(v-text="group.name") span.extra ({{ group.memberCount }}) template(v-if="userGroups.mutualGroups.length > 0") - span(style="font-weight:bold;font-size:16px") Mutual Groups + span(style="font-weight:bold;font-size:16px") {{ $t('dialog.user.groups.mutual_groups') }} span(style="color:#909399;font-size:12px;margin-left:5px") {{ userGroups.mutualGroups.length }} .x-friend-list(style="margin-top:10px;margin-bottom:15px;min-height:60px") .x-friend-item(v-for="group in userGroups.mutualGroups" :key="group.id" @click="showGroupDialog(group.id)" class="x-friend-item-border") @@ -1847,7 +1854,7 @@ html span.name(v-text="group.name") span.extra ({{ group.memberCount }}) template(v-if="userGroups.remainingGroups.length > 0") - span(style="font-weight:bold;font-size:16px") Groups + span(style="font-weight:bold;font-size:16px") {{ $t('dialog.user.groups.groups') }} span(style="color:#909399;font-size:12px;margin-left:5px") {{ userGroups.remainingGroups.length }} .x-friend-list(style="margin-top:10px;margin-bottom:15px;min-height:60px") .x-friend-item(v-for="group in userGroups.remainingGroups" :key="group.id" @click="showGroupDialog(group.id)" class="x-friend-item-border") @@ -1856,12 +1863,12 @@ html .detail span.name(v-text="group.name") span.extra ({{ group.memberCount }}) - el-tab-pane(label="Worlds") + el-tab-pane(:label="$t('dialog.user.worlds.header')") el-button(type="default" :loading="userDialog.isWorldsLoading" @click="refreshUserDialogWorlds()" size="mini" icon="el-icon-refresh" circle) - span(style="margin-left:5px") Total {{ userDialog.worlds.length }} + span(style="margin-left:5px") {{ $t('dialog.user.worlds.total_count', { count: userDialog.worlds.length }) }} el-radio-group(v-model="userDialog.worldSorting" size="mini" style="margin-left:30px" @change="changeUserDialogWorldSorting") - el-radio(label="name") by name - el-radio(label="update") by update + el-radio(label="name") {{ $t('dialog.user.worlds.sort_by_name') }} + el-radio(label="update") {{ $t('dialog.user.worlds.sort_by_update') }} .x-friend-list(v-loading="userDialog.isWorldsLoading" style="margin-top:10px;min-height:60px") .x-friend-item(v-for="world in userDialog.worlds" :key="world.id" @click="showWorldDialog(world.id)" class="x-friend-item-border") .avatar @@ -1869,7 +1876,7 @@ html .detail span.name(v-text="world.name") span.extra(v-if="world.occupants") ({{ world.occupants }}) - el-tab-pane(label="Favorite Worlds") + el-tab-pane(:label="$t('dialog.user.favorite_worlds.header')") el-button(type="default" :loading="userDialog.isFavoriteWorldsLoading" @click="getUserFavoriteWorlds(userDialog.id)" size="mini" icon="el-icon-refresh" circle) el-tabs(type="card" v-loading="userDialog.isFavoriteWorldsLoading" style="margin-top:10px") template(v-for="(list, index) in userFavoriteWorlds" v-if="list") @@ -1885,17 +1892,17 @@ html .detail span.name(v-text="world.name") span.extra(v-if="world.occupants") ({{ world.occupants }}) - el-tab-pane(label="Avatars") + el-tab-pane(:label="$t('dialog.user.avatars.header')") template(v-if="userDialog.ref.id === API.currentUser.id") el-button(type="default" :loading="userDialog.isAvatarsLoading" @click="refreshUserDialogAvatars()" size="mini" icon="el-icon-refresh" circle) - span(style="margin-left:5px") Total {{ userDialogAvatars.length }} + span(style="margin-left:5px") {{ $t('dialog.user.avatars.total_count', { count: userDialogAvatars.length }) }} el-radio-group(v-if="userDialog.ref.id === API.currentUser.id" v-model="userDialog.avatarSorting" size="mini" style="margin-left:30px;margin-right:30px" @change="changeUserDialogAvatarSorting") - el-radio(label="name") by name - el-radio(label="update") by update + el-radio(label="name") {{ $t('dialog.user.avatars.sort_by_name') }} + el-radio(label="update") {{ $t('dialog.user.avatars.sort_by_update') }} el-radio-group(v-if="userDialog.ref.id === API.currentUser.id" v-model="userDialog.avatarReleaseStatus" size="mini" style="margin-left:30px") - el-radio(label="all") all - el-radio(label="public") public - el-radio(label="private") private + el-radio(label="all") {{ $t('dialog.user.avatars.all') }} + el-radio(label="public") {{ $t('dialog.user.avatars.public') }} + el-radio(label="private") {{ $t('dialog.user.avatars.private') }} .x-friend-list(style="margin-top:10px;min-height:60px") .x-friend-item(v-for="avatar in userDialogAvatars" @click="showAvatarDialog(avatar.id)" class="x-friend-item-border") .avatar @@ -1905,7 +1912,7 @@ html span.extra(v-text="avatar.releaseStatus" v-if="avatar.releaseStatus === 'public'" style="color: #67c23a;") span.extra(v-text="avatar.releaseStatus" v-else-if="avatar.releaseStatus === 'private'" style="color: #f56c6c;") span.extra(v-text="avatar.releaseStatus" v-else) - el-tab-pane(label="JSON") + el-tab-pane(:label="$t('dialog.user.json.header')") el-button(type="default" @click="refreshUserDialogTreeData()" size="mini" icon="el-icon-refresh" circle) el-tree(:data="userDialog.treeData" style="margin-top:5px;font-size:12px") template(#default="scope") @@ -1928,57 +1935,57 @@ html div(style="margin-top:5px") span.x-link(v-text="worldDialog.ref.authorName" @click="showUserDialog(worldDialog.ref.authorId)" style="color:#909399;font-family:monospace") div - el-tag(v-if="worldDialog.ref.$isLabs" type="primary" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Labs - el-tag(v-else-if="worldDialog.ref.releaseStatus === 'public'" type="success" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Public - el-tag(v-else type="danger" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Private + el-tag(v-if="worldDialog.ref.$isLabs" type="primary" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.world.tags.labs') }} + el-tag(v-else-if="worldDialog.ref.releaseStatus === 'public'" type="success" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.world.tags.public') }} + el-tag(v-else type="danger" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.world.tags.private') }} el-tag.x-tag-platform-pc(v-if="worldDialog.isPC" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") PC el-tag.x-tag-platform-quest(v-if="worldDialog.isQuest" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Quest el-tag(type="info" effect="plain" size="mini" v-text="worldDialog.fileSize" style="margin-right:5px;margin-top:5px") el-tag(v-if="worldDialog.inCache" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") span(v-text="worldDialog.cacheSize") - | Cache + | {{ $t('dialog.world.tags.cache')}} div(style="margin-top:5px") span(v-show="worldDialog.ref.name !== worldDialog.ref.description" v-text="worldDialog.ref.description" style="font-size:12px") div(style="flex:none;margin-left:10px") - el-tooltip(v-if="worldDialog.inCache" placement="top" content="Delete world from cache" :disabled="hideTooltips") + el-tooltip(v-if="worldDialog.inCache" placement="top" :content="$t('dialog.world.actions.delete_cache_tooltip')" :disabled="hideTooltips") el-button(icon="el-icon-delete" circle @click="deleteVRChatCache(worldDialog.ref)" :disabled="isGameRunning && worldDialog.cacheLocked") - el-tooltip(v-if="worldDialog.isFavorite" placement="top" content="Favorite/Unfavorite" :disabled="hideTooltips") + el-tooltip(v-if="worldDialog.isFavorite" placement="top" :content="$t('dialog.world.actions.unfavorite_tooltip')" :disabled="hideTooltips") el-button(type="default" icon="el-icon-star-on" circle @click="worldDialogCommand('Add Favorite')" style="margin-left:5px") - el-tooltip(v-else placement="top" content="Favorite/Unfavorite" :disabled="hideTooltips") + el-tooltip(v-else placement="top" :content="$t('dialog.world.actions.favorite_tooltip')" :disabled="hideTooltips") el-button(type="default" icon="el-icon-star-off" circle @click="worldDialogCommand('Add Favorite')" style="margin-left:5px") el-dropdown(trigger="click" @command="worldDialogCommand" size="small" style="margin-left:5px") el-button(type="default" icon="el-icon-more" circle) el-dropdown-menu(#default="dropdown") - el-dropdown-item(icon="el-icon-refresh" command="Refresh") Refresh - el-dropdown-item(icon="el-icon-s-flag" command="New Instance" divided) New Instance - el-dropdown-item(v-if="API.currentUser.$homeLocation && API.currentUser.$homeLocation.worldId === worldDialog.id" icon="el-icon-magic-stick" command="Reset Home" divided) Reset Home - el-dropdown-item(v-else icon="el-icon-s-home" command="Make Home" divided) Make Home - el-dropdown-item(icon="el-icon-tickets" command="Previous Instances") Show Previous Instances + el-dropdown-item(icon="el-icon-refresh" command="Refresh") {{ $t('dialog.world.actions.refresh') }} + el-dropdown-item(icon="el-icon-s-flag" command="New Instance" divided) {{ $t('dialog.world.actions.new_instance') }} + el-dropdown-item(v-if="API.currentUser.$homeLocation && API.currentUser.$homeLocation.worldId === worldDialog.id" icon="el-icon-magic-stick" command="Reset Home" divided) {{ $t('dialog.world.actions.reset_home') }} + el-dropdown-item(v-else icon="el-icon-s-home" command="Make Home" divided) {{ $t('dialog.world.actions.make_home') }} + el-dropdown-item(icon="el-icon-tickets" command="Previous Instances") {{ $t('dialog.world.actions.show_previous_instances') }} template(v-if="API.currentUser.id !== worldDialog.ref.authorId") - el-dropdown-item(icon="el-icon-picture-outline" command="Previous Images") Show Previous Images + el-dropdown-item(icon="el-icon-picture-outline" command="Previous Images") {{ $t('dialog.world.actions.show_previous_images') }} template(v-else) - el-dropdown-item(icon="el-icon-edit" command="Rename") Rename - el-dropdown-item(icon="el-icon-edit" command="Change Description") Change Description - el-dropdown-item(icon="el-icon-edit" command="Change Capacity") Change Capacity - el-dropdown-item(icon="el-icon-edit" command="Change YouTube Preview") Change YouTube Preview - el-dropdown-item(icon="el-icon-edit" command="Change Tags") Change Tags - el-dropdown-item(icon="el-icon-picture-outline" command="Change Image") Change Image - el-dropdown-item(v-if="worldDialog.ref.unityPackageUrl" icon="el-icon-download" command="Download Unity Package") Download Unity Package - el-dropdown-item(v-if="worldDialog.ref.tags.includes('system_approved') || worldDialog.ref.tags.includes('system_labs')" icon="el-icon-view" command="Unpublish" divided) Unpublish - el-dropdown-item(v-else icon="el-icon-view" command="Publish" divided) Publish To Labs - el-dropdown-item(icon="el-icon-delete" command="Delete" style="color:#F56C6C") Delete + el-dropdown-item(icon="el-icon-edit" command="Rename") {{ $t('dialog.world.actions.rename') }} + el-dropdown-item(icon="el-icon-edit" command="Change Description") {{ $t('dialog.world.actions.change_description') }} + el-dropdown-item(icon="el-icon-edit" command="Change Capacity") {{ $t('dialog.world.actions.change_capacity') }} + el-dropdown-item(icon="el-icon-edit" command="Change YouTube Preview") {{ $t('dialog.world.actions.change_preview') }} + el-dropdown-item(icon="el-icon-edit" command="Change Tags") {{ $t('dialog.world.actions.change_tags') }} + el-dropdown-item(icon="el-icon-picture-outline" command="Change Image") {{ $t('dialog.world.actions.change_image') }} + el-dropdown-item(v-if="worldDialog.ref.unityPackageUrl" icon="el-icon-download" command="Download Unity Package") {{ $t('dialog.world.actions.download_package') }} + el-dropdown-item(v-if="worldDialog.ref.tags.includes('system_approved') || worldDialog.ref.tags.includes('system_labs')" icon="el-icon-view" command="Unpublish" divided) {{ $t('dialog.world.actions.unpublish') }} + el-dropdown-item(v-else icon="el-icon-view" command="Publish" divided) {{ $t('dialog.world.actions.publish_to_labs') }} + el-dropdown-item(icon="el-icon-delete" command="Delete" style="color:#F56C6C") {{ $t('dialog.world.actions.delete') }} el-tabs - el-tab-pane(label="Instances") + el-tab-pane(:label="$t('dialog.world.instances.header')") div. - #[i.el-icon-user] Public {{ worldDialog.ref.publicOccupants | commaNumber }} - #[i.el-icon-user-solid(style="margin-left:10px")] Private {{ worldDialog.ref.privateOccupants | commaNumber }} - #[i.el-icon-check(style="margin-left:10px")] Capacity {{ worldDialog.ref.capacity | commaNumber }} ({{ worldDialog.ref.capacity * 2 | commaNumber }}) + #[i.el-icon-user] {{ $t('dialog.world.instances.public_count', { count: worldDialog.ref.publicOccupants }) }} + #[i.el-icon-user-solid(style="margin-left:10px")] {{ $t('dialog.world.instances.private_count', { count: worldDialog.ref.privateOccupants }) }} + #[i.el-icon-check(style="margin-left:10px")] {{ $t('dialog.world.instances.capacity_count', { count: worldDialog.ref.capacity, max: worldDialog.ref.capacity * 2 }) }} div(v-for="room in worldDialog.rooms" :key="room.id") div(style="margin:5px 0") location-world(:locationobject="room.$location" :currentuserid="API.currentUser.id" :worlddialogshortname="worldDialog.$location.shortName") - el-tooltip(placement="top" content="Invite yourself" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('dialog.world.instances.self_invite_tooltip')" :disabled="hideTooltips") invite-yourself(:location="room.$location.tag" :shortname="room.$location.shortName" style="margin-left:5px") - el-tooltip(placement="top" content="Refresh player count" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('dialog.world.instances.refresh_user_count_tooltip')" :disabled="hideTooltips") el-button(v-if="room.$location.tag !== lastLocation.location" @click="refreshInstancePlayerCount(room.$location.tag)" size="mini" icon="el-icon-refresh" style="margin-left:5px" circle) span(v-if="room.occupants" style="margin-left:5px") {{ room.occupants }} #[template(v-if="room.friendCount > 0") ({{ room.friendCount }})] .x-friend-list(style="margin:10px 0;max-height:unset" v-if="room.$location.userId || room.users.length") @@ -1988,7 +1995,7 @@ html img(v-lazy="userImage(room.$location.user)") .detail span.name(v-text="room.$location.user.displayName" :style="{'color':room.$location.user.$userColour}") - span.extra Instance Creator + span.extra {{ $t('dialog.world.instances.instance_creator') }} span(v-else v-text="room.$location.userId") .x-friend-item(v-for="user in room.users" :key="user.id" @click="showUserDialog(user.id)" class="x-friend-item-border") .avatar(:class="userStatusClass(user)") @@ -2000,84 +2007,84 @@ html timer(:epoch="user.$travelingToTime") span.extra(v-else) timer(:epoch="user.$location_at") - el-tab-pane(label="Info") + el-tab-pane(:label="$t('dialog.world.info.header')") .x-friend-list(style="max-height:none") div(style="width:100%;display:flex") .x-friend-item(style="width:350px;cursor:default") .detail - span.name World ID + span.name {{ $t('dialog.world.info.id') }} span.extra {{ worldDialog.id }} - el-tooltip(placement="top" content="Copy to clipboard" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('dialog.world.info.id_tooltip')" :disabled="hideTooltips") el-dropdown(trigger="click" @click.native.stop size="mini" style="margin-left:5px") el-button(type="default" icon="el-icon-s-order" size="mini" circle) el-dropdown-menu(#default="dropdown") - el-dropdown-item(@click.native="copyWorldId(worldDialog.id)") Copy ID - el-dropdown-item(@click.native="copyWorldUrl(worldDialog.id)") Copy URL + el-dropdown-item(@click.native="copyWorldId(worldDialog.id)") {{ $t('dialog.world.info.copy_id') }} + el-dropdown-item(@click.native="copyWorldUrl(worldDialog.id)") {{ $t('dialog.world.info.copy_url') }} .x-friend-item(v-if="worldDialog.ref.previewYoutubeId" style="width:350px" @click="openExternalLink(`https://www.youtube.com/watch?v=${worldDialog.ref.previewYoutubeId}`)") .detail - span.name YouTube Preview + span.name {{ $t('dialog.world.info.youtube_preview') }} span.extra https://www.youtube.com/watch?v={{ worldDialog.ref.previewYoutubeId }} .x-friend-item(style="cursor:default") .detail - span.name Players + span.name {{ $t('dialog.world.info.players') }} span.extra {{ worldDialog.ref.occupants | commaNumber }} .x-friend-item(style="cursor:default") .detail - span.name Favorites + span.name {{ $t('dialog.world.info.favorites') }} span.extra {{ worldDialog.ref.favorites | commaNumber }} | #[template(v-if="worldDialog.ref.favorites > 0 && worldDialog.ref.visits > 0") ({{ Math.round(((worldDialog.ref.favorites - worldDialog.ref.visits) / worldDialog.ref.visits * 100 + 100) * 100) / 100 }}%)] .x-friend-item(style="cursor:default") .detail - span.name Visits + span.name {{ $t('dialog.world.info.visits') }} span.extra {{ worldDialog.ref.visits | commaNumber }} .x-friend-item(style="cursor:default") .detail - span.name Capacity + span.name {{ $t('dialog.world.info.capacity') }} span.extra {{ worldDialog.ref.capacity | commaNumber }} ({{ worldDialog.ref.capacity * 2 | commaNumber }}) .x-friend-item(style="cursor:default") .detail - span.name Heat + span.name {{ $t('dialog.world.info.heat') }} span.extra {{ worldDialog.ref.heat | commaNumber }} {{ '🔥'.repeat(worldDialog.ref.heat) }} .x-friend-item(style="cursor:default") .detail - span.name Popularity + span.name {{ $t('dialog.world.info.popularity') }} span.extra {{ worldDialog.ref.popularity | commaNumber }} {{ '💖'.repeat(worldDialog.ref.popularity) }} .x-friend-item(style="cursor:default") .detail - span.name Created + span.name {{ $t('dialog.world.info.created_at') }} span.extra {{ worldDialog.ref.created_at | formatDate('long') }} .x-friend-item(style="cursor:default") .detail - span.name Last Updated + span.name {{ $t('dialog.world.info.last_updated') }} span.extra {{ worldDialog.fileCreatedAt | formatDate('long') }} .x-friend-item(style="cursor:default") .detail - span.name Version + span.name {{ $t('dialog.world.info.version') }} span.extra(v-text="worldDialog.ref.version") .x-friend-item(style="width:525px;cursor:default") .detail - span.name Platform + span.name {{ $t('dialog.world.info.platform') }} span.extra(v-text="worldDialogPlatform") .x-friend-item(style="cursor:default") .detail - span.name Last Visit - el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" content="Info from local database may not be accurate") + span.name {{ $t('dialog.world.info.last_visited') }} + el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" :content="$t('dialog.world.info.accuracy_notice')") i.el-icon-warning span.extra {{ worldDialog.lastVisit | formatDate('long') }} .x-friend-item(@click="showPreviousInstancesWorldDialog(worldDialog.ref)") .detail - span.name Visit Count - el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" content="Info from local database may not be accurate") + span.name {{ $t('dialog.world.info.visit_count') }} + el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" :content="$t('dialog.world.info.accuracy_notice')") i.el-icon-warning span.extra(v-text="worldDialog.visitCount") .x-friend-item(style="cursor:default") .detail - span.name Time Spent - el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" content="Info from local database may not be accurate") + span.name {{ $t('dialog.world.info.time_spent') }} + el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" :content="$t('dialog.world.info.accuracy_notice')") i.el-icon-warning span.extra(v-if="worldDialog.timeSpent === 0") - span.extra(v-else) {{ worldDialog.timeSpent | timeToText }} - el-tab-pane(label="JSON") + el-tab-pane(:label="$t('dialog.world.json.header')") el-button(type="default" @click="refreshWorldDialogTreeData()" size="mini" icon="el-icon-refresh" circle) el-tree(:data="worldDialog.treeData" style="margin-top:5px;font-size:12px") template(#default="scope") @@ -2099,71 +2106,71 @@ html div(style="margin-top:5px") span.x-link(v-text="avatarDialog.ref.authorName" @click="showUserDialog(avatarDialog.ref.authorId)" style="color:#909399;font-family:monospace") div(style="margin-top:5px") - el-tag(v-if="avatarDialog.ref.releaseStatus === 'public'" type="success" effect="plain" size="mini" style="margin-right:5px") Public - el-tag(v-else type="danger" effect="plain" size="mini" style="margin-right:5px") Private - el-tag(v-if="avatarDialog.isQuestFallback" type="info" effect="plain" size="mini" style="margin-right:5px") Fallback + el-tag(v-if="avatarDialog.ref.releaseStatus === 'public'" type="success" effect="plain" size="mini" style="margin-right:5px") {{ $t('dialog.avatar.tags.public') }} + el-tag(v-else type="danger" effect="plain" size="mini" style="margin-right:5px") {{ $t('dialog.avatar.tags.private') }} + el-tag(v-if="avatarDialog.isQuestFallback" type="info" effect="plain" size="mini" style="margin-right:5px") {{ $t('dialog.avatar.tags.fallback') }} el-tag(v-if="avatarDialog.fileSize" type="info" effect="plain" size="mini" v-text="avatarDialog.fileSize" style="margin-right:5px") el-tag(v-if="avatarDialog.inCache" type="info" effect="plain" size="mini") span(v-text="avatarDialog.cacheSize") - | Cache + | {{ $t('dialog.avatar.tags.cache') }} div(style="margin-top:5px") span(v-show="avatarDialog.ref.name !== avatarDialog.ref.description" v-text="avatarDialog.ref.description" style="font-size:12px") div(style="flex:none;margin-left:10px") - el-tooltip(v-if="avatarDialog.inCache" placement="top" content="Delete avatar from cache" :disabled="hideTooltips") + el-tooltip(v-if="avatarDialog.inCache" placement="top" :content="$t('dialog.avatar.actions.delete_cache_tooltip')" :disabled="hideTooltips") el-button(icon="el-icon-delete" circle @click="deleteVRChatCache(avatarDialog.ref)" :disabled="isGameRunning && avatarDialog.cacheLocked") - el-tooltip(v-if="avatarDialog.isFavorite" placement="top" content="Remove from favorites" :disabled="hideTooltips") + el-tooltip(v-if="avatarDialog.isFavorite" placement="top" :content="$t('dialog.avatar.actions.unfavorite_tooltip')" :disabled="hideTooltips") el-button(type="warning" icon="el-icon-star-on" circle @click="avatarDialogCommand('Delete Favorite')" style="margin-left:5px") - el-tooltip(v-else placement="top" content="Add to favorites" :disabled="hideTooltips") + el-tooltip(v-else placement="top" :content="$t('dialog.avatar.actions.favorite_tooltip')" :disabled="hideTooltips") el-button(type="default" icon="el-icon-star-off" circle @click="avatarDialogCommand('Add Favorite')" style="margin-left:5px") el-dropdown(trigger="click" @command="avatarDialogCommand" size="small" style="margin-left:5px") el-button(:type="avatarDialog.isBlocked ? 'danger' : 'default'" icon="el-icon-more" circle style="margin-left:5px") el-dropdown-menu(#default="dropdown") - el-dropdown-item(icon="el-icon-refresh" command="Refresh") Refresh - el-dropdown-item(icon="el-icon-check" command="Select Avatar") Select Avatar - el-dropdown-item(v-if="/quest/.test(avatarDialog.ref.tags)" icon="el-icon-check" command="Select Fallback Avatar") Select Fallback Avatar - el-dropdown-item(v-if="avatarDialog.isBlocked" icon="el-icon-circle-check" command="Unblock Avatar" style="color:#F56C6C") Unblock Avatar - el-dropdown-item(v-else icon="el-icon-circle-close" command="Block Avatar") Block Avatar - el-dropdown-item(v-if="avatarDialog.ref.authorId !== API.currentUser.id" icon="el-icon-picture-outline" command="Previous Images") Previous Images + el-dropdown-item(icon="el-icon-refresh" command="Refresh") {{ $t('dialog.avatar.actions.refresh') }} + el-dropdown-item(icon="el-icon-check" command="Select Avatar") {{ $t('dialog.avatar.actions.select') }} + el-dropdown-item(v-if="/quest/.test(avatarDialog.ref.tags)" icon="el-icon-check" command="Select Fallback Avatar") {{ $t('dialog.avatar.actions.select_fallback') }} + el-dropdown-item(v-if="avatarDialog.isBlocked" icon="el-icon-circle-check" command="Unblock Avatar" style="color:#F56C6C") {{ $t('dialog.avatar.actions.unblock') }} + el-dropdown-item(v-else icon="el-icon-circle-close" command="Block Avatar") {{ $t('dialog.avatar.actions.block') }} + el-dropdown-item(v-if="avatarDialog.ref.authorId !== API.currentUser.id" icon="el-icon-picture-outline" command="Previous Images") {{ $t('dialog.avatar.actions.show_previous_images') }} template(v-if="avatarDialog.ref.authorId === API.currentUser.id") - el-dropdown-item(v-if="avatarDialog.ref.releaseStatus === 'public'" icon="el-icon-user-solid" command="Make Private" divided) Make Private - el-dropdown-item(v-else icon="el-icon-user" command="Make Public" divided) Make Public - el-dropdown-item(icon="el-icon-edit" command="Rename") Rename - el-dropdown-item(icon="el-icon-edit" command="Change Description") Change Description - el-dropdown-item(icon="el-icon-picture-outline" command="Change Image") Change Image - el-dropdown-item(v-if="avatarDialog.ref.unityPackageUrl" icon="el-icon-download" command="Download Unity Package") Download Unity Package - el-dropdown-item(icon="el-icon-user" command="Delete" style="color:#F56C6C" divided) Delete + el-dropdown-item(v-if="avatarDialog.ref.releaseStatus === 'public'" icon="el-icon-user-solid" command="Make Private" divided) {{ $t('dialog.avatar.actions.make_private') }} + el-dropdown-item(v-else icon="el-icon-user" command="Make Public" divided) {{ $t('dialog.avatar.actions.make_public') }} + el-dropdown-item(icon="el-icon-edit" command="Rename") {{ $t('dialog.avatar.actions.rename') }} + el-dropdown-item(icon="el-icon-edit" command="Change Description") {{ $t('dialog.avatar.actions.change_description') }} + el-dropdown-item(icon="el-icon-picture-outline" command="Change Image") {{ $t('dialog.avatar.actions.change_image') }} + el-dropdown-item(v-if="avatarDialog.ref.unityPackageUrl" icon="el-icon-download" command="Download Unity Package") {{ $t('dialog.avatar.actions.download_package') }} + el-dropdown-item(icon="el-icon-user" command="Delete" style="color:#F56C6C" divided) {{ $t('dialog.avatar.actions.delete') }} el-tabs - el-tab-pane(label="Info") + el-tab-pane(:label="$t('dialog.avatar.info.header')") .x-friend-list .x-friend-item(style="width:100%;cursor:default") .detail - span.name Avatar ID + span.name {{ $t('dialog.avatar.info.id') }} span.extra {{ avatarDialog.id }} - el-tooltip(placement="top" content="Copy to clipboard" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('dialog.avatar.info.id_tooltip')" :disabled="hideTooltips") el-dropdown(trigger="click" @click.native.stop size="mini" style="margin-left:5px") el-button(type="default" icon="el-icon-s-order" size="mini" circle) el-dropdown-menu(#default="dropdown") - el-dropdown-item(@click.native="copyAvatarId(avatarDialog.id)") Copy ID - el-dropdown-item(@click.native="copyAvatarUrl(avatarDialog.id)") Copy URL + el-dropdown-item(@click.native="copyAvatarId(avatarDialog.id)") {{ $t('dialog.avatar.info.copy_id') }} + el-dropdown-item(@click.native="copyAvatarUrl(avatarDialog.id)") {{ $t('dialog.avatar.info.copy_url') }} .x-friend-item(style="cursor:default") .detail - span.name Created + span.name {{ $t('dialog.avatar.info.created_at') }} span.extra {{ avatarDialog.ref.created_at | formatDate('long') }} .x-friend-item(style="cursor:default") .detail - span.name Last Updated + span.name {{ $t('dialog.avatar.info.last_updated') }} span.extra {{ avatarDialog.ref.updated_at | formatDate('long') }} .x-friend-item(style="cursor:default") .detail - span.name Version + span.name {{ $t('dialog.avatar.info.version') }} span.extra(v-if="avatarDialog.ref.version !== 0" v-text="avatarDialog.ref.version") span.extra(v-else) - .x-friend-item(style="width:100%;cursor:default") .detail - span.name Platform + span.name {{ $t('dialog.avatar.info.platform') }} span.extra(v-if="avatarDialogPlatform" v-text="avatarDialogPlatform") span.extra(v-else) - - el-tab-pane(label="JSON") + el-tab-pane(:label="$t('dialog.avatar.json.header')") el-button(type="default" @click="refreshAvatarDialogTreeData()" size="mini" icon="el-icon-refresh" circle) el-tree(:data="avatarDialog.treeData" style="margin-top:5px;font-size:12px") template(#default="scope") @@ -2194,66 +2201,66 @@ html div(style="margin-top:5px") span.x-link(v-text="groupDialog.ownerDisplayName" @click="showUserDialog(groupDialog.ref.ownerId)" style="color:#909399;font-family:monospace") .group-tags - el-tag(v-if="groupDialog.ref.isVerified" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Verified + el-tag(v-if="groupDialog.ref.isVerified" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.group.tags.verified') }} - el-tag(v-if="groupDialog.ref.privacy === 'private'" type="danger" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Private - el-tag(v-if="groupDialog.ref.privacy === 'default'" type="success" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Public + el-tag(v-if="groupDialog.ref.privacy === 'private'" type="danger" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.group.tags.private') }} + el-tag(v-if="groupDialog.ref.privacy === 'default'" type="success" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.group.tags.public') }} - el-tag(v-if="groupDialog.ref.joinState === 'open'" type="success" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Open - el-tag(v-else-if="groupDialog.ref.joinState === 'request'" type="warning" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Request - el-tag(v-else-if="groupDialog.ref.joinState === 'invite'" type="danger" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Invite - el-tag(v-else-if="groupDialog.ref.joinState === 'closed'" type="danger" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Closed + el-tag(v-if="groupDialog.ref.joinState === 'open'" type="success" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.group.tags.open') }} + el-tag(v-else-if="groupDialog.ref.joinState === 'request'" type="warning" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.group.tags.request') }} + el-tag(v-else-if="groupDialog.ref.joinState === 'invite'" type="danger" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.group.tags.invite') }} + el-tag(v-else-if="groupDialog.ref.joinState === 'closed'" type="danger" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.group.tags.closed') }} - el-tag(v-if="groupDialog.inGroup" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Joined - el-tag(v-if="groupDialog.ref.myMember && groupDialog.ref.myMember.bannedAt" type="danger" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Banned + el-tag(v-if="groupDialog.inGroup" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.group.tags.joined') }} + el-tag(v-if="groupDialog.ref.myMember && groupDialog.ref.myMember.bannedAt" type="danger" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.group.tags.banned') }} template(v-if="groupDialog.inGroup && groupDialog.ref.myMember") - el-tag(v-if="groupDialog.ref.myMember.visibility === 'visible'" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Visible - el-tag(v-else-if="groupDialog.ref.myMember.visibility === 'friends'" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Friends - el-tag(v-else-if="groupDialog.ref.myMember.visibility === 'hidden'" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Hidden - el-tag(v-if="groupDialog.ref.myMember.isSubscribedToAnnouncements" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Subscribed + el-tag(v-if="groupDialog.ref.myMember.visibility === 'visible'" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.group.tags.visible') }} + el-tag(v-else-if="groupDialog.ref.myMember.visibility === 'friends'" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.group.tags.friends') }} + el-tag(v-else-if="groupDialog.ref.myMember.visibility === 'hidden'" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.group.tags.hidden') }} + el-tag(v-if="groupDialog.ref.myMember.isSubscribedToAnnouncements" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.group.tags.subscribed') }} .group-description(style="margin-top:5px") span(v-show="groupDialog.ref.name !== groupDialog.ref.description" v-text="groupDialog.ref.description" style="font-size:12px") div(style="flex:none;margin-left:10px") template(v-if="groupDialog.inGroup") - el-tooltip(v-if="groupDialog.ref.isRepresenting" placement="top" content="Stop Representing" :disabled="hideTooltips") + el-tooltip(v-if="groupDialog.ref.isRepresenting" placement="top" :content="$t('dialog.group.actions.unrepresent_tooltip')" :disabled="hideTooltips") el-button(type="warning" icon="el-icon-star-on" circle @click="clearGroupRepresentation(groupDialog.id)" style="margin-left:5px") - el-tooltip(v-else placement="top" content="Set Representing" :disabled="hideTooltips") + el-tooltip(v-else placement="top" :content="$t('dialog.group.actions.represent_tooltip')" :disabled="hideTooltips") span el-button(type="default" icon="el-icon-star-off" circle @click="setGroupRepresentation(groupDialog.id)" style="margin-left:5px" :disabled="groupDialog.ref.privacy === 'private'") template(v-else-if="groupDialog.ref.membershipStatus === 'requested'") - el-tooltip(placement="top" content="Cancel join request" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('dialog.group.actions.cancel_join_request_tooltip')" :disabled="hideTooltips") span el-button(type="default" icon="el-icon-close" circle @click="cancelGroupRequest(groupDialog.id)" style="margin-left:5px") template(v-else-if="groupDialog.ref.membershipStatus === 'invited'") - el-tooltip(placement="top" content="Pending invite" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('dialog.group.actions.pending_request_tooltip')" :disabled="hideTooltips") span el-button(type="default" icon="el-icon-check" circle @click="joinGroup(groupDialog.id)" style="margin-left:5px") template(v-else) - el-tooltip(v-if="groupDialog.ref.joinState === 'request'" placement="top" content="Request to join" :disabled="hideTooltips") + el-tooltip(v-if="groupDialog.ref.joinState === 'request'" placement="top" :content="$t('dialog.group.actions.request_join_tooltip')" :disabled="hideTooltips") el-button(type="default" icon="el-icon-message" circle @click="joinGroup(groupDialog.id)" style="margin-left:5px") - el-tooltip(v-if="groupDialog.ref.joinState === 'invite'" placement="top" content="Invite required" :disabled="hideTooltips") + el-tooltip(v-if="groupDialog.ref.joinState === 'invite'" placement="top" :content="$t('dialog.group.actions.invite_required_tooltip')" :disabled="hideTooltips") span el-button(type="default" icon="el-icon-message" disabled circle style="margin-left:5px") - el-tooltip(v-if="groupDialog.ref.joinState === 'open'" placement="top" content="Join Group" :disabled="hideTooltips") + el-tooltip(v-if="groupDialog.ref.joinState === 'open'" placement="top" :content="$t('dialog.group.actions.join_group_tooltip')" :disabled="hideTooltips") el-button(type="default" icon="el-icon-check" circle @click="joinGroup(groupDialog.id)" style="margin-left:5px") el-dropdown(trigger="click" @command="groupDialogCommand" size="small" style="margin-left:5px") el-button(type="default" icon="el-icon-more" circle) el-dropdown-menu(#default="dropdown") - el-dropdown-item(icon="el-icon-refresh" command="Refresh") Refresh + el-dropdown-item(icon="el-icon-refresh" command="Refresh") {{ $t('dialog.group.actions.refresh') }} template(v-if="groupDialog.inGroup") template(v-if="groupDialog.ref.myMember") - el-dropdown-item(v-if="groupDialog.ref.myMember.isSubscribedToAnnouncements" icon="el-icon-close" command="Unsubscribe To Announcements" divided) Unsubscribe From Announcements - el-dropdown-item(v-else icon="el-icon-check" command="Subscribe To Announcements" divided) Subscribe To Announcements - el-dropdown-item(v-if="hasGroupPermission(groupDialog.ref, 'group-invites-manage')" icon="el-icon-message" command="Invite To Group") Invite To Group + el-dropdown-item(v-if="groupDialog.ref.myMember.isSubscribedToAnnouncements" icon="el-icon-close" command="Unsubscribe To Announcements" divided) {{ $t('dialog.group.actions.unsubscribe') }} + el-dropdown-item(v-else icon="el-icon-check" command="Subscribe To Announcements" divided) {{ $t('dialog.group.actions.subscribe') }} + el-dropdown-item(v-if="hasGroupPermission(groupDialog.ref, 'group-invites-manage')" icon="el-icon-message" command="Invite To Group") {{ $t('dialog.group.actions.invite_to_group') }} template(v-if="groupDialog.ref.myMember && groupDialog.ref.privacy === 'default'") - el-dropdown-item(icon="el-icon-view" command="Visibility Everyone" divided) #[i.el-icon-check(v-if="groupDialog.ref.myMember.visibility === 'visible'")] Visibility Everyone - el-dropdown-item(icon="el-icon-view" command="Visibility Friends") #[i.el-icon-check(v-if="groupDialog.ref.myMember.visibility === 'friends'")] Visibility Friends - el-dropdown-item(icon="el-icon-view" command="Visibility Hidden") #[i.el-icon-check(v-if="groupDialog.ref.myMember.visibility === 'hidden'")] Visibility Hidden - el-dropdown-item(icon="el-icon-delete" command="Leave Group" style="color:#F56C6C" divided) Leave Group + el-dropdown-item(icon="el-icon-view" command="Visibility Everyone" divided) #[i.el-icon-check(v-if="groupDialog.ref.myMember.visibility === 'visible'")] {{ $t('dialog.group.actions.visibility_everyone') }} + el-dropdown-item(icon="el-icon-view" command="Visibility Friends") #[i.el-icon-check(v-if="groupDialog.ref.myMember.visibility === 'friends'")] {{ $t('dialog.group.actions.visibility_friends') }} + el-dropdown-item(icon="el-icon-view" command="Visibility Hidden") #[i.el-icon-check(v-if="groupDialog.ref.myMember.visibility === 'hidden'")] {{ $t('dialog.group.actions.visibility_hidden') }} + el-dropdown-item(icon="el-icon-delete" command="Leave Group" style="color:#F56C6C" divided) {{ $t('dialog.group.actions.leave') }} el-tabs(ref="groupDialogTabs" @tab-click="groupDialogTabClick") - el-tab-pane(label="Info") + el-tab-pane(:label="$t('dialog.group.info.header')") .group-banner-image-info el-popover(placement="right" width="500px" trigger="click") img.x-link(slot="reference" v-lazy="groupDialog.ref.bannerUrl" style="flex:none;width:100%;aspect-ratio:6/1;object-fit:cover;border-radius:4px") @@ -2261,7 +2268,7 @@ html .x-friend-list(style="max-height:none") .x-friend-item(v-if="groupDialog.ref.membershipStatus === 'member'" style="width:100%;cursor:default") .detail - span.name Announcement + span.name {{ $t('dialog.group.info.announcement') }} span(style="display:block" v-text="groupDialog.announcement.title") div(v-if="groupDialog.announcement.imageUrl" style="display:inline-block;margin-right:5px") el-popover(placement="right" width="500px" trigger="click") @@ -2297,19 +2304,19 @@ html timer(:epoch="user.$location_at") .x-friend-item(style="width:100%;cursor:default") .detail - span.name Rules + span.name {{ $t('dialog.group.info.rules') }} pre.extra(style="font-family:inherit;font-size:12px;white-space:pre-wrap;margin:0 0.5em 0 0") {{ groupDialog.ref.rules || '-' }} .x-friend-item(style="cursor:default") .detail - span.name Members + span.name {{ $t('dialog.group.info.members') }} .extra {{ groupDialog.ref.memberCount }} ({{ groupDialog.ref.onlineMemberCount }}) .x-friend-item(style="cursor:default") .detail - span.name Created + span.name {{ $t('dialog.group.info.created_at') }} span.extra {{ groupDialog.ref.createdAt | formatDate('long') }} .x-friend-item(style="cursor:default") .detail - span.name Links + span.name {{ $t('dialog.group.info.links') }} div(v-if="groupDialog.ref.links && groupDialog.ref.links.length > 0" style="margin-top:5px") el-tooltip(v-if="link" v-for="(link, index) in groupDialog.ref.links" :key="index") template(#content) @@ -2318,45 +2325,45 @@ html .extra(v-else) - .x-friend-item(style="width:350px;cursor:default") .detail - span.name Group URL + span.name {{ $t('dialog.group.info.url') }} span.extra {{ groupDialog.ref.$url }} - el-tooltip(placement="top" content="Copy URL to clipboard" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('dialog.group.info.url_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="copyGroupUrl(groupDialog.ref.$url)" size="mini" icon="el-icon-s-order" circle style="margin-left:5px") .x-friend-item(style="width:350px;cursor:default") .detail - span.name Group ID + span.name {{ $t('dialog.group.info.id') }} span.extra {{ groupDialog.id }} - el-tooltip(placement="top" content="Copy ID to clipboard" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('dialog.group.info.id_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="copyGroupId(groupDialog.id)" size="mini" icon="el-icon-s-order" circle style="margin-left:5px") div(v-if="groupDialog.ref.membershipStatus === 'member'" style="width:100%;margin-top:10px;border-top:1px solid #e4e7ed14") div(style="width:100%;display:flex;margin-top:10px") .x-friend-item(style="cursor:default") .detail - span.name Joined At + span.name {{ $t('dialog.group.info.joined_at') }} span.extra {{ groupDialog.ref.myMember.joinedAt | formatDate('long') }} .x-friend-item(style="cursor:default") .detail - span.name Roles + span.name {{ $t('dialog.group.info.roles') }} span.extra(v-if="groupDialog.memberRoles.length === 0") - span.extra(v-else) template(v-for="(role, rIndex) in groupDialog.memberRoles" :key="rIndex") el-tooltip(placement="top") template(#content) - span Description: {{ role.description }} + span {{ $t('dialog.group.info.role_description') }} {{ role.description }} br - span(v-if="role.updatedAt") Updated At: {{ role.updatedAt | formatDate('long') }} - span(v-else) Created At: {{ role.createdAt | formatDate('long') }} + span(v-if="role.updatedAt") {{ $t('dialog.group.info.role_updated_at') }} {{ role.updatedAt | formatDate('long') }} + span(v-else) {{ $t('dialog.group.info.role_created_at') }} {{ role.createdAt | formatDate('long') }} br - span Permissions: + span {{ $t('dialog.group.info.role_permissions') }} br template(v-for="(permission, pIndex) in role.permissions" :key="pIndex") span {{ permission }} br span {{ role.name }}{{ rIndex < groupDialog.memberRoles.length - 1 ? ', ' : '' }} - el-tab-pane(label="Members") + el-tab-pane(:label="$t('dialog.group.members.header')") template(v-if="groupDialog.visible && groupDialog.ref.membershipStatus === 'member'") - span(v-if="hasGroupPermission(groupDialog.ref, 'group-members-viewall')" style="font-weight:bold;font-size:16px") All Members - span(v-else style="font-weight:bold;font-size:16px") Friends Only + span(v-if="hasGroupPermission(groupDialog.ref, 'group-members-viewall')" style="font-weight:bold;font-size:16px") {{ $t('dialog.group.members.all_members') }} + span(v-else style="font-weight:bold;font-size:16px") {{ $t('dialog.group.members.friends_only') }} br el-button(type="default" @click="getGroupDialogGroupMembers()" size="mini" icon="el-icon-refresh" circle) span(style="font-size:14px;margin-left:5px;margin-right:5px") {{ groupDialog.members.length }}/{{ groupDialog.ref.memberCount }} @@ -2369,8 +2376,8 @@ html span.extra .x-friend-item(v-if="!isGroupMembersDone" v-loading="isGroupMembersLoading" style="width:100%;height:45px;text-align:center" @click="loadMoreGroupMembers") .detail(v-if="!isGroupMembersLoading") - span.name Load more... - el-tab-pane(label="JSON") + span.name {{ $t('dialog.group.members.load_more') }} + el-tab-pane(:label="$t('dialog.group.json.header')") el-button(type="default" @click="refreshGroupDialogTreeData()" size="mini" icon="el-icon-refresh" circle) el-tree(:data="groupDialog.treeData" style="margin-top:5px;font-size:12px") template(#default="scope") @@ -2379,31 +2386,31 @@ html span(v-if="!scope.data.children" v-text="scope.data.value") //- dialog: favorite - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="favoriteDialog" :visible.sync="favoriteDialog.visible" title="Choose Group" width="300px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="favoriteDialog" :visible.sync="favoriteDialog.visible" :title="$t('dialog.favorite.header')" width="300px") div(v-if="favoriteDialog.visible" v-loading="favoriteDialog.loading") - span(style="display:block;text-align:center") VRChat Favorites + span(style="display:block;text-align:center") {{ $t('dialog.favorite.vrchat_favorites') }} template(v-if="favoriteDialog.currentGroup && favoriteDialog.currentGroup.key") el-button(style="display:block;width:100%;margin:10px 0" @click="deleteFavorite(favoriteDialog.objectId)") #[i.el-icon-check] {{ favoriteDialog.currentGroup.displayName }} ({{ favoriteDialog.currentGroup.count }} / {{ favoriteDialog.currentGroup.capacity }}) template(v-else) el-button(v-for="group in favoriteDialog.groups" :key="group" style="display:block;width:100%;margin:10px 0" @click="addFavorite(group)") {{ group.displayName }} ({{ group.count }} / {{ group.capacity }}) div(v-if="favoriteDialog.visible && favoriteDialog.type === 'world'" style="margin-top:20px") - span(style="display:block;text-align:center") Local Favorites + span(style="display:block;text-align:center") {{ $t('dialog.favorite.local_favorites') }} template(v-for="group in localWorldFavoriteGroups" :key="group") el-button(v-if="hasLocalWorldFavorite(favoriteDialog.objectId, group)" style="display:block;width:100%;margin:10px 0" @click="removeLocalWorldFavorite(favoriteDialog.objectId, group)") #[i.el-icon-check] {{ group }} ({{ getLocalWorldFavoriteGroupLength(group) }}) el-button(v-else style="display:block;width:100%;margin:10px 0" @click="addLocalWorldFavorite(favoriteDialog.objectId, group)") {{ group }} ({{ getLocalWorldFavoriteGroupLength(group) }}) //- dialog: invite - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="inviteDialog" :visible.sync="inviteDialog.visible" title="Invite" width="450px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="inviteDialog" :visible.sync="inviteDialog.visible" :title="$t('dialog.invite.header')" width="450px") div(v-if="inviteDialog.visible" v-loading="inviteDialog.loading") location(:location="inviteDialog.worldId" :link="false") - el-select(v-model="inviteDialog.userIds" multiple clearable placeholder="Choose Friends" filterable :disabled="inviteDialog.loading" style="width:100%;margin-top:15px") - el-option-group(v-if="API.currentUser" label="ME") + el-select(v-model="inviteDialog.userIds" multiple clearable :placeholder="$t('dialog.invite.select_placeholder')" filterable :disabled="inviteDialog.loading" style="width:100%;margin-top:15px") + el-option-group(v-if="API.currentUser" :label="$t('side_panel.me')") el-option.x-friend-item(:label="API.currentUser.displayName" :value="API.currentUser.id" style="height:auto") .avatar(:class="userStatusClass(API.currentUser)") img(v-lazy="userImage(API.currentUser)") .detail span.name(v-text="API.currentUser.displayName") - el-option-group(v-if="friendsGroup0.length" label="VIP") + el-option-group(v-if="friendsGroup0.length" :label="$t('side_panel.favorite')") el-option.x-friend-item(v-for="friend in friendsGroup0" :key="friend.id" :label="friend.name" :value="friend.id" style="height:auto") template(v-if="friend.ref") .avatar(:class="userStatusClass(friend.ref)") @@ -2411,7 +2418,7 @@ html .detail span.name(v-text="friend.ref.displayName" :style="{'color':friend.ref.$userColour}") span(v-else v-text="friend.id") - el-option-group(v-if="friendsGroup1.length" label="ONLINE") + el-option-group(v-if="friendsGroup1.length" :label="$t('side_panel.online')") el-option.x-friend-item(v-for="friend in friendsGroup1" :key="friend.id" :label="friend.name" :value="friend.id" style="height:auto") template(v-if="friend.ref") .avatar(:class="userStatusClass(friend.ref)") @@ -2419,7 +2426,7 @@ html .detail span.name(v-text="friend.ref.displayName" :style="{'color':friend.ref.$userColour}") span(v-else v-text="friend.id") - el-option-group(v-if="friendsGroup2.length" label="ACTIVE") + el-option-group(v-if="friendsGroup2.length" :label="$t('side_panel.active')") el-option.x-friend-item(v-for="friend in friendsGroup2" :key="friend.id" :label="friend.name" :value="friend.id" style="height:auto") template(v-if="friend.ref") .avatar @@ -2428,94 +2435,94 @@ html span.name(v-text="friend.ref.displayName" :style="{'color':friend.ref.$userColour}") span(v-else v-text="friend.id") template(#footer) - el-button(size="small" :disabled="inviteDialog.loading || !inviteDialog.userIds.length" @click="showSendInviteDialog()") Invite With Message - el-button(type="primary" size="small" :disabled="inviteDialog.loading || !inviteDialog.userIds.length" @click="sendInvite()") Invite + el-button(size="small" :disabled="inviteDialog.loading || !inviteDialog.userIds.length" @click="showSendInviteDialog()") {{ $t('dialog.invite.invite_with_message') }} + el-button(type="primary" size="small" :disabled="inviteDialog.loading || !inviteDialog.userIds.length" @click="sendInvite()") {{ $t('dialog.invite.invite') }} //- dialog: social status - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="socialStatusDialog" :visible.sync="socialStatusDialog.visible" title="Social Status" width="400px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="socialStatusDialog" :visible.sync="socialStatusDialog.visible" :title="$t('dialog.social_status.header')" width="400px") div(v-loading="socialStatusDialog.loading") el-collapse(style="border:0") el-collapse-item template(slot="title") - span(style="font-size:16px") History + span(style="font-size:16px") {{ $t('dialog.social_status.history') }} data-tables(v-bind="socialStatusHistoryTable" @row-click="setSocialStatusFromHistory" style="cursor:pointer") - el-table-column(label="No" prop="no" width="40") - el-table-column(label="Status" prop="status") + el-table-column(:label="$t('table.social_status.no')" prop="no" width="50") + el-table-column(:label="$t('table.social_status.status')" prop="status") el-select(v-model="socialStatusDialog.status" style="dispaly:block;margin-top:10px") - el-option(label="Online" value="active"). - #[i.x-user-status.online] Online - el-option(label="Join Me" value="join me"). - #[i.x-user-status.joinme] Join Me - el-option(label="Ask Me" value="ask me"). - #[i.x-user-status.askme] Ask Me - el-option(label="Do Not Disturb" value="busy"). - #[i.x-user-status.busy] Do Not Disturb - el-option(v-if="API.currentUser.$isModerator" label="Offline" value="offline"). - #[i.x-user-status.offline] Offline - el-input(v-model="socialStatusDialog.statusDescription" placeholder="Status" maxlength="32" show-word-limit style="dispaly:block;margin-top:10px") + el-option(:label="$t('dialog.user.status.online')" value="active"). + #[i.x-user-status.online] {{ $t('dialog.user.status.online') }} + el-option(:label="$t('dialog.user.status.join_me')" value="join me"). + #[i.x-user-status.joinme] {{ $t('dialog.user.status.join_me') }} + el-option(:label="$t('dialog.user.status.ask_me')" value="ask me"). + #[i.x-user-status.askme] {{ $t('dialog.user.status.ask_me') }} + el-option(:label="$t('dialog.user.status.busy')" value="busy"). + #[i.x-user-status.busy] {{ $t('dialog.user.status.busy') }} + el-option(v-if="API.currentUser.$isModerator" :label="$t('dialog.user.status.offline')" value="offline"). + #[i.x-user-status.offline] {{ $t('dialog.user.status.offline') }} + el-input(v-model="socialStatusDialog.statusDescription" :placeholder="$t('dialog.social_status.status_placeholder')" maxlength="32" show-word-limit style="dispaly:block;margin-top:10px") template(#footer) - el-button(type="primary" size="small" :disabled="socialStatusDialog.loading" @click="saveSocialStatus") Update + el-button(type="primary" size="small" :disabled="socialStatusDialog.loading" @click="saveSocialStatus") {{ $t('dialog.social_status.update') }} //- dialog: language - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="languageDialog" :visible.sync="languageDialog.visible" title="Language" width="400px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="languageDialog" :visible.sync="languageDialog.visible" :title="$t('dialog.language.header')" width="400px") div(v-loading="languageDialog.loading") div(style="margin:5px 0") el-tag(v-for="item in API.currentUser.$languages" :key="item.key" size="small" type="info" effect="plain" closable @close="removeUserLanguage(item.key)" style="margin-right:5px") span.flags(:class="languageClass(item.key)" style="display:inline-block;margin-right:5px") | {{ item.value }} ({{ item.key }}) div(v-if="languageDialog.languageChoice === true") - el-select(v-model="languageDialog.languageValue" size="mini") + el-select(v-model="languageDialog.languageValue" :placeholder="$t('dialog.language.select_language')" size="mini") el-option(v-for="item in languageDialog.languages" :key="item.key" :value="item.key" :label="item.value") span.flags(:class="languageClass(item.key)" style="display:inline-block;margin-right:5px") | {{ item.value }} ({{ item.key }}) - el-button(@click="languageDialog.languageChoice=false; addUserLanguage(languageDialog.languageValue)" size="mini") Ok - el-button(@click="languageDialog.languageChoice=false" size="mini" style="margin-left:0") Cancel + el-button(@click="languageDialog.languageChoice=false; addUserLanguage(languageDialog.languageValue)" size="mini") {{ $t('dialog.language.ok') }} + el-button(@click="languageDialog.languageChoice=false" size="mini" style="margin-left:0") {{ $t('dialog.language.cancel') }} div(v-else) - el-button(@click="languageDialog.languageValue='';languageDialog.languageChoice=true" size="mini") Add Language + el-button(@click="languageDialog.languageValue='';languageDialog.languageChoice=true" size="mini") {{ $t('dialog.language.add_language') }} //- dialog: bio - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="bioDialog" :visible.sync="bioDialog.visible" title="Bio" width="600px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="bioDialog" :visible.sync="bioDialog.visible" :title="$t('dialog.bio.header')" width="600px") div(v-loading="bioDialog.loading") - el-input(type="textarea" v-model="bioDialog.bio" size="mini" maxlength="512" show-word-limit :autosize="{ minRows:2, maxRows:5 }" placeholder="Please input a bio") + el-input(type="textarea" v-model="bioDialog.bio" size="mini" maxlength="512" show-word-limit :autosize="{ minRows:2, maxRows:5 }" :placeholder="$t('dialog.bio.bio_placeholder')") el-input(v-for="(link, index) in bioDialog.bioLinks" :key="index" :value="link" v-model="bioDialog.bioLinks[index]" size="small" style="margin-top:5px") img(slot="prepend" :src="getFaviconUrl(link)" style="width:16px;height:16px") el-button(slot="append" icon="el-icon-delete" @click="bioDialog.bioLinks.splice(index, 1)") - el-button(@click="bioDialog.bioLinks.push('')" size="mini" style="margin-top:5px") Add Link + el-button(@click="bioDialog.bioLinks.push('')" size="mini" style="margin-top:5px") {{ $t('dialog.bio.add_link') }} template(#footer) - el-button(type="primary" size="small" :disabled="bioDialog.loading" @click="saveBio") Update + el-button(type="primary" size="small" :disabled="bioDialog.loading" @click="saveBio") {{ $t('dialog.bio.update') }} //- dialog: new instance - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="newInstanceDialog" :visible.sync="newInstanceDialog.visible" title="New Instance" width="600px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="newInstanceDialog" :visible.sync="newInstanceDialog.visible" :title="$t('dialog.new_instance.header')" width="650px") el-form(v-if="newInstanceDialog.visible" :model="newInstanceDialog" label-width="130px") - el-form-item(label="Access Type") + el-form-item(:label="$t('dialog.new_instance.access_type')") el-radio-group(v-model="newInstanceDialog.accessType" size="mini" @change="buildInstance") - el-radio-button(label="public") - el-radio-button(label="group") - el-radio-button(label="friends+") - el-radio-button(label="friends") - el-radio-button(label="invite+") - el-radio-button(label="invite") + el-radio-button(label="public") {{ $t('dialog.new_instance.access_type_public') }} + el-radio-button(label="group") {{ $t('dialog.new_instance.access_type_group') }} + el-radio-button(label="friends+") {{ $t('dialog.new_instance.access_type_friend_plus') }} + el-radio-button(label="friends") {{ $t('dialog.new_instance.access_type_friend') }} + el-radio-button(label="invite+") {{ $t('dialog.new_instance.access_type_invite_plus') }} + el-radio-button(label="invite") {{ $t('dialog.new_instance.access_type_invite') }} //- el-form-item(label="Strict" v-if="newInstanceDialog.accessType === 'friends' || newInstanceDialog.accessType === 'invite'") //- el-checkbox(v-model="newInstanceDialog.strict") Prevent non friends joining via URL/Instance ID - el-form-item(label="Region") + el-form-item(:label="$t('dialog.new_instance.region')") el-radio-group(v-model="newInstanceDialog.region" size="mini" @change="buildInstance") - el-radio-button(label="US West") - el-radio-button(label="US East") - el-radio-button(label="Europe") - el-radio-button(label="Japan") - el-form-item(label="World ID") + el-radio-button(label="US West") {{ $t('dialog.new_instance.region_usw') }} + el-radio-button(label="US East") {{ $t('dialog.new_instance.region_use') }} + el-radio-button(label="Europe") {{ $t('dialog.new_instance.region_eu') }} + el-radio-button(label="Japan") {{ $t('dialog.new_instance.region_jp') }} + el-form-item(:label="$t('dialog.new_instance.world_id')") el-input(v-model="newInstanceDialog.worldId" size="mini" @click.native="$event.target.tagName === 'INPUT' && $event.target.select()") - el-form-item(label="Instance ID") - el-input(v-model="newInstanceDialog.instanceName" placeholder="Random" size="mini") - el-form-item(label="Instance Creator" v-if="newInstanceDialog.accessType !== 'public' && newInstanceDialog.accessType !== 'group'") - el-select(v-model="newInstanceDialog.userId" clearable placeholder="Choose User" filterable style="width:100%") - el-option-group(v-if="API.currentUser" label="ME") + el-form-item(:label="$t('dialog.new_instance.instance_id')") + el-input(v-model="newInstanceDialog.instanceName" :placeholder="$t('dialog.new_instance.instance_id_placeholder')" size="mini") + el-form-item(:label="$t('dialog.new_instance.instance_creator')" v-if="newInstanceDialog.accessType !== 'public' && newInstanceDialog.accessType !== 'group'") + el-select(v-model="newInstanceDialog.userId" clearable :placeholder="$t('dialog.new_instance.instance_creator_placeholder')" filterable style="width:100%") + el-option-group(v-if="API.currentUser" :label="$t('side_panel.me')") el-option.x-friend-item(:label="API.currentUser.displayName" :value="API.currentUser.id" style="height:auto") .avatar(:class="userStatusClass(API.currentUser)") img(v-lazy="userImage(API.currentUser)") .detail span.name(v-text="API.currentUser.displayName") - el-option-group(v-if="friendsGroup0.length" label="VIP") + el-option-group(v-if="friendsGroup0.length" :label="$t('side_panel.favorite')") el-option.x-friend-item(v-for="friend in friendsGroup0" :key="friend.id" :label="friend.name" :value="friend.id" style="height:auto") template(v-if="friend.ref") .avatar(:class="userStatusClass(friend.ref)") @@ -2523,7 +2530,7 @@ html .detail span.name(v-text="friend.ref.displayName" :style="{'color':friend.ref.$userColour}") span(v-else v-text="friend.id") - el-option-group(v-if="friendsGroup1.length" label="ONLINE") + el-option-group(v-if="friendsGroup1.length" :label="$t('side_panel.online')") el-option.x-friend-item(v-for="friend in friendsGroup1" :key="friend.id" :label="friend.name" :value="friend.id" style="height:auto") template(v-if="friend.ref") .avatar(:class="userStatusClass(friend.ref)") @@ -2531,7 +2538,7 @@ html .detail span.name(v-text="friend.ref.displayName" :style="{'color':friend.ref.$userColour}") span(v-else v-text="friend.id") - el-option-group(v-if="friendsGroup2.length" label="ACTIVE") + el-option-group(v-if="friendsGroup2.length" :label="$t('side_panel.active')") el-option.x-friend-item(v-for="friend in friendsGroup2" :key="friend.id" :label="friend.name" :value="friend.id" style="height:auto") template(v-if="friend.ref") .avatar @@ -2539,7 +2546,7 @@ html .detail span.name(v-text="friend.ref.displayName" :style="{'color':friend.ref.$userColour}") span(v-else v-text="friend.id") - el-option-group(v-if="friendsGroup3.length" label="OFFLINE") + el-option-group(v-if="friendsGroup3.length" :label="$t('side_panel.offline')") el-option.x-friend-item(v-for="friend in friendsGroup3" :key="friend.id" :label="friend.name" :value="friend.id" style="height:auto") template(v-if="friend.ref") .avatar @@ -2547,59 +2554,59 @@ html .detail span.name(v-text="friend.ref.displayName" :style="{'color':friend.ref.$userColour}") span(v-else v-text="friend.id") - el-form-item(label="Group ID" v-if="newInstanceDialog.accessType === 'group'") + el-form-item(:label="$t('dialog.new_instance.group_id')" v-if="newInstanceDialog.accessType === 'group'") el-input(v-model="newInstanceDialog.groupId" placeholder="grp_UUID" size="mini") - el-form-item(label="Location") + el-form-item(:label="$t('dialog.new_instance.location')") el-input(v-model="newInstanceDialog.location" size="mini" readonly) - el-form-item(label="URL") + el-form-item(:label="$t('dialog.new_instance.url')") el-input(v-model="newInstanceDialog.url" size="mini" readonly @click.native="$event.target.tagName === 'INPUT' && $event.target.select()") template(#footer) - el-button(size="small" @click="copyInstanceUrl(newInstanceDialog.location)") Copy URL - el-button(size="small" @click="selfInvite(newInstanceDialog.location)") Self Invite - el-button(size="small" @click="showInviteDialog(newInstanceDialog.location)" :disabled="(newInstanceDialog.accessType === 'friends' || newInstanceDialog.accessType === 'invite') && newInstanceDialog.userId !== API.currentUser.id") Invite - el-button(type="primary" size="small" @click="showLaunchDialog(newInstanceDialog.location, newInstanceDialog.secureOrShortName)") Launch + el-button(size="small" @click="copyInstanceUrl(newInstanceDialog.location)") {{ $t('dialog.new_instance.copy_url') }} + el-button(size="small" @click="selfInvite(newInstanceDialog.location)") {{ $t('dialog.new_instance.self_invite') }} + el-button(size="small" @click="showInviteDialog(newInstanceDialog.location)" :disabled="(newInstanceDialog.accessType === 'friends' || newInstanceDialog.accessType === 'invite') && newInstanceDialog.userId !== API.currentUser.id") {{ $t('dialog.new_instance.invite') }} + el-button(type="primary" size="small" @click="showLaunchDialog(newInstanceDialog.location, newInstanceDialog.secureOrShortName)") {{ $t('dialog.new_instance.launch') }} //- dialog: launch options - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="launchOptionsDialog" :visible.sync="launchOptionsDialog.visible" title="Launch Options" width="500px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="launchOptionsDialog" :visible.sync="launchOptionsDialog.visible" :title="$t('dialog.launch_options.header')" width="500px") div(style="font-size:12px") - | These options are for advanced users only. #[br] - | to change max fps: --fps=<N> e.g.) #[el-tag(size="mini") --fps=144] + | {{ $t('dialog.launch_options.description') }} #[br] + | {{ $t('dialog.launch_options.example') }} #[el-tag(size="mini") --fps=144] el-input(type="textarea" v-model="launchOptionsDialog.launchArguments" size="mini" show-word-limit :autosize="{ minRows:2, maxRows:5 }" placeholder="" style="margin-top:10px") div(style="font-size:12px;margin-top:10px") - | VRChat Path Override + | {{ $t('dialog.launch_options.path_override') }} el-input(type="textarea" v-model="launchOptionsDialog.vrcLaunchPathOverride" placeholder="C:\\Program Files (x86)\\Steam\\steamapps\\common\\VRChat" :rows="1" style="dispaly:block;margin-top:10px") template(#footer) div(style="display:flex") - el-button(size="small" @click="openExternalLink('https://docs.vrchat.com/docs/launch-options')") VRChat Docs - el-button(size="small" @click="openExternalLink('https://docs.unity3d.com/Manual/CommandLineArguments.html')") Unity Manual - el-button(type="primary" size="small" :disabled="launchOptionsDialog.loading" @click="updateLaunchOptions" style="margin-left:auto") Save + el-button(size="small" @click="openExternalLink('https://docs.vrchat.com/docs/launch-options')") {{ $t('dialog.launch_options.vrchat_docs') }} + el-button(size="small" @click="openExternalLink('https://docs.unity3d.com/Manual/CommandLineArguments.html')") {{ $t('dialog.launch_options.unity_manual') }} + el-button(type="primary" size="small" :disabled="launchOptionsDialog.loading" @click="updateLaunchOptions" style="margin-left:auto") {{ $t('dialog.launch_options.save') }} //- dialog: VRChat Config JSON - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="VRChatConfigDialog" :visible.sync="VRChatConfigDialog.visible" title="VRChat Config JSON" width="420px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="VRChatConfigDialog" :visible.sync="VRChatConfigDialog.visible" :title="$t('dialog.config_json.header')" width="420px") div(style='font-size:12px;word-break:keep-all') - | These options are for advanced users only. #[br] - | Leave field empty to set as default, game restart required to apply settings. + | {{ $t('dialog.config_json.description1') }} #[br] + | {{ $t('dialog.config_json.description2') }} br - span Cache Size: + span(style="margin-right:5px") {{ $t('dialog.config_json.cache_size') }} span(v-text="VRChatUsedCacheSize") span / span(v-text="VRChatTotalCacheSize") span GB - el-tooltip(placement="top" content="Refresh" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('dialog.config_json.refresh')" :disabled="hideTooltips") el-button(type="default" :loading="VRChatCacheSizeLoading" @click="getVRChatCacheSize" size="small" icon="el-icon-refresh" circle style="margin-left:5px") br - span Delete all cache - el-button(size="small" style="margin-left:5px" icon="el-icon-delete" @click="showDeleteAllVRChatCacheConfirm()") Delete Cache + span {{ $t('dialog.config_json.delete_all_cache') }} + el-button(size="small" style="margin-left:5px" icon="el-icon-delete" @click="showDeleteAllVRChatCacheConfirm()") {{ $t('dialog.config_json.delete_cache') }} br - span Delete old versions from cache - el-button(size="small" style="margin-left:5px" icon="el-icon-folder-delete" @click="sweepVRChatCache()") Sweep Cache + span {{ $t('dialog.config_json.delete_old_cache') }} + el-button(size="small" style="margin-left:5px" icon="el-icon-folder-delete" @click="sweepVRChatCache()") {{ $t('dialog.config_json.sweep_cache') }} br div(style="display:inline-block;margin-top:10px" v-for="(item, value) in VRChatConfigList" :key="value") span(v-text="item.name" style="word-break:keep-all") |: el-input(v-model="VRChatConfigFile[value]" :placeholder="item.default" size="mini" :type="item.type?item.type:'text'" :min="item.min" :max="item.max") div(style="display:inline-block;margin-top:10px") - span Camera Resolution + span {{ $t('dialog.config_json.camera_resolution') }} br el-dropdown(@command="(command) => setVRChatCameraResolution(command)" size="small" trigger="click" style="margin-top:5px") el-button(size="small") @@ -2607,128 +2614,128 @@ html el-dropdown-menu(#default="dropdown") el-dropdown-item(v-for="row in VRChatResolutions" :key="row.index" v-text="row.name" :command="row") div(style="display:inline-block;margin-top:10px;margin-left:10px") - span Screenshot Resolution + span {{ $t('dialog.config_json.screenshot_resolution') }} br el-dropdown(@command="(command) => setVRChatScreenshotResolution(command)" size="small" trigger="click" style="margin-top:5px") el-button(size="small") span #[span(v-text="getVRChatScreenshotResolution()")] #[i.el-icon-arrow-down.el-icon--right] el-dropdown-menu(#default="dropdown") el-dropdown-item(v-for="row in VRChatResolutions" :key="row.index" v-text="row.name" :command="row") - el-checkbox(v-model="VRChatConfigFile.disableRichPresence" style="margin-top:5px;display:block") Disable Discord Rich Presence + el-checkbox(v-model="VRChatConfigFile.disableRichPresence" style="margin-top:5px;display:block") {{ $t('dialog.config_json.disable_discord_presence') }} template(#footer) - el-button(size="small" @click="openExternalLink('https://docs.vrchat.com/docs/configuration-file')") VRChat Docs - el-button(size="small" @click="VRChatConfigDialog.visible = false") Cancel - el-button(type="primary" size="small" :disabled="VRChatConfigDialog.loading" @click="saveVRChatConfigFile") Save + el-button(size="small" @click="openExternalLink('https://docs.vrchat.com/docs/configuration-file')") {{ $t('dialog.config_json.vrchat_docs') }} + el-button(size="small" @click="VRChatConfigDialog.visible = false") {{ $t('dialog.config_json.cancel') }} + el-button(type="primary" size="small" :disabled="VRChatConfigDialog.loading" @click="saveVRChatConfigFile") {{ $t('dialog.config_json.save') }} //- dialog: YouTube Api Dialog - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="youTubeApiDialog" :visible.sync="youTubeApiDialog.visible" title="YouTube API" width="400px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="youTubeApiDialog" :visible.sync="youTubeApiDialog.visible" :title="$t('dialog.youtube_api.header')" width="400px") div(style='font-size:12px;') - | Enter your YouTube API Key (optional) #[br] - el-input(type="textarea" v-model="youTubeApiKey" placeholder="YouTube API Key" maxlength="39" show-word-limit style="dispaly:block;margin-top:10px") + | {{ $t('dialog.youtube_api.description') }} #[br] + el-input(type="textarea" v-model="youTubeApiKey" :placeholder="$t('dialog.youtube_api.placeholder')" maxlength="39" show-word-limit style="dispaly:block;margin-top:10px") template(#footer) div(style="display:flex") - el-button(size="small" @click="openExternalLink('https://rapidapi.com/blog/how-to-get-youtube-api-key/')") Guide - el-button(type="primary" size="small" @click="testYouTubeApiKey" style="margin-left:auto") Save + el-button(size="small" @click="openExternalLink('https://rapidapi.com/blog/how-to-get-youtube-api-key/')") {{ $t('dialog.youtube_api.guide') }} + el-button(type="primary" size="small" @click="testYouTubeApiKey" style="margin-left:auto") {{ $t('dialog.youtube_api.save') }} //- dialog: Set World Tags - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="setWorldTagsDialog" :visible.sync="setWorldTagsDialog.visible" title="Set World Tags" width="400px") - el-checkbox(v-model="setWorldTagsDialog.debugAllowed") Enable world debugging for others + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="setWorldTagsDialog" :visible.sync="setWorldTagsDialog.visible" :title="$t('dialog.set_world_tags.header')" width="400px") + el-checkbox(v-model="setWorldTagsDialog.debugAllowed") {{ $t('dialog.set_world_tags.enable_debugging') }} div(style='font-size:12px;margin-top:10px') - | Enter tags comma separated #[br] + | {{ $t('dialog.set_world_tags.seprator') }} #[br] el-input(type="textarea" v-model="setWorldTagsDialog.tags" size="mini" show-word-limit :autosize="{ minRows:2, maxRows:5 }" placeholder="" style="margin-top:10px") template(#footer) div(style="display:flex") - el-button(size="small" @click="setWorldTagsDialog.visible = false") Cancel - el-button(type="primary" size="small" @click="saveSetWorldTagsDialog") Save + el-button(size="small" @click="setWorldTagsDialog.visible = false") {{ $t('dialog.set_world_tags.cancel') }} + el-button(type="primary" size="small" @click="saveSetWorldTagsDialog") {{ $t('dialog.set_world_tags.save') }} //- dialog: Cache Download - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="downloadDialog" :visible.sync="downloadDialog.visible" title="Download History" width="770px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="downloadDialog" :visible.sync="downloadDialog.visible" :title="$t('dialog.download_history.header')" width="770px") template(v-if="downloadDialog.visible") div(v-if="downloadInProgress && downloadCurrent.ref") span(v-text="downloadCurrent.ref.name") el-button(type="text" icon="el-icon-close" size="mini" @click="cancelDownload(downloadCurrent.id)" style="margin-left:5px") el-progress(:percentage="downloadProgress" :format="downloadProgressText") template(v-if="downloadQueueTable.data.length >= 1") - span(style="margin-top:15px") Queue: + span(style="margin-top:15px") {{ $t('dialog.download_history.queue') }} data-tables(v-bind="downloadQueueTable" style="margin-top:10px") - el-table-column(label="Name" prop="name") - el-table-column(label="Type" prop="type" width="70") - el-table-column(label="Cancel" width="60" align="right") + el-table-column(:label="$t('table.download_history.name')" prop="name") + el-table-column(:label="$t('table.download_history.type')" prop="type" width="70") + el-table-column(:label="$t('table.download_history.cancel')" width="60" align="right") template(v-once #default="scope") el-button(type="text" icon="el-icon-close" size="mini" @click="cancelDownload(scope.row.ref.id)") - span(style="margin-top:15px") History: + span(style="margin-top:15px") {{ $t('dialog.download_history.history') }} data-tables(v-bind="downloadHistoryTable" style="margin-top:10px") - el-table-column(label="Time" prop="date" width="90") + el-table-column(:label="$t('table.download_history.time')" prop="date" width="90") template(v-once #default="scope") timer(:epoch="scope.row.date") - el-table-column(label="Name" prop="name") + el-table-column(:label="$t('table.download_history.name')" prop="name") template(v-once #default="scope") span(v-text="scope.row.ref.name") - el-table-column(label="Type" prop="type" width="70") - el-table-column(label="Status" prop="status" width="80") + el-table-column(:label="$t('table.download_history.type')" prop="type" width="70") + el-table-column(:label="$t('table.download_history.status')" prop="status" width="80") template(#footer) - el-button(v-if="downloadQueue.size >= 1" size="small" @click="cancelAllDownloads") Cancel All - el-button(size="small" @click="downloadDialog.visible = false") Close + el-button(v-if="downloadQueue.size >= 1" size="small" @click="cancelAllDownloads") {{ $t('dialog.download_history.cancel_all') }} + el-button(size="small" @click="downloadDialog.visible = false") {{ $t('dialog.download_history.close') }} //- dialog: update VRCX - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="VRCXUpdateDialog" :visible.sync="VRCXUpdateDialog.visible" title="VRCX Updater" width="400px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="VRCXUpdateDialog" :visible.sync="VRCXUpdateDialog.visible" :title="$t('dialog.vrcx_updater.header')" width="400px") div(v-loading="checkingForVRCXUpdate" style="margin-top:15px") div(v-if="VRCXUpdateDialog.updatePending" style="margin-bottom:15px") span(v-text="pendingVRCXUpdate") br - span Ready for install, restart VRCX to apply. + span {{ $t('dialog.vrcx_updater.ready_for_update') }} el-select(v-model="branch" @change="loadBranchVersions" style="display:inline-block;width:150px;margin-right:15px") el-option(v-once v-for="branch in branches" :key="branch.name" :label="branch.name" :value="branch.name") el-select(v-model="VRCXUpdateDialog.release" style="display:inline-block;width:150px") el-option(v-for="item in VRCXUpdateDialog.releases" :key="item.name" :label="item.tag_name" :value="item.name") div(v-if="!VRCXUpdateDialog.updatePending && VRCXUpdateDialog.release === appVersion" style="margin-top:15px") - span VRCX is up to date. + span {{ $t('dialog.vrcx_updater.latest_version') }} template(#footer) - el-button(v-if="(VRCXUpdateDialog.updatePending && VRCXUpdateDialog.release !== pendingVRCXUpdate) || VRCXUpdateDialog.release !== appVersion" type="primary" size="small" @click="installVRCXUpdate") Download - el-button(v-if="VRCXUpdateDialog.updatePending" type="primary" size="small" @click="restartVRCX") Install + el-button(v-if="(VRCXUpdateDialog.updatePending && VRCXUpdateDialog.release !== pendingVRCXUpdate) || VRCXUpdateDialog.release !== appVersion" type="primary" size="small" @click="installVRCXUpdate") {{ $t('dialog.vrcx_updater.download') }} + el-button(v-if="VRCXUpdateDialog.updatePending" type="primary" size="small" @click="restartVRCX") {{ $t('dialog.vrcx_updater.install') }} //- dialog: launch - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="launchDialog" :visible.sync="launchDialog.visible" title="Launch" width="450px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="launchDialog" :visible.sync="launchDialog.visible" :title="$t('dialog.launch.header')" width="450px") el-form(:model="launchDialog" label-width="80px") - el-form-item(label="URL") + el-form-item(:label="$t('dialog.launch.url')") el-input(v-model="launchDialog.url" size="mini" @click.native="$event.target.tagName === 'INPUT' && $event.target.select()" style="width:260px") - el-tooltip(placement="right" content="Copy to clipboard" :disabled="hideTooltips") + el-tooltip(placement="right" :content="$t('dialog.launch.copy_tooltip')" :disabled="hideTooltips") el-button(@click="copyInstanceMessage(launchDialog.url)" size="mini" icon="el-icon-s-order" style="margin-right:5px" circle) - el-form-item(v-if="launchDialog.shortUrl" label="Short URL") - el-tooltip(placement="top" style="margin-left:5px" content="Short URL's expire after a set period of time") + el-form-item(v-if="launchDialog.shortUrl" :label="$t('dialog.launch.short_url')") + el-tooltip(placement="top" style="margin-left:5px" :content="$t('dialog.launch.short_url_notice')") i.el-icon-warning el-input(v-model="launchDialog.shortUrl" size="mini" @click.native="$event.target.tagName === 'INPUT' && $event.target.select()" style="width:241px") - el-tooltip(placement="right" content="Copy to clipboard" :disabled="hideTooltips") + el-tooltip(placement="right" :content="$t('dialog.launch.copy_tooltip')" :disabled="hideTooltips") el-button(@click="copyInstanceMessage(launchDialog.shortUrl)" size="mini" icon="el-icon-s-order" style="margin-right:5px" circle) - el-form-item(label="Location") + el-form-item(:label="$t('dialog.launch.location')") el-input(v-model="launchDialog.location" size="mini" @click.native="$event.target.tagName === 'INPUT' && $event.target.select()" style="width:260px") - el-tooltip(placement="right" content="Copy to clipboard" :disabled="hideTooltips") + el-tooltip(placement="right" :content="$t('dialog.launch.copy_tooltip')" :disabled="hideTooltips") el-button(@click="copyInstanceMessage(launchDialog.location)" size="mini" icon="el-icon-s-order" style="margin-right:5px" circle) template(#footer) - el-checkbox(v-model="launchDialog.desktop" style="float:left;margin-top:5px") Start as Desktop (No VR) - el-button(size="small" @click="showPreviousInstanceInfoDialog(launchDialog.location)") Info - el-button(size="small" @click="showInviteDialog(launchDialog.location)" :disabled="!checkCanInvite(launchDialog.location)") Invite - el-button(type="primary" size="small" @click="launchGame(launchDialog.location, launchDialog.secureOrShortName)" :disabled="!launchDialog.secureOrShortName") Launch + el-checkbox(v-model="launchDialog.desktop" style="float:left;margin-top:5px") {{ $t('dialog.launch.start_as_desktop') }} + el-button(size="small" @click="showPreviousInstanceInfoDialog(launchDialog.location)") {{ $t('dialog.launch.info') }} + el-button(size="small" @click="showInviteDialog(launchDialog.location)" :disabled="!checkCanInvite(launchDialog.location)") {{ $t('dialog.launch.invite') }} + el-button(type="primary" size="small" @click="launchGame(launchDialog.location, launchDialog.secureOrShortName)" :disabled="!launchDialog.secureOrShortName") {{ $t('dialog.launch.launch') }} //- dialog: export friends list - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" :visible.sync="exportFriendsListDialog" title="Export Friends List" width="650px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" :visible.sync="exportFriendsListDialog" :title="$t('dialog.export_friends_list.header')" width="650px") el-input(type="textarea" v-if="exportFriendsListDialog" v-model="exportFriendsListContent" size="mini" rows="15" resize="none" readonly style="margin-top:15px" @click.native="$event.target.tagName === 'TEXTAREA' && $event.target.select()") //- dialog: export avatars list - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" :visible.sync="exportAvatarsListDialog" title="Export Own Avatars" width="650px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" :visible.sync="exportAvatarsListDialog" :title="$t('dialog.export_own_avatars.header')" width="650px") el-input(type="textarea" v-if="exportAvatarsListDialog" v-model="exportAvatarsListContent" size="mini" rows="15" resize="none" readonly style="margin-top:15px" @click.native="$event.target.tagName === 'TEXTAREA' && $event.target.select()") //- dialog: Discord username list - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" :visible.sync="discordNamesDialogVisible" title="Discord Names" width="650px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" :visible.sync="discordNamesDialogVisible" :title="$t('dialog.discord_names.header')" width="650px") div(style='font-size:12px;') - | Click load missing entries in the Friends List tab to search entire friends list + | {{ $t('dialog.discord_names.description') }} el-input(type="textarea" v-if="discordNamesDialogVisible" v-model="discordNamesContent" size="mini" rows="15" resize="none" readonly style="margin-top:15px") //- dialog: Notification position - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="notificationPositionDialog" :visible.sync="notificationPositionDialog.visible" title="Notification Position" width="400px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="notificationPositionDialog" :visible.sync="notificationPositionDialog.visible" :title="$t('dialog.notification_position.header')" width="400px") div(style='font-size:12px;') - | Choose a notification position. - .notification-position.svg(version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 300 200" style="margin-top:15px;" xml:space="preserve") + | {{ $t('dialog.notification_position.description') }} + svg.notification-position(version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 300 200" style="margin-top:15px;" xml:space="preserve") path(style="fill:black;" d="M291.89,5A3.11,3.11,0,0,1,295,8.11V160.64a3.11,3.11,0,0,1-3.11,3.11H8.11A3.11,3.11,0,0,1,5,160.64V8.11A3.11,3.11,0,0,1,8.11,5H291.89m0-5H8.11A8.11,8.11,0,0,0,0,8.11V160.64a8.11,8.11,0,0,0,8.11,8.11H291.89a8.11,8.11,0,0,0,8.11-8.11V8.11A8.11,8.11,0,0,0,291.89,0Z") rect(style="fill:#c4c4c4;" x="5" y="5" width="290" height="158.75" rx="2.5") el-radio-group(v-model="notificationPosition" size="mini" @change="changeNotificationPosition") @@ -2743,173 +2750,173 @@ html el-radio(label="bottomRight" v-model="notificationPosition" style="margin:0;position:absolute;right:25px;top:280px;") ‎ template(#footer) div(style="display:flex") - el-button(type="primary" size="small" style="margin-left:auto" @click="notificationPositionDialog.visible = false") OK + el-button(type="primary" size="small" style="margin-left:auto" @click="notificationPositionDialog.visible = false") {{ $t('dialog.notification_position.ok') }} //- dialog: Noty feed filters - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="notyFeedFiltersDialog" :visible.sync="notyFeedFiltersDialog.visible" title="Notification Filters" width="550px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="notyFeedFiltersDialog" :visible.sync="notyFeedFiltersDialog.visible" :title="$t('dialog.shared_feed_filters.notification')" width="550px") .toggle-list .toggle-item span.toggle-name OnPlayerJoining el-radio-group(v-model="sharedFeedFilters.noty.OnPlayerJoining" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} .toggle-item span.toggle-name OnPlayerJoined el-radio-group(v-model="sharedFeedFilters.noty.OnPlayerJoined" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") - el-radio-button(label="Everyone") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} + el-radio-button(label="Everyone") {{ $t('dialog.shared_feed_filters.everyone') }} .toggle-item span.toggle-name OnPlayerLeft el-radio-group(v-model="sharedFeedFilters.noty.OnPlayerLeft" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") - el-radio-button(label="Everyone") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} + el-radio-button(label="Everyone") {{ $t('dialog.shared_feed_filters.everyone') }} .toggle-item span.toggle-name Online el-radio-group(v-model="sharedFeedFilters.noty.Online" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} .toggle-item span.toggle-name Offline el-radio-group(v-model="sharedFeedFilters.noty.Offline" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} .toggle-item span.toggle-name GPS el-radio-group(v-model="sharedFeedFilters.noty.GPS" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} .toggle-item span.toggle-name Status el-radio-group(v-model="sharedFeedFilters.noty.Status" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} .toggle-item span.toggle-name Invite el-radio-group(v-model="sharedFeedFilters.noty.invite" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} .toggle-item span.toggle-name Request Invite el-radio-group(v-model="sharedFeedFilters.noty.requestInvite" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} .toggle-item span.toggle-name Invite Response el-radio-group(v-model="sharedFeedFilters.noty.inviteResponse" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} .toggle-item span.toggle-name Request Invite Response el-radio-group(v-model="sharedFeedFilters.noty.requestInviteResponse" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} .toggle-item span.toggle-name Friend Request el-radio-group(v-model="sharedFeedFilters.noty.friendRequest" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} .toggle-item span.toggle-name New Friend el-radio-group(v-model="sharedFeedFilters.noty.Friend" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} .toggle-item span.toggle-name Unfriend el-radio-group(v-model="sharedFeedFilters.noty.Unfriend" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} .toggle-item span.toggle-name Display Name el-radio-group(v-model="sharedFeedFilters.noty.DisplayName" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} .toggle-item span.toggle-name Trust Level el-radio-group(v-model="sharedFeedFilters.noty.TrustLevel" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} .toggle-item span.toggle-name Group Announcement el-radio-group(v-model="sharedFeedFilters.noty['group.announcement']" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} .toggle-item span.toggle-name Group Join/Leave el-radio-group(v-model="sharedFeedFilters.noty['group.informative']" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} .toggle-item span.toggle-name Group Invite el-radio-group(v-model="sharedFeedFilters.noty['group.invite']" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} .toggle-item span.toggle-name Group Join Request el-radio-group(v-model="sharedFeedFilters.noty['group.joinRequest']" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} .toggle-item span.toggle-name Portal Spawn el-radio-group(v-model="sharedFeedFilters.noty.PortalSpawn" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") - el-radio-button(label="Everyone") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} + el-radio-button(label="Everyone") {{ $t('dialog.shared_feed_filters.everyone') }} .toggle-item span.toggle-name Video Play el-tooltip(placement="top" style="margin-left:5px" content="Requires VRCX YouTube API option enabled") i.el-icon-warning el-radio-group(v-model="sharedFeedFilters.noty.VideoPlay" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} .toggle-item span.toggle-name Events el-radio-group(v-model="sharedFeedFilters.noty.Event" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} .toggle-item span.toggle-name Blocked Player Joins el-radio-group(v-model="sharedFeedFilters.noty.BlockedOnPlayerJoined" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") - el-radio-button(label="Everyone") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} + el-radio-button(label="Everyone") {{ $t('dialog.shared_feed_filters.everyone') }} .toggle-item span.toggle-name Blocked Player Leaves el-radio-group(v-model="sharedFeedFilters.noty.BlockedOnPlayerLeft" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") - el-radio-button(label="Everyone") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} + el-radio-button(label="Everyone") {{ $t('dialog.shared_feed_filters.everyone') }} .toggle-item span.toggle-name Muted Player Joins el-radio-group(v-model="sharedFeedFilters.noty.MutedOnPlayerJoined" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") - el-radio-button(label="Everyone") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} + el-radio-button(label="Everyone") {{ $t('dialog.shared_feed_filters.everyone') }} .toggle-item span.toggle-name Muted Player Leaves el-radio-group(v-model="sharedFeedFilters.noty.MutedOnPlayerLeft" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") - el-radio-button(label="Everyone") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} + el-radio-button(label="Everyone") {{ $t('dialog.shared_feed_filters.everyone') }} template(v-if="photonLoggingEnabled") br .toggle-item @@ -2917,211 +2924,211 @@ html .toggle-item span.toggle-name Lobby Avatar Change el-radio-group(v-model="sharedFeedFilters.noty.AvatarChange" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") - el-radio-button(label="Everyone") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} + el-radio-button(label="Everyone") {{ $t('dialog.shared_feed_filters.everyone') }} .toggle-item span.toggle-name Lobby ChatBox Message el-radio-group(v-model="sharedFeedFilters.noty.ChatBoxMessage" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") - el-radio-button(label="Everyone") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} + el-radio-button(label="Everyone") {{ $t('dialog.shared_feed_filters.everyone') }} .toggle-item span.toggle-name Blocked el-radio-group(v-model="sharedFeedFilters.noty.Blocked" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} .toggle-item span.toggle-name Unblocked el-radio-group(v-model="sharedFeedFilters.noty.Unblocked" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} .toggle-item span.toggle-name Muted el-radio-group(v-model="sharedFeedFilters.noty.Muted" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} .toggle-item span.toggle-name Unmuted el-radio-group(v-model="sharedFeedFilters.noty.Unmuted" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} template(#footer) - el-button(type="small" @click="cancelSharedFeedFilters") Cancel - el-button(type="primary" size="small" style="margin-left:10px" @click="saveSharedFeedFilters") Save + el-button(type="small" @click="cancelSharedFeedFilters") {{ $t('dialog.shared_feed_filters.cancel') }} + el-button(type="primary" size="small" style="margin-left:10px" @click="saveSharedFeedFilters") {{ $t('dialog.shared_feed_filters.save') }} //- dialog: wrist feed filters - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="wristFeedFiltersDialog" :visible.sync="wristFeedFiltersDialog.visible" title="Wrist Feed Filters" width="550px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="wristFeedFiltersDialog" :visible.sync="wristFeedFiltersDialog.visible" :title="$t('dialog.shared_feed_filters.wrist')" width="550px") .toggle-list .toggle-item span.toggle-name Self Location el-radio-group(v-model="sharedFeedFilters.wrist.Location" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} .toggle-item span.toggle-name OnPlayerJoining el-radio-group(v-model="sharedFeedFilters.wrist.OnPlayerJoining" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} .toggle-item span.toggle-name OnPlayerJoined el-radio-group(v-model="sharedFeedFilters.wrist.OnPlayerJoined" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") - el-radio-button(label="Everyone") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} + el-radio-button(label="Everyone") {{ $t('dialog.shared_feed_filters.everyone') }} .toggle-item span.toggle-name OnPlayerLeft el-radio-group(v-model="sharedFeedFilters.wrist.OnPlayerLeft" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") - el-radio-button(label="Everyone") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} + el-radio-button(label="Everyone") {{ $t('dialog.shared_feed_filters.everyone') }} .toggle-item span.toggle-name Online el-radio-group(v-model="sharedFeedFilters.wrist.Online" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} .toggle-item span.toggle-name Offline el-radio-group(v-model="sharedFeedFilters.wrist.Offline" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} .toggle-item span.toggle-name GPS el-radio-group(v-model="sharedFeedFilters.wrist.GPS" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} .toggle-item span.toggle-name Status el-radio-group(v-model="sharedFeedFilters.wrist.Status" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} .toggle-item span.toggle-name Invite el-radio-group(v-model="sharedFeedFilters.wrist.invite" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} .toggle-item span.toggle-name Request Invite el-radio-group(v-model="sharedFeedFilters.wrist.requestInvite" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} .toggle-item span.toggle-name Invite Response el-radio-group(v-model="sharedFeedFilters.wrist.inviteResponse" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} .toggle-item span.toggle-name Request Invite Response el-radio-group(v-model="sharedFeedFilters.wrist.requestInviteResponse" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} .toggle-item span.toggle-name Friend Request el-radio-group(v-model="sharedFeedFilters.wrist.friendRequest" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} .toggle-item span.toggle-name New Friend el-radio-group(v-model="sharedFeedFilters.wrist.Friend" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} .toggle-item span.toggle-name Unfriend el-radio-group(v-model="sharedFeedFilters.wrist.Unfriend" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} .toggle-item span.toggle-name Display Name el-radio-group(v-model="sharedFeedFilters.wrist.DisplayName" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} .toggle-item span.toggle-name Trust Level el-radio-group(v-model="sharedFeedFilters.wrist.TrustLevel" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} .toggle-item span.toggle-name Group Announcement el-radio-group(v-model="sharedFeedFilters.wrist['group.announcement']" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} .toggle-item span.toggle-name Group Join/Leave el-radio-group(v-model="sharedFeedFilters.wrist['group.informative']" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} .toggle-item span.toggle-name Group Invite el-radio-group(v-model="sharedFeedFilters.wrist['group.invite']" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} .toggle-item span.toggle-name Group Join Request el-radio-group(v-model="sharedFeedFilters.wrist['group.joinRequest']" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} .toggle-item span.toggle-name Portal Spawn el-radio-group(v-model="sharedFeedFilters.wrist.PortalSpawn" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") - el-radio-button(label="Everyone") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} + el-radio-button(label="Everyone") {{ $t('dialog.shared_feed_filters.everyone') }} .toggle-item span.toggle-name Video Play el-tooltip(placement="top" style="margin-left:5px" content="Requires VRCX YouTube API option enabled") i.el-icon-warning el-radio-group(v-model="sharedFeedFilters.wrist.VideoPlay" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} .toggle-item span.toggle-name Events el-radio-group(v-model="sharedFeedFilters.wrist.Event" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} .toggle-item span.toggle-name Blocked Player Joins el-radio-group(v-model="sharedFeedFilters.wrist.BlockedOnPlayerJoined" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") - el-radio-button(label="Everyone") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} + el-radio-button(label="Everyone") {{ $t('dialog.shared_feed_filters.everyone') }} .toggle-item span.toggle-name Blocked Player Leaves el-radio-group(v-model="sharedFeedFilters.wrist.BlockedOnPlayerLeft" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") - el-radio-button(label="Everyone") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} + el-radio-button(label="Everyone") {{ $t('dialog.shared_feed_filters.everyone') }} .toggle-item span.toggle-name Muted Player Joins el-radio-group(v-model="sharedFeedFilters.wrist.MutedOnPlayerJoined" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") - el-radio-button(label="Everyone") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} + el-radio-button(label="Everyone") {{ $t('dialog.shared_feed_filters.everyone') }} .toggle-item span.toggle-name Muted Player Leaves el-radio-group(v-model="sharedFeedFilters.wrist.MutedOnPlayerLeft" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") - el-radio-button(label="Everyone") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} + el-radio-button(label="Everyone") {{ $t('dialog.shared_feed_filters.everyone') }} template(v-if="photonLoggingEnabled") br .toggle-item @@ -3129,161 +3136,161 @@ html .toggle-item span.toggle-name Lobby Avatar Change el-radio-group(v-model="sharedFeedFilters.wrist.AvatarChange" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") - el-radio-button(label="Everyone") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} + el-radio-button(label="Everyone") {{ $t('dialog.shared_feed_filters.everyone') }} .toggle-item span.toggle-name Lobby ChatBox Message el-radio-group(v-model="sharedFeedFilters.wrist.ChatBoxMessage" size="mini") - el-radio-button(label="Off") - el-radio-button(label="VIP") - el-radio-button(label="Friends") - el-radio-button(label="Everyone") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="VIP") {{ $t('dialog.shared_feed_filters.favorite') }} + el-radio-button(label="Friends") {{ $t('dialog.shared_feed_filters.friends') }} + el-radio-button(label="Everyone") {{ $t('dialog.shared_feed_filters.everyone') }} .toggle-item span.toggle-name Blocked el-radio-group(v-model="sharedFeedFilters.wrist.Blocked" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} .toggle-item span.toggle-name Unblocked el-radio-group(v-model="sharedFeedFilters.wrist.Unblocked" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} .toggle-item span.toggle-name Muted el-radio-group(v-model="sharedFeedFilters.wrist.Muted" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} .toggle-item span.toggle-name Unmuted el-radio-group(v-model="sharedFeedFilters.wrist.Unmuted" size="mini") - el-radio-button(label="Off") - el-radio-button(label="On") + el-radio-button(label="Off") {{ $t('dialog.shared_feed_filters.off') }} + el-radio-button(label="On") {{ $t('dialog.shared_feed_filters.on') }} template(#footer) - el-button(type="small" @click="cancelSharedFeedFilters") Cancel - el-button(type="primary" size="small" @click="saveSharedFeedFilters") Save + el-button(type="small" @click="cancelSharedFeedFilters") {{ $t('dialog.shared_feed_filters.cancel') }} + el-button(type="primary" size="small" @click="saveSharedFeedFilters") {{ $t('dialog.shared_feed_filters.save') }} //- dialog: Edit Invite Message - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="editInviteMessageDialog" :visible.sync="editInviteMessageDialog.visible" title="Edit Invite Message" width="400px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="editInviteMessageDialog" :visible.sync="editInviteMessageDialog.visible" :title="$t('dialog.edit_invite_message.header')" width="400px") div(style='font-size:12px') - span 1 hour edit cool down time. + span {{ $t('dialog.edit_invite_message.description') }} el-input(type="textarea" v-model="editInviteMessageDialog.newMessage" size="mini" maxlength="64" show-word-limit :autosize="{ minRows:2, maxRows:5 }" placeholder="" style="margin-top:10px") template(#footer) - el-button(type="small" @click="cancelEditInviteMessage") Cancel - el-button(type="primary" size="small" @click="saveEditInviteMessage") Save + el-button(type="small" @click="cancelEditInviteMessage") {{ $t('dialog.edit_invite_message.cancel') }} + el-button(type="primary" size="small" @click="saveEditInviteMessage") {{ $t('dialog.edit_invite_message.save') }} //- dialog: Edit And Send Invite Response Message - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="editAndSendInviteResponseDialog" :visible.sync="editAndSendInviteResponseDialog.visible" title="Edit and Send Invite Message" width="400px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="editAndSendInviteResponseDialog" :visible.sync="editAndSendInviteResponseDialog.visible" :title="$t('dialog.edit_send_invite_response_message.header')" width="400px") div(style='font-size:12px') - span 1 hour edit cool down time. + span {{ $t('dialog.edit_send_invite_response_message.description') }} el-input(type="textarea" v-model="editAndSendInviteResponseDialog.newMessage" size="mini" maxlength="64" show-word-limit :autosize="{ minRows:2, maxRows:5 }" placeholder="" style="margin-top:10px") template(#footer) - el-button(type="small" @click="cancelEditAndSendInviteResponse") Cancel - el-button(type="primary" size="small" @click="saveEditAndSendInviteResponse") Send + el-button(type="small" @click="cancelEditAndSendInviteResponse") {{ $t('dialog.edit_send_invite_response_message.cancel') }} + el-button(type="primary" size="small" @click="saveEditAndSendInviteResponse") {{ $t('dialog.edit_send_invite_response_message.send') }} //- dialog Table: Send Invite Response Message - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="sendInviteResponseDialog" :visible.sync="sendInviteResponseDialogVisible" title="Send Invite Response Message" width="800px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="sendInviteResponseDialog" :visible.sync="sendInviteResponseDialogVisible" :title="$t('dialog.invite_response_message.header')" width="800px") template(v-if="API.currentUser.$isVRCPlus") input.inviteImageUploadButton(type="file" accept="image/png" @change="inviteImageUpload") data-tables(v-if="sendInviteResponseDialogVisible" v-bind="inviteResponseMessageTable" @row-click="showSendInviteResponseConfirmDialog" style="margin-top:10px;cursor:pointer") - el-table-column(label="Slot" prop="slot" sortable="custom" width="70") - el-table-column(label="Message" prop="message") - el-table-column(label="Cool Down" prop="updatedAt" sortable="custom" width="110" align="right") + el-table-column(:label="$t('table.profile.invite_messages.slot')" prop="slot" sortable="custom" width="70") + el-table-column(:label="$t('table.profile.invite_messages.message')" prop="message") + el-table-column(:label="$t('table.profile.invite_messages.cool_down')" prop="updatedAt" sortable="custom" width="110" align="right") template(v-once #default="scope") countdown-timer(:datetime="scope.row.updatedAt" :hours="1") - el-table-column(label="Action" width="70" align="right") + el-table-column(:label="$t('table.profile.invite_messages.action')" width="70" align="right") template(v-once #default="scope") el-button(type="text" icon="el-icon-edit" size="mini" @click="showEditAndSendInviteResponseDialog('response', scope.row)") template(#footer) - el-button(type="small" @click="cancelSendInviteResponse") Cancel - el-button(type="small" @click="API.refreshInviteMessageTableData('response')") Refresh + el-button(type="small" @click="cancelSendInviteResponse") {{ $t('dialog.invite_response_message.cancel') }} + el-button(type="small" @click="API.refreshInviteMessageTableData('response')") {{ $t('dialog.invite_response_message.refresh') }} //- dialog Table: Send Invite Request Response Message - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="sendInviteRequestResponseDialog" :visible.sync="sendInviteRequestResponseDialogVisible" title="Send Invite Request Response Message" width="800px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="sendInviteRequestResponseDialog" :visible.sync="sendInviteRequestResponseDialogVisible" :title="$t('dialog.invite_request_response_message.header')" width="800px") template(v-if="API.currentUser.$isVRCPlus") input.inviteImageUploadButton(type="file" accept="image/png" @change="inviteImageUpload") data-tables(v-if="sendInviteRequestResponseDialogVisible" v-bind="inviteRequestResponseMessageTable" @row-click="showSendInviteResponseConfirmDialog" style="margin-top:10px;cursor:pointer") - el-table-column(label="Slot" prop="slot" sortable="custom" width="70") - el-table-column(label="Message" prop="message") - el-table-column(label="Cool Down" prop="updatedAt" sortable="custom" width="110" align="right") + el-table-column(:label="$t('table.profile.invite_messages.slot')" prop="slot" sortable="custom" width="70") + el-table-column(:label="$t('table.profile.invite_messages.message')" prop="message") + el-table-column(:label="$t('table.profile.invite_messages.cool_down')" prop="updatedAt" sortable="custom" width="110" align="right") template(v-once #default="scope") countdown-timer(:datetime="scope.row.updatedAt" :hours="1") - el-table-column(label="Action" width="70" align="right") + el-table-column(:label="$t('table.profile.invite_messages.action')" width="70" align="right") template(v-once #default="scope") el-button(type="text" icon="el-icon-edit" size="mini" @click="showEditAndSendInviteResponseDialog('requestResponse', scope.row)") template(#footer) - el-button(type="small" @click="cancelSendInviteRequestResponse") Cancel - el-button(type="small" @click="API.refreshInviteMessageTableData('requestResponse')") Refresh + el-button(type="small" @click="cancelSendInviteRequestResponse") {{ $t('dialog.invite_request_response_message.cancel') }} + el-button(type="small" @click="API.refreshInviteMessageTableData('requestResponse')") {{ $t('dialog.invite_request_response_message.refresh') }} //- dialog: Send Invite Response Message Confirm - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="sendInviteResponseConfirmDialog" :visible.sync="sendInviteResponseConfirmDialog.visible" title="Send Invite Response Message" width="400px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="sendInviteResponseConfirmDialog" :visible.sync="sendInviteResponseConfirmDialog.visible" :title="$t('dialog.invite_response_message.header')" width="400px") div(style='font-size:12px') - span Are you sure you want to send? + span {{ $t('dialog.invite_response_message.confirmation') }} template(#footer) - el-button(type="small" @click="cancelInviteResponseConfirm") Cancel - el-button(type="primary" size="small" @click="sendInviteResponseConfirm") Confirm + el-button(type="small" @click="cancelInviteResponseConfirm") {{ $t('dialog.invite_response_message.cancel') }} + el-button(type="primary" size="small" @click="sendInviteResponseConfirm") {{ $t('dialog.invite_response_message.confirm') }} //- dialog Table: Send Invite Message - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="sendInviteDialog" :visible.sync="sendInviteDialogVisible" title="Send Invite Message" width="800px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="sendInviteDialog" :visible.sync="sendInviteDialogVisible" :title="$t('dialog.invite_message.header')" width="800px") template(v-if="API.currentUser.$isVRCPlus") input.inviteImageUploadButton(type="file" accept="image/png" @change="inviteImageUpload") data-tables(v-if="sendInviteDialogVisible" v-bind="inviteMessageTable" @row-click="showSendInviteConfirmDialog" style="margin-top:10px;cursor:pointer") - el-table-column(label="Slot" prop="slot" sortable="custom" width="70") - el-table-column(label="Message" prop="message") - el-table-column(label="Cool Down" prop="updatedAt" sortable="custom" width="110" align="right") + el-table-column(:label="$t('table.profile.invite_messages.slot')" prop="slot" sortable="custom" width="70") + el-table-column(:label="$t('table.profile.invite_messages.message')" prop="message") + el-table-column(:label="$t('table.profile.invite_messages.cool_down')" prop="updatedAt" sortable="custom" width="110" align="right") template(v-once #default="scope") countdown-timer(:datetime="scope.row.updatedAt" :hours="1") - el-table-column(label="Action" width="70" align="right") + el-table-column(:label="$t('table.profile.invite_messages.action')" width="70" align="right") template(v-once #default="scope") el-button(type="text" icon="el-icon-edit" size="mini" @click="showEditAndSendInviteDialog('message', scope.row)") template(#footer) - el-button(type="small" @click="cancelSendInvite") Cancel - el-button(type="small" @click="API.refreshInviteMessageTableData('message')") Refresh + el-button(type="small" @click="cancelSendInvite") {{ $t('dialog.invite_message.cancel') }} + el-button(type="small" @click="API.refreshInviteMessageTableData('message')") {{ $t('dialog.invite_message.refresh') }} //- dialog Table: Send Invite Request Message - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="sendInviteRequestDialog" :visible.sync="sendInviteRequestDialogVisible" title="Send Invite Request Message" width="800px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="sendInviteRequestDialog" :visible.sync="sendInviteRequestDialogVisible" :title="$t('dialog.invite_request_message.header')" width="800px") template(v-if="API.currentUser.$isVRCPlus") input.inviteImageUploadButton(type="file" accept="image/png" @change="inviteImageUpload") data-tables(v-if="sendInviteRequestDialogVisible" v-bind="inviteRequestMessageTable" @row-click="showSendInviteConfirmDialog" style="margin-top:10px;cursor:pointer") - el-table-column(label="Slot" prop="slot" sortable="custom" width="70") - el-table-column(label="Message" prop="message") - el-table-column(label="Cool Down" prop="updatedAt" sortable="custom" width="110" align="right") + el-table-column(:label="$t('table.profile.invite_messages.slot')" prop="slot" sortable="custom" width="70") + el-table-column(:label="$t('table.profile.invite_messages.message')" prop="message") + el-table-column(:label="$t('table.profile.invite_messages.cool_down')" prop="updatedAt" sortable="custom" width="110" align="right") template(v-once #default="scope") countdown-timer(:datetime="scope.row.updatedAt" :hours="1") - el-table-column(label="Action" width="70" align="right") + el-table-column(:label="$t('table.profile.invite_messages.action')" width="70" align="right") template(v-once #default="scope") el-button(type="text" icon="el-icon-edit" size="mini" @click="showEditAndSendInviteDialog('request', scope.row)") template(#footer) - el-button(type="small" @click="cancelSendInviteRequest") Cancel - el-button(type="small" @click="API.refreshInviteMessageTableData('request')") Refresh + el-button(type="small" @click="cancelSendInviteRequest") {{ $t('dialog.invite_request_message.cancel') }} + el-button(type="small" @click="API.refreshInviteMessageTableData('request')") {{ $t('dialog.invite_request_message.refresh') }} //- dialog: Send Invite Message Confirm - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="sendInviteConfirmDialog" :visible.sync="sendInviteConfirmDialog.visible" title="Send Invite Message" width="400px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="sendInviteConfirmDialog" :visible.sync="sendInviteConfirmDialog.visible" :title="$t('dialog.invite_message.header')" width="400px") div(style='font-size:12px') - span Are you sure you want to send? + span {{ $t('dialog.invite_message.confirmation') }} template(#footer) - el-button(type="small" @click="cancelInviteConfirm") Cancel - el-button(type="primary" size="small" @click="sendInviteConfirm") Confirm + el-button(type="small" @click="cancelInviteConfirm") {{ $t('dialog.invite_message.cancel') }} + el-button(type="primary" size="small" @click="sendInviteConfirm") {{ $t('dialog.invite_message.confirm') }} //- dialog: Edit And Send Invite Message - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="editAndSendInviteDialog" :visible.sync="editAndSendInviteDialog.visible" title="Edit and Send Invite Message" width="400px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="editAndSendInviteDialog" :visible.sync="editAndSendInviteDialog.visible" :title="$t('dialog.edit_send_invite_message.header')" width="400px") div(style='font-size:12px') - span 1 hour edit cool down time. + span {{ $t('dialog.edit_send_invite_message.description') }} el-input(type="textarea" v-model="editAndSendInviteDialog.newMessage" size="mini" maxlength="64" show-word-limit :autosize="{ minRows:2, maxRows:5 }" placeholder="" style="margin-top:10px") template(#footer) - el-button(type="small" @click="cancelEditAndSendInvite") Cancel - el-button(type="primary" size="small" @click="saveEditAndSendInvite") Send + el-button(type="small" @click="cancelEditAndSendInvite") {{ $t('dialog.edit_send_invite_message.cancel') }} + el-button(type="primary" size="small" @click="saveEditAndSendInvite") {{ $t('dialog.edit_send_invite_message.send') }} //- dialog: Change avatar image - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="changeAvatarImageDialog" :visible.sync="changeAvatarImageDialogVisible" title="Change Avatar Image" width="800px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="changeAvatarImageDialog" :visible.sync="changeAvatarImageDialogVisible" :title="$t('dialog.change_content_image.avatar')" width="800px") div(v-if="changeAvatarImageDialogVisible" v-loading="changeAvatarImageDialogLoading") input(type="file" accept="image/*" @change="onFileChangeAvatarImage" id="AvatarImageUploadButton" style="display:none") - span Recommended image size 1200x900px (4:3) + span {{ $t('dialog.change_content_image.description') }} br el-button-group(style="padding-bottom:10px;padding-top:10px") - el-button(type="default" size="small" @click="displayPreviousImages('Avatar', 'Change')" icon="el-icon-refresh") Refresh - el-button(type="default" size="small" @click="uploadAvatarImage" icon="el-icon-upload2") Upload Image + el-button(type="default" size="small" @click="displayPreviousImages('Avatar', 'Change')" icon="el-icon-refresh") {{ $t('dialog.change_content_image.refresh') }} + el-button(type="default" size="small" @click="uploadAvatarImage" icon="el-icon-upload2") {{ $t('dialog.change_content_image.upload') }} //- el-button(type="default" size="small" @click="deleteAvatarImage" icon="el-icon-delete") Delete Latest Image br div(style="display:inline-block" v-for="image in previousImagesTable" :key="image.version" v-if="image.file") @@ -3291,14 +3298,14 @@ html img.image(v-lazy="image.file.url") //- dialog: Change world image - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="changeWorldImageDialog" :visible.sync="changeWorldImageDialogVisible" title="Change World Image" width="800px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="changeWorldImageDialog" :visible.sync="changeWorldImageDialogVisible" :title="$t('dialog.change_content_image.world')" width="800px") div(v-if="changeWorldImageDialogVisible" v-loading="changeWorldImageDialogLoading") input(type="file" accept="image/*" @change="onFileChangeWorldImage" id="WorldImageUploadButton" style="display:none") - span Recommended image size 1200x900px (4:3) + span {{ $t('dialog.change_content_image.description') }} br el-button-group(style="padding-bottom:10px;padding-top:10px") - el-button(type="default" size="small" @click="displayPreviousImages('World', 'Change')" icon="el-icon-refresh") Refresh - el-button(type="default" size="small" @click="uploadWorldImage" icon="el-icon-upload2") Upload Image + el-button(type="default" size="small" @click="displayPreviousImages('World', 'Change')" icon="el-icon-refresh") {{ $t('dialog.change_content_image.refresh') }} + el-button(type="default" size="small" @click="uploadWorldImage" icon="el-icon-upload2") {{ $t('dialog.change_content_image.upload') }} //- el-button(type="default" size="small" @click="deleteWorldImage" icon="el-icon-delete") Delete Latest Image br div(style="display:inline-block" v-for="image in previousImagesTable" :key="image.version" v-if="image.file") @@ -3306,7 +3313,7 @@ html img.image(v-lazy="image.file.url") //- dialog: Display previous avatar/world images - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="previousImagesDialog" :visible.sync="previousImagesDialogVisible" title="Previous Images" width="800px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="previousImagesDialog" :visible.sync="previousImagesDialogVisible" :title="$t('dialog.previous_images.header')" width="800px") div(v-if="previousImagesDialogVisible") div(style="display:inline-block" v-for="image in previousImagesTable" :key="image.version" v-if="image.file") el-popover.x-change-image-item(placement="right" width="500px" trigger="click") @@ -3314,17 +3321,17 @@ html img.x-link(v-lazy="image.file.url" style="width:500px;height:375px" @click="downloadAndSaveImage(image.file.url)") //- dialog: Gallery/VRCPlusIcons - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="galleryDialog" :visible.sync="galleryDialogVisible" title="Gallery and Icons" width="100%") - span(style="padding-bottom:10px") Recommended image size 1200x900px (4:3) + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="galleryDialog" :visible.sync="galleryDialogVisible" :title="$t('dialog.gallery_icons.header')" width="100%") + span(style="padding-bottom:10px") {{ $t('dialog.gallery_icons.description') }} (4:3) el-tabs(type="card") el-tab-pane(v-if="galleryDialogVisible" v-loading="galleryDialogGalleryLoading") - span(slot="label") Gallery + span(slot="label") {{ $t('dialog.gallery_icons.gallery') }} span(style="color:#909399;font-size:12px;margin-left:5px") {{ galleryTable.length }}/64 input(type="file" accept="image/*" @change="onFileChangeGallery" id="GalleryUploadButton" style="display:none") el-button-group - el-button(type="default" size="small" @click="refreshGalleryTable" icon="el-icon-refresh") Refresh - el-button(type="default" size="small" @click="displayGalleryUpload" icon="el-icon-upload2" :disabled="!API.currentUser.$isVRCPlus") Upload - el-button(type="default" size="small" @click="setProfilePicOverride('')" icon="el-icon-close" :disabled="!API.currentUser.profilePicOverride") Clear + el-button(type="default" size="small" @click="refreshGalleryTable" icon="el-icon-refresh") {{ $t('dialog.gallery_icons.refresh') }} + el-button(type="default" size="small" @click="displayGalleryUpload" icon="el-icon-upload2" :disabled="!API.currentUser.$isVRCPlus") {{ $t('dialog.gallery_icons.upload') }} + el-button(type="default" size="small" @click="setProfilePicOverride('')" icon="el-icon-close" :disabled="!API.currentUser.profilePicOverride") {{ $t('dialog.gallery_icons.clear') }} br .x-friend-item(v-if="image.versions && image.versions.length > 0" v-for="image in galleryTable" :key="image.id" style="display:inline-block;margin-top:10px;width:unset;cursor:default") .vrcplus-icon(v-if="image.versions[image.versions.length - 1].file.url" @click="setProfilePicOverride(image.id)" :class="{ 'current-vrcplus-icon': compareCurrentProfilePic(image.id) }") @@ -3333,13 +3340,13 @@ html el-button(type="default" @click="downloadAndSaveImage(image.versions[image.versions.length - 1].file.url)" size="mini" icon="el-icon-download" circle) el-button(type="default" @click="deleteGalleryImage(image.id)" size="mini" icon="el-icon-delete" circle style="margin-left:5px") el-tab-pane(v-if="galleryDialogVisible" v-loading="galleryDialogIconsLoading") - span(slot="label") Icons + span(slot="label") {{ $t('dialog.gallery_icons.icons') }} span(style="color:#909399;font-size:12px;margin-left:5px") {{ VRCPlusIconsTable.length }}/64 input(type="file" accept="image/*" @change="onFileChangeVRCPlusIcon" id="VRCPlusIconUploadButton" style="display:none") el-button-group - el-button(type="default" size="small" @click="refreshVRCPlusIconsTable" icon="el-icon-refresh") Refresh - el-button(type="default" size="small" @click="displayVRCPlusIconUpload" icon="el-icon-upload2" :disabled="!API.currentUser.$isVRCPlus") Upload - el-button(type="default" size="small" @click="setVRCPlusIcon('')" icon="el-icon-close" :disabled="!API.currentUser.userIcon") Clear + el-button(type="default" size="small" @click="refreshVRCPlusIconsTable" icon="el-icon-refresh") {{ $t('dialog.gallery_icons.refresh') }} + el-button(type="default" size="small" @click="displayVRCPlusIconUpload" icon="el-icon-upload2" :disabled="!API.currentUser.$isVRCPlus") {{ $t('dialog.gallery_icons.upload') }} + el-button(type="default" size="small" @click="setVRCPlusIcon('')" icon="el-icon-close" :disabled="!API.currentUser.userIcon") {{ $t('dialog.gallery_icons.clear') }} br .x-friend-item(v-if="image.versions && image.versions.length > 0" v-for="image in VRCPlusIconsTable" :key="image.id" style="display:inline-block;margin-top:10px;width:unset;cursor:default") .vrcplus-icon(v-if="image.versions[image.versions.length - 1].file.url" @click="setVRCPlusIcon(image.id)" :class="{ 'current-vrcplus-icon': compareCurrentVRCPlusIcon(image.id) }") @@ -3347,81 +3354,81 @@ html div(style="float:right;margin-top:5px") el-button(type="default" @click="downloadAndSaveImage(image.versions[image.versions.length - 1].file.url)" size="mini" icon="el-icon-download" circle) el-button(type="default" @click="deleteVRCPlusIcon(image.id)" size="mini" icon="el-icon-delete" circle style="margin-left:5px") - + //- dialog Table: Previous Instances User - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="previousInstancesUserDialog" :visible.sync="previousInstancesUserDialog.visible" title="Previous Instances" width="800px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="previousInstancesUserDialog" :visible.sync="previousInstancesUserDialog.visible" :title="$t('dialog.previous_instances.header')" width="800px") span(v-text="previousInstancesUserDialog.userRef.displayName" style="font-size:14px") - el-input(v-model="previousInstancesUserDialogTable.filters[0].value" placeholder="Search" style="display:block;width:150px;margin-top:15px") + el-input(v-model="previousInstancesUserDialogTable.filters[0].value" :placeholder="$t('dialog.previous_instances.search_placeholder')" style="display:block;width:150px;margin-top:15px") data-tables(v-if="previousInstancesUserDialog.visible" v-bind="previousInstancesUserDialogTable" v-loading="previousInstancesUserDialog.loading" style="margin-top:10px") - el-table-column(label="Date" prop="created_at" sortable width="120") + el-table-column(:label="$t('table.previous_instances.date')" prop="created_at" sortable width="120") template(v-once #default="scope") el-tooltip(placement="left") template(#content) span {{ scope.row.created_at | formatDate('long') }} span {{ scope.row.created_at | formatDate('short') }} - el-table-column(label="World" prop="name" sortable) + el-table-column(:label="$t('table.previous_instances.world')" prop="name" sortable) template(v-once #default="scope") location(:location="scope.row.location" :hint="scope.row.worldName" :grouphint="scope.row.groupName") - el-table-column(label="Instance Creator" prop="location" width="160") + el-table-column(:label="$t('table.previous_instances.instance_creator')" prop="location" width="160") template(v-once #default="scope") display-name(:userid="scope.row.$location.userId" :location="scope.row.$location.tag" :key="previousInstancesUserDialog.forceUpdate") - el-table-column(label="Time" prop="time" width="90" sortable) + el-table-column(:label="$t('table.previous_instances.time')" prop="time" width="90" sortable) template(v-once #default="scope") span(v-text="scope.row.timer") - el-table-column(label="Action" width="90" align="right") + el-table-column(:label="$t('table.previous_instances.action')" width="90" align="right") template(v-once #default="scope") el-button(type="text" icon="el-icon-info" size="mini" @click="showLaunchDialog(scope.row.location)") el-button(type="text" icon="el-icon-tickets" size="mini" @click="showPreviousInstanceInfoDialog(scope.row.location)") el-button(type="text" icon="el-icon-close" size="mini" @click="confirmDeleteGameLogUserInstance(scope.row)") - + //- dialog Table: Previous Instances World - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="previousInstancesWorldDialog" :visible.sync="previousInstancesWorldDialog.visible" title="Previous Instances" width="800px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="previousInstancesWorldDialog" :visible.sync="previousInstancesWorldDialog.visible" :title="$t('dialog.previous_instances.header')" width="800px") span(v-text="previousInstancesWorldDialog.worldRef.name" style="font-size:14px") - el-input(v-model="previousInstancesWorldDialogTable.filters[0].value" placeholder="Search" style="display:block;width:150px;margin-top:15px") + el-input(v-model="previousInstancesWorldDialogTable.filters[0].value" :placeholder="$t('dialog.previous_instances.search_placeholder')" style="display:block;width:150px;margin-top:15px") data-tables(v-if="previousInstancesWorldDialog.visible" v-bind="previousInstancesWorldDialogTable" v-loading="previousInstancesWorldDialog.loading" style="margin-top:10px") - el-table-column(label="Date" prop="created_at" sortable width="120") + el-table-column(:label="$t('table.previous_instances.date')" prop="created_at" sortable width="120") template(v-once #default="scope") el-tooltip(placement="left") template(#content) span {{ scope.row.created_at | formatDate('long') }} span {{ scope.row.created_at | formatDate('short') }} - el-table-column(label="Instance Name" prop="name") + el-table-column(:label="$t('table.previous_instances.instance_name')" prop="name") template(v-once #default="scope") location-world(:locationobject="scope.row.$location" :grouphint="scope.row.groupName" :currentuserid="API.currentUser.id") - el-table-column(label="Instance Creator" prop="location") + el-table-column(:label="$t('table.previous_instances.instance_creator')" prop="location") template(v-once #default="scope") display-name(:userid="scope.row.$location.userId" :location="scope.row.$location.tag" :key="previousInstancesWorldDialog.forceUpdate") - el-table-column(label="Time" prop="time" width="90" sortable) + el-table-column(:label="$t('table.previous_instances.time')" prop="time" width="90" sortable) template(v-once #default="scope") span(v-text="scope.row.timer") - el-table-column(label="Action" width="90" align="right") + el-table-column(:label="$t('table.previous_instances.action')" width="90" align="right") template(v-once #default="scope") el-button(type="text" icon="el-icon-tickets" size="mini" @click="showPreviousInstanceInfoDialog(scope.row.location)") el-button(type="text" icon="el-icon-close" size="mini" @click="confirmDeleteGameLogWorldInstance(scope.row)") //- dialog Table: Previous Instance Info - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="previousInstanceInfoDialog" :visible.sync="previousInstanceInfoDialog.visible" title="Previous Instance Info" width="800px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="previousInstanceInfoDialog" :visible.sync="previousInstanceInfoDialog.visible" :title="$t('dialog.previous_instances.info')" width="800px") location(:location="previousInstanceInfoDialog.$location.tag" style="font-size:14px") el-input(v-model="previousInstanceInfoDialogTable.filters[0].value" placeholder="Search" style="display:block;width:150px;margin-top:15px") data-tables(v-if="previousInstanceInfoDialog.visible" v-bind="previousInstanceInfoDialogTable" v-loading="previousInstanceInfoDialog.loading" style="margin-top:10px") - el-table-column(label="Date" prop="created_at" sortable width="120") + el-table-column(:label="$t('table.previous_instances.date')" prop="created_at" sortable width="120") template(v-once #default="scope") el-tooltip(placement="left") template(#content) span {{ scope.row.created_at | formatDate('long') }} span {{ scope.row.created_at | formatDate('short') }} - el-table-column(label="Display Name" prop="displayName" sortable) + el-table-column(:label="$t('table.previous_instances.display_name')" prop="displayName" sortable) template(v-once #default="scope") span.x-link(v-text="scope.row.displayName" @click="lookupUser(scope.row)") - el-table-column(label="Time" prop="time" width="90" sortable) + el-table-column(:label="$t('table.previous_instances.time')" prop="time" width="90" sortable) template(v-once #default="scope") span(v-text="scope.row.timer") - el-table-column(label="Count" prop="count" width="90" sortable) + el-table-column(:label="$t('table.previous_instances.count')" prop="count" width="90" sortable) template(v-once #default="scope") span(v-text="scope.row.count") //- dialog: export world list - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="worldExportDialogRef" :visible.sync="worldExportDialogVisible" title="World Favorites Export" width="650px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="worldExportDialogRef" :visible.sync="worldExportDialogVisible" :title="$t('dialog.world_export.header')" width="650px") el-dropdown(@click.native.stop trigger="click" size="small") el-button(size="mini") span(v-if="worldExportFavoriteGroup") {{ worldExportFavoriteGroup.displayName }} ({{ worldExportFavoriteGroup.count }}/{{ worldExportFavoriteGroup.capacity }}) #[i.el-icon-arrow-down.el-icon--right] @@ -3442,60 +3449,60 @@ html el-input(type="textarea" v-if="worldExportDialogVisible" v-model="worldExportContent" size="mini" rows="15" resize="none" readonly style="margin-top:15px" @click.native="$event.target.tagName === 'TEXTAREA' && $event.target.select()") //- dialog: World import dialog - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="worldImportDialog" :visible.sync="worldImportDialog.visible" title="World Favorites Import" width="650px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="worldImportDialog" :visible.sync="worldImportDialog.visible" :title="$t('dialog.world_import.header')" width="650px") div(style="font-size:12px") - | Enter a list of world IDs + | {{ $t('dialog.world_import.description') }} el-input(type="textarea" v-model="worldImportDialog.input" size="mini" rows="10" resize="none" style="margin-top:15px") - el-button(size="small" @click="processWorldImportList" :disabled="!worldImportDialog.input") Process List - span(v-if="worldImportDialog.progress" style="margin-top:10px") #[i.el-icon-loading(style="margin-right:5px")] Progress: {{ worldImportDialog.progress }}/{{ worldImportDialog.progressTotal }} + el-button(size="small" @click="processWorldImportList" :disabled="!worldImportDialog.input") {{ $t('dialog.world_import.process_list') }} + span(v-if="worldImportDialog.progress" style="margin-top:10px") #[i.el-icon-loading(style="margin-right:5px")] {{ $t('dialog.world_import.process_progress') }} {{ worldImportDialog.progress }}/{{ worldImportDialog.progressTotal }} br el-dropdown(@click.native.stop trigger="click" size="small" style="margin-right:5px") el-button(size="mini") span(v-if="worldImportDialog.worldImportFavoriteGroup") {{ worldImportDialog.worldImportFavoriteGroup.displayName }} ({{ worldImportDialog.worldImportFavoriteGroup.count }}/{{ worldImportDialog.worldImportFavoriteGroup.capacity }}) #[i.el-icon-arrow-down.el-icon--right] - span(v-else) Select Group #[i.el-icon-arrow-down.el-icon--right] + span(v-else) {{ $t('dialog.world_import.select_vrchat_group_placeholder') }} #[i.el-icon-arrow-down.el-icon--right] el-dropdown-menu(#default="dropdown") template(v-for="groupAPI in API.favoriteWorldGroups" :key="groupAPI.name") el-dropdown-item(style="display:block;margin:10px 0" @click.native="selectWorldImportGroup(groupAPI)" :disabled="groupAPI.count >= groupAPI.capacity") {{ groupAPI.displayName }} ({{ groupAPI.count }}/{{ groupAPI.capacity }}) el-dropdown(@click.native.stop trigger="click" size="small" style="margin:5px") el-button(size="mini") span(v-if="worldImportDialog.worldImportLocalFavoriteGroup") {{ worldImportDialog.worldImportLocalFavoriteGroup }} ({{ getLocalWorldFavoriteGroupLength(worldImportDialog.worldImportLocalFavoriteGroup) }}) #[i.el-icon-arrow-down.el-icon--right] - span(v-else) Select Group #[i.el-icon-arrow-down.el-icon--right] + span(v-else) {{ $t('dialog.world_import.select_local_group_placeholder') }} #[i.el-icon-arrow-down.el-icon--right] el-dropdown-menu(#default="dropdown") template(v-for="group in localWorldFavoriteGroups" :key="group") el-dropdown-item(style="display:block;margin:10px 0" @click.native="selectWorldImportLocalGroup(group)" ) {{ group }} ({{ getLocalWorldFavoriteGroupLength(group) }}) - el-button(size="small" @click="importWorldImportTable" style="margin:5px" :disabled="worldImportTable.data.length === 0 || (!worldImportDialog.worldImportFavoriteGroup && !worldImportDialog.worldImportLocalFavoriteGroup)") Import Worlds - el-button(v-if="worldImportDialog.loading" size="small" @click="cancelWorldImport" style="margin-top:10px") Cancel + el-button(size="small" @click="importWorldImportTable" style="margin:5px" :disabled="worldImportTable.data.length === 0 || (!worldImportDialog.worldImportFavoriteGroup && !worldImportDialog.worldImportLocalFavoriteGroup)") {{ $t('dialog.world_import.import') }} + el-button(v-if="worldImportDialog.loading" size="small" @click="cancelWorldImport" style="margin-top:10px") {{ $t('dialog.world_import.cancel') }} span(v-if="worldImportDialog.worldImportFavoriteGroup") {{ worldImportTable.data.length }} / {{ worldImportDialog.worldImportFavoriteGroup.capacity - worldImportDialog.worldImportFavoriteGroup.count }} - span(v-if="worldImportDialog.importProgress" style="margin:10px") #[i.el-icon-loading(style="margin-right:5px")] Import Progress: {{ worldImportDialog.importProgress }}/{{ worldImportDialog.importProgressTotal }} + span(v-if="worldImportDialog.importProgress" style="margin:10px") #[i.el-icon-loading(style="margin-right:5px")] {{ $t('dialog.world_import.import_progress') }} {{ worldImportDialog.importProgress }}/{{ worldImportDialog.importProgressTotal }} br - el-button(size="small" @click="clearWorldImportTable") Clear Table + el-button(size="small" @click="clearWorldImportTable") {{ $t('dialog.world_import.clear_table') }} template(v-if="worldImportDialog.errors") - el-button(size="small" @click="worldImportDialog.errors = ''" style="margin-left:5px") Clear Errors - h2(style="font-weight:bold;margin:0") Errors: + el-button(size="small" @click="worldImportDialog.errors = ''" style="margin-left:5px") {{ $t('dialog.world_import.clear_errors') }} + h2(style="font-weight:bold;margin:0") {{ $t('dialog.world_import.errors') }} pre(v-text="worldImportDialog.errors" style="white-space:pre-wrap;font-size:12px") data-tables(v-if="worldImportDialog.visible" v-bind="worldImportTable" v-loading="worldImportDialog.loading" style="margin-top:10px") - el-table-column(label="Image" width="70" prop="thumbnailImageUrl") + el-table-column(:label="$t('table.import.image')" width="70" prop="thumbnailImageUrl") template(v-once #default="scope") el-popover(placement="right" height="500px" trigger="hover") img.friends-list-avatar(slot="reference" v-lazy="scope.row.thumbnailImageUrl") img.friends-list-avatar(v-lazy="scope.row.imageUrl" style="height:500px;cursor:pointer" @click="downloadAndSaveImage(scope.row.imageUrl)") - el-table-column(label="Name" prop="name") + el-table-column(:label="$t('table.import.name')" prop="name") template(v-once #default="scope") span.x-link(v-text="scope.row.name" @click="showWorldDialog(scope.row.id)") - el-table-column(label="Author" width="120" prop="authorName") + el-table-column(:label="$t('table.import.author')" width="120" prop="authorName") template(v-once #default="scope") span.x-link(v-text="scope.row.authorName" @click="showUserDialog(scope.row.authorId)") - el-table-column(label="Status" width="70" prop="releaseStatus") + el-table-column(:label="$t('table.import.status')" width="70" prop="releaseStatus") template(v-once #default="scope") span(v-text="scope.row.releaseStatus" v-if="scope.row.releaseStatus === 'public'" style="color:#67c23a") span(v-text="scope.row.releaseStatus" v-else-if="scope.row.releaseStatus === 'private'" style="color:#f56c6c") span(v-text="scope.row.releaseStatus" v-else) - el-table-column(label="Action" width="90" align="right") + el-table-column(:label="$t('table.import.action')" width="90" align="right") template(v-once #default="scope") el-button(type="text" icon="el-icon-close" size="mini" @click="deleteItemWorldImport(scope.row)") //- dialog: export avatar list - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="avatarExportDialogRef" :visible.sync="avatarExportDialogVisible" title="Avatar Favorites Export" width="650px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="avatarExportDialogRef" :visible.sync="avatarExportDialogVisible" :title="$t('dialog.avatar_export.header')" width="650px") el-dropdown(@click.native.stop trigger="click" size="small") el-button(size="mini") span(v-if="avatarExportFavoriteGroup") {{ avatarExportFavoriteGroup.displayName }} ({{ avatarExportFavoriteGroup.count }}/{{ avatarExportFavoriteGroup.capacity }}) #[i.el-icon-arrow-down.el-icon--right] @@ -3508,53 +3515,53 @@ html el-input(type="textarea" v-if="avatarExportDialogVisible" v-model="avatarExportContent" size="mini" rows="15" resize="none" readonly style="margin-top:15px" @click.native="$event.target.tagName === 'TEXTAREA' && $event.target.select()") //- dialog: Avatar import dialog - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="avatarImportDialog" :visible.sync="avatarImportDialog.visible" title="Avatar Favorites Import" width="650px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="avatarImportDialog" :visible.sync="avatarImportDialog.visible" :title="$t('dialog.avatar_import.header')" width="650px") div(style="font-size:12px") - | Enter a list of avatar IDs + | {{ $t('dialog.avatar_import.description') }} el-input(type="textarea" v-model="avatarImportDialog.input" size="mini" rows="10" resize="none" style="margin-top:15px") - el-button(size="small" @click="processAvatarImportList" :disabled="!avatarImportDialog.input") Process List - span(v-if="avatarImportDialog.progress" style="margin-top:10px") #[i.el-icon-loading(style="margin-right:5px")] Progress: {{ avatarImportDialog.progress }}/{{ avatarImportDialog.progressTotal }} + el-button(size="small" @click="processAvatarImportList" :disabled="!avatarImportDialog.input") {{ $t('dialog.avatar_import.process_list') }} + span(v-if="avatarImportDialog.progress" style="margin-top:10px") #[i.el-icon-loading(style="margin-right:5px")] {{ $t('dialog.avatar_import.process_progress') }} {{ avatarImportDialog.progress }}/{{ avatarImportDialog.progressTotal }} br el-dropdown(@click.native.stop trigger="click" size="small") el-button(size="mini") span(v-if="avatarImportDialog.avatarImportFavoriteGroup") {{ avatarImportDialog.avatarImportFavoriteGroup.displayName }} ({{ avatarImportDialog.avatarImportFavoriteGroup.count }}/{{ avatarImportDialog.avatarImportFavoriteGroup.capacity }}) #[i.el-icon-arrow-down.el-icon--right] - span(v-else) Select Group #[i.el-icon-arrow-down.el-icon--right] + span(v-else) {{ $t('dialog.avatar_import.select_group_placeholder') }} #[i.el-icon-arrow-down.el-icon--right] el-dropdown-menu(#default="dropdown") template(v-for="groupAPI in API.favoriteAvatarGroups" :key="groupAPI.name") el-dropdown-item(style="display:block;margin:10px 0" @click.native="selectAvatarImportGroup(groupAPI)" :disabled="groupAPI.count >= groupAPI.capacity") {{ groupAPI.displayName }} ({{ groupAPI.count }}/{{ groupAPI.capacity }}) - el-button(size="small" @click="importAvatarImportTable" style="margin:5px" :disabled="avatarImportTable.data.length === 0 || !avatarImportDialog.avatarImportFavoriteGroup") Import Avatars - el-button(v-if="avatarImportDialog.loading" size="small" @click="cancelAvatarImport" style="margin-top:10px") Cancel + el-button(size="small" @click="importAvatarImportTable" style="margin:5px" :disabled="avatarImportTable.data.length === 0 || !avatarImportDialog.avatarImportFavoriteGroup") {{ $t('dialog.avatar_import.import') }} + el-button(v-if="avatarImportDialog.loading" size="small" @click="cancelAvatarImport" style="margin-top:10px") {{ $t('dialog.avatar_import.cancel') }} span(v-if="avatarImportDialog.avatarImportFavoriteGroup") {{ avatarImportTable.data.length }} / {{ avatarImportDialog.avatarImportFavoriteGroup.capacity - avatarImportDialog.avatarImportFavoriteGroup.count }} - span(v-if="avatarImportDialog.importProgress" style="margin:10px") #[i.el-icon-loading(style="margin-right:5px")] Import Progress: {{ avatarImportDialog.importProgress }}/{{ avatarImportDialog.importProgressTotal }} + span(v-if="avatarImportDialog.importProgress" style="margin:10px") #[i.el-icon-loading(style="margin-right:5px")] {{ $t('dialog.avatar_import.import_progress') }} {{ avatarImportDialog.importProgress }}/{{ avatarImportDialog.importProgressTotal }} br - el-button(size="small" @click="clearAvatarImportTable") Clear Table + el-button(size="small" @click="clearAvatarImportTable") {{ $t('dialog.avatar_import.clear_table') }} template(v-if="avatarImportDialog.errors") - el-button(size="small" @click="avatarImportDialog.errors = ''" style="margin-left:5px") Clear Errors - h2(style="font-weight:bold;margin:0") Errors: + el-button(size="small" @click="avatarImportDialog.errors = ''" style="margin-left:5px") {{ $t('dialog.avatar_import.clear_errors') }} + h2(style="font-weight:bold;margin:0") {{ $t('dialog.avatar_import.errors') }} pre(v-text="avatarImportDialog.errors" style="white-space:pre-wrap;font-size:12px") data-tables(v-if="avatarImportDialog.visible" v-bind="avatarImportTable" v-loading="avatarImportDialog.loading" style="margin-top:10px") - el-table-column(label="Image" width="70" prop="thumbnailImageUrl") + el-table-column(:label="$t('table.import.image')" width="70" prop="thumbnailImageUrl") template(v-once #default="scope") el-popover(placement="right" height="500px" trigger="hover") img.friends-list-avatar(slot="reference" v-lazy="scope.row.thumbnailImageUrl") img.friends-list-avatar(v-lazy="scope.row.imageUrl" style="height:500px;cursor:pointer" @click="downloadAndSaveImage(scope.row.imageUrl)") - el-table-column(label="Name" prop="name") + el-table-column(:label="$t('table.import.name')" prop="name") template(v-once #default="scope") span.x-link(v-text="scope.row.name" @click="showAvatarDialog(scope.row.id)") - el-table-column(label="Author" width="120" prop="authorName") + el-table-column(:label="$t('table.import.author')" width="120" prop="authorName") template(v-once #default="scope") span.x-link(v-text="scope.row.authorName" @click="showUserDialog(scope.row.authorId)") - el-table-column(label="Status" width="70" prop="releaseStatus") + el-table-column(:label="$t('table.import.status')" width="70" prop="releaseStatus") template(v-once #default="scope") span(v-text="scope.row.releaseStatus" v-if="scope.row.releaseStatus === 'public'" style="color:#67c23a") span(v-text="scope.row.releaseStatus" v-else-if="scope.row.releaseStatus === 'private'" style="color:#f56c6c") span(v-text="scope.row.releaseStatus" v-else) - el-table-column(label="Action" width="90" align="right") + el-table-column(:label="$t('table.import.action')" width="90" align="right") template(v-once #default="scope") el-button(type="text" icon="el-icon-close" size="mini" @click="deleteItemAvatarImport(scope.row)") //- dialog: export friend list - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="friendExportDialogRef" :visible.sync="friendExportDialogVisible" title="Friend Favorites Export" width="650px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="friendExportDialogRef" :visible.sync="friendExportDialogVisible" :title="$t('dialog.friend_export.header')" width="650px") el-dropdown(@click.native.stop trigger="click" size="small") el-button(size="mini") span(v-if="friendExportFavoriteGroup") {{ friendExportFavoriteGroup.displayName }} ({{ friendExportFavoriteGroup.count }}/{{ friendExportFavoriteGroup.capacity }}) #[i.el-icon-arrow-down.el-icon--right] @@ -3567,111 +3574,111 @@ html el-input(type="textarea" v-if="friendExportDialogVisible" v-model="friendExportContent" size="mini" rows="15" resize="none" readonly style="margin-top:15px" @click.native="$event.target.tagName === 'TEXTAREA' && $event.target.select()") //- dialog: Friend import dialog - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="friendImportDialog" :visible.sync="friendImportDialog.visible" title="Friend Favorites Import" width="650px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="friendImportDialog" :visible.sync="friendImportDialog.visible" :title="$t('dialog.friend_import.header')" width="650px") div(style="font-size:12px") - | Enter a list of user IDs + | {{ $t('dialog.friend_import.description') }} el-input(type="textarea" v-model="friendImportDialog.input" size="mini" rows="10" resize="none" style="margin-top:15px") - el-button(size="small" @click="processFriendImportList" :disabled="!friendImportDialog.input") Process List - span(v-if="friendImportDialog.progress" style="margin-top:10px") #[i.el-icon-loading(style="margin-right:5px")] Progress: {{ friendImportDialog.progress }}/{{ friendImportDialog.progressTotal }} + el-button(size="small" @click="processFriendImportList" :disabled="!friendImportDialog.input") {{ $t('dialog.friend_import.process_list') }} + span(v-if="friendImportDialog.progress" style="margin-top:10px") #[i.el-icon-loading(style="margin-right:5px")] {{ $t('dialog.friend_import.process_progress') }} {{ friendImportDialog.progress }}/{{ friendImportDialog.progressTotal }} br el-dropdown(@click.native.stop trigger="click" size="small") el-button(size="mini") span(v-if="friendImportDialog.friendImportFavoriteGroup") {{ friendImportDialog.friendImportFavoriteGroup.displayName }} ({{ friendImportDialog.friendImportFavoriteGroup.count }}/{{ friendImportDialog.friendImportFavoriteGroup.capacity }}) #[i.el-icon-arrow-down.el-icon--right] - span(v-else) Select Group #[i.el-icon-arrow-down.el-icon--right] + span(v-else) {{ $t('dialog.friend_import.select_group_placeholder') }} #[i.el-icon-arrow-down.el-icon--right] el-dropdown-menu(#default="dropdown") template(v-for="groupAPI in API.favoriteFriendGroups" :key="groupAPI.name") el-dropdown-item(style="display:block;margin:10px 0" @click.native="selectFriendImportGroup(groupAPI)" :disabled="groupAPI.count >= groupAPI.capacity") {{ groupAPI.displayName }} ({{ groupAPI.count }}/{{ groupAPI.capacity }}) - el-button(size="small" @click="importFriendImportTable" style="margin:5px" :disabled="friendImportTable.data.length === 0 || !friendImportDialog.friendImportFavoriteGroup") Import Friends - el-button(v-if="friendImportDialog.loading" size="small" @click="cancelFriendImport" style="margin-top:10px") Cancel + el-button(size="small" @click="importFriendImportTable" style="margin:5px" :disabled="friendImportTable.data.length === 0 || !friendImportDialog.friendImportFavoriteGroup") {{ $t('dialog.friend_import.import') }} + el-button(v-if="friendImportDialog.loading" size="small" @click="cancelFriendImport" style="margin-top:10px") {{ $t('dialog.friend_import.cancel') }} span(v-if="friendImportDialog.friendImportFavoriteGroup") {{ friendImportTable.data.length }} / {{ friendImportDialog.friendImportFavoriteGroup.capacity - friendImportDialog.friendImportFavoriteGroup.count }} - span(v-if="friendImportDialog.importProgress" style="margin:10px") #[i.el-icon-loading(style="margin-right:5px")] Import Progress: {{ friendImportDialog.importProgress }}/{{ friendImportDialog.importProgressTotal }} + span(v-if="friendImportDialog.importProgress" style="margin:10px") #[i.el-icon-loading(style="margin-right:5px")] {{ $t('dialog.friend_import.import_progress') }} {{ friendImportDialog.importProgress }}/{{ friendImportDialog.importProgressTotal }} br - el-button(size="small" @click="clearFriendImportTable") Clear Table + el-button(size="small" @click="clearFriendImportTable") {{ $t('dialog.friend_import.clear_table') }} template(v-if="friendImportDialog.errors") - el-button(size="small" @click="friendImportDialog.errors = ''" style="margin-left:5px") Clear Errors - h2(style="font-weight:bold;margin:0") Errors: + el-button(size="small" @click="friendImportDialog.errors = ''" style="margin-left:5px") {{ $t('dialog.friend_import.clear_errors') }} + h2(style="font-weight:bold;margin:0") {{ $t('dialog.friend_import.errors') }} pre(v-text="friendImportDialog.errors" style="white-space:pre-wrap;font-size:12px") data-tables(v-if="friendImportDialog.visible" v-bind="friendImportTable" v-loading="friendImportDialog.loading" style="margin-top:10px") - el-table-column(label="Image" width="70" prop="currentAvatarThumbnailImageUrl") + el-table-column(:label="$t('table.import.image')" width="70" prop="currentAvatarThumbnailImageUrl") template(v-once #default="scope") el-popover(placement="right" height="500px" trigger="hover") img.friends-list-avatar(slot="reference" v-lazy="userImage(scope.row)") img.friends-list-avatar(v-lazy="userImageFull(scope.row)" style="height:500px;cursor:pointer" @click="downloadAndSaveImage(userImageFull(scope.row))") - el-table-column(label="Name" prop="displayName") + el-table-column(:label="$t('table.import.name')" prop="displayName") template(v-once #default="scope") span.x-link(v-text="scope.row.displayName" @click="showUserDialog(scope.row.id)") - el-table-column(label="Action" width="90" align="right") + el-table-column(:label="$t('table.import.action')" width="90" align="right") template(v-once #default="scope") el-button(type="text" icon="el-icon-close" size="mini" @click="deleteItemFriendImport(scope.row)") //- dialog: Note export dialog - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="noteExportDialog" :visible.sync="noteExportDialog.visible" title="Note Export" width="1000px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="noteExportDialog" :visible.sync="noteExportDialog.visible" :title="$t('dialog.note_export.header')" width="1000px") div(style="font-size:12px") - | This process will export all of your VRCX memos and import them into VRChat notes. #[br] - | Be warned of the following limitations: #[br] - | - API endpoint has a rate limit that requires a large delay between requests. #[br] - | - Character limit of 256 per note. #[br] - | - Swear words filter (no fun allowed). #[br] - | - No new lines (they will replaced with a space). #[br] - | - This will overwrite any existing VRChat notes for these users. #[br] - | - Any edits made here wont affect VRCX memos but will affect VRChat notes once exported. #[br] - el-button(size="small" @click="updateNoteExportDialog" :disabled="noteExportDialog.loading" style="margin-top:10px") Refresh - el-button(size="small" @click="exportNoteExport" :disabled="noteExportDialog.loading" style="margin-top:10px") Export - el-button(v-if="noteExportDialog.loading" size="small" @click="cancelNoteExport" style="margin-top:10px") Cancel - span(v-if="noteExportDialog.loading" style="margin:10px") #[i.el-icon-loading(style="margin-right:5px")] Progress: {{ noteExportDialog.progress }}/{{ noteExportDialog.progressTotal }} + | {{ $t('dialog.note_export.description1') }} #[br] + | {{ $t('dialog.note_export.description2') }} #[br] + | {{ $t('dialog.note_export.description3') }} #[br] + | {{ $t('dialog.note_export.description4') }} #[br] + | {{ $t('dialog.note_export.description5') }} #[br] + | {{ $t('dialog.note_export.description6') }} #[br] + | {{ $t('dialog.note_export.description7') }} #[br] + | {{ $t('dialog.note_export.description8') }} #[br] + el-button(size="small" @click="updateNoteExportDialog" :disabled="noteExportDialog.loading" style="margin-top:10px") {{ $t('dialog.note_export.refresh') }} + el-button(size="small" @click="exportNoteExport" :disabled="noteExportDialog.loading" style="margin-top:10px") {{ $t('dialog.note_export.export') }} + el-button(v-if="noteExportDialog.loading" size="small" @click="cancelNoteExport" style="margin-top:10px") {{ $t('dialog.note_export.cancel') }} + span(v-if="noteExportDialog.loading" style="margin:10px") #[i.el-icon-loading(style="margin-right:5px")] {{ $t('dialog.note_export.progress') }} {{ noteExportDialog.progress }}/{{ noteExportDialog.progressTotal }} template(v-if="noteExportDialog.errors") - el-button(size="small" @click="noteExportDialog.errors = ''") Clear Errors - h2(style="font-weight:bold;margin:0") Errors: + el-button(size="small" @click="noteExportDialog.errors = ''") {{ $t('dialog.note_export.clear_errors') }} + h2(style="font-weight:bold;margin:0") {{ $t('dialog.note_export.errors') }} pre(v-text="noteExportDialog.errors" style="white-space:pre-wrap;font-size:12px") data-tables(v-if="noteExportDialog.visible" v-bind="noteExportTable" v-loading="noteExportDialog.loading" style="margin-top:10px") - el-table-column(label="Image" width="70" prop="currentAvatarThumbnailImageUrl") + el-table-column(:label="$t('table.import.image')" width="70" prop="currentAvatarThumbnailImageUrl") template(v-once #default="scope") el-popover(placement="right" height="500px" trigger="hover") img.friends-list-avatar(slot="reference" v-lazy="userImage(scope.row.ref)") img.friends-list-avatar(v-lazy="userImageFull(scope.row.ref)" style="height:500px;cursor:pointer" @click="downloadAndSaveImage(userImageFull(scope.row.ref))") - el-table-column(label="Name" width="170" prop="name") + el-table-column(:label="$t('table.import.name')" width="170" prop="name") template(v-once #default="scope") span.x-link(v-text="scope.row.name" @click="showUserDialog(scope.row.id)") - el-table-column(label="Note" prop="memo") + el-table-column(:label="$t('table.import.note')" prop="memo") template(v-once #default="scope") el-input(v-model="scope.row.memo" type="textarea" maxlength="256" show-word-limit :rows="2" :autosize="{ minRows: 1, maxRows: 10 }" size="mini" resize="none") - el-table-column(label="Skip Export" width="90" align="right") + el-table-column(:label="$t('table.import.skip_export')" width="90" align="right") template(v-once #default="scope") el-button(type="text" icon="el-icon-close" size="mini" @click="removeFromNoteExportTable(scope.row)") //- dialog: avatar database provider - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="avatarProviderDialog" :visible.sync="avatarProviderDialog.visible" title="Avatar Database Provider" width="600px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="avatarProviderDialog" :visible.sync="avatarProviderDialog.visible" :title="$t('dialog.avatar_database_provider.header')" width="600px") div el-input(v-for="(provider, index) in avatarRemoteDatabaseProviderList" :key="index" :value="provider" v-model="avatarRemoteDatabaseProviderList[index]" @change="saveAvatarProviderList" size="small" style="margin-top:5px") el-button(slot="append" icon="el-icon-delete" @click="removeAvatarProvider(provider)") - el-button(@click="avatarRemoteDatabaseProviderList.push('')" size="mini" style="margin-top:5px") Add Provider + el-button(@click="avatarRemoteDatabaseProviderList.push('')" size="mini" style="margin-top:5px") {{ $t('dialog.avatar_database_provider.add_provider') }} //- dialog: chatbox blacklist - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="chatboxBlacklistDialog" :visible.sync="chatboxBlacklistDialog.visible" title="Chatbox Blacklist" width="600px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="chatboxBlacklistDialog" :visible.sync="chatboxBlacklistDialog.visible" :title="$t('dialog.chatbox_blacklist.header')" width="600px") div(v-loading="chatboxBlacklistDialog.loading" v-if="chatboxBlacklistDialog.visible") - h2 Keyword Blacklist + h2 {{ $t('dialog.chatbox_blacklist.keyword_blacklist') }} el-input(v-for="(item, index) in chatboxBlacklist" :key="index" :value="item" v-model="chatboxBlacklist[index]" size="small" style="margin-top:5px" @change="saveChatboxBlacklist") el-button(slot="append" icon="el-icon-delete" @click="chatboxBlacklist.splice(index, 1); saveChatboxBlacklist()") - el-button(@click="chatboxBlacklist.push('')" size="mini" style="margin-top:5px") Add Item + el-button(@click="chatboxBlacklist.push('')" size="mini" style="margin-top:5px") {{ $t('dialog.chatbox_blacklist.add_item') }} br - h2 User Blacklist + h2 {{ $t('dialog.chatbox_blacklist.user_blacklist') }} el-tag(v-for="user in chatboxUserBlacklist" type="info" disable-transitions="true" :key="user[0]" style="margin-right:5px;margin-top:5px" closable @close="deleteChatboxUserBlacklist(user[0])") span {{user[1]}} //- dialog: invite group - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="inviteGroupDialog" :visible.sync="inviteGroupDialog.visible" title="Invite To Group" width="450px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="inviteGroupDialog" :visible.sync="inviteGroupDialog.visible" :title="$t('dialog.invite_to_group.header')" width="450px") div(v-if="inviteGroupDialog.visible" v-loading="inviteGroupDialog.loading") - span Don't spam invite users, inviting too many users to a group is known to cause a ban. + span {{ $t('dialog.invite_to_group.description') }} br - el-select(v-model="inviteGroupDialog.groupId" clearable placeholder="Choose Group" filterable :disabled="inviteGroupDialog.loading" @change="isAllowedToInviteToGroup" style="margin-top:15px") - el-option-group(v-if="inviteGroupDialog.groups.length" label="Groups" style="width:410px") + el-select(v-model="inviteGroupDialog.groupId" clearable :placeholder="$t('dialog.invite_to_group.choose_group_placeholder')" filterable :disabled="inviteGroupDialog.loading" @change="isAllowedToInviteToGroup" style="margin-top:15px") + el-option-group(v-if="inviteGroupDialog.groups.length" :label="$t('dialog.invite_to_group.groups')" style="width:410px") el-option.x-friend-item(v-for="group in inviteGroupDialog.groups" :key="group.id" :label="group.name" :value="group.id" style="height:auto") .avatar img(v-lazy="group.iconUrl") .detail span.name(v-text="group.name") - el-select(v-model="inviteGroupDialog.userIds" clearable placeholder="Choose Friends" filterable :disabled="inviteGroupDialog.loading" style="width:100%;margin-top:15px") - el-option-group(v-if="inviteGroupDialog.userId" label="Selected User") + el-select(v-model="inviteGroupDialog.userIds" clearable :placeholder="$t('dialog.invite_to_group.choose_friends_placeholder')" filterable :disabled="inviteGroupDialog.loading" style="width:100%;margin-top:15px") + el-option-group(v-if="inviteGroupDialog.userId" :label="$t('dialog.invite_to_group.selected_users')") el-option.x-friend-item(:key="inviteGroupDialog.userObject.id" :label="inviteGroupDialog.userObject.displayName" :value="inviteGroupDialog.userObject.id" style="height:auto") template(v-if="inviteGroupDialog.userObject.id") .avatar(:class="userStatusClass(inviteGroupDialog.userObject)") @@ -3679,7 +3686,7 @@ html .detail span.name(v-text="inviteGroupDialog.userObject.displayName" :style="{'color':inviteGroupDialog.userObject.$userColour}") span(v-else v-text="inviteGroupDialog.userId") - el-option-group(v-if="friendsGroup0.length" label="VIP") + el-option-group(v-if="friendsGroup0.length" :label="$t('side_panel.favorite')") el-option.x-friend-item(v-for="friend in friendsGroup0" :key="friend.id" :label="friend.name" :value="friend.id" style="height:auto") template(v-if="friend.ref") .avatar(:class="userStatusClass(friend.ref)") @@ -3687,7 +3694,7 @@ html .detail span.name(v-text="friend.ref.displayName" :style="{'color':friend.ref.$userColour}") span(v-else v-text="friend.id") - el-option-group(v-if="friendsGroup1.length" label="ONLINE") + el-option-group(v-if="friendsGroup1.length" :label="$t('side_panel.online')") el-option.x-friend-item(v-for="friend in friendsGroup1" :key="friend.id" :label="friend.name" :value="friend.id" style="height:auto") template(v-if="friend.ref") .avatar(:class="userStatusClass(friend.ref)") @@ -3695,7 +3702,7 @@ html .detail span.name(v-text="friend.ref.displayName" :style="{'color':friend.ref.$userColour}") span(v-else v-text="friend.id") - el-option-group(v-if="friendsGroup2.length" label="ACTIVE") + el-option-group(v-if="friendsGroup2.length" :label="$t('side_panel.active')") el-option.x-friend-item(v-for="friend in friendsGroup2" :key="friend.id" :label="friend.name" :value="friend.id" style="height:auto") template(v-if="friend.ref") .avatar @@ -3703,7 +3710,7 @@ html .detail span.name(v-text="friend.ref.displayName" :style="{'color':friend.ref.$userColour}") span(v-else v-text="friend.id") - el-option-group(v-if="friendsGroup3.length" label="OFFLINE") + el-option-group(v-if="friendsGroup3.length" :label="$t('side_panel.offline')") el-option.x-friend-item(v-for="friend in friendsGroup3" :key="friend.id" :label="friend.name" :value="friend.id" style="height:auto") template(v-if="friend.ref") .avatar @@ -3715,10 +3722,10 @@ html el-button(type="primary" size="small" :disabled="inviteGroupDialog.loading || !inviteGroupDialog.userIds.length" @click="sendGroupInvite()") Invite //- dialog: open source software notice - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" :visible.sync="ossDialog" title="Open Source Software Notice" width="650px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" :visible.sync="ossDialog" :title="$t('dialog.open_source.header')" width="650px") div(v-if="ossDialog" style="height:350px;overflow:hidden scroll;word-break:break-all") div - span VRCX is based on open source software. It was possible because of their contribution. + span {{ $t('dialog.open_source.description') }} div(style="margin-top:15px") p(style="font-weight:bold") animate.css pre(style="font-size:12px;white-space:pre-line"). @@ -4050,12 +4057,12 @@ html :before-close="enablePrimaryPasswordDialog.beforeClose" ref="primaryPasswordDialog" :close-on-click-modal="false" - title="Primary Password Required" + :title="$t('dialog.primary_password.header')" width="400px" ) el-input( v-model="enablePrimaryPasswordDialog.password" - placeholder="Input new password" + :placeholder="$t('dialog.primary_password.password_placeholder')" type="password" size="mini" maxlength="32" @@ -4064,7 +4071,7 @@ html ) el-input( v-model="enablePrimaryPasswordDialog.rePassword" - placeholder="Re-input password" + :placeholder="$t('dialog.primary_password.re_input_placeholder')" type="password" style="margin-top:5px" size="mini" @@ -4075,6 +4082,6 @@ html el-button( type="primary" size="small" @click="setPrimaryPassword" :disabled="enablePrimaryPasswordDialog.password.length===0||enablePrimaryPasswordDialog.password!==enablePrimaryPasswordDialog.rePassword" - ) OK + ) {{ $t('dialog.primary_password.ok') }} script(src="vendor.js") script(src="app.js") diff --git a/html/src/localization/localizedStrings.js b/html/src/localization/localizedStrings.js new file mode 100644 index 00000000..860697d5 --- /dev/null +++ b/html/src/localization/localizedStrings.js @@ -0,0 +1,10 @@ +import en from './strings/en.json' assert {type: 'JSON'}; +import elements_en from 'element-ui/lib/locale/lang/en'; +// import ja from './strings/ja.json' assert { type: 'JSON' }; +import zh_TW from './strings/zh_TW.json' assert {type: 'JSON'}; +import elements_zh_TW from 'element-ui/lib/locale/lang/zh-TW'; + +const localized_en = {...en, ...elements_en}; +const localized_zh_TW = {...zh_TW, ...elements_zh_TW}; + +export {localized_en as en, localized_zh_TW as zh_TW}; diff --git a/html/src/localization/strings/en.json b/html/src/localization/strings/en.json new file mode 100644 index 00000000..f96ff2f0 --- /dev/null +++ b/html/src/localization/strings/en.json @@ -0,0 +1,1376 @@ +{ + "language": "English (en)", + "translator": "-", + "nav_tooltip": { + "feed": "Feed", + "game_log": "Game Log", + "player_list": "Player List", + "search": "Search", + "favorites": "Favorites", + "friend_log": "Friend Log", + "moderation": "Moderation", + "notification": "Notification", + "friend_list": "Friend List", + "profile": "Profile", + "settings": "Settings" + }, + "view": { + "login": { + "savedAccounts": "Saved Accounts", + "login": "Login", + "register": "Register", + "forgotPassword": "Forgot Password?", + "field": { + "username": "Username or Email", + "password": "Password", + "saveCredentials": "Save Credentials", + "devEndpoint": "Dev Endpoint", + "endpoint": "Endpoint", + "websocket": "WebSocket" + } + }, + "feed": { + "favorites_only_tooltip": "Filter VIP only", + "filter_placeholder": "Filter", + "search_placeholder": "Search" + }, + "game_log": { + "filter_placeholder": "Filter", + "search_placeholder": "Search" + }, + "player_list": { + "photon": { + "current": "Current", + "previous": "Previous", + "search_placeholder": "Search", + "filter_placeholder": "Filter", + "chatbox_blacklist": "Chatbox Blacklist", + "status_tooltip": "VRCX Companion Status" + } + }, + "search": { + "search_placeholder": "Search", + "clear_results_tooltip": "Clear Search Results", + "user": { + "header": "User" + }, + "world": { + "header": "World", + "category": "Search by category", + "community_lab": "Include community labs" + }, + "avatar": { + "header": "Avatar", + "search_provider": "Search Provider", + "refresh_tooltip": "Refresh own avatars", + "result_count": "Results {count}", + "all": "All", + "public": "Public", + "private": "Private", + "local": "Local", + "remote": "Remote", + "sort_name": "Sort by name", + "sort_update": "Sort by update", + "sort_created": "Sort by created" + }, + "prev_page": "Prev", + "next_page": "Nect" + }, + "favorite": { + "friends": { + "header": "Friends" + }, + "worlds": { + "header": "Worlds", + "vrchat_favorites": "VRChat Favorites", + "local_favorites": "Local Favorites", + "new_group": "New Group" + }, + "avatars": { + "header": "Avatars" + }, + "refresh_tooltip": "Refresh all favorites", + "export": "Export", + "import": "Import", + "move_tooltip": "Move", + "unfavorite_tooltip": "Unfavorite", + "visibility_tooltip": "Change Visibility", + "rename_tooltip": "Rename", + "clear_tooltip": "Clear", + "delete_tooltip": "Delete" + }, + "friend_log": { + "filter_placeholder": "Filter", + "search_placeholder": "Search" + }, + "moderation": { + "filter_placeholder": "Filter", + "search_placeholder": "Search", + "refresh_tooltip": "Refresh" + }, + "notification": { + "filter_placeholder": "Filter", + "search_placeholder": "Search", + "refresh_tooltip": "Refresh" + }, + "friend_list": { + "header": "Friend List", + "bulk_unfriend": "Bulk Unfriend Mode", + "bulk_unfriend_selection": "Bulk Unfriend Selection", + "load": "Load missing entries", + "load_notice": "This takes a lot of API requests so use it sparingly", + "load_tooltip": "Load", + "favorites_only_tooltip": "Filter VIP only", + "search_placeholder": "Search", + "filter_placeholder": "Filter", + "refresh_tooltip": "Refresh", + "clear_tooltip": "Clear Results", + "cancel_tooltip": "Cancel" + }, + "profile": { + "profile": { + "header": "Profile", + "last_activity": "Last Activity", + "two_factor": "Two-Factor Auth (2FA)", + "two_factor_enabled": "Enabled", + "two_factor_disabled": "Disabled", + "logout": "Logout", + "export_friend_list": "Export Friends List", + "export_own_avatars": "Export Own Avatars", + "discord_names": "Discord Names", + "export_notes": "Export Notes" + }, + "game_info": { + "header": "Game Info", + "online_users": "Online Users", + "user_online": "{count} users online.", + "refresh": "Click to refresh" + }, + "vrc_sdk_downloads": { + "header": "VRC SDK Downloads" + }, + "direct_access": { + "header": "Direct Access", + "username": "Username", + "user_id": "User ID", + "world_instance": "World/Instance", + "avatar": "Avatar" + }, + "invite_messages": "Invite Messages", + "invite_response_messages": "Invite Response Messages", + "invite_request_messages": "Invite Request Messages", + "invite__request_response_messages": "Invite Request Response Messages", + "past_display_names": "Past Display Names", + "config_json": "Config JSON", + "current_user_json": "Current User JSON", + "refresh_tooltip": "Refresh", + "clear_results_tooltip": "Clear results" + }, + "settings": { + "header": "Settings", + "category": { + "general": "General", + "appearance": "Appearance", + "notifications": "Notifications", + "wrist_overlay": "Wrist Overlay", + "discord_presence": "Discord Presence", + "advanced": "Advanced" + }, + "general": { + "general": { + "header": "General", + "version": "Version", + "latest_app_version": "Latest Version", + "latest_app_version_refresh": "Click to refresh", + "repository_url": "Repository URL", + "support": "Support" + }, + "vrcx_updater": { + "header": "VRCX Updater", + "change_build": "Change build", + "auto_update": "Auto update", + "auto_update_off": "Off", + "auto_update_notify": "Notify", + "auto_update_download": "Auto Download", + "auto_update_install": "Auto Install" + }, + "application": { + "header": "Application", + "startup": "Start as Windows startup", + "minimized": "Start as minimized state", + "tray": "Close to tray" + }, + "legal_notice": { + "header": "Legal Notice", + "info": "VRCX is an assistant application for provide information about manage friendship. this application uses unofficial VRChat API (VRCSDK).", + "disclaimer1": "VRCX isn't endorsed by VRChat and doesn't reflect the views or opinions of VRChat or anyone officially involved in producing or managing VRChat. VRChat is trademark of VRChat Inc. VRChat © VRChat Inc.", + "disclaimer2": "pypy or Natsumi aren't responsible for any problems caused by VRCX. Use at your own risk!", + "open_source_software_notice": "Open Source Software Notice" + } + }, + "appearance": { + "appearance": { + "header": "Appearance", + "language": "Language", + "theme_mode": "Theme mode", + "theme_mode_system": "System", + "theme_mode_light": "Light", + "theme_mode_dark": "Dark", + "vrcplus_profile_icons": "VRCPlus Profile Icons", + "disable_tooltips": "Disable Tooltips", + "sort_favorite_by": "Sort Favorites by", + "sort_favorite_by_name": "name", + "sort_favorite_by_date": "date", + "sort_instance_users_by": "Sort Instance Users by", + "sort_instance_users_by_time": "time", + "sort_instance_users_by_alphabet": "alphabetical", + "table_max_size": "Table Max Size", + "page_size": "Page Size:" + }, + "timedate": { + "header": "Time/Date", + "time_format": "Time Format", + "time_format_24": "24 Hour", + "time_format_12": "12 Hour", + "force_iso_date_format": "Force ISO Date Format" + }, + "side_panel": { + "header": "Side Panel", + "sorting": { + "header": "Sorting", + "sort_private_to_bottom": "Sort Private to bottom", + "sort_by_status": "Sort by status", + "sort_gps_to_top": "Sort GPS to top", + "sort_gps_to_top_notice": "(online for only)", + "sort_favorite_by": "Sort VIP by", + "sort_favorite_by_alphabet": "alphabetical", + "sort_favorite_by_online_time": "online for", + "sort_online_by": "Sort Online by", + "sort_online_by_alphabet": "alphabetical", + "sort_online_by_online_time": "online for", + "sort_active_by": "Sort Active by", + "sort_active_by_alphabet": "alphabetical", + "sort_active_by_online_time": "online for", + "sort_offline_by": "Sort Offline by", + "sort_offline_by_alphabet": "alphabetical", + "sort_offline_by_offline_time": "offline for" + }, + "width": "Width" + }, + "user_dialog": { + "header": "User Dialog", + "hide_vrchat_notes": "Hide VRChat Notes", + "hide_vrcx_memos": "Hide VRCX Memos", + "export_vrcx_memos_into_vrchat_notes": "Export VRCX Memos into VRChat notes", + "export_notes": "Export Notes" + }, + "user_colors": { + "header": "User Colors", + "random_colors_from_user_id": "Random Colors from User ID" + } + }, + "notifications": { + "notifications": { + "header": "Notifications", + "notification_filter": "Notification Filter", + "steamvr_notifications": { + "header": "SteamVR Notifications", + "steamvr_overlay": "SteamVR Overlay", + "overlay_notifications": "Overlay Notifications", + "notification_position": "Notification Position", + "xsoverlay_notifications": "XSOverlay Notifications", + "user_images": "User Images (slower)", + "notification_timeout": "Notification Timeout" + }, + "desktop_notifications": { + "header": "Desktop Notifications", + "when_to_display": "When to display", + "when_to_display_never": "Never", + "when_to_display_desktop": "Desktop Mode", + "when_to_display_inside_vr": "Inside VR", + "when_to_display_outside_vr": "Outside VR", + "when_to_display_game_closed": "Game Closed", + "when_to_display_game_running": "Game Running", + "when_to_display_always": "Always" + }, + "text_to_speech": { + "header": "Text-To-Speech Options", + "when_to_play": "Notification TTS. When to play", + "when_to_play_never": "Never", + "when_to_play_inside_vr": "Inside VR", + "when_to_play_game_closed": "Game Closed", + "when_to_play_game_running": "Game Running", + "when_to_play_always": "Always", + "tts_voice": "TTS Voice" + } + } + }, + "wrist_overlay": { + "steamvr_wrist_overlay": { + "header": "SteamVR Wrist Overlay", + "description": "* It runs automatically when VRChat is running.", + "grip": "Grip: Vive or Other Controllers Grab, Oculus X/A Buttons", + "menu": "Menu: Vive Menu, Index B, Oculus Y/B Buttons", + "steamvr_overlay": "SteamVR Overlay", + "wrist_feed_overlay": "Wrist Feed Overlay", + "hide_private_worlds": "Hide Private Worlds", + "start_overlay_with": "Start Overlay With", + "overlay_button": "Overlay Button", + "overlay_button_grip": "Grip", + "overlay_button_menu": "Menu", + "display_overlay_on": "Display Overlay On", + "display_overlay_on_left": "Left Hand", + "display_overlay_on_right": "Right Hand", + "display_overlay_on_both": "Both Hand", + "background_color": "Background Color", + "minimal_feed_icons": "Minimal Feed Icons", + "hide_vr_devices": "Hide VR Devices", + "hide_cpu_usage": "Hide CPU Usage", + "hide_game_uptime": "Hide Game Uptime", + "show_pc_uptime": "Show PC Uptime", + "wrist_feed_filters": "Wrist Feed Filters" + } + }, + "discord_presence": { + "discord_presence": { + "header": "Discord Presence", + "description": "* Only works when VRChat is running.", + "enable": "Enable", + "enable_tooltip": "Recommended to disable Rich Presence in VRChat config.json to stop it from conflicting", + "instance_type_player_count": "Instance type/player count", + "join_button": "Join button (public only)", + "hide_details_in_private": "Hide world details in private", + "hide_images": "Hide World Images" + } + }, + "advanced": { + "advanced": { + "header": "Advanced", + "launch_options": "Launch Options", + "pending_offline": { + "header": "Pending Offline", + "description": "Delay before marking user as offline (fixes false positives)", + "set_delay": "Set Delay" + }, + "primary_password": { + "header": "Primary Password", + "description": "Encrypt password (disables auto login)" + }, + "vrchat_quit_fix": { + "header": "VRChat Quit Fix", + "description": "Kill VRChat after exiting game" + }, + "auto_cache_management": { + "header": "Automatically Manage Cache When Closing VRChat", + "description": "Auto delete old versions from cache" + }, + "remote_database": { + "header": "Remote Avatar Database", + "enable": "Enable", + "avatar_database_provider": "Avatar Database Provider" + }, + "youtube_api": { + "header": "Youtube API", + "enable": "Enable", + "youtube_api_key": "Youtube API Key" + }, + "video_progress_pie": { + "header": "Progress pie overlay for videos", + "enable": "Enable", + "enable_tooltip": "Requires SteamVR overlay to be enabled", + "dance_world_only": "Dance worlds only" + }, + "cache_debug": { + "header": "VRCX Instance Cache/Debug", + "disable_gamelog": "Disable GameLog", + "disable_gamelog_notice": "(will likely break things)", + "user_cache": "User cache:", + "world_cache": "World cache:", + "avatar_cache": "Avatar cache:", + "avatar_name_cache": "Avatar Name cache:", + "clear_cache": "Clear Cache", + "auto_clear_cache": "Auto Clear Cache", + "download_history": "Download History", + "show_console": "Show Console" + }, + "sqlite_table_size": { + "header": "SQLite Table Size", + "refresh": "Refresh", + "gps": "GPS:", + "status": "Status:", + "bio": "Bio:", + "avatar": "Avatar:", + "online_offline": "Online/Offline:", + "friend_log_history": "Friend Log History:", + "notification": "Notifications:", + "location": "Location:", + "join_leave": "Join/Leave:", + "portal_spawn": "Portal Spawn:", + "video_play": "Video Play:", + "event": "Event:" + } + }, + "photon": { + "header": "Photon Logging Overlay", + "event_hud": { + "header": "Photon Event HUD", + "enable": "Enable", + "enable_tooltip": "Requires SteamVR overlay to be enabled", + "filter": "Filter", + "filter_favorites": "VIP", + "filter_friends": "Friends", + "filter_everyone": "Everyone", + "message_timeout": "Message Timeout" + }, + "timeout_hud": { + "header": "User Timeout HUD", + "enable": "Enable", + "enable_tooltip": "Requires SteamVR overlay to be enabled", + "filter": "Filter", + "filter_favorites": "VIP", + "filter_friends": "Friends", + "filter_everyone": "Everyone", + "timeout_threshold": "Timeout Threshold" + } + } + } + } + }, + "side_panel": { + "search_placeholder": "Search", + "search_result_active": "Offline", + "search_result_offline": "Active", + "search_result_more": "Search More:", + "direct_access_tooltip": "Direct access ID/URL from clipboard", + "refresh_tooltip": "Refresh friends", + "friends": "FRIENDS", + "me": "ME", + "favorite": "VIP", + "online": "ONLINE", + "active": "ACTIVE", + "offline": "OFFLINE", + "penfing_offline": "Pending Offline" + }, + "dialog": { + "user": { + "status": { + "active": "Active", + "offline": "Offline", + "online": "Online", + "join_me": "Join Me", + "ask_me": "Ask Me", + "busy": "Do Not Disturb" + }, + "previous_display_names": "Previous Display Names:", + "tags": { + "friend_no": "Friend No.{number}", + "vrchat_team": "VRChat Team" + }, + "actions": { + "favorite_tooltip": "Add to favorites", + "unfavorite_tooltip": "Remove from favorites", + "refresh": "Refresh", + "copy_url": "Copy User URL", + "invite": "Invite", + "invite_with_message": "Invite With Message", + "request_invite": "Request Invite", + "request_invite_with_message": "Request Invite With Message", + "invite_to_group": "Invite To Group", + "manage_gallery_icon": "Manage Gallery/Icons", + "accept_friend_request": "Accept Friend Request", + "decline_friend_request": "Decline Friend Request", + "cancel_friend_request": "Cancel Friend Request", + "send_friend_request": "Send Friend Request", + "show_avatar_author": "Show Avatar Author", + "show_fallback_avatar": "Show Fallback Avatar Details", + "show_previous_instances": "Show Previous Instances", + "show_previous_images": "Show Previous Images", + "moderation_block": "Block", + "moderation_unblock": "Unblock", + "moderation_mute": "Mute", + "moderation_unmute": "Unmute", + "moderation_hide_avatar": "Show Avatar", + "moderation_show_avatar": "Hide Avatar", + "moderation_enable_avatar_interaction": "Enable Avatar Interaction", + "moderation_disable_avatar_interaction": "Disable Avatar Interaction", + "edit_status": "Social Status", + "edit_language": "Language", + "edit_bio": "Bio", + "unfriend": "Unfriend", + "logout": "Logout" + }, + "info": { + "header": "Info", + "launch_invite_tooltip": "Launch/Invite", + "self_invite_tooltip": "Invite Yourself", + "refresh_user_count_tooltip": "Refresh User Count", + "instance_creator": "Instance Creator", + "note": "Note", + "note_placeholder": "Click to add a note", + "memo": "Memo", + "memo_placeholder": "Click to add a memo", + "avatar_info": "Avatar Info", + "avatar_info_last_seen": "Avatar Info Last Seen", + "represented_group": "Represented Group", + "bio": "Bio", + "last_seen": "Last Seen", + "join_count": "Join Count", + "time_together": "Time Together", + "online_for": "Online For", + "offline_for": "Offline For", + "last_activity": "Last Activity", + "last_login": "Last Login", + "date_joined": "Date Joined", + "friended": "Friended", + "unfriended": "Unfriended", + "avatar_cloning": "Avatar Cloning", + "avatar_cloning_allow": "Allowed", + "avatar_cloning_deny": "Deny", + "home_location": "Home Location", + "accuracy_notice": "Info from local database may not be accurate" + }, + "groups": { + "header": "Groups", + "total_count": "Total {count}", + "own_groups": "Own Groups", + "mutual_groups": "Mutual Groups", + "groups": "Groups" + }, + "worlds": { + "header": "Worlds", + "total_count": "Total {count}", + "sort_by_name": "Sort by name", + "sort_by_update": "Sort by update" + }, + "favorite_worlds": { + "header": "Favorite Worlds" + }, + "avatars": { + "header": "Avatars", + "total_count": "Total {count}", + "sort_by_name": "Sort by name", + "sort_by_update": "Sort by update", + "all": "All", + "public": "Public", + "private": "Private" + }, + "json": { + "header": "JSON" + } + }, + "world": { + "tags": { + "public": "Public", + "private": "Private", + "labs": "Labs", + "cache": "Cache" + }, + "actions": { + "delete_cache_tooltip": "Delete world from cache", + "favorite_tooltip": "Add to favorites", + "unfavorite_tooltip": "Remove from favorites", + "refresh": "Refresh", + "new_instance": "New Instance", + "make_home": "Make Home", + "reset_home": "Reset Home", + "show_previous_instances": "Show Previous Instances", + "show_previous_images": "Show Previous Images", + "rename": "Rename", + "change_description": "Change Description", + "change_capacity": "Change Capacity", + "change_preview": "Change Youtube Preview", + "change_tags": "Change Tags", + "change_image": "Change Image", + "download_package": "Download Unity Package", + "publish_to_labs": "Publish To Labs", + "unpublish": "Unpublish", + "delete": "Delete" + }, + "instances": { + "header": "Instances", + "public_count": "Public {count}", + "private_count": "Private {count}", + "capacity_count": "Capacity {count} ({max})", + "self_invite_tooltip": "Invite Yourself", + "refresh_user_count_tooltip": "Refresh User Count", + "instance_creator": "Instance Creator" + }, + "info": { + "header": "Info", + "id": "World ID", + "id_tooltip": "Copy to clipboard", + "copy_id": "Copy ID", + "copy_url": "Copy URL", + "youtube_preview": "Youtube Preview", + "players": "Players", + "favorites": "Favorites", + "visits": "Visits", + "capacity": "Capacity", + "heat": "Heat", + "popularity": "Popularity", + "created_at": "Created At", + "last_updated": "Last Updated", + "version": "Version", + "platform": "Platform", + "last_visited": "Last Visited", + "visit_count": "Visit Count", + "time_spent": "Time Spent", + "accuracy_notice": "Info from local database may not be accurate" + }, + "json": { + "header": "JSON" + } + }, + "avatar": { + "tags": { + "public": "Public", + "private": "Private", + "fallback": "Fallback", + "cache": "Cache" + }, + "labels": { + "public": "(Public)", + "private": "(Private)", + "own": "(Own)" + }, + "actions": { + "delete_cache_tooltip": "Delete avatar from cache", + "favorite_tooltip": "Add to favorites", + "unfavorite_tooltip": "Remove from favorites", + "refresh": "Refresh", + "select": "Select Avatar", + "select_fallback": "Select Fallback Avatar", + "block": "Block Avatar", + "unblock": "Unblock Avatar", + "show_previous_images": "Show Previous Images", + "make_public": "Make Public", + "make_private": "Make Private", + "rename": "Rename", + "change_description": "Change Description", + "change_image": "Change Image", + "download_package": "Download Unity Package", + "delete": "Delete" + }, + "info": { + "header": "Info", + "id": "Avatar ID", + "id_tooltip": "Copy to clipboard", + "copy_id": "Copy ID", + "copy_url": "Copy URL", + "created_at": "Created At", + "last_updated": "Last Updated", + "version": "Version", + "platform": "Platform" + }, + "json": { + "header": "JSON" + } + }, + "group": { + "tags": { + "verified": "Verified", + "public": "Public", + "private": "Private", + "open": "Open", + "request": "Request", + "invite": "Invite", + "closed": "Closed", + "joined": "Joined", + "banned": "Banned", + "visible": "Visible", + "friends": "Friends", + "hidden": "Hidden", + "subscribed": "Subscribed" + }, + "actions": { + "represent_tooltip": "Set Representing", + "unrepresent_tooltip": "Stop Representing", + "cancel_join_request_tooltip": "Cancel join request", + "pending_request_tooltip": "Pending invite", + "request_join_tooltip": "Request to join", + "invite_required_tooltip": "Invite required", + "join_group_tooltip": "Join Group", + "refresh": "Refresh", + "unsubscribe": "Unsubscribe From Announcements", + "subscribe": "Subscribe To Announcements", + "invite_to_group": "Invite To Group", + "visibility_everyone": "Visibility Everyone", + "visibility_friends": "Visibility Friends", + "visibility_hidden": "Visibility Hidden", + "leave": "Leave Group" + }, + "info": { + "header": "Info", + "announcement": "Announcement", + "rules": "Rules", + "members": "Members", + "created_at": "Created At", + "links": "Links", + "url": "Group URL", + "url_tooltip": "Copy URL to clipboard", + "id": "Group ID", + "id_tooltip": "Copy ID to clipboard", + "joined_at": "Joined At", + "roles": "Roles", + "role_description": "Description:", + "role_updated_at": "Updated At:", + "role_created_at": "Created At:", + "role_permissions": "Permissions:" + }, + "members": { + "header": "Members", + "all_members": "All Members", + "friends_only": "Friends Only", + "load_more": "Load more..." + }, + "json": { + "header": "JSON" + } + }, + "favorite": { + "header": "Choose Group", + "vrchat_favorites": "VRChat Favorites", + "local_favorites": "Local Favorites" + }, + "invite": { + "header": "傳送邀請", + "select_placeholder": "選擇好友", + "invite_with_message": "訊息邀請", + "invite": "邀請" + }, + "social_status": { + "header": "Social Status", + "history": "History", + "status_placeholder": "Status", + "update": "Update" + }, + "language": { + "header": "Language", + "add_language": "Add Language", + "select_language": "Select Language", + "ok": "OK", + "cancel": "Cancel" + }, + "bio": { + "header": "Bio", + "bio_placeholder": "Please input a bio", + "add_link": "Add Link", + "update": "Update" + }, + "new_instance": { + "header": "New Instance", + "access_type": "Access Type", + "access_type_public": "Public", + "access_type_group": "Group", + "access_type_friend_plus": "Friends+", + "access_type_friend": "Friends", + "access_type_invite_plus": "Invite+", + "access_type_invite": "Invite", + "region": "Region", + "region_usw": "US West", + "region_use": "US East", + "region_eu": "Europe", + "region_jp": "Japan", + "world_id": "World ID", + "instance_id": "Instance ID", + "instance_id_placeholder": "Random", + "instance_creator": "Instance Creator", + "instance_creator_placeholder": "Choose User", + "group_id": "Group ID", + "location": "Location", + "url": "URL", + "copy_url": "Copy URL", + "self_invite": "Self invite", + "invite": "Invite", + "launch": "Launch" + }, + "launch_options": { + "header": "Launch Options", + "description": "These options are for advanced users only.", + "example": "to change max fps: --fps= e.g.)", + "path_override": "VRChat Path Override", + "vrchat_docs": "VRChat Docs", + "unity_manual": "Unity Manual", + "save": "Save" + }, + "config_json": { + "header": "VRChat Config JSON", + "description1": "These options are for advanced users only.", + "description2": "Leave field empty to set as default, game restart required to apply settings.", + "cache_size": "Cache Size:", + "refresh": "Refresh", + "delete_all_cache": "Delete all cache", + "delete_cache": "Delete Cache", + "delete_old_cache": "Delete old versions from cache", + "sweep_cache": "Sweep Cache", + "max_cache_size": "Max Cache Size [GB] (min 20)", + "cache_expiry_delay": "Cache Expiry [Days] (30 - 150)", + "cache_directory": "Custom Cache Folder Location", + "fpv_steadycam_fov": "First-Person Steadycam FOV", + "camera_resolution": "Camera Resolution", + "screenshot_resolution": "Screenshot Resolution", + "disable_discord_presence": "Disable Discord Rich Presence", + "vrchat_docs": "VRChat Docs", + "cancel": "Cancel", + "save": "Save" + }, + "youtube_api": { + "header": "YouTube API", + "description": "Enter your YouTube API Key (optional)", + "placeholder": "YouTube API Key", + "guide": "Guide", + "save": "Save" + }, + "set_world_tags": { + "header": "Set World Tags", + "enable_debugging": "Enable world debugging for others", + "seprator": "Enter tags comma separated", + "cancel": "Cancel", + "save": "Save" + }, + "download_history": { + "header": "Download History", + "queue": "Queue:", + "history": "History:", + "cancel_all": "Cancel All", + "close": "Close" + }, + "vrcx_updater": { + "header": "VRCX Updater", + "latest_version": "VRCX is up to date.", + "ready_for_update": "Ready for install, restart VRCX to apply.", + "download": "Download", + "install": "Install" + }, + "launch": { + "header": "Launch", + "url": "URL", + "short_url": "Short URL", + "short_url_notice": "Short URL's expire after a set period of time", + "location": "Location", + "copy_tooltip": "Copy to clipboard", + "start_as_desktop": "Start as Desktop (No VR)", + "info": "Info", + "invite": "Invite", + "launch": "Launch" + }, + "export_friends_list": { + "header": "Export Friends List" + }, + "export_own_avatars": { + "header": "Export Own Avatars" + }, + "discord_names": { + "header": "Discord Names", + "description": "Click load missing entries in the Friends List tab to search entire friends list" + }, + "notification_position": { + "header": "Notification Position", + "description": "Choose a notification position.", + "ok": "OK" + }, + "shared_feed_filters": { + "notification": "Notification Filters", + "wrist": "Wrist Feed Filters", + "on": "On", + "off": "Off", + "favorite": "VIP", + "friends": "Friends", + "everyone": "Everyone", + "cancel": "Cancel", + "save": "Save" + }, + "world_export": { + "header": "World Favorites Export" + }, + "world_import": { + "header": "World Favorites Import", + "description": "Enter a list of world IDs", + "process_list": "Process List", + "process_progress": "Progress:", + "select_vrchat_group_placeholder": "Select Group", + "select_local_group_placeholder": "Select Group", + "import": "Import Worlds", + "cancel": "Cancel", + "import_progress": "Import Progress:", + "clear_table": "Clear Table", + "errors": "Errors:", + "clear_errors": "Clear Errors" + }, + "avatar_export": { + "header": "Avatar Favorites Export" + }, + "avatar_import": { + "header": "Avatar Favorites Import", + "description": "Enter a list of avatar IDs", + "process_list": "Process List", + "process_progress": "Progress:", + "select_group_placeholder": "Select Group", + "import": "Import Avatars", + "cancel": "Cancel", + "import_progress": "Import Progress:", + "clear_table": "Clear Table", + "errors": "Errors:", + "clear_errors": "Clear Errors" + }, + "friend_export": { + "header": "Friend Favorites Export" + }, + "friend_import": { + "header": "Friend Favorites Import", + "description": "Enter a list of user IDs", + "process_list": "Process List", + "process_progress": "Progress:", + "select_group_placeholder": "Select Group", + "import": "Import Friends", + "cancel": "Cancel", + "import_progress": "Import Progress:", + "clear_table": "Clear Table", + "errors": "Errors:", + "clear_errors": "Clear Errors" + }, + "avatar_database_provider": { + "header": "Avatar Database Provider", + "add_provider": "Add Provider" + }, + "chatbox_blacklist": { + "header": "Chatbox Blacklist", + "keyword_blacklist": "Keyword Blacklist", + "user_blacklist": "User Blacklist", + "add_item": "Add Item" + }, + "invite_to_group": { + "header": "Invite To Group", + "description": "Don't spam invite users, inviting too many users to a group is known to cause a ban.", + "choose_group_placeholder": "Choose Group", + "groups": "Groups", + "choose_friends_placeholder": "Choose Friends", + "selected_users": "Selected Users" + }, + "note_export": { + "header": "Note Export", + "description1": "This process will export all of your VRCX memos and import them into VRChat notes.", + "description2": "Be warned of the following limitations:", + "description3": "- API endpoint has a rate limit that requires a large delay between requests.", + "description4": "- Character limit of 256 per note.", + "description5": "- Swear words filter (no fun allowed).", + "description6": "- No new lines (they will replaced with a space).", + "description7": "- This will overwrite any existing VRChat notes for these users.", + "description8": "- Any edits made here wont affect VRCX memos but will affect VRChat notes once exported.", + "refresh": "Refresh", + "export": "Export", + "cancel": "Cancel", + "progress": "Progress:", + "errors": "Errors:", + "clear_errors": "Clear Errors" + }, + "edit_invite_message": { + "header": "Edit Invite Message", + "description": "1 hour edit cool down time.", + "cancel": "Cancel", + "save": "Save" + }, + "invite_message": { + "header": "Send Invite Message", + "confirmation": "Are you sure you want to send?", + "cancel": "Cancel", + "refresh": "Refresh", + "confirm": "Confirm" + }, + "invite_request_message": { + "header": "Send Invite Request Message", + "cancel": "Cancel", + "refresh": "Refresh" + }, + "invite_response_message": { + "header": "Send Invite Response Message", + "confirmation": "Are you sure you want to send?", + "cancel": "Cancel", + "refresh": "Refresh", + "confirm": "Confirm" + }, + "invite_request_response_message": { + "header": "Send Invite Request Response Message", + "cancel": "Cancel", + "refresh": "Refresh" + }, + "edit_send_invite_message": { + "header": "Edit and Send Invite Message", + "description": "1 hour edit cool down time.", + "cancel": "Cancel", + "send": "Send" + }, + "edit_send_invite_response_message": { + "header": "Edit and Send Invite Response Message", + "description": "1 hour edit cool down time.", + "cancel": "Cancel", + "send": "Send" + }, + "gallery_icons": { + "header": "Gallery and Icons", + "description": "Recommended image size 1200x900px", + "gallery": "Gallery", + "icons": "Icons", + "refresh": "Refresh", + "upload": "Upload", + "clear": "Clear" + }, + "change_content_image": { + "avatar": "Change Avatar Image", + "world": "Change World Image", + "description": "Recommended image size: 1200x900px (4:3)", + "refresh": "Refresh", + "upload": "Upload Image" + }, + "previous_images": { + "header": "Previous Images" + }, + "previous_instances": { + "header": "Previous Instances", + "info": "Previous Instance Info", + "search_placeholder": "Search" + }, + "open_source": { + "header": "Open Source Software Notice", + "description": "VRCX is based on open source software. It was possible because of their contribution." + }, + "primary_password": { + "header": "Primary Password Required", + "password_placeholder": "Input new password", + "re_input_placeholder": "Re-input password", + "ok": "OK" + } + }, + "prompt": { + "totp": { + "header": "Two-factor Authentication", + "description": "Enter a numeric code from your authenticator app", + "use_otp": "Use OTP", + "verify": "Verify", + "input_placeholder": "Code", + "input_error": "Invalid Code" + }, + "otp": { + "header": "Two-factor Authentication", + "description": "Enter one of your saved recovery codes", + "use_otp": "Use TOTP", + "verify": "Verify", + "input_placeholder": "Code", + "input_error": "Invalid Code" + }, + "email_otp": { + "header": "Two-factor Authentication", + "description": "Enter a numeric code that was sent to your email", + "cancel": "Cancel", + "verify": "Verify", + "input_placeholder": "Code", + "input_error": "Invalid Code" + }, + "primary_password": { + "header": "Primary Password Required", + "description": "Please enter your Primary Password." + }, + "change_favorite_group_name": { + "header": "Change Group Name", + "description": "Enter a new name", + "cancel": "Cancel", + "change": "Change", + "input_placeholder": "Name", + "input_error": "Name is required", + "message": { + "success": "Group renamed" + } + }, + "direct_access_user_id": { + "header": "Direct Access", + "description": "Enter a User URL or ID (UUID)", + "cancel": "Cancel", + "ok": "OK", + "input_error": "User URL/ID is required", + "message": { + "error": "Invalid URL/ID" + } + }, + "direct_access_username": { + "header": "Direct Access", + "description": "Enter a Username", + "cancel": "Cancel", + "ok": "OK", + "input_error": "Username is required" + }, + "direct_access_world_id": { + "header": "Direct Access", + "description": "Enter a World URL or ID (UUID)", + "cancel": "Cancel", + "ok": "OK", + "input_error": "World URL/ID is required", + "message": { + "error": "Invalid URL/ID" + } + }, + "direct_access_avatar_id": { + "header": "Direct Access", + "description": "Enter a Avatar URL or ID (UUID)", + "cancel": "Cancel", + "ok": "OK", + "input_error": "Avatar URL/ID is required", + "message": { + "error": "Invalid URL/ID" + } + }, + "direct_access_omni": { + "header": "Direct Access", + "description": "Enter a User/World/Instance/Avatar/Group URL or ID (UUID)", + "cancel": "Cancel", + "ok": "OK", + "input_error": "URL/ID is required", + "message": { + "error": "Invalid URL/ID" + } + }, + "notification_timeout": { + "header": "Notification Timeout", + "description": "Enter amount of seconds", + "cancel": "Cancel", + "ok": "OK", + "input_error": "Valid number is required" + }, + "overlay_message_timeout": { + "header": "Overlay Message Timeout", + "description": "Enter amount of seconds", + "cancel": "Cancel", + "ok": "OK", + "input_error": "Valid number is required" + }, + "rename_avatar": { + "header": "Rename Avatar", + "description": "Enter avatar name", + "cancel": "Cancel", + "ok": "OK", + "input_error": "Valid name is required", + "message": { + "success": "Avatar renamed" + } + }, + "change_avatar_description": { + "header": "Change Description", + "description": "Enter avatar description", + "cancel": "Cancel", + "ok": "OK", + "input_error": "Valid description is required", + "message": { + "success": "Avatar description changed" + } + }, + "rename_world": { + "header": "Rename World", + "description": "Enter world name", + "cancel": "Cancel", + "ok": "OK", + "input_error": "Valid name is required", + "message": { + "success": "World renamed" + } + }, + "change_world_description": { + "header": "Change Description", + "description": "Enter world description", + "cancel": "Cancel", + "ok": "OK", + "input_error": "Valid description is required", + "message": { + "success": "World description changed" + } + }, + "change_world_capacity": { + "header": "Change Capacity", + "description": "Enter world capacity, Max: 40", + "cancel": "Cancel", + "ok": "OK", + "input_error": "Valid number is required", + "message": { + "success": "World capacity changed" + } + }, + "change_world_preview": { + "header": "Change YouTube Preview", + "description": "Enter world YouTube preview", + "cancel": "Cancel", + "ok": "OK", + "input_error": "Valid YouTube URL is required", + "message": { + "error": "Invalid YouTube URL", + "success": "World YouTube preview changed" + } + }, + "change_table_size": { + "header": "Max Table Size", + "description": "Larger table sizes may impact RAM usage and performance (default: 1000)", + "cancel": "Cancel", + "save": "Save", + "input_error": "Valid number is required" + }, + "photon_lobby_timeout": { + "header": "User Timeout Threshold", + "description": "Enter amount of seconds (default: 3)", + "cancel": "Cancel", + "ok": "OK", + "input_error": "Valid number is required" + }, + "auto_clear_cache": { + "header": "Clear VRCX Cache Timer", + "description": "Enter amount of hours, larger values may impact RAM usage and performance (default: 24, disabled: 0)", + "cancel": "Cancel", + "ok": "OK", + "input_error": "Valid number is required" + }, + "new_local_favorite_group": { + "header": "New Group", + "description": "Enter a world favorite group name", + "cancel": "Cancel", + "ok": "OK", + "input_error": "Name is required", + "message": { + "error": "Group already exists with the name {name}" + } + }, + "local_favorite_group_rename": { + "header": "Rename Group", + "description": "Enter a world favorite group name", + "cancel": "Cancel", + "save": "Save", + "input_error": "Name is required", + "message": { + "error": "Group already exists with the name {name}" + } + }, + "pending_offline_delay": { + "header": "Pending Offline", + "description": "Set pending offline delay in seconds (default: 110)", + "cancel": "Cancel", + "save": "Save", + "input_error": "Valid number is required" + } + }, + "table": { + "feed": { + "date": "Date", + "type": "Type", + "user": "User", + "detail": "Detail" + }, + "gameLog": { + "date": "Date", + "type": "Type", + "user": "User", + "detail": "Detail" + }, + "playerList": { + "avatar": "Avatar", + "timer": "Timer", + "photonId": "Photon ID", + "icon": "Icons", + "platform": "Platform", + "displayName": "Display Name", + "status": "Status", + "rank": "Rank", + "language": "Language", + "bioLink": "Bio Links", + "date": "Date", + "user": "User", + "type": "Type", + "detail": "Detail" + }, + "friendLog": { + "date": "Date", + "type": "Type", + "user": "User", + "action": "Action" + }, + "moderation": { + "date": "Date", + "type": "Type", + "source": "Source", + "target": "Target", + "action": "Action" + }, + "notification": { + "date": "Date", + "type": "Type", + "user": "User", + "photo": "Photo", + "message": "Message", + "action": "Action" + }, + "friendList": { + "no": "No.", + "avatar": "Avatar", + "displayName": "Display Name", + "rank": "Rank", + "status": "Status", + "language": "Language", + "bioLink": "Bio Links", + "joinCount": "Join Counts", + "timeTogether": "Time Together", + "lastSeen": "Last Seen", + "lastActivity": "Last Activity", + "lastLogin": "Last Login", + "dateJoined": "Date Joined", + "unfriend": "Unfriend" + }, + "profile": { + "invite_messages": { + "slot": "Slot", + "message": "Message", + "cool_down": "Cool Down", + "action": "Action" + }, + "previous_display_name": { + "date": "Date", + "name": "Name" + } + }, + "social_status": { + "no": "No.", + "status": "Status" + }, + "download_history": { + "time": "Time", + "name": "Name", + "type": "Type", + "status": "Status", + "cancel": "Cancel" + }, + "import": { + "image": "Image", + "name": "Name", + "author": "Author", + "status": "Status", + "note": "Note", + "skip_export": "Skip Export", + "action": "Action" + }, + "previous_instances": { + "date": "Date", + "display_name": "Display Name", + "world": "World", + "instance_name": "Instance Name", + "instance_creator": "Instance Creator", + "time": "Time", + "count": "Count", + "action": "Action" + } + }, + "vr": { + "status": { + "timer": "Timer:", + "players": "Players:", + "cpu": "CPU:", + "online": "Online:", + "devices": { + "left": "L:", + "right": "R:" + } + } + } +} diff --git a/html/src/localization/strings/zh_TW.json b/html/src/localization/strings/zh_TW.json new file mode 100644 index 00000000..90b7d345 --- /dev/null +++ b/html/src/localization/strings/zh_TW.json @@ -0,0 +1,1376 @@ +{ + "language": "繁體中文 (zh_TW)", + "translator": "Kamiya", + "nav_tooltip": { + "feed": "動態", + "game_log": "遊戲紀錄", + "player_list": "玩家列表", + "search": "搜尋", + "favorites": "收藏", + "friend_log": "好友紀錄", + "moderation": "玩家處置", + "notification": "通知", + "friend_list": "好友列表", + "profile": "個人檔案", + "settings": "設定" + }, + "view": { + "login": { + "savedAccounts": "已儲存的帳號", + "login": "登入", + "register": "註冊", + "forgotPassword": "忘記密碼?", + "field": { + "username": "玩家名稱或電子信箱", + "password": "密碼", + "saveCredentials": "儲存登入資料", + "devEndpoint": "開發接口", + "endpoint": "Endpoint", + "websocket": "WebSocket" + } + }, + "feed": { + "favorites_only_tooltip": "僅篩選收藏", + "filter_placeholder": "篩選動態", + "search_placeholder": "搜尋動態" + }, + "game_log": { + "filter_placeholder": "篩選遊戲紀錄", + "search_placeholder": "搜尋遊戲紀錄" + }, + "player_list": { + "photon": { + "current": "目前", + "previous": "上一個", + "search_placeholder": "搜尋", + "filter_placeholder": "篩選", + "chatbox_blacklist": "聊天框黑名單", + "status_tooltip": "VRCX Companion 狀態" + } + }, + "search": { + "search_placeholder": "搜尋", + "clear_results_tooltip": "清除搜尋結果", + "user": { + "header": "玩家" + }, + "world": { + "header": "世界", + "category": "依類別搜尋", + "community_lab": "包含社區實驗室" + }, + "avatar": { + "header": "角色", + "search_provider": "搜尋提供芳", + "refresh_tooltip": "重新整理自己的角色", + "result_count": "{count} 個搜尋結果", + "all": "所有", + "public": "公開", + "private": "私人", + "local": "本地", + "remote": "遠端", + "sort_name": "依名稱排序", + "sort_update": "依更新排序", + "sort_created": "依建立時間排序" + }, + "prev_page": "上一頁", + "next_page": "下一頁" + }, + "favorite": { + "friends": { + "header": "好友" + }, + "worlds": { + "header": "世界", + "vrchat_favorites": "VRChat 收藏", + "local_favorites": "本地收藏", + "new_group": "新群組" + }, + "avatars": { + "header": "角色" + }, + "refresh_tooltip": "重新整理所有收藏", + "export": "匯出", + "import": "匯入", + "move_tooltip": "移動", + "unfavorite_tooltip": "解除收藏", + "visibility_tooltip": "變更可見度", + "rename_tooltip": "重新命名", + "clear_tooltip": "清除", + "delete_tooltip": "刪除" + }, + "friend_log": { + "filter_placeholder": "篩選好友紀錄", + "search_placeholder": "搜尋好友紀錄" + }, + "moderation": { + "filter_placeholder": "篩選玩家處置", + "search_placeholder": "搜尋玩家處置", + "refresh_tooltip": "重新整理" + }, + "notification": { + "filter_placeholder": "篩選通知", + "search_placeholder": "搜尋通知", + "refresh_tooltip": "重新整理" + }, + "friend_list": { + "header": "好友列表", + "bulk_unfriend": "批量解除好友", + "bulk_unfriend_selection": "批量解除已選擇的好友", + "load": "讀取缺失的項目", + "load_notice": "這會向 API 傳送大量請求,所以請謹慎使用", + "load_tooltip": "讀取", + "cancel_tooltip": "取消", + "favorites_only_tooltip": "僅篩選收藏", + "search_placeholder": "搜尋好友", + "filter_placeholder": "篩選好友", + "refresh_tooltip": "重新整理", + "clear_tooltip": "清除結果" + }, + "profile": { + "profile": { + "header": "個人檔案", + "last_activity": "最後動態", + "two_factor": "雙重認證 (2FA)", + "two_factor_enabled": "已啟用", + "two_factor_disabled": "已停用", + "logout": "登出", + "export_friend_list": "匯出好友列表", + "export_own_avatars": "匯出私有角色", + "discord_names": "Discord 名稱", + "export_notes": "匯出備註" + }, + "game_info": { + "header": "遊戲資訊", + "online_users": "線上玩家", + "user_online": "{count} 位玩家在線上", + "refresh": "點擊以重新整理" + }, + "vrc_sdk_downloads": { + "header": "下載 VRC SDK" + }, + "direct_access": { + "header": "直接存取", + "username": "玩家名稱", + "user_id": "玩家 ID", + "world_instance": "世界 / 房間", + "avatar": "角色" + }, + "invite_messages": "邀請訊息", + "invite_response_messages": "邀請回覆訊息", + "invite_request_messages": "邀請請求訊息", + "invite__request_response_messages": "邀請請求回覆訊息", + "past_display_names": "過去顯示名稱", + "config_json": "JSON 資料", + "current_user_json": "目前玩家的 JSON 資料", + "refresh_tooltip": "重新整理", + "clear_results_tooltip": "清除結果" + }, + "settings": { + "header": "設定", + "category": { + "general": "一般", + "appearance": "外觀", + "notifications": "通知", + "wrist_overlay": "手腕疊層", + "discord_presence": "Discord 遊戲動態", + "advanced": "進階" + }, + "general": { + "general": { + "header": "一般", + "version": "版本", + "latest_app_version": "最新版本", + "latest_app_version_refresh": "點擊以重新整理", + "repository_url": "原始碼連結", + "support": "支援" + }, + "vrcx_updater": { + "header": "VRCX 更新器", + "change_build": "變更版本", + "auto_update": "自動更新", + "auto_update_off": "關閉", + "auto_update_notify": "通知", + "auto_update_download": "自動下載", + "auto_update_install": "自動安裝" + }, + "application": { + "header": "應用程式", + "startup": "在 Windows 啟動時啟動", + "minimized": "以最小化啟動", + "tray": "最小化到系統列" + }, + "legal_notice": { + "header": "法律聲明", + "info": "VRCX 是一個提供好友管理的輔助應用程式。這個程式使用非官方的 VRChat API (VRCSDK)。", + "disclaimer1": "VRCX 不受 VRChat 的認可,也不反應 VRChat 或任何正式參與製作或管理 VRChat 的觀點或意見。VRChat 是 VRChat Inc. 的商標。 VRChat © VRChat Inc.", + "disclaimer2": "pypy 和 Natsumi 將不對使用 VRCX 引起的任何問題負責。使用時請自負風險!", + "open_source_software_notice": "開放原始碼軟體授權條款" + } + }, + "appearance": { + "appearance": { + "header": "外觀", + "language": "語言 (Language)", + "theme_mode": "主題", + "theme_mode_system": "系統", + "theme_mode_light": "淺色", + "theme_mode_dark": "深色", + "vrcplus_profile_icons": "VRChat+ 個人檔案圖示", + "disable_tooltips": "關閉提示", + "sort_favorite_by": "收藏排序依據", + "sort_favorite_by_name": "名稱", + "sort_favorite_by_date": "時間", + "sort_instance_users_by": "坊間玩家排序依據", + "sort_instance_users_by_time": "時間", + "sort_instance_users_by_alphabet": "字母順序", + "table_max_size": "表格大小", + "page_size": "頁面大小:" + }, + "timedate": { + "header": "時間 / 日期", + "time_format": "時間格式", + "time_format_24": "24 小時制", + "time_format_12": "12 小時制", + "force_iso_date_format": "強制使用 ISO 時間格式" + }, + "side_panel": { + "header": "側板", + "sorting": { + "header": "排序", + "sort_private_to_bottom": "將 私人世界 排序到底部", + "sort_by_status": "依狀態排序", + "sort_gps_to_top": "將 GPS 排序到頂部", + "sort_gps_to_top_notice": "(僅限上線玩家)", + "sort_favorite_by": "收藏玩家 排序依據", + "sort_favorite_by_alphabet": "字母順序", + "sort_favorite_by_online_time": "上線時長", + "sort_online_by": "網頁玩家 排序依據", + "sort_online_by_alphabet": "字母順序", + "sort_online_by_online_time": "上線時長", + "sort_active_by": "上線玩家 排序依據", + "sort_active_by_alphabet": "字母順序", + "sort_active_by_online_time": "上線時長", + "sort_offline_by": "離線玩家 排序依據", + "sort_offline_by_alphabet": "字母順序", + "sort_offline_by_offline_time": "離線時長" + }, + "width": "寬度" + }, + "user_dialog": { + "header": "玩家資訊", + "hide_vrchat_notes": "隱藏 VRChat 備註", + "hide_vrcx_memos": "隱藏 VRCX 備忘錄", + "export_vrcx_memos_into_vrchat_notes": "將 VRCX 備忘錄匯出成 VRChat 備註", + "export_notes": "匯出備註" + }, + "user_colors": { + "header": "玩家名稱顏色", + "random_colors_from_user_id": "從玩家 ID 隨機挑選顏色" + } + }, + "notifications": { + "notifications": { + "header": "通知", + "notification_filter": "通知篩選器", + "steamvr_notifications": { + "header": "SteamVR 通知", + "steamvr_overlay": "SteamVR 疊層", + "overlay_notifications": "疊層通知", + "notification_position": "通知位置", + "xsoverlay_notifications": "XSOverlay 通知", + "user_images": "玩家照片(較慢)", + "notification_timeout": "通知時長" + }, + "desktop_notifications": { + "header": "桌面通知", + "when_to_display": "顯示時機", + "when_to_display_never": "永不", + "when_to_display_desktop": "在桌面模式時", + "when_to_display_inside_vr": "在 VR 裡時", + "when_to_display_outside_vr": "在 VR 外時", + "when_to_display_game_closed": "遊戲關閉時", + "when_to_display_game_running": "遊戲執行中", + "when_to_display_always": "總是" + }, + "text_to_speech": { + "header": "文字轉語音選項", + "when_to_play": "通知文字轉語音播放時機", + "when_to_play_never": "永不", + "when_to_play_inside_vr": "在 VR 裡時", + "when_to_play_game_closed": "遊戲關閉時", + "when_to_play_game_running": "遊戲執行中", + "when_to_play_always": "總是", + "tts_voice": "語音樣式" + } + } + }, + "wrist_overlay": { + "steamvr_wrist_overlay": { + "header": "SteamVR 手腕疊層", + "description": "* 當 VRChat 開啟時它會自動開啟", + "grip": "握持:Vive 或其它控制器的握持鍵、Oculus X/A 按鍵", + "menu": "選單:Vive 選單鍵、Index B、Oculus Y/B 按鍵", + "steamvr_overlay": "SteamVR 疊層", + "wrist_feed_overlay": "手腕動態疊層", + "hide_private_worlds": "隱藏私人世界", + "start_overlay_with": "啟動時一併啟動", + "overlay_button": "疊層按鍵", + "overlay_button_grip": "握持", + "overlay_button_menu": "選單", + "display_overlay_on": "疊層顯示位置", + "display_overlay_on_left": "左手", + "display_overlay_on_right": "右手", + "display_overlay_on_both": "雙手", + "background_color": "背景顏色", + "minimal_feed_icons": "迷你動態圖示", + "hide_vr_devices": "隱藏 VR 裝置", + "hide_cpu_usage": "隱藏 CPU 使用率", + "hide_game_uptime": "隱藏啟動時長", + "show_pc_uptime": "顯示電腦啟動時長", + "wrist_feed_filters": "手腕動態篩選器" + } + }, + "discord_presence": { + "discord_presence": { + "header": "Discord 遊戲動態", + "description": "* 僅在 VRChat 開啟時有效", + "enable": "啟用", + "enable_tooltip": "建議在 VRChat config.json 中停用原生 Discord 遊戲動態來防止衝突", + "instance_type_player_count": "房間種類 / 玩家人數", + "join_button": "加入按鈕(僅限公開房間)", + "hide_details_in_private": "在私人房間時隱藏世界資訊", + "hide_images": "隱藏世界縮圖" + } + }, + "advanced": { + "advanced": { + "header": "進階設定", + "launch_options": "啟動選項", + "pending_offline": { + "header": "待確認離線", + "description": "將玩家標記為離線之前延遲(防止誤判)", + "set_delay": "設定延遲" + }, + "primary_password": { + "header": "主密碼", + "description": "密碼加密(將停用自動登入)" + }, + "vrchat_quit_fix": { + "header": "VRChat 關閉修正", + "description": "在離開遊戲時強制停止 VRChat" + }, + "auto_cache_management": { + "header": "關閉 VRChat 時自動管理快取", + "description": "自動從快取中刪除舊版本" + }, + "remote_database": { + "header": "遠端角色資料庫", + "enable": "啟用", + "avatar_database_provider": "角色資料庫提供方" + }, + "youtube_api": { + "header": "Youtube API", + "enable": "啟用", + "youtube_api_key": "Youtube API 金鑰" + }, + "video_progress_pie": { + "header": "影片進度圓餅疊層", + "enable": "啟用", + "enable_tooltip": "需要啟用 SteamVR 疊層選項", + "dance_world_only": "僅限跳舞世界" + }, + "cache_debug": { + "header": "VRCX 世界快取/除錯", + "disable_gamelog": "關閉遊戲紀錄", + "disable_gamelog_notice": "(可能會弄壞很多東西)", + "user_cache": "玩家快取:", + "world_cache": "世界快取:", + "avatar_cache": "角色快取:", + "avatar_name_cache": "角色名稱快取:", + "clear_cache": "清除快取", + "auto_clear_cache": "自動清除快取", + "download_history": "下載紀錄", + "show_console": "顯示主控台" + }, + "sqlite_table_size": { + "header": "SQLite 數據表大小", + "refresh": "重新整理", + "gps": "GPS:", + "status": "狀態:", + "bio": "自我介紹:", + "avatar": "角色:", + "online_offline": "上線 / 離線:", + "friend_log_history": "好友歷史紀錄:", + "notification": "通知:", + "location": "位置:", + "join_leave": "加入 / 離開:", + "portal_spawn": "開啟傳送門:", + "video_play": "影片播放:", + "event": "事件:" + } + }, + "photon": { + "header": "Photon 紀錄疊層", + "event_hud": { + "header": "Photon 事件 HUD", + "enable": "啟用", + "enable_tooltip": "需要啟用 SteamVR 疊層選項", + "filter": "篩選器", + "filter_favorites": "收藏", + "filter_friends": "好友", + "filter_everyone": "所有人", + "message_timeout": "訊息時長" + }, + "timeout_hud": { + "header": "玩家愈時 HUD", + "enable": "啟用", + "enable_tooltip": "需要啟用 SteamVR 疊層選項", + "filter": "篩選器", + "filter_favorites": "收藏", + "filter_friends": "好友", + "filter_everyone": "所有人", + "timeout_threshold": "愈時閾值" + } + } + } + } + }, + "side_panel": { + "search_placeholder": "搜尋", + "search_result_active": "活躍", + "search_result_offline": "離線", + "search_result_more": "搜尋更多:", + "direct_access_tooltip": "直接存取解貼簿的 ID / 連結", + "refresh_tooltip": "重新整理好友", + "friends": "好友", + "me": "我", + "favorite": "收藏", + "online": "上線", + "active": "活躍", + "offline": "離線", + "penfing_offline": "待確認離線" + }, + "dialog": { + "user": { + "status": { + "active": "活躍", + "offline": "離線", + "online": "上線", + "join_me": "加入我", + "ask_me": "詢問我", + "busy": "請勿打擾" + }, + "previous_display_names": "過去的顯示名稱:", + "tags": { + "friend_no": "第 {number} 位好友", + "vrchat_team": "VRChat 團隊" + }, + "actions": { + "favorite_tooltip": "添加到我的收藏", + "unfavorite_tooltip": "從我的收藏中移除", + "refresh": "重新整理", + "copy_url": "複製玩家連結", + "invite": "邀請", + "invite_with_message": "邀請(訊息)", + "request_invite": "請求邀請", + "request_invite_with_message": "請求邀請(訊息)", + "invite_to_group": "邀情到群組", + "manage_gallery_icon": "管理相簿 / 圖示", + "accept_friend_request": "接受好友邀請", + "decline_friend_request": "回絕好友邀請", + "cancel_friend_request": "取消好友邀請", + "send_friend_request": "傳送好友邀請", + "show_avatar_author": "顯示角色作者", + "show_fallback_avatar": "顯示備用角色資訊", + "show_previous_instances": "顯示過去的房間", + "show_previous_images": "顯示角色以前的圖片", + "moderation_block": "封鎖", + "moderation_unblock": "解除封鎖", + "moderation_mute": "靜音", + "moderation_unmute": "解除靜音", + "moderation_hide_avatar": "顯示角色", + "moderation_show_avatar": "隱藏角色", + "moderation_enable_avatar_interaction": "開啟角色互動", + "moderation_disable_avatar_interaction": "關閉角色互動", + "edit_status": "社交狀態", + "edit_language": "語言", + "edit_bio": "自我介紹", + "unfriend": "解除好友", + "logout": "登出" + }, + "info": { + "header": "資訊", + "launch_invite_tooltip": "啟動 / 邀請", + "self_invite_tooltip": "自我邀請", + "refresh_user_count_tooltip": "重新整理房間人數", + "instance_creator": "房間建立者", + "note": "備註", + "note_placeholder": "點擊添加備註", + "memo": "備忘錄", + "memo_placeholder": "點擊添加備忘錄", + "avatar_info": "角色資訊", + "avatar_info_last_seen": "最後已知角色資訊", + "represented_group": "代表群組", + "bio": "自我介紹", + "last_seen": "最後上線", + "join_count": "加入次數", + "time_together": "一起遊玩時長", + "online_for": "上線時長", + "offline_for": "離線時長", + "last_activity": "最後動態", + "last_login": "最後登入", + "date_joined": "加入時間", + "friended": "好友", + "unfriended": "解除好友", + "avatar_cloning": "角色複製", + "avatar_cloning_allow": "允許", + "avatar_cloning_deny": "不允許", + "home_location": "家點", + "accuracy_notice": "本地資料庫的資料可能不精確" + }, + "groups": { + "header": "群組", + "total_count": "總共 {count}", + "own_groups": "擁有群組", + "mutual_groups": "共同群組", + "groups": "群組" + }, + "worlds": { + "header": "世界", + "total_count": "總共 {count}", + "sort_by_name": "依名稱排序", + "sort_by_update": "依更新排序" + }, + "favorite_worlds": { + "header": "收藏世界" + }, + "avatars": { + "header": "角色", + "total_count": "總共 {count}", + "sort_by_name": "依名稱排序", + "sort_by_update": "依更新排序", + "all": "所有", + "public": "公開", + "private": "私人" + }, + "json": { + "header": "原始資料" + } + }, + "world": { + "tags": { + "public": "公開", + "private": "私人", + "labs": "社區實驗室", + "cache": "快取" + }, + "actions": { + "delete_cache_tooltip": "從快取中刪除世界", + "favorite_tooltip": "添加到我的收藏", + "unfavorite_tooltip": "從我的收藏中移除", + "refresh": "重新整理", + "new_instance": "新房間", + "make_home": "設為家點", + "reset_home": "重設家點", + "show_previous_instances": "顯示過去的房間", + "show_previous_images": "顯示過去的圖片", + "rename": "重新命名", + "change_description": "變更敘述", + "change_capacity": "變更最大玩家上限", + "change_preview": "變更 YouTube 預覽", + "change_tags": "變更標籤", + "change_image": "變更圖片", + "download_package": "下載 Unity Package", + "publish_to_labs": "發佈到社區實驗室", + "unpublish": "取消發佈", + "delete": "刪除" + }, + "instances": { + "header": "房間", + "public_count": "公開 {count}", + "private_count": "私人 {count}", + "capacity_count": "玩家上限 {count} ({max})", + "self_invite_tooltip": "自我邀請", + "refresh_user_count_tooltip": "重新整理房間人數", + "instance_creator": "房間建立者" + }, + "info": { + "header": "資訊", + "id": "世界 ID", + "id_tooltip": "複製到剪貼簿", + "copy_id": "複製 ID", + "copy_url": "複製連結", + "youtube_preview": "YouTube 預覽", + "players": "玩家人數", + "favorites": "收藏次數", + "visits": "總綁訪次數", + "capacity": "最大玩家上限", + "heat": "熱度", + "popularity": "熱門度", + "created_at": "創建時間", + "last_updated": "最後更新", + "version": "版本", + "platform": "平台", + "last_visited": "上次拜訪", + "visit_count": "我綁訪次數", + "time_spent": "停留時長", + "accuracy_notice": "本地資料庫的資料可能不精確" + }, + "json": { + "header": "原始資料" + } + }, + "avatar": { + "tags": { + "public": "公開", + "private": "私人", + "fallback": "備用", + "cache": "快取" + }, + "labels": { + "public": "(公開)", + "private": "(私人)", + "own": "(自有)" + }, + "actions": { + "delete_cache_tooltip": "從快取中刪除角色", + "favorite_tooltip": "添加到我的收藏", + "unfavorite_tooltip": "從我的收藏中移除", + "refresh": "重新整理", + "select": "選擇角色", + "select_fallback": "選擇為備用角色", + "block": "封鎖角色", + "unblock": "解除封鎖角色", + "show_previous_images": "顯示過去的圖片", + "make_public": "設為公開", + "make_private": "設為私人", + "rename": "重新命名", + "change_description": "變更敘述", + "change_image": "變更圖片", + "download_package": "下載 Unity Package", + "delete": "刪除" + }, + "info": { + "header": "資訊", + "id": "角色 ID", + "id_tooltip": "複製到剪貼簿", + "copy_id": "複製 ID", + "copy_url": "複製連結", + "created_at": "創建時間", + "last_updated": "最後更新", + "version": "版本", + "platform": "平台" + }, + "json": { + "header": "原始資料" + } + }, + "group": { + "tags": { + "verified": "已認證", + "public": "公開", + "private": "私人", + "open": "開放", + "request": "請求", + "invite": "邀請", + "closed": "關閉", + "joined": "已加入", + "banned": "已封鎖", + "visible": "能見度:所有人", + "friends": "能見度:好友", + "hidden": "能見度:隱藏", + "subscribed": "已訂閱公告" + }, + "actions": { + "represent_tooltip": "顯示在個人檔案上", + "unrepresent_tooltip": "停止顯示在個人檔案上", + "cancel_join_request_tooltip": "取消加入請求", + "pending_request_tooltip": "待接受邀請", + "request_join_tooltip": "清求加入", + "invite_required_tooltip": "需要被邀請才能加入", + "join_group_tooltip": "加入群組", + "refresh": "重新整理", + "unsubscribe": "取消訂閱公告", + "subscribe": "訂閱公告", + "invite_to_group": "邀請到群組", + "visibility_everyone": "能見度:所有人", + "visibility_friends": "能見度:好友", + "visibility_hidden": "能見度:隱藏", + "leave": "離開群組" + }, + "info": { + "header": "資訊", + "announcement": "公告", + "rules": "規則", + "members": "成員", + "created_at": "創建時間", + "links": "連結", + "url": "群組連結", + "url_tooltip": "複製連結到剪貼簿", + "id": "群組 ID", + "id_tooltip": "複製 ID 到剪貼簿", + "joined_at": "加入時間", + "roles": "身分", + "role_description": "敘述:", + "role_updated_at": "更新時間:", + "role_created_at": "創建時間:", + "role_permissions": "權限:" + }, + "members": { + "header": "成員", + "all_members": "所有成員", + "friends_only": "好友", + "load_more": "載入更多……" + }, + "json": { + "header": "原始資料" + } + }, + "favorite": { + "header": "選擇群組", + "vrchat_favorites": "VRChat 收藏", + "local_favorites": "本地收藏" + }, + "invite": { + "header": "Invite", + "select_placeholder": "Choose Friends", + "invite_with_message": "Invite With Message", + "invite": "Invite" + }, + "social_status": { + "header": "社交狀態", + "history": "過去的社交狀態", + "status_placeholder": "今天心情如何?", + "update": "更新" + }, + "language": { + "header": "語言", + "add_language": "新增語言", + "select_language": "選擇語言", + "ok": "確定", + "cancel": "取消" + }, + "bio": { + "header": "自我介紹", + "bio_placeholder": "在這裡介紹一下自己吧!", + "add_link": "新增社交連結", + "update": "更新" + }, + "new_instance": { + "header": "新房間", + "access_type": "房間種類", + "access_type_public": "公開", + "access_type_group": "群組", + "access_type_friend_plus": "好友+", + "access_type_friend": "好友", + "access_type_invite_plus": "邀請+", + "access_type_invite": "邀請", + "region": "地區", + "region_usw": "美國西部", + "region_use": "美國東部", + "region_eu": "歐洲", + "region_jp": "日本", + "world_id": "世界 ID", + "instance_id": "房間 ID", + "instance_id_placeholder": "亂數", + "instance_creator": "房間建立者", + "instance_creator_placeholder": "選擇玩家", + "group_id": "群組 ID", + "location": "地點", + "url": "連結", + "copy_url": "複製連結", + "self_invite": "自我邀請", + "invite": "邀請", + "launch": "啟動" + }, + "launch_options": { + "header": "啟動選項", + "description": "這些選項僅適用於高級玩家。", + "example": "變更 FPS 限制:--fps= 例:", + "path_override": "VRChat 位置覆蓋", + "vrchat_docs": "VRChat 文檔", + "unity_manual": "Unity 手冊", + "save": "儲存" + }, + "config_json": { + "header": "VRChat JSON 設定檔", + "description1": "這些選項僅適用於高級玩家。", + "description2": "將輸入框留白來設為預設值,設定需要重新啟動遊戲才會套用。", + "cache_size": "快取大小:", + "refresh": "重新整理", + "delete_all_cache": "刪除所有快取", + "delete_cache": "刪除快取", + "delete_old_cache": "從快取中刪除舊版本", + "sweep_cache": "清理快取", + "max_cache_size": "最大快取大小 [GB] (最小 20GB)", + "cache_expiry_delay": "快取保存時長 [日] (30 - 150)", + "cache_directory": "覆蓋快取資料夾位置", + "fpv_steadycam_fov": "第一人稱平滑鏡頭視野範圍", + "camera_resolution": "相機解析度", + "screenshot_resolution": "螢幕截圖解析度", + "disable_discord_presence": "停用 Discord 遊戲狀態", + "vrchat_docs": "VRChat 文檔", + "cancel": "取消", + "save": "儲存" + }, + "youtube_api": { + "header": "YouTube API", + "description": "輸入你的 YouTube API 金鑰(選擇性)", + "placeholder": "YouTube API 金鑰", + "guide": "教學", + "save": "儲存" + }, + "set_world_tags": { + "header": "設定世界標籤", + "enable_debugging": "為其他人啟用世界偵錯", + "seprator": "使用逗號來分隔每個標籤", + "cancel": "取消", + "save": "儲存" + }, + "vrcx_updater": { + "header": "VRCX 更新器", + "latest_version": "VRCX 已是最新版本。", + "ready_for_update": "已準備好安裝更新,重新啟動 VRCX 來套用更新。", + "download": "下載", + "install": "安裝" + }, + "launch": { + "header": "啟動", + "url": "連結", + "short_url": "短連結", + "short_url_notice": "短網址會在一段時間後過期", + "location": "地點", + "copy_tooltip": "複製到剪貼簿", + "start_as_desktop": "以桌面模式啟動(無 VR)", + "info": "資訊", + "invite": "邀請", + "launch": "啟動" + }, + "export_friends_list": { + "header": "匯出好友列表" + }, + "export_own_avatars": { + "header": "匯出私有角色" + }, + "discord_names": { + "header": "Discord 名稱", + "description": "點擊好友列表中的「讀取缺失的項目」來搜尋整個好友列表" + }, + "notification_position": { + "header": "通知位置", + "description": "選擇通知位置", + "ok": "OK" + }, + "shared_feed_filters": { + "notification": "通知篩選器", + "wrist": "手腕動態篩選器", + "on": "開啟", + "off": "關閉", + "favorite": "收藏", + "friends": "好友", + "everyone": "所有人", + "cancel": "取消", + "save": "儲存" + }, + "world_export": { + "header": "世界收藏匯出" + }, + "world_import": { + "header": "世界收藏匯入", + "description": "輸入世界 ID 列表", + "process_list": "讀取列表", + "process_progress": "進度:", + "select_vrchat_group_placeholder": "選擇 VRChat 群組", + "select_local_group_placeholder": "選擇本地群組", + "import": "匯入世界", + "cancel": "取消", + "import_progress": "匯入進度:", + "clear_table": "清除表格", + "errors": "錯誤:", + "clear_errors": "清除錯誤" + }, + "avatar_export": { + "header": "角色收藏匯出" + }, + "avatar_import": { + "header": "角色收藏匯入", + "description": "輸入角色 ID 列表", + "process_list": "讀取列表", + "process_progress": "進度:", + "select_group_placeholder": "選擇群組", + "import": "匯入角色", + "cancel": "取消", + "import_progress": "匯入進度:", + "clear_table": "清除表格", + "errors": "錯誤:", + "clear_errors": "清除錯誤" + }, + "friend_export": { + "header": "好友收藏匯出" + }, + "friend_import": { + "header": "好友收藏匯入", + "description": "輸入玩家 ID 列表", + "process_list": "讀取列表", + "process_progress": "進度:", + "select_group_placeholder": "選擇群組", + "import": "匯入好友", + "cancel": "取消", + "import_progress": "匯入進度:", + "clear_table": "清除表格", + "errors": "錯誤:", + "clear_errors": "清除錯誤" + }, + "avatar_database_provider": { + "header": "角色資料庫提供方", + "add_provider": "新增提供方" + }, + "chatbox_blacklist": { + "header": "聊天框黑名單", + "keyword_blacklist": "關鍵字黑名單", + "user_blacklist": "玩家黑名單", + "add_item": "新增項目" + }, + "invite_to_group": { + "header": "邀請到群組", + "description": "請不要濫用群組邀請,邀請太多玩家加入群組會導致你被停權。", + "choose_group_placeholder": "選擇群組", + "groups": "群組", + "choose_friends_placeholder": "選擇好友", + "selected_users": "已選擇的玩家" + }, + "download_history": { + "header": "下載紀錄", + "queue": "下載佇列:", + "history": "歷史紀錄:", + "cancel_all": "取消全部", + "close": "關閉" + }, + "note_export": { + "header": "備註匯出", + "description1": "這個過程將匯出你所有的 VRCX 備忘錄並將它們匯入到 VRChat 備註中。", + "description2": "請注意以下限制:", + "description3": "- API 接口有速率限制,每個請求之間會有很大的延遲。", + "description4": "- 每個備註的字數限制為 256 個字元。", + "description5": "- 髒話過濾器(沒有樂趣)。", + "description6": "- 不能換行(將會被替換成空格)。", + "description7": "- 這將會覆蓋這些玩家現有的任何 VRChat 備註。", + "description8": "- 在這裡所做的任何編輯都不會影響 VRCX 備忘錄,但會在匯出後會影響 VRChat 備註。", + "refresh": "重新整理", + "export": "匯出", + "cancel": "取消", + "progress": "進度:", + "errors": "錯誤:", + "clear_errors": "清除錯誤" + }, + "edit_invite_message": { + "header": "編輯邀請訊息", + "description": "一小時編輯冷卻時間。", + "cancel": "取消", + "save": "儲存" + }, + "invite_message": { + "header": "傳送邀請的訊息", + "confirmation": "你確定你要傳送邀請?", + "cancel": "取消", + "refresh": "重新整理", + "confirm": "確定" + }, + "invite_request_message": { + "header": "傳送邀請請求的訊息", + "cancel": "取消", + "refresh": "重新整理" + }, + "invite_response_message": { + "header": "傳送邀請回覆的訊息", + "confirmation": "你確定你要傳送邀請回覆?", + "cancel": "取消", + "refresh": "重新整理", + "confirm": "確定" + }, + "invite_request_response_message": { + "header": "傳送邀請請求回覆的訊息", + "cancel": "取消", + "refresh": "重新整理" + }, + "edit_send_invite_message": { + "header": "編輯並傳送邀請訊息", + "description": "一小時編輯冷卻時間。", + "cancel": "取消", + "send": "傳送" + }, + "edit_send_invite_response_message": { + "header": "編輯並傳送邀請回覆訊息", + "description": "一小時編輯冷卻時間。", + "cancel": "取消", + "send": "傳送" + }, + "gallery_icons": { + "header": "相簿和圖示", + "description": "推薦圖片尺寸:1200 像素 x 900 像素", + "gallery": "相簿", + "icons": "圖示", + "refresh": "重新整理", + "upload": "上傳", + "clear": "清除" + }, + "change_content_image": { + "avatar": "變更角色圖片", + "world": "變更世界圖片", + "description": "推薦圖片尺寸:1200 像素 x 900 像素 (4:3)", + "refresh": "重新整理", + "upload": "上傳圖片" + }, + "previous_images": { + "header": "過去的圖片" + }, + "previous_instances": { + "header": "過去的房間", + "info": "過去的房間資訊", + "search_placeholder": "搜尋" + }, + "open_source": { + "header": "開放原始碼軟體授權條款", + "description": "VRCX 是基於開放原始碼軟體上開發的。沒有他們的貢獻的話,這個程式是不可能開發出來的。" + }, + "primary_password": { + "header": "需要設定主密碼", + "password_placeholder": "輸入新密碼", + "re_input_placeholder": "確認密碼", + "ok": "OK" + } + }, + "prompt": { + "totp": { + "header": "雙重認證", + "description": "輸入你的身份驗證器應用程式中的數字代碼", + "use_otp": "使用一次性密碼", + "verify": "驗證", + "input_placeholder": "驗證碼", + "input_error": "無效的代碼" + }, + "otp": { + "header": "雙重認證", + "description": "輸入你儲存的其中一個備份驗證碼", + "use_otp": "使用驗證碼", + "verify": "驗證", + "input_placeholder": "備份驗證碼", + "input_error": "無效的代碼" + }, + "email_otp": { + "header": "雙重認證", + "description": "輸入寄送到電子信箱的數字代碼", + "cancel": "取消", + "verify": "驗證", + "input_placeholder": "代碼", + "input_error": "無效的代碼" + }, + "primary_password": { + "header": "需要主密碼", + "description": "請輸入你的主密碼" + }, + "change_favorite_group_name": { + "header": "變更收藏群組名稱", + "description": "輸入新名稱", + "cancel": "取消", + "change": "變更", + "input_placeholder": "名稱", + "input_error": "需要名稱", + "message": { + "success": "已重新命名收藏群組" + } + }, + "direct_access_user_id": { + "header": "直接存取", + "description": "輸入玩家連結或玩家 ID (UUID)", + "cancel": "取消", + "ok": "OK", + "input_error": "需要玩家連結 / 玩家 ID", + "message": { + "error": "無效的連結或 ID" + } + }, + "direct_access_username": { + "header": "直接存取", + "description": "輸入玩家名稱", + "cancel": "取消", + "ok": "OK", + "input_error": "需要玩家名稱" + }, + "direct_access_world_id": { + "header": "直接存取", + "description": "輸入世界連結或世界 ID (UUID)", + "cancel": "取消", + "ok": "OK", + "input_error": "需要世界連結 / 世界 ID", + "message": { + "error": "無效的連結或 ID" + } + }, + "direct_access_avatar_id": { + "header": "直接存取", + "description": "輸入角色連結或角色 ID (UUID)", + "cancel": "取消", + "ok": "OK", + "input_error": "需要角色連結 / 角色 ID", + "message": { + "error": "無效的連結或 ID" + } + }, + "direct_access_omni": { + "header": "直接存取", + "description": "輸入玩家 / 世界 / 房間 / 角色連結 或 ID (UUID)", + "cancel": "取消", + "ok": "OK", + "input_error": "需要連結或 ID", + "message": { + "error": "無效的連結或 ID" + } + }, + "notification_timeout": { + "header": "通知顯示時間", + "description": "輸入秒數", + "cancel": "取消", + "ok": "OK", + "input_error": "請輸入有效的秒數" + }, + "overlay_message_timeout": { + "header": "訊息疊層顯示時間", + "description": "輸入秒數", + "cancel": "取消", + "ok": "OK", + "input_error": "請輸入有效的秒數" + }, + "rename_avatar": { + "header": "重新命名角色", + "description": "輸入角色名稱", + "cancel": "取消", + "ok": "OK", + "input_error": "請輸入有效的名稱", + "message": { + "success": "已重新命名角色" + } + }, + "change_avatar_description": { + "header": "變更角色敘述", + "description": "輸入角色敘述", + "cancel": "取消", + "ok": "OK", + "input_error": "請輸入有效的敘述", + "message": { + "success": "已變更角色敘述" + } + }, + "rename_world": { + "header": "重新命名世界", + "description": "輸入世界名稱", + "cancel": "取消", + "ok": "OK", + "input_error": "請輸入有效的名稱", + "message": { + "success": "已重新命名世界" + } + }, + "change_world_description": { + "header": "變更世界敘述", + "description": "輸入世界敘述", + "cancel": "取消", + "ok": "OK", + "input_error": "請輸入有效的敘述", + "message": { + "success": "已變更世界敘述" + } + }, + "change_world_capacity": { + "header": "變更世界最大人數", + "description": "輸入世界最大人數, 最大:40", + "cancel": "取消", + "ok": "OK", + "input_error": "請輸入有效的人數", + "message": { + "success": "已變更世界最大人數" + } + }, + "change_world_preview": { + "header": "變更 YouTube 預覽", + "description": "輸入世界 YouTube 預覽", + "cancel": "取消", + "ok": "OK", + "input_error": "請輸入有效的 Youtube 連結", + "message": { + "error": "無效的 Youtube 連結", + "success": "世界 YouTube 預覽已變更" + } + }, + "change_table_size": { + "header": "最大表格大小", + "description": "較大的資料表大小可能會影響內存用量和性能 (預設:1000)", + "cancel": "取消", + "save": "儲存", + "input_error": "請輸入有效的行數" + }, + "photon_lobby_timeout": { + "header": "玩家愈時閥值", + "description": "輸入秒數(預設:3)", + "cancel": "取消", + "ok": "OK", + "input_error": "請輸入有效的秒數" + }, + "auto_clear_cache": { + "header": "VRCX 快取清除間隔", + "description": "輸入小時數,較大的數值可能會影響內存用量和性能 (預設:24,關閉:0)", + "cancel": "取消", + "ok": "OK", + "input_error": "請輸入有效的小時數" + }, + "new_local_favorite_group": { + "header": "新增收藏群組", + "description": "輸入世界收藏群組名稱", + "cancel": "取消", + "ok": "OK", + "input_error": "請輸入有效的名稱", + "message": { + "error": "名稱為 {name} 的群組已存在" + } + }, + "local_favorite_group_rename": { + "header": "重新命名收藏群組", + "description": "輸入世界收藏群組名稱", + "cancel": "取消", + "save": "儲存", + "input_error": "請輸入有效的名稱", + "message": { + "error": "名稱為 {name} 的群組已存在" + } + }, + "pending_offline_delay": { + "header": "待確認離線", + "description": "設定將玩家標記為離線之前的延遲秒數(預設:110)", + "cancel": "取消", + "save": "儲存", + "input_error": "請輸入有效的秒數" + } + }, + "table": { + "feed": { + "date": "時間", + "type": "類型", + "user": "玩家", + "detail": "詳細" + }, + "gameLog": { + "date": "時間", + "type": "類型", + "user": "玩家", + "detail": "詳細" + }, + "playerList": { + "avatar": "角色", + "timer": "時長", + "photonId": "Photon ID", + "icon": "圖示", + "platform": "平台", + "displayName": "顯示名稱", + "status": "狀態", + "rank": "階級", + "language": "語言", + "bioLink": "社交連結", + "user": "玩家", + "type": "種類", + "detail": "詳細", + "date": "時間" + }, + "friendLog": { + "date": "時間", + "type": "類型", + "user": "玩家", + "action": "動作" + }, + "moderation": { + "date": "時間", + "type": "類型", + "source": "來源", + "target": "目標", + "action": "動作" + }, + "notification": { + "date": "時間", + "type": "類型", + "user": "玩家", + "photo": "照片", + "message": "訊息", + "action": "動作" + }, + "friendList": { + "no": "No.", + "avatar": "角色", + "displayName": "顯示名稱", + "rank": "階級", + "status": "狀態", + "language": "語言", + "bioLink": "社交連結", + "joinCount": "加入次數", + "timeTogether": "一起遊玩時長", + "lastSeen": "最後上線", + "lastActivity": "最後活動", + "lastLogin": "最後登入", + "dateJoined": "加入時間", + "unfriend": "解除好友" + }, + "profile": { + "invite_messages": { + "slot": "欄位", + "message": "訊息", + "cool_down": "編輯冷卻", + "action": "動作" + }, + "previous_display_name": { + "date": "時間", + "name": "名稱" + } + }, + "social_status": { + "no": "No.", + "status": "狀蓋" + }, + "download_history": { + "time": "時間", + "name": "名稱", + "type": "種類", + "status": "狀態", + "cancel": "取消" + }, + "import": { + "image": "圖片", + "name": "名稱", + "author": "作者", + "status": "狀態", + "note": "備註", + "skip_export": "跳過匯出", + "action": "動作" + }, + "previous_instances": { + "date": "日期", + "display_name": "顯示名稱", + "world": "世界", + "instance_name": "房間名稱", + "instance_creator": "房間創建者", + "time": "時間", + "count": "次數", + "action": "動作" + } + }, + "vr": { + "status": { + "timer": "時長:", + "players": "玩家人數:", + "cpu": "CPU:", + "online": "線上:", + "devices": { + "left": "左:", + "right": "右:" + } + } + } +} diff --git a/html/src/vr.js b/html/src/vr.js index 5398269c..4eff4194 100644 --- a/html/src/vr.js +++ b/html/src/vr.js @@ -8,10 +8,11 @@ import '@fontsource/noto-sans-kr'; import '@fontsource/noto-sans-jp'; import Noty from 'noty'; import Vue from 'vue'; +import VueI18n from 'vue-i18n'; import ElementUI from 'element-ui'; -import locale from 'element-ui/lib/locale/lang/en'; import * as workerTimers from 'worker-timers'; import MarqueeText from 'vue-marquee-text-component'; +import * as localizedStrings from './localization/localizedStrings.js'; Vue.component('marquee-text', MarqueeText); (async function () { @@ -29,8 +30,18 @@ Vue.component('marquee-text', MarqueeText); timeout: 3000 }); + Vue.use(VueI18n); + + var i18n = new VueI18n({ + locale: 'en', + fallbackLocale: 'en', + messages: localizedStrings + }); + + var $t = i18n.t.bind(i18n); + Vue.use(ElementUI, { - locale + i18n: (key, value) => i18n.t(key, value) }); var escapeTag = (s) => @@ -163,10 +174,12 @@ Vue.component('marquee-text', MarqueeText); }; var $app = { + i18n, data: { // 1 = 대시보드랑 손목에 보이는거 // 2 = 항상 화면에 보이는 거 appType: location.href.substr(-1), + appLanguage: 'en', currentTime: new Date().toJSON(), cpuUsage: 0, pcUptime: '', @@ -310,6 +323,7 @@ Vue.component('marquee-text', MarqueeText); this.hudFeed = []; this.hudTimeout = []; this.setDatetimeFormat(); + this.setAppLanguage(this.config.appLanguage); }; $app.methods.updateOnlineFriendCount = function (count) { @@ -699,6 +713,16 @@ Vue.component('marquee-text', MarqueeText); Vue.filter('formatDate', formatDate); }; + $app.methods.setAppLanguage = function (appLanguage) { + if (!appLanguage) { + return; + } + if (appLanguage !== this.appLanguage) { + this.appLanguage = appLanguage; + i18n.locale = this.appLanguage; + } + }; + $app = new Vue($app); window.$app = $app; })(); diff --git a/html/src/vr.pug b/html/src/vr.pug index 13309bf8..c309db29 100644 --- a/html/src/vr.pug +++ b/html/src/vr.pug @@ -30,14 +30,14 @@ html .detail span.extra span.time {{ feed.created_at | formatDate }} - | #[span.name(v-text="feed.displayName")] ✔ + | #[span.name(v-text="feed.displayName")] ✔ template(v-if="feed.worldName") - | #[location(:location="feed.location" :hint="feed.worldName")] + | #[location(:location="feed.location" :hint="feed.worldName" style="margin-left:5px")] div(v-else-if="feed.type === 'Status'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }") .detail span.extra span.time {{ feed.created_at | formatDate }} - | #[span.name(v-text="feed.displayName")] + | #[span.name(v-text="feed.displayName" style="margin-right:5px")] template(v-if="feed.statusDescription === feed.previousStatusDescription") i.x-user-status(:class="statusClass(feed.previousStatus)") i.el-icon-right @@ -69,7 +69,7 @@ html .detail span.extra span.time {{ feed.created_at | formatDate }} - | 🎵 #[span.name(v-text="feed.displayName")] + | 🎵 #[span.name(v-text="feed.displayName" style="margin-right:5px")] template(v-if="feed.videoName") | #[span(v-text="feed.videoName")] template(v-else) @@ -144,7 +144,7 @@ html span.extra span.time {{ feed.created_at | formatDate }} template(v-if="feed.displayName") - | ✨ #[span.name(v-text="feed.displayName")] + | ✨ #[span.name(v-text="feed.displayName" style="margin-right:5px")] | #[location(:location="feed.instanceId" :hint="feed.worldName")] template(v-else) | ✨ User has spawned a portal @@ -152,7 +152,7 @@ html .detail span.extra span.time {{ feed.created_at | formatDate }} - | 🧍 #[span.name(v-text="feed.displayName")] + | 🧍 #[span.name(v-text="feed.displayName" style="margin-right:5px")] template(v-if="feed.releaseStatus === 'public'") | #[i.x-user-status.online] template(v-else) @@ -229,14 +229,15 @@ html .detail span.extra span.time {{ feed.created_at | formatDate }} - | #[span.name(v-text="feed.displayName")] has logged in + | #[span.name(v-text="feed.displayName")] + span(style="margin-left:5px;margin-right:5px") has logged in template(v-if="feed.worldName") | to #[location(:location="feed.location" :hint="feed.worldName")] div(v-else-if="feed.type === 'Status'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }") .detail span.extra span.time {{ feed.created_at | formatDate }} - | #[span.name(v-text="feed.displayName")] + | #[span.name(v-text="feed.displayName" style="margin-right:5px")] template(v-if="feed.statusDescription === feed.previousStatusDescription") i.x-user-status(:class="statusClass(feed.previousStatus)") i.el-icon-right @@ -267,7 +268,8 @@ html .detail span.extra span.time {{ feed.created_at | formatDate }} - | #[span.name(v-text="feed.displayName")] changed video to + | #[span.name(v-text="feed.displayName")] + span(style="margin-left:5px;margin-right:5px") changed video to template(v-if="feed.videoName") | #[span(v-text="feed.videoName")] template(v-else) @@ -342,15 +344,16 @@ html span.extra span.time {{ feed.created_at | formatDate }} template(v-if="feed.displayName") - | #[span.name(v-text="feed.displayName")] has spawned a portal to - | #[location(:location="feed.instanceId" :hint="feed.worldName")] + | #[span.name(v-text="feed.displayName")] has spawned a portal to + | #[location(:location="feed.instanceId" :hint="feed.worldName" style="margin-left:5px")] template(v-else) | User has spawned a portal div(v-else-if="feed.type === 'AvatarChange'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }") .detail span.extra span.time {{ feed.created_at | formatDate }} - | #[span.name(v-text="feed.displayName")] changed into avatar + | #[span.name(v-text="feed.displayName")] + span(style="margin-left:5px;margin-right:5px") changed into avatar template(v-if="feed.releaseStatus === 'public'") | #[i.x-user-status.online] template(v-else) @@ -415,12 +418,12 @@ html img(v-if="device[1] !== 'connected'" src="images/controller_status_off.png" class="tracker-device") img(v-else-if="device[2] < 20" src="images/controller_status_ready_low.png" class="tracker-device") img(v-else src="images/controller_status_ready.png" class="tracker-device") - span L:{{ device[2] }}% + span {{ $t('vr.status.devices.left') }}{{ device[2] }}% template(v-else-if="device[0] === 'rightController'") img(v-if="device[1] !== 'connected'" src="images/controller_status_off.png" class="tracker-device") img(v-else-if="device[2] < 20" src="images/controller_status_ready_low.png" class="tracker-device") img(v-else src="images/controller_status_ready.png" class="tracker-device") - span R:{{ device[2] }}% + span {{ $t('vr.status.devices.right') }}{{ device[2] }}% template(v-else-if="device[0] === 'controller'") img(v-if="device[1] !== 'connected'" src="images/controller_status_off.png" class="tracker-device") img(v-else-if="device[2] < 20" src="images/controller_status_ready_low.png" class="tracker-device") @@ -454,17 +457,17 @@ html span(style="display:inline-block") {{ lastLocation.playerList.length }} span(style="display:inline-block;font-weight:bold") {{ lastLocation.friendList.length !== 0 ? `‎‎‎‎‎‎‎‎‏‏‎ ‎(${lastLocation.friendList.length})` : ''}} template(v-else) - span(style="float:right") Timer: {{ lastLocationTimer }} + span(style="float:right") {{ $t('vr.status.timer') }} {{ lastLocationTimer }} template(v-if="onlineForTimer") | / {{ onlineForTimer }} template(v-if="pcUptime") | / {{ pcUptime }} - span(style="display:inline-block") Players: {{ lastLocation.playerList.length }} + span(style="display:inline-block") {{ $t('vr.status.players') }} {{ lastLocation.playerList.length }} span(style="display:inline-block;font-weight:bold") {{ lastLocation.friendList.length !== 0 ? `‎‎‎‎‎‎‎‎‏‏‎ ‎(${lastLocation.friendList.length})` : ''}} br span(style="float:right") {{ currentTime }} - span(v-if="config && !config.hideCpuUsageFromFeed" style="display:inline-block;margin-right:5px") CPU: {{ cpuUsage }}% - span(style="display:inline-block") Online: {{ onlineFriendCount }} + span(v-if="config && !config.hideCpuUsageFromFeed" style="display:inline-block;margin-right:5px") {{ $t('vr.status.cpu') }} {{ cpuUsage }}% + span(style="display:inline-block") {{ $t('vr.status.online') }} {{ onlineFriendCount }} template(v-else) svg(class="np-progress-circle") circle(class="np-progress-circle-stroke" cx="60" cy="60" stroke="white" r="30" fill="transparent" stroke-width="60")