diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 451cb00c9c19b1e11fc357fa19162547f9e9a31a..522ac51c59ad499187aee5d451e5096bde325a77 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -37,6 +37,16 @@ docker-build-image-tag: rules: - if: '$CI_COMMIT_TAG' +check: + stage: build + image: node:23-alpine + script: + - cd app + - npm install + - npm run check + rules: + - if: $CI_PIPELINE_SOURCE == 'merge_request_event' + deploy_staging: stage: deploy-staging needs: ["docker-build-image-latest"] diff --git a/app/.prettierignore b/app/.prettierignore new file mode 100644 index 0000000000000000000000000000000000000000..ea0e65aedf916ec5de7d17749ccbe4a1287ecf55 --- /dev/null +++ b/app/.prettierignore @@ -0,0 +1,3 @@ +# Ignore artifacts: +lib +dist diff --git a/app/.prettierrc b/app/.prettierrc new file mode 100644 index 0000000000000000000000000000000000000000..0967ef424bce6791893e9a57bb952f80fd536e93 --- /dev/null +++ b/app/.prettierrc @@ -0,0 +1 @@ +{} diff --git a/app/eslint.config.js b/app/eslint.config.js new file mode 100644 index 0000000000000000000000000000000000000000..29b428e82dd21b12dca6c6d8b8ee28bd0d39ecc9 --- /dev/null +++ b/app/eslint.config.js @@ -0,0 +1,9 @@ +import globals from "globals"; +import pluginJs from "@eslint/js"; + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + { languageOptions: { globals: globals.browser } }, + pluginJs.configs.recommended, + { ignores: ["src/lib/*", "dist/*"] }, +]; diff --git a/app/index.html b/app/index.html index 44149d5f5de268572c8ce19d569f0d37372911b4..6f5040372801e62bdc24df22fdc7f5a9335ff4c1 100644 --- a/app/index.html +++ b/app/index.html @@ -1,630 +1,838 @@ - - - - - - - - - /e/OS Installer - - - - - - -
-
- -
- -
- -

/e/OS Installer

-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
- -
-
-
-
- -

-
-

-
- -
- -
-
-
-

-
- -
-

-
- -
-
- -
-
-
-
-

-
- - -
-
- -
-
-
-
-

-
- -
-

-
- -
-
- -
-
-
-
-

-
- -
-

-
- -
-
- -
- -
-
-
-
- -

-
-
- -

-
-
- -
- -
-
-
- -

-

-
-
-
-
-
- -

-

-
-
-
-
-
-

-
-

- -

-
-
-
-
-
- -
-
-
-

-

-
- -
- - -
-
-
-

-
- -
-

-
- -
- -
-
-
-

-

-

-

-

-
- -
-
- -
- -
-
-
-

-

-

-

-

-
- -
-
- -
- -
-
-
-

-

-
- -
-
- -
-
-
-
-

-

-
- -
-
- -
- -
-
-
-
- -
-

-

-

-

-
-
-
- -
- -
-
-
-
- -
-

-

-

-

-
-
-
- -
- -
-
-
-

-

-

-

-

-
- -
- - - -
-
-
-

-
-

- -
-
-
- -
-
-
-

-

-

-

-
- -
- - -
-
-
-

-

-

-

-

-

-

-
- -
-
-
-
-

-

-

-

-
- -
-
-
-
-

-
-

- -
-

-
-
-
-
-
-

-

-

-
- -
- - -
-
-
-

-

-
- -
-
- -
- -
-
-
-

-

-
- -
-
- -
- -
-
-
-

-

-
- -
-

-
- -
- -
-
-
-

-
- -
-

-
- -
- -
-
-
-

-

-
- -
- -
-
-
-
- -
-

- murena.io -
- -
-
-
-
-

-
- -
-

-
-
-
-
-
-
- -

-

-
-
- -
- - + + + + + + + + + /e/OS Installer + + + + + + +
+
+ +
+ +
+ +

/e/OS Installer

+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +

+
+

+
+ +
+ +
+
+
+

+
+ +
+

+
+ +
+
+ +
+
+
+
+

+
+ + +
+
+ +
+
+
+
+

+
+ +
+

+
+ +
+
+ +
+
+
+
+

+
+ +
+

+
+ +
+
+ +
+ +
+
+
+
+ +

+
+
+ +

+
+
+ +
+ +
+
+
+ +

+

+
+
+
+
+
+ +

+

+
+
+
+
+
+

+
+

+ +

+
+
+
+
+
+ +
+
+
+

+

+
+ +
+ + +
+
+
+

+
+ +
+

+
+ +
+ +
+
+
+

+

+

+

+

+
+ +
+
+ +
+ +
+
+
+

+

+

+

+

+
+ +
+
+ +
+ +
+
+
+

+

+
+ +
+
+ +
+
+
+
+

+

+
+ +
+
+ +
+ +
+
+
+
+ +
+

+

+

+

+
+
+
+ +
+ +
+
+
+
+ +
+

+

+

+

+
+
+
+ +
+ +
+
+
+

+

+

+

+

+
+ +
+ + + +
+
+
+

+
+

+ +
+
+
+ +
+
+
+

+

+

+

+
+ +
+ + +
+
+
+

+

+

+

+

+

+

+
+ +
+
+
+
+

+

+

+

+
+ +
+
+
+
+

+
+

+ +
+

+
+
+
+
+
+

+

+

+
+ +
+ + +
+
+
+

+

+
+ +
+
+ +
+ +
+
+
+

+

+
+ +
+
+ +
+ +
+
+
+

+

+
+ +
+

+
+ +
+ +
+
+
+

+
+ +
+

+
+ +
+ +
+
+
+

+

+
+ +
+ +
+
+
+
+ +
+

+ murena.io +
+ +
+
+
+
+

+
+ +
+

+
+
+
+
+
+
+ +

+

+
+
+ +
+ + diff --git a/app/package-lock.json b/app/package-lock.json index 208923aff899f15af0866e35dfe4328fb4070cc9..6ba53db8e44aca4ebc681368950ba262e0d01cef 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -13,6 +13,10 @@ "ky": "^1.7.4" }, "devDependencies": { + "@eslint/js": "^9.17.0", + "eslint": "^9.17.0", + "globals": "^15.14.0", + "prettier": "3.4.2", "vite": "^6.0.5" } }, @@ -33,6 +37,212 @@ "node": ">=18" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.1.tgz", + "integrity": "sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.5", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.1.tgz", + "integrity": "sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", + "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.17.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz", + "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.5.tgz", + "integrity": "sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.4.tgz", + "integrity": "sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.29.1", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.29.1.tgz", @@ -42,82 +252,650 @@ ], "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.29.1.tgz", + "integrity": "sha512-xufkSNppNOdVRCEC4WKvlR1FBDyqCSCpQeMMgv9ZyXqqtKBfkw1yfGMTUTs9Qsl6WQbJnsGboWCp7pJGkeMhKA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@zip.js/zip.js": { + "version": "2.7.54", + "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.7.54.tgz", + "integrity": "sha512-qMrJVg2hoEsZJjMJez9yI2+nZlBUxgYzGV3mqcb2B/6T1ihXp0fWBDYlVHlHquuorgNUQP5a8qSmX6HF5rFJNg==", + "license": "BSD-3-Clause", + "engines": { + "bun": ">=0.7.0", + "deno": ">=1.0.0", + "node": ">=16.5.0" + } + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", + "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.24.2", + "@esbuild/android-arm": "0.24.2", + "@esbuild/android-arm64": "0.24.2", + "@esbuild/android-x64": "0.24.2", + "@esbuild/darwin-arm64": "0.24.2", + "@esbuild/darwin-x64": "0.24.2", + "@esbuild/freebsd-arm64": "0.24.2", + "@esbuild/freebsd-x64": "0.24.2", + "@esbuild/linux-arm": "0.24.2", + "@esbuild/linux-arm64": "0.24.2", + "@esbuild/linux-ia32": "0.24.2", + "@esbuild/linux-loong64": "0.24.2", + "@esbuild/linux-mips64el": "0.24.2", + "@esbuild/linux-ppc64": "0.24.2", + "@esbuild/linux-riscv64": "0.24.2", + "@esbuild/linux-s390x": "0.24.2", + "@esbuild/linux-x64": "0.24.2", + "@esbuild/netbsd-arm64": "0.24.2", + "@esbuild/netbsd-x64": "0.24.2", + "@esbuild/openbsd-arm64": "0.24.2", + "@esbuild/openbsd-x64": "0.24.2", + "@esbuild/sunos-x64": "0.24.2", + "@esbuild/win32-arm64": "0.24.2", + "@esbuild/win32-ia32": "0.24.2", + "@esbuild/win32-x64": "0.24.2" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.17.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.17.0.tgz", + "integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.9.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.17.0", + "@eslint/plugin-kit": "^0.2.3", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", + "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", + "dev": true, + "license": "ISC" + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "15.14.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.14.0.tgz", + "integrity": "sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.29.1.tgz", - "integrity": "sha512-xufkSNppNOdVRCEC4WKvlR1FBDyqCSCpQeMMgv9ZyXqqtKBfkw1yfGMTUTs9Qsl6WQbJnsGboWCp7pJGkeMhKA==", - "cpu": [ - "x64" - ], + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": ">=0.8.19" + } }, - "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, - "license": "MIT" - }, - "node_modules/@zip.js/zip.js": { - "version": "2.7.54", - "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.7.54.tgz", - "integrity": "sha512-qMrJVg2hoEsZJjMJez9yI2+nZlBUxgYzGV3mqcb2B/6T1ihXp0fWBDYlVHlHquuorgNUQP5a8qSmX6HF5rFJNg==", - "license": "BSD-3-Clause", + "license": "MIT", "engines": { - "bun": ">=0.7.0", - "deno": ">=1.0.0", - "node": ">=16.5.0" + "node": ">=0.10.0" } }, - "node_modules/esbuild": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", - "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, - "hasInstallScript": true, "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" + "dependencies": { + "is-extglob": "^2.1.1" }, "engines": { - "node": ">=18" + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.24.2", - "@esbuild/android-arm": "0.24.2", - "@esbuild/android-arm64": "0.24.2", - "@esbuild/android-x64": "0.24.2", - "@esbuild/darwin-arm64": "0.24.2", - "@esbuild/darwin-x64": "0.24.2", - "@esbuild/freebsd-arm64": "0.24.2", - "@esbuild/freebsd-x64": "0.24.2", - "@esbuild/linux-arm": "0.24.2", - "@esbuild/linux-arm64": "0.24.2", - "@esbuild/linux-ia32": "0.24.2", - "@esbuild/linux-loong64": "0.24.2", - "@esbuild/linux-mips64el": "0.24.2", - "@esbuild/linux-ppc64": "0.24.2", - "@esbuild/linux-riscv64": "0.24.2", - "@esbuild/linux-s390x": "0.24.2", - "@esbuild/linux-x64": "0.24.2", - "@esbuild/netbsd-arm64": "0.24.2", - "@esbuild/netbsd-x64": "0.24.2", - "@esbuild/openbsd-arm64": "0.24.2", - "@esbuild/openbsd-x64": "0.24.2", - "@esbuild/sunos-x64": "0.24.2", - "@esbuild/win32-arm64": "0.24.2", - "@esbuild/win32-ia32": "0.24.2", - "@esbuild/win32-x64": "0.24.2" + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" } }, "node_modules/ky": { @@ -132,6 +910,63 @@ "url": "https://github.com/sindresorhus/ky?sponsor=1" } }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, "node_modules/nanoid": { "version": "3.3.8", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", @@ -151,6 +986,96 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -187,6 +1112,52 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", + "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/rollup": { "version": "4.29.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.29.1.tgz", @@ -226,6 +1197,29 @@ "fsevents": "~2.3.2" } }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -236,6 +1230,55 @@ "node": ">=0.10.0" } }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/vite": { "version": "6.0.6", "resolved": "https://registry.npmjs.org/vite/-/vite-6.0.6.tgz", @@ -307,6 +1350,45 @@ "optional": true } } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/app/package.json b/app/package.json index 63881d6e8584b9608bd9530c6037602291bbe701..ff2269abb7957d2a6aaa1c7d5059953ae65d32f7 100644 --- a/app/package.json +++ b/app/package.json @@ -6,9 +6,15 @@ "scripts": { "dev": "vite", "build": "vite build", - "preview": "vite preview" + "preview": "vite preview", + "check": "npx eslint . && npx prettier . --check", + "format": "npx prettier . --write" }, "devDependencies": { + "@eslint/js": "^9.17.0", + "eslint": "^9.17.0", + "globals": "^15.14.0", + "prettier": "3.4.2", "vite": "^6.0.5" }, "dependencies": { diff --git a/app/public/assets/languages/de.json b/app/public/assets/languages/de.json index 6fd519e2638164997e8a2dfc3a2ae931b05e13fb..2c61a8442949cc0b367eefadf7d9b729ca2582ee 100644 --- a/app/public/assets/languages/de.json +++ b/app/public/assets/languages/de.json @@ -1,111 +1,111 @@ { - "Ex 1: before installing /e/OS Android 12, you should update to the latest stock Android 12": "Beispiel 1: Bevor du /e/OS Android 12 installierst, solltest du auf die neueste Standardversion von Android 12 aktualisieren.", - "Ex 2: or if you're installing /e/OS Android 11, make sure to update to the latest stock Android 11": "Beispiel 2: Oder wenn du /e/OS Android 11 installierst, stelle sicher, dass du vorher auf die neueste Standardversion von Android 11 aktualisierst.", - "Ex 3: similarly, if you're installing /e/OS Android 11, it should be the latest stock Android 10": "Beispiel 3: Ähnlich, wenn du /e/OS Android 11 installierst, sollte es die neueste Standardversion von Android 10 sein.", - "activate-developer-options": "Entwickleroptionen aktivieren", - "activate-developer-options-instructions-1": "1. Öffne das Einstellungsmenü und gib ‘Build’ in die Suchleiste ein.", - "activate-developer-options-instructions-2": "2. Auf dem nächsten Bildschirm finde ‘Build-Nummer’ und tippe 7 Mal darauf.", - "activate-usb-debugging": "USB-Debugging aktivieren", - "activate-usb-debugging-instructions-1": "1. Gehe zurück zum Einstellungsmenü und gib ‘USB-Debugging’ in die Suchleiste ein.", - "activate-usb-debugging-instructions-2": "2. Zu diesem Zeitpunkt solltest du im Bildschirm ‘Entwickleroptionen’ sein. Tippe nun auf ‘USB-Debugging’, um es zu aktivieren (bei einigen Geräten wird es ‘Android-Debugging’ genannt).", - "bootloader-to-recovery-manually": "Bootloader zu Recovery", - "bootloader-to-recovery-manually-instructions": "Jetzt werden wir dein Gerät im Recovery-Modus neu starten. Bitte folge den untenstehenden Schritten:", - "bootloader-to-recovery-manually-instructions-1": "1. Wähle im Bootloader Recovery Modus aus, indem du Lautstärke lauter und Lautstärke leiser verwendest, um zu navigieren", - "bootloader-to-recovery-manually-instructions-2": "2. Drücke Ausschalten, um zu bestätigen", - "bootloader-to-recovery-manually-instructions-3": "3. Warte bis dein Telefon im Recovery-Modus neu startet", - "check-update-android-version": "Überprüfe und aktualisiere deine Android-Version", - "check-update-android-version-caution": "Vorsicht: Bevor du mit der Installation fortfährst, vergewissere dich, ob die neueste Android-Firmware für dein Gerät verfügbar ist.", - "connect": "Verbinden", - "connect-bootloader": "Bootloader-Verbindung", - "connect-bootloader-instructions-1": "Dein Telefon wird jetzt im Bootloader-Modus neu starten.", - "connect-bootloader-instructions-2": "Wenn dein Telefon eingeschaltet ist, verbinde es im Bootloader-Modus, indem du auf die untenstehende Schaltfläche tippst.", - "connect-your-phone": "Verbinde dein Telefon", - "connect-your-phone-instructions": "Verbinde dein Telefon mit einem USB-Kabel mit deinem Computer. Wir erkennen dein Telefon automatisch, um /e/OS zu installieren.", - "connect-your-phone-instructions-notes": "Hinweis: ‘USB-Debugging’ ist erforderlich, damit die automatische Geräteerkennung funktioniert. Wenn du es noch nicht aktiviert hast, helfen wir dir in den nächsten Schritten.", - "device-detection": "Geräteerkennung", - "device-detection-detected": "Ein Gerät wurde erkannt.", - "device-detection-instructions-1": "Wir verbinden jetzt dein Telefon mit dem Browser. Wenn dieses Pop-up erscheint, wähle dein Telefon aus der Liste aus.", - "device-detection-instructions-2": "Es wird ein Pop-up-Fenster auf deinem Telefon erscheinen. Du musst Immer von diesem Computer zulassen auswählen, bevor du auf OK drückst.", - "device-detection-instructions-3": "Tippe auf die untenstehende Schaltfläche, um die Verbindung zu starten.", - "device-model-not-supported": "Gerätemodell nicht unterstützt", - "device-model-not-supported-instructions": "Du kannst /e/OS nicht mit diesem Programm installieren", - "device-model-not-supported-title": "Dein Telefon {{product-name}} ist nicht kompatibel", - "dissatisfied": "Unzufrieden", - "donate": "Spenden", - "enable-usb-file-transfer": "USB-Dateiübertragung aktivieren", - "enable-usb-file-transfer-instructions-1": "Immer noch in den ‘Entwickleroptionen’, scrolle nach unten, um ‘Standard-USB-Konfiguration’ zu finden und tippe darauf.", - "enable-usb-file-transfer-instructions-2": "Wähle jetzt die Option ‘Dateiübertragung’ (bei einigen Geräten wird es ‘MTP-Modus (Media Transfer Protocol)’ genannt).", - "format-device": "Gerät formatieren", - "format-device-instructions-1": "1. Wähle Werkseinstellung zurücksetzen", - "format-device-instructions-2": "2. Wähle die Option Daten formatieren / Werkseinstellung zurücksetzen", - "format-device-instructions-3": "3. Der nächste Bildschirm zeigt eine Warnung an, dass diese Aktion nicht rückgängig gemacht werden kann", - "format-device-instructions-4": "4. Wähle Daten formatieren, um fortzufahren", - "format-device-instructions-5": "5. Bitte warten, der Formatierungsprozess wird abgeschlossen", - "format-device-instructions-6": "6. Der Bildschirm kehrt jetzt zum Werkseinstellungsbildschirm zurück", - "go-to-apply-update": "Fast geschafft!", - "go-to-apply-update-instructions-1": "1. Wähle Aktualisierung anwenden", - "go-to-apply-update-instructions-2": "2. und dann Aktualisierung von adb anwenden", - "go-to-apply-update-instructions-3": "3. Das Gerät befindet sich jetzt im Sideload-Modus und du bist bereit für den nächsten Schritt.", - "help": "Hilfe", - "help-us-improve-the-tool": "Hilf uns, das Programm zu verbessern", - "help-us-improve-the-tool-instructions-1": "Bitte bewerte deine Erfahrung mit dem /e/OS Installer.", - "help-us-improve-the-tool-instructions-2": "Hast du irgendwelche Idee dazu, wie wir dieses Programm verbessern können?", - "i-already-have-an-account": "Ich habe bereits ein Konto", - "i-m-ready": "Ich bin bereit!", - "installation-complete": "Die Installation ist abgeschlossen!", - "installation-complete-instructions-1": "Glückwunsch! Während dein Telefon hochfährt, solltest du das untenstehende Logo sehen. Das kann eine Weile dauern, bitte habe etwas Geduld.", - "installation-complete-instructions-2": "Tipp: Folge den Anweisungen auf deinem Telefon, um dein Gerät einzurichten. Du kannst jetzt deine Dateien zurück auf dein Telefon übertragen.", - "let-s-get-started": "Los geht's", - "let-s-get-started-instruction-1": "Der komplette Installationsprozess dauert etwa 1 Stunde. Bring etwas Geduld mit!", - "let-s-get-started-instruction-2": "Du brauchst mindestens 6 GB freien Speicherplatz auf deinem Computer, um /e/OS herunterzuladen und zu installieren. Stelle sicher, dass du genügend freien Speicherplatz hast.", - "let-s-get-started-instruction-3": "Bevor du /e/OS installierst, stelle sicher, dass dein Telefon mindestens 50% Akku hat.", - "let-s-get-started-instruction-4": "Alle Daten werden während der Installation von deinem Smartphone gelöscht, daher empfehlen wir, deine Daten vorher zu sichern.", - "let-s-get-started-instruction-5": "Ein funktionierendes USB-Datenkabel ist erforderlich. Stromkabel übertragen keine Daten und funktionieren nicht! Wir empfehlen USB 3.x oder neuer.", - "let-s-get-started-instruction-title-1": "1. Nimm dir etwas freie Zeit", - "let-s-get-started-instruction-title-2": "2. Mach Platz auf deiner Festplatte", - "let-s-get-started-instruction-title-3": "3. Lade dein Telefon auf", - "let-s-get-started-instruction-title-4": "4. Sichere deine Daten", - "let-s-get-started-instruction-title-5": "5. Hol dir ein USB-Datenkabel", - "locking": "Sperren", - "locking-instructions-1": "Dein Telefon fragt nach einer Sperre. Wähle lock bootloader", - "locking-instructions-2": "Wenn sich das Gerät nicht automatisch neu startet, starte es neu", - "murena-workspace-account": "Murena Workspace-Konto", - "murena-workspace-account-instructions": "Sichere deine Daten und synchronisiere dieses Gerät mit deinem persönlichen Murena Workspace-Konto. 1 GB sind kostenlos, es gibt auch ein Bezahl-Abo für mehr Speicherplatz.", - "navigator-detection": "Browser-Erkennung", - "navigator-not-supported": "Dein Browser wird nicht unterstützt", - "navigator-not-supported-instructions": "Du kannst die folgenden Browser verwenden", - "neutral": "Neutral", - "next": "Weiter", - "ready-to-install-e-os": "Du bist jetzt bereit, /e/OS zu installieren.", - "recovery-to-bootloader": "Recovery zu Bootloader", - "recovery-to-bootloader-instructions": "Im Hauptmenü", - "recovery-to-bootloader-instructions-1": "1. Wähle Erweitert", - "recovery-to-bootloader-instructions-2": "2. Wähle Reboot to bootloader", - "satisfied": "Zufrieden", - "send-to-e-team": "An das Murena Team senden", - "sideload": "Installation läuft", - "sideload-instructions-1": "Der Bildschirm zeigt den Fortschritt an … ", - "sideload-instructions-2": "Dies kann einige Minuten dauern, bitte übe dich etwas in Geduld.", - "sideload-instructions-3": "Sobald die Installation abgeschlossen ist, kehrt das Telefon zum Hauptbildschirm zurück.", - "sideload-instructions-4": "Erst dann kannst du auf Next klicken.", - "sign-up-free": "Kostenlos registrieren", - "skip": "Überspringen", - "start": "Start", - "this-might-take-some-time-please-be-patient": "Das könnte einige Zeit dauern, bitte habe etwas Geduld", - "unlocking-instructions-1": "Dein Telefon fragt nach dem Entsperren. Wähle unlock bootloader aus, indem du Lautstärke lauter und Lautstärke leiser zum Navigieren benutzt.", - "unlocking-instructions-2": "Wenn sich das Gerät nicht automatisch neu startet, starte es neu.", - "unlocking-instructions-3": "Da das Gerät vollständig zurückgesetzt wird, musst du USB-Debugging erneut aktivieren.", - "unlocking-instructions-4": "Überspringe die Einrichtung auf dem Telefon und klicke auf Weiter", - "very-dissatisfied": "Sehr unzufrieden", - "very-satisfied": "Sehr zufrieden", - "format-device-instructions-7": "7. Auf den Rückwärts-Pfeil tippen, dann auf Weiter", - "locking-instructions-3": "Dann auf Weiter tippen", - "unlocking-instructions-2-a": "Das Gerät wird neu starten. Warte, bis der Bootloader-Bildschirm erneut erscheint, bevor du zum nächsten Schritt übergehst.", - "unlocking-instructions-5": "Dann auf Weiter tippen", - "unlocking-instructions-1-a": "Benutze den Ausschalten zum Bestätigen.", - "android-version-not-supported-title": "Ihre Android-Version {{android-version}} wird nicht unterstützt", - "android-version-not-supported": "Android-Version veraltet", - "android-version-not-supported-instructions": "Aktualisieren Sie Ihr System auf die erforderliche Minimal-Version {{android-version-required}}", - "go-to-apply-update-instructions-4": "Bemerkung: Für den nächsten Schritt muss sich dein Browser wahrscheinlich mit dem Telefon neu verbinden. Wenn ein Fenster aufscheint, wähle bitte dein Gerät aus der Liste aus.", - "installing": "Wird installiert" + "Ex 1: before installing /e/OS Android 12, you should update to the latest stock Android 12": "Beispiel 1: Bevor du /e/OS Android 12 installierst, solltest du auf die neueste Standardversion von Android 12 aktualisieren.", + "Ex 2: or if you're installing /e/OS Android 11, make sure to update to the latest stock Android 11": "Beispiel 2: Oder wenn du /e/OS Android 11 installierst, stelle sicher, dass du vorher auf die neueste Standardversion von Android 11 aktualisierst.", + "Ex 3: similarly, if you're installing /e/OS Android 11, it should be the latest stock Android 10": "Beispiel 3: Ähnlich, wenn du /e/OS Android 11 installierst, sollte es die neueste Standardversion von Android 10 sein.", + "activate-developer-options": "Entwickleroptionen aktivieren", + "activate-developer-options-instructions-1": "1. Öffne das Einstellungsmenü und gib ‘Build’ in die Suchleiste ein.", + "activate-developer-options-instructions-2": "2. Auf dem nächsten Bildschirm finde ‘Build-Nummer’ und tippe 7 Mal darauf.", + "activate-usb-debugging": "USB-Debugging aktivieren", + "activate-usb-debugging-instructions-1": "1. Gehe zurück zum Einstellungsmenü und gib ‘USB-Debugging’ in die Suchleiste ein.", + "activate-usb-debugging-instructions-2": "2. Zu diesem Zeitpunkt solltest du im Bildschirm ‘Entwickleroptionen’ sein. Tippe nun auf ‘USB-Debugging’, um es zu aktivieren (bei einigen Geräten wird es ‘Android-Debugging’ genannt).", + "bootloader-to-recovery-manually": "Bootloader zu Recovery", + "bootloader-to-recovery-manually-instructions": "Jetzt werden wir dein Gerät im Recovery-Modus neu starten. Bitte folge den untenstehenden Schritten:", + "bootloader-to-recovery-manually-instructions-1": "1. Wähle im Bootloader Recovery Modus aus, indem du Lautstärke lauter und Lautstärke leiser verwendest, um zu navigieren", + "bootloader-to-recovery-manually-instructions-2": "2. Drücke Ausschalten, um zu bestätigen", + "bootloader-to-recovery-manually-instructions-3": "3. Warte bis dein Telefon im Recovery-Modus neu startet", + "check-update-android-version": "Überprüfe und aktualisiere deine Android-Version", + "check-update-android-version-caution": "Vorsicht: Bevor du mit der Installation fortfährst, vergewissere dich, ob die neueste Android-Firmware für dein Gerät verfügbar ist.", + "connect": "Verbinden", + "connect-bootloader": "Bootloader-Verbindung", + "connect-bootloader-instructions-1": "Dein Telefon wird jetzt im Bootloader-Modus neu starten.", + "connect-bootloader-instructions-2": "Wenn dein Telefon eingeschaltet ist, verbinde es im Bootloader-Modus, indem du auf die untenstehende Schaltfläche tippst.", + "connect-your-phone": "Verbinde dein Telefon", + "connect-your-phone-instructions": "Verbinde dein Telefon mit einem USB-Kabel mit deinem Computer. Wir erkennen dein Telefon automatisch, um /e/OS zu installieren.", + "connect-your-phone-instructions-notes": "Hinweis: ‘USB-Debugging’ ist erforderlich, damit die automatische Geräteerkennung funktioniert. Wenn du es noch nicht aktiviert hast, helfen wir dir in den nächsten Schritten.", + "device-detection": "Geräteerkennung", + "device-detection-detected": "Ein Gerät wurde erkannt.", + "device-detection-instructions-1": "Wir verbinden jetzt dein Telefon mit dem Browser. Wenn dieses Pop-up erscheint, wähle dein Telefon aus der Liste aus.", + "device-detection-instructions-2": "Es wird ein Pop-up-Fenster auf deinem Telefon erscheinen. Du musst Immer von diesem Computer zulassen auswählen, bevor du auf OK drückst.", + "device-detection-instructions-3": "Tippe auf die untenstehende Schaltfläche, um die Verbindung zu starten.", + "device-model-not-supported": "Gerätemodell nicht unterstützt", + "device-model-not-supported-instructions": "Du kannst /e/OS nicht mit diesem Programm installieren", + "device-model-not-supported-title": "Dein Telefon {{product-name}} ist nicht kompatibel", + "dissatisfied": "Unzufrieden", + "donate": "Spenden", + "enable-usb-file-transfer": "USB-Dateiübertragung aktivieren", + "enable-usb-file-transfer-instructions-1": "Immer noch in den ‘Entwickleroptionen’, scrolle nach unten, um ‘Standard-USB-Konfiguration’ zu finden und tippe darauf.", + "enable-usb-file-transfer-instructions-2": "Wähle jetzt die Option ‘Dateiübertragung’ (bei einigen Geräten wird es ‘MTP-Modus (Media Transfer Protocol)’ genannt).", + "format-device": "Gerät formatieren", + "format-device-instructions-1": "1. Wähle Werkseinstellung zurücksetzen", + "format-device-instructions-2": "2. Wähle die Option Daten formatieren / Werkseinstellung zurücksetzen", + "format-device-instructions-3": "3. Der nächste Bildschirm zeigt eine Warnung an, dass diese Aktion nicht rückgängig gemacht werden kann", + "format-device-instructions-4": "4. Wähle Daten formatieren, um fortzufahren", + "format-device-instructions-5": "5. Bitte warten, der Formatierungsprozess wird abgeschlossen", + "format-device-instructions-6": "6. Der Bildschirm kehrt jetzt zum Werkseinstellungsbildschirm zurück", + "go-to-apply-update": "Fast geschafft!", + "go-to-apply-update-instructions-1": "1. Wähle Aktualisierung anwenden", + "go-to-apply-update-instructions-2": "2. und dann Aktualisierung von adb anwenden", + "go-to-apply-update-instructions-3": "3. Das Gerät befindet sich jetzt im Sideload-Modus und du bist bereit für den nächsten Schritt.", + "help": "Hilfe", + "help-us-improve-the-tool": "Hilf uns, das Programm zu verbessern", + "help-us-improve-the-tool-instructions-1": "Bitte bewerte deine Erfahrung mit dem /e/OS Installer.", + "help-us-improve-the-tool-instructions-2": "Hast du irgendwelche Idee dazu, wie wir dieses Programm verbessern können?", + "i-already-have-an-account": "Ich habe bereits ein Konto", + "i-m-ready": "Ich bin bereit!", + "installation-complete": "Die Installation ist abgeschlossen!", + "installation-complete-instructions-1": "Glückwunsch! Während dein Telefon hochfährt, solltest du das untenstehende Logo sehen. Das kann eine Weile dauern, bitte habe etwas Geduld.", + "installation-complete-instructions-2": "Tipp: Folge den Anweisungen auf deinem Telefon, um dein Gerät einzurichten. Du kannst jetzt deine Dateien zurück auf dein Telefon übertragen.", + "let-s-get-started": "Los geht's", + "let-s-get-started-instruction-1": "Der komplette Installationsprozess dauert etwa 1 Stunde. Bring etwas Geduld mit!", + "let-s-get-started-instruction-2": "Du brauchst mindestens 6 GB freien Speicherplatz auf deinem Computer, um /e/OS herunterzuladen und zu installieren. Stelle sicher, dass du genügend freien Speicherplatz hast.", + "let-s-get-started-instruction-3": "Bevor du /e/OS installierst, stelle sicher, dass dein Telefon mindestens 50% Akku hat.", + "let-s-get-started-instruction-4": "Alle Daten werden während der Installation von deinem Smartphone gelöscht, daher empfehlen wir, deine Daten vorher zu sichern.", + "let-s-get-started-instruction-5": "Ein funktionierendes USB-Datenkabel ist erforderlich. Stromkabel übertragen keine Daten und funktionieren nicht! Wir empfehlen USB 3.x oder neuer.", + "let-s-get-started-instruction-title-1": "1. Nimm dir etwas freie Zeit", + "let-s-get-started-instruction-title-2": "2. Mach Platz auf deiner Festplatte", + "let-s-get-started-instruction-title-3": "3. Lade dein Telefon auf", + "let-s-get-started-instruction-title-4": "4. Sichere deine Daten", + "let-s-get-started-instruction-title-5": "5. Hol dir ein USB-Datenkabel", + "locking": "Sperren", + "locking-instructions-1": "Dein Telefon fragt nach einer Sperre. Wähle lock bootloader", + "locking-instructions-2": "Wenn sich das Gerät nicht automatisch neu startet, starte es neu", + "murena-workspace-account": "Murena Workspace-Konto", + "murena-workspace-account-instructions": "Sichere deine Daten und synchronisiere dieses Gerät mit deinem persönlichen Murena Workspace-Konto. 1 GB sind kostenlos, es gibt auch ein Bezahl-Abo für mehr Speicherplatz.", + "navigator-detection": "Browser-Erkennung", + "navigator-not-supported": "Dein Browser wird nicht unterstützt", + "navigator-not-supported-instructions": "Du kannst die folgenden Browser verwenden", + "neutral": "Neutral", + "next": "Weiter", + "ready-to-install-e-os": "Du bist jetzt bereit, /e/OS zu installieren.", + "recovery-to-bootloader": "Recovery zu Bootloader", + "recovery-to-bootloader-instructions": "Im Hauptmenü", + "recovery-to-bootloader-instructions-1": "1. Wähle Erweitert", + "recovery-to-bootloader-instructions-2": "2. Wähle Reboot to bootloader", + "satisfied": "Zufrieden", + "send-to-e-team": "An das Murena Team senden", + "sideload": "Installation läuft", + "sideload-instructions-1": "Der Bildschirm zeigt den Fortschritt an … ", + "sideload-instructions-2": "Dies kann einige Minuten dauern, bitte übe dich etwas in Geduld.", + "sideload-instructions-3": "Sobald die Installation abgeschlossen ist, kehrt das Telefon zum Hauptbildschirm zurück.", + "sideload-instructions-4": "Erst dann kannst du auf Next klicken.", + "sign-up-free": "Kostenlos registrieren", + "skip": "Überspringen", + "start": "Start", + "this-might-take-some-time-please-be-patient": "Das könnte einige Zeit dauern, bitte habe etwas Geduld", + "unlocking-instructions-1": "Dein Telefon fragt nach dem Entsperren. Wähle unlock bootloader aus, indem du Lautstärke lauter und Lautstärke leiser zum Navigieren benutzt.", + "unlocking-instructions-2": "Wenn sich das Gerät nicht automatisch neu startet, starte es neu.", + "unlocking-instructions-3": "Da das Gerät vollständig zurückgesetzt wird, musst du USB-Debugging erneut aktivieren.", + "unlocking-instructions-4": "Überspringe die Einrichtung auf dem Telefon und klicke auf Weiter", + "very-dissatisfied": "Sehr unzufrieden", + "very-satisfied": "Sehr zufrieden", + "format-device-instructions-7": "7. Auf den Rückwärts-Pfeil tippen, dann auf Weiter", + "locking-instructions-3": "Dann auf Weiter tippen", + "unlocking-instructions-2-a": "Das Gerät wird neu starten. Warte, bis der Bootloader-Bildschirm erneut erscheint, bevor du zum nächsten Schritt übergehst.", + "unlocking-instructions-5": "Dann auf Weiter tippen", + "unlocking-instructions-1-a": "Benutze den Ausschalten zum Bestätigen.", + "android-version-not-supported-title": "Ihre Android-Version {{android-version}} wird nicht unterstützt", + "android-version-not-supported": "Android-Version veraltet", + "android-version-not-supported-instructions": "Aktualisieren Sie Ihr System auf die erforderliche Minimal-Version {{android-version-required}}", + "go-to-apply-update-instructions-4": "Bemerkung: Für den nächsten Schritt muss sich dein Browser wahrscheinlich mit dem Telefon neu verbinden. Wenn ein Fenster aufscheint, wähle bitte dein Gerät aus der Liste aus.", + "installing": "Wird installiert" } diff --git a/app/public/assets/languages/en.json b/app/public/assets/languages/en.json index 905caaa94754f186678e0cf69106b1fe5bdf68d4..4f946b802a74c3a0a8491d1b95ab5930829e2c55 100644 --- a/app/public/assets/languages/en.json +++ b/app/public/assets/languages/en.json @@ -1,114 +1,114 @@ { - "_err_01": "Error", - "_err_02": "Your browser does not support Web USB", - "Ex 1: before installing /e/OS Android 12, you should update to the latest stock Android 12": "Ex 1: before installing /e/OS Android 12, you should update to the latest stock Android 12", - "Ex 2: or if you're installing /e/OS Android 11, make sure to update to the latest stock Android 11": "Ex 2: or if you're installing /e/OS Android 11, make sure to update to the latest stock Android 11", - "Ex 3: similarly, if you're installing /e/OS Android 11, it should be the latest stock Android 10": "Ex 3: similarly, if you're installing /e/OS Android 11, it should be the latest stock Android 10", - "activate-developer-options": "Activate Developer options", - "activate-developer-options-instructions-1": "1. Open the settings menu and type ‘build’ in the search bar.", - "activate-developer-options-instructions-2": "2. On the next screen, find ‘Build number’ and tap 7 times on it.", - "activate-oem-unlock": "OEM Unlock", - "activate-oem-unlock-instruction": "If you have not already done so, unlock the OEM function", - "activate-usb-debugging": "Activate USB Debugging", - "activate-usb-debugging-instructions-1": "1. Go back to the settings menu and type ‘USB debugging’ in the search bar.", - "activate-usb-debugging-instructions-2": "2. At this point you should be in the ‘Developer options screen’. Now tap on ’USB debugging’ to activate it (on some devices it is called ’Android Debugging’).", - "android-version-not-supported": "Android version outdated", - "android-version-not-supported-instructions": "Update your system to the minimum version required {{android-version-required}}", - "android-version-not-supported-title": "Your Android version {{android-version}} is not supported", - "bootloader-to-recovery-manually": "Bootloader to recovery", - "bootloader-to-recovery-manually-instructions": "Now we will restart your device in Recovery mode. Please, follow the steps below:", - "bootloader-to-recovery-manually-instructions-1": "1. In the bootloader, select Recovery Mode by using Volume Up and Volume Down to navigate", - "bootloader-to-recovery-manually-instructions-2": "2. Press Power to confirm", - "bootloader-to-recovery-manually-instructions-3": "3. Wait for your phone to start in recovery", - "check-update-android-version": "Check & update your Android version", - "check-update-android-version-caution": "Caution: before proceeding with the installation, verify if the latest Android firmware is available for your device.", - "connect": "Connect", - "connect-bootloader": "Bootloader connection", - "connect-bootloader-instructions-1": "Your phone will now reboot in bootloader mode", - "connect-bootloader-instructions-2": "When your phone is on, connect your phone in bootloader mode by clicking on the button below", - "connect-your-phone": "Connect your phone", - "connect-your-phone-instructions": "Connect your phone to your computer with a USB cable. We will automatically detect your phone to install /e/OS.", - "connect-your-phone-instructions-notes": "Note: ’USB debugging’ is required for automatic device detection to work. If you haven't enabled it yet, we will help you out in the next steps.", - "device-detection": "Device detection", - "device-detection-detected": "A device has been detected.", - "device-detection-instructions-1": "We'll now connect your phone to the browser. When this pop-up appears, select your telephone from the list.", - "device-detection-instructions-2": "A pop-up window will then appeared on your phone. You will have to check always allow from this computer before pressing ok.", - "device-detection-instructions-3": "Click on the button below to start the connection", - "device-model-not-supported": "Device model not supported", - "device-model-not-supported-instructions": "you can't install /e/OS using this tool", - "device-model-not-supported-title": "Your phone {{product-name}} is not compatible", - "dissatisfied": "Dissatisfied", - "donate": "Donate", - "enable-usb-file-transfer": "Enable USB file transfer", - "enable-usb-file-transfer-instructions-1": "Still inside the ‘Developer options’, scroll down to find ’Default USB configuration’ and tap on it.", - "enable-usb-file-transfer-instructions-2": "Now select the ’File Transfer’ option (on some devices it is called 'MTP mode (media transfer protocol)').", - "format-device": "Format the device", - "format-device-instructions-1": "1. Select Factory reset", - "format-device-instructions-2": "2. Select Format data / Factory reset option", - "format-device-instructions-3": "3. Next screen will display a warning that this action cannot be undone", - "format-device-instructions-4": "4. Select Format data to proceed", - "format-device-instructions-5": "5. Wait the format process will complete", - "format-device-instructions-6": "6. Display will now return to the Factory Reset screen", - "format-device-instructions-7": "7. Press Back arrow, and click Next", - "go-to-apply-update": "Almost there!", - "go-to-apply-update-instructions-1": "1. Select Apply Update.", - "go-to-apply-update-instructions-2": "2. And then Apply update from adb.", - "go-to-apply-update-instructions-3": "3. The device is now in sideload mode, you're ready for the next step.", - "go-to-apply-update-instructions-4": "Note: For the next step, your browser may need to reconnect your phone. If a pop-up window appears, select your phone from the list.", - "help": "Help", - "i-already-have-an-account": "I already have an account", - "i-m-ready": "I'm ready !", - "installation-complete": "The installation is complete!", - "installation-complete-instructions-1": "Congrats! While your phone is booting, you should see the logo below. This takes time, please be patient.", - "installation-complete-instructions-2": "Tip: follow the instructions on your phone to set up your device. You can now add your files back to your phone.", - "installing": "Installing", - "let-s-get-started": "Let's get started", - "let-s-get-started-instruction-1": "The complete installation process requires around 1 hour. Be\n patient!", - "let-s-get-started-instruction-2": "You'll need to have at least 6GB of free space in your computer to\n download and install /e/OS. Make sure you have enough free disk space.", - "let-s-get-started-instruction-3": "Before installing /e/OS, ensure your phone has at least 50% battery", - "let-s-get-started-instruction-4": "All data will be erased from your smartphone during the installation,\n so we recommend that you back up your data.", - "let-s-get-started-instruction-5": "A working USB data cable is required. Power cables don't transfer date\n and will not work! We recommend USB 3.x or newer.", - "let-s-get-started-instruction-title-1": "1. Free up some time", - "let-s-get-started-instruction-title-2": "2. Free up some disk space", - "let-s-get-started-instruction-title-3": "3. Charge your phone", - "let-s-get-started-instruction-title-4": "4. Back up your data", - "let-s-get-started-instruction-title-5": "5. Grab a USB data cable", - "locking": "Locking", - "locking-instructions-1": "The phone is asking for the bootloader to be locked. Select lock bootloader", - "locking-instructions-2": "The device will automatically reboot.", - "locking-instructions-3": "Then click Next", - "locking-instructions-4": "On the phone, press the start button.", - "locking-instructions-1-teracube": "The phone is asking for the bootloader to be locked. Select lock bootloader by using Volume Up button.", - "locking-instructions-1-teracube-a": "Then click Next.", - "murena-workspace-account": "Murena Workspace account", - "murena-workspace-account-instructions": "Keep your data safe and sync this device with your personal Murena Workspace account. 1GB free and paid plans available for more storage.", - "navigator-detection": "Navigator detection", - "navigator-not-supported": "Your navigator is not supported", - "navigator-not-supported-instructions": "You can use the following browsers", - "neutral": "Neutral", - "next": "Next", - "ready-to-install-e-os": "You're now ready to install /e/OS.", - "recovery-to-bootloader": "Recovery to Bootloader", - "recovery-to-bootloader-instructions": "In the main menu", - "recovery-to-bootloader-instructions-1": "1. Select Advanced", - "recovery-to-bootloader-instructions-2": "2. Select Reboot to bootloader", - "satisfied": "Satisfied", - "send-to-e-team": "Send to Murena team", - "sideload": "Installation in progress", - "sideload-instructions-3": "Once the installation is finished, the phone returns to the main recovery screen.", - "sign-up-free": "Sign up FREE", - "skip": "Skip", - "start": "Start", - "this-might-take-some-time-please-be-patient": "This might take some time please be patient", - "unlocking-instructions-1": "The phone is asking for the bootloader to be unlocked. Select unlock bootloader by using Volume Up and Volume Down to navigate.", - "unlocking-instructions-1-a": "Use the button Power to confirm.", - "unlocking-instructions-1-b": "The phone is asking for the bootloader to be unlocked. Select unlock bootloader by using Volume Up button.", - "unlocking-instructions-2": "The device will automatically reboot.", - "unlocking-instructions-2-a": "Wait until the bootloader screen is visible again before going to the next step", - "unlocking-instructions-3": "Since the device resets completely, you will need to re-enable USB debugging.", - "unlocking-instructions-4": "Pass the setup on the phone and click on next", - "unlocking-instructions-1-teracube": "The phone is asking for the bootloader to be unlocked. Select unlock bootloader by using Volume Up button.", - "unlocking-instructions-1-teracube-a": "Then click Next.", - "very-dissatisfied": "Very Dissatisfied", - "very-satisfied": "Very Satisfied" + "_err_01": "Error", + "_err_02": "Your browser does not support Web USB", + "Ex 1: before installing /e/OS Android 12, you should update to the latest stock Android 12": "Ex 1: before installing /e/OS Android 12, you should update to the latest stock Android 12", + "Ex 2: or if you're installing /e/OS Android 11, make sure to update to the latest stock Android 11": "Ex 2: or if you're installing /e/OS Android 11, make sure to update to the latest stock Android 11", + "Ex 3: similarly, if you're installing /e/OS Android 11, it should be the latest stock Android 10": "Ex 3: similarly, if you're installing /e/OS Android 11, it should be the latest stock Android 10", + "activate-developer-options": "Activate Developer options", + "activate-developer-options-instructions-1": "1. Open the settings menu and type ‘build’ in the search bar.", + "activate-developer-options-instructions-2": "2. On the next screen, find ‘Build number’ and tap 7 times on it.", + "activate-oem-unlock": "OEM Unlock", + "activate-oem-unlock-instruction": "If you have not already done so, unlock the OEM function", + "activate-usb-debugging": "Activate USB Debugging", + "activate-usb-debugging-instructions-1": "1. Go back to the settings menu and type ‘USB debugging’ in the search bar.", + "activate-usb-debugging-instructions-2": "2. At this point you should be in the ‘Developer options screen’. Now tap on ’USB debugging’ to activate it (on some devices it is called ’Android Debugging’).", + "android-version-not-supported": "Android version outdated", + "android-version-not-supported-instructions": "Update your system to the minimum version required {{android-version-required}}", + "android-version-not-supported-title": "Your Android version {{android-version}} is not supported", + "bootloader-to-recovery-manually": "Bootloader to recovery", + "bootloader-to-recovery-manually-instructions": "Now we will restart your device in Recovery mode. Please, follow the steps below:", + "bootloader-to-recovery-manually-instructions-1": "1. In the bootloader, select Recovery Mode by using Volume Up and Volume Down to navigate", + "bootloader-to-recovery-manually-instructions-2": "2. Press Power to confirm", + "bootloader-to-recovery-manually-instructions-3": "3. Wait for your phone to start in recovery", + "check-update-android-version": "Check & update your Android version", + "check-update-android-version-caution": "Caution: before proceeding with the installation, verify if the latest Android firmware is available for your device.", + "connect": "Connect", + "connect-bootloader": "Bootloader connection", + "connect-bootloader-instructions-1": "Your phone will now reboot in bootloader mode", + "connect-bootloader-instructions-2": "When your phone is on, connect your phone in bootloader mode by clicking on the button below", + "connect-your-phone": "Connect your phone", + "connect-your-phone-instructions": "Connect your phone to your computer with a USB cable. We will automatically detect your phone to install /e/OS.", + "connect-your-phone-instructions-notes": "Note: ’USB debugging’ is required for automatic device detection to work. If you haven't enabled it yet, we will help you out in the next steps.", + "device-detection": "Device detection", + "device-detection-detected": "A device has been detected.", + "device-detection-instructions-1": "We'll now connect your phone to the browser. When this pop-up appears, select your telephone from the list.", + "device-detection-instructions-2": "A pop-up window will then appeared on your phone. You will have to check always allow from this computer before pressing ok.", + "device-detection-instructions-3": "Click on the button below to start the connection", + "device-model-not-supported": "Device model not supported", + "device-model-not-supported-instructions": "you can't install /e/OS using this tool", + "device-model-not-supported-title": "Your phone {{product-name}} is not compatible", + "dissatisfied": "Dissatisfied", + "donate": "Donate", + "enable-usb-file-transfer": "Enable USB file transfer", + "enable-usb-file-transfer-instructions-1": "Still inside the ‘Developer options’, scroll down to find ’Default USB configuration’ and tap on it.", + "enable-usb-file-transfer-instructions-2": "Now select the ’File Transfer’ option (on some devices it is called 'MTP mode (media transfer protocol)').", + "format-device": "Format the device", + "format-device-instructions-1": "1. Select Factory reset", + "format-device-instructions-2": "2. Select Format data / Factory reset option", + "format-device-instructions-3": "3. Next screen will display a warning that this action cannot be undone", + "format-device-instructions-4": "4. Select Format data to proceed", + "format-device-instructions-5": "5. Wait the format process will complete", + "format-device-instructions-6": "6. Display will now return to the Factory Reset screen", + "format-device-instructions-7": "7. Press Back arrow, and click Next", + "go-to-apply-update": "Almost there!", + "go-to-apply-update-instructions-1": "1. Select Apply Update.", + "go-to-apply-update-instructions-2": "2. And then Apply update from adb.", + "go-to-apply-update-instructions-3": "3. The device is now in sideload mode, you're ready for the next step.", + "go-to-apply-update-instructions-4": "Note: For the next step, your browser may need to reconnect your phone. If a pop-up window appears, select your phone from the list.", + "help": "Help", + "i-already-have-an-account": "I already have an account", + "i-m-ready": "I'm ready !", + "installation-complete": "The installation is complete!", + "installation-complete-instructions-1": "Congrats! While your phone is booting, you should see the logo below. This takes time, please be patient.", + "installation-complete-instructions-2": "Tip: follow the instructions on your phone to set up your device. You can now add your files back to your phone.", + "installing": "Installing", + "let-s-get-started": "Let's get started", + "let-s-get-started-instruction-1": "The complete installation process requires around 1 hour. Be\n patient!", + "let-s-get-started-instruction-2": "You'll need to have at least 6GB of free space in your computer to\n download and install /e/OS. Make sure you have enough free disk space.", + "let-s-get-started-instruction-3": "Before installing /e/OS, ensure your phone has at least 50% battery", + "let-s-get-started-instruction-4": "All data will be erased from your smartphone during the installation,\n so we recommend that you back up your data.", + "let-s-get-started-instruction-5": "A working USB data cable is required. Power cables don't transfer date\n and will not work! We recommend USB 3.x or newer.", + "let-s-get-started-instruction-title-1": "1. Free up some time", + "let-s-get-started-instruction-title-2": "2. Free up some disk space", + "let-s-get-started-instruction-title-3": "3. Charge your phone", + "let-s-get-started-instruction-title-4": "4. Back up your data", + "let-s-get-started-instruction-title-5": "5. Grab a USB data cable", + "locking": "Locking", + "locking-instructions-1": "The phone is asking for the bootloader to be locked. Select lock bootloader", + "locking-instructions-2": "The device will automatically reboot.", + "locking-instructions-3": "Then click Next", + "locking-instructions-4": "On the phone, press the start button.", + "locking-instructions-1-teracube": "The phone is asking for the bootloader to be locked. Select lock bootloader by using Volume Up button.", + "locking-instructions-1-teracube-a": "Then click Next.", + "murena-workspace-account": "Murena Workspace account", + "murena-workspace-account-instructions": "Keep your data safe and sync this device with your personal Murena Workspace account. 1GB free and paid plans available for more storage.", + "navigator-detection": "Navigator detection", + "navigator-not-supported": "Your navigator is not supported", + "navigator-not-supported-instructions": "You can use the following browsers", + "neutral": "Neutral", + "next": "Next", + "ready-to-install-e-os": "You're now ready to install /e/OS.", + "recovery-to-bootloader": "Recovery to Bootloader", + "recovery-to-bootloader-instructions": "In the main menu", + "recovery-to-bootloader-instructions-1": "1. Select Advanced", + "recovery-to-bootloader-instructions-2": "2. Select Reboot to bootloader", + "satisfied": "Satisfied", + "send-to-e-team": "Send to Murena team", + "sideload": "Installation in progress", + "sideload-instructions-3": "Once the installation is finished, the phone returns to the main recovery screen.", + "sign-up-free": "Sign up FREE", + "skip": "Skip", + "start": "Start", + "this-might-take-some-time-please-be-patient": "This might take some time please be patient", + "unlocking-instructions-1": "The phone is asking for the bootloader to be unlocked. Select unlock bootloader by using Volume Up and Volume Down to navigate.", + "unlocking-instructions-1-a": "Use the button Power to confirm.", + "unlocking-instructions-1-b": "The phone is asking for the bootloader to be unlocked. Select unlock bootloader by using Volume Up button.", + "unlocking-instructions-2": "The device will automatically reboot.", + "unlocking-instructions-2-a": "Wait until the bootloader screen is visible again before going to the next step", + "unlocking-instructions-3": "Since the device resets completely, you will need to re-enable USB debugging.", + "unlocking-instructions-4": "Pass the setup on the phone and click on next", + "unlocking-instructions-1-teracube": "The phone is asking for the bootloader to be unlocked. Select unlock bootloader by using Volume Up button.", + "unlocking-instructions-1-teracube-a": "Then click Next.", + "very-dissatisfied": "Very Dissatisfied", + "very-satisfied": "Very Satisfied" } diff --git a/app/public/assets/languages/es.json b/app/public/assets/languages/es.json index e6a54f0051abc84ba812a8ba952d9521b59afb4c..ada7d854e2bc8807742a48e606ade670862e352c 100644 --- a/app/public/assets/languages/es.json +++ b/app/public/assets/languages/es.json @@ -1,110 +1,110 @@ { - "Ex 1: before installing /e/OS Android 12, you should update to the latest stock Android 12": "Ej 1: antes de instalar /e/OS Android 12, debes actualizar a la última versión stock de Android 12", - "Ex 2: or if you're installing /e/OS Android 11, make sure to update to the latest stock Android 11": "Ej 2: o si estás instalando /e/OS Android 11, asegúrate de actualizar a la última versión stock de Android 11", - "Ex 3: similarly, if you're installing /e/OS Android 11, it should be the latest stock Android 10": "Ej 3: similarmente, si estás instalando /e/OS Android 11, debes tener la última versión stock de Android 10", - "activate-developer-options": "Activar opciones de desarrollador", - "activate-developer-options-instructions-1": "1. Abre el menú de configuración y escribe 'versión' en la barra de búsqueda.", - "activate-developer-options-instructions-2": "2. En la siguiente pantalla, busca 'Número de compilación' y toca 7 veces sobre él.", - "activate-usb-debugging": "Activar depuración USB", - "activate-usb-debugging-instructions-1": "1. Regresa al menú de configuración y escribe 'depuración USB' en la barra de búsqueda.", - "activate-usb-debugging-instructions-2": "2. En este punto deberías estar en la pantalla 'Opciones de desarrollador'. Ahora toca en 'Depuración USB' para activarla (en algunos dispositivos se llama 'Depuración de Android').", - "bootloader-to-recovery-manually": "Gestor de arranque a recovery", - "bootloader-to-recovery-manually-instructions": "Ahora reiniciaremos tu dispositivo en modo Recovery. Por favor, sigue los siguientes pasos:", - "bootloader-to-recovery-manually-instructions-1": "1. En el gestor de arranque, selecciona recovery usando Subir volumen y Bajar volumen para navegar", - "bootloader-to-recovery-manually-instructions-2": "2. Presiona Encender para confirmar", - "check-update-android-version": "Verifica y actualiza tu versión de Android", - "check-update-android-version-caution": "Precaución: antes de proceder con la instalación, verifica si el último firmware de Android está disponible para tu dispositivo.", - "connect": "Conectar", - "connect-bootloader": "Conexión del gestor de arranque", - "connect-bootloader-instructions-1": "Tu teléfono se reiniciará ahora en modo gestor de arranque", - "connect-bootloader-instructions-2": "Si tu teléfono esté encendido, conéctalo en modo gestor de arranque tocando en el botón abajo", - "connect-your-phone": "Conecta tu teléfono", - "connect-your-phone-instructions": "Conecta el teléfono a tu computadora con un cable USB. Detectaremos tu teléfono automáticamente para instalar /e/OS.", - "connect-your-phone-instructions-notes": "Nota: la 'depuración USB' se requiere para que la detección automática funcione. Si aún no la has habilitado, te ayudaremos en los siguientes pasos.", - "device-detection": "Detección del dispositivo", - "device-detection-detected": "Se ha detectado un dispositivo.", - "device-detection-instructions-1": "Ahora conectaremos tu teléfono al navegador. Cuando aparezca esta ventana, selecciona tu teléfono de la lista.", - "device-detection-instructions-2": "Aparecerá una ventana emergente en tu teléfono. Marca siempre permitir desde esta computadora antes de presionar OK.", - "device-detection-instructions-3": "Toca el botón de abajo para iniciar la conexión", - "device-model-not-supported": "Dispositivo no compatible", - "device-model-not-supported-instructions": "no puedes instalar /e/OS usando esta herramienta", - "device-model-not-supported-title": "Tu teléfono {{product-name}} no es compatible", - "dissatisfied": "Insatisfecho", - "donate": "Donar", - "enable-usb-file-transfer": "Activar transferencia de archivos USB", - "enable-usb-file-transfer-instructions-1": "Dentro de 'Opciones de desarrollador', desliza hacia abajo hasta encontrar 'Configuración USB predeterminada' y tócala.", - "enable-usb-file-transfer-instructions-2": "Ahora selecciona la opción 'Transferencia de archivos' (también llamada 'modo MTP (protocolo de transferencia de medios)').", - "format-device": "Formatear dispositivo", - "format-device-instructions-1": "1. Selecciona Reinicio de fábrica", - "format-device-instructions-2": "2. Selecciona Formatear datos / Reinicio de fábrica", - "format-device-instructions-3": "3. La siguiente pantalla mostrará una advertencia que esta acción no se puede deshacer", - "format-device-instructions-4": "4. Selecciona Formatear datos para continuar", - "format-device-instructions-5": "5. Espera que finalice el proceso de formateo", - "format-device-instructions-6": "6. La pantalla ahora volverá a la página de Reinicio de fábrica", - "go-to-apply-update": "¡Casi terminas!", - "go-to-apply-update-instructions-1": "1. Selecciona Aplicar actualización.", - "go-to-apply-update-instructions-2": "2. Y luego Aplicar actualización desde adb.", - "go-to-apply-update-instructions-3": "3. El dispositivo ahora está en modo sideload, listo para el siguiente paso.", - "help": "Ayuda", - "help-us-improve-the-tool": "Ayúdanos a mejorar esta herramienta", - "help-us-improve-the-tool-instructions-1": "Por favor, califica tu experiencia con el /e/OS Installer.", - "help-us-improve-the-tool-instructions-2": "¿Tienes sugerencias cómo podríamos mejorar este software?", - "i-already-have-an-account": "Ya tengo una cuenta", - "i-m-ready": "¡Estoy listo!", - "installation-complete": "¡La instalación está completa!", - "installation-complete-instructions-1": "¡Felicidades! Mientras tu teléfono se inicia, deberías ver el siguiente logo. Esto tarda un poco, ten paciencia.", - "installation-complete-instructions-2": "Consejo: sigue las instrucciones en tu teléfono para configurarlo. Ahora puedes volver a agregar tus archivos al teléfono.", - "let-s-get-started": "Empecemos", - "let-s-get-started-instruction-1": "El proceso completo de instalación tarda alrededor de 1 hora. ¡Ten \npaciencia!", - "let-s-get-started-instruction-2": "Necesitarás al menos 6GB de espacio libre en tu computadora para descargar e instalar /e/OS. Asegúrate de tener suficiente espacio libre en tu disco.", - "let-s-get-started-instruction-3": "Antes de instalar /e/OS, asegúrate que tu teléfono este cargado al menos 50%", - "let-s-get-started-instruction-4": "Todos los datos en tu teléfono se borrarán durante la instalación, por lo que te recomendamos que hagas una copia de seguridad.", - "let-s-get-started-instruction-5": "Se requiere un cable USB en buen estado. ¡Los cables de recargue no transfieren datos y no funcionarán! Recomendamos USB 3.x o más nuevo.", - "let-s-get-started-instruction-title-1": "1. Tómate algo de tiempo", - "let-s-get-started-instruction-title-2": "2. Libera espacio en tu disco", - "let-s-get-started-instruction-title-3": "3. Carga tu teléfono", - "let-s-get-started-instruction-title-4": "4. Haz una copia de seguridad de tus datos", - "let-s-get-started-instruction-title-5": "5. Toma un cable de datos USB", - "locking": "Bloqueo", - "locking-instructions-1": "Tu teléfono está pidiendo un desbloqueo. Selecciona lock bootloader", - "locking-instructions-2": "Si tu dispositivo no se reinicia automáticamente, reinícialo", - "murena-workspace-account": "Cuenta Murena Workspace", - "murena-workspace-account-instructions": "Mantén tus datos seguros y sincroniza este dispositivo con tu cuenta personal de Murena Workspace. 1GB gratis y planes de pago disponibles para más almacenamiento.", - "navigator-detection": "Detectando el navegador", - "navigator-not-supported": "Tu navegador no es compatible", - "navigator-not-supported-instructions": "Puedes usar los siguientes navegadores", - "neutral": "Neutral", - "next": "Siguiente", - "ready-to-install-e-os": "Estás listo para instalar /e/OS.", - "recovery-to-bootloader": "Recovery a Gestor de arranque", - "recovery-to-bootloader-instructions": "En el menú principal", - "recovery-to-bootloader-instructions-1": "1. Selecciona Avanzado", - "recovery-to-bootloader-instructions-2": "2. Selecciona Reiniciar en gestor de arranque", - "satisfied": "Satisfecho", - "send-to-e-team": "Enviar al equipo Murena", - "sideload": "Instalación en progreso", - "sideload-instructions-1": "La pantalla mostrará el progreso... ", - "sideload-instructions-2": "Esto puede tardar varios minutos, dale algo de tiempo.", - "sideload-instructions-3": "Una vez que la instalación concluya, el teléfono regresará a la pantalla principal.", - "sideload-instructions-4": "Solo entonces puedes hacer clic en Siguiente.", - "sign-up-free": "Regístrate GRATIS", - "skip": "Saltar", - "start": "Comenzar", - "this-might-take-some-time-please-be-patient": "Esto puede tomar algo de tiempo, ten paciencia", - "unlocking-instructions-1": "El teléfono solicita un desbloqueo. Selecciona desbloquear gestor de arranque usando Volumen arriba y Volumen abajo para navegar.", - "unlocking-instructions-2": "Si tu dispositivo no se reinicia automáticamente, reinícialo.", - "unlocking-instructions-3": "Como el dispositivo se reinicia completamente, necesitarás reactivar la depuración USB.", - "unlocking-instructions-4": "Después de la configuración haz clic en siguiente", - "very-dissatisfied": "Muy insatisfecho", - "very-satisfied": "Muy satisfecho", - "format-device-instructions-7": "7. Pulsa la flecha Atrás y haz clic en Siguiente", - "locking-instructions-3": "A continuación, haz clic en Siguiente", - "android-version-not-supported": "Versión de Android no actualizada", - "android-version-not-supported-instructions": "Actualiza tu sistema a la versión mínima requerida {{android-version-required}}", - "android-version-not-supported-title": "Tu versión de Android {{android-version}} no es compatible", - "bootloader-to-recovery-manually-instructions-3": "3. Espera que tu teléfono se reinicie en modo recuperación", - "go-to-apply-update-instructions-4": "Nota: Para el siguiente paso, es posible que tu navegador necesite volver a conectarse con tu teléfono. Si aparece una ventana emergente, selecciona tu teléfono de la lista.", - "installing": "Instalando", - "unlocking-instructions-1-a": "Usa el botón Encender para confirmar.", - "unlocking-instructions-2-a": "Tu dispositivo se reiniciará. Espera hasta que la pantalla del gestor de arranque sea visible otra vez antes de ir al siguiente paso" + "Ex 1: before installing /e/OS Android 12, you should update to the latest stock Android 12": "Ej 1: antes de instalar /e/OS Android 12, debes actualizar a la última versión stock de Android 12", + "Ex 2: or if you're installing /e/OS Android 11, make sure to update to the latest stock Android 11": "Ej 2: o si estás instalando /e/OS Android 11, asegúrate de actualizar a la última versión stock de Android 11", + "Ex 3: similarly, if you're installing /e/OS Android 11, it should be the latest stock Android 10": "Ej 3: similarmente, si estás instalando /e/OS Android 11, debes tener la última versión stock de Android 10", + "activate-developer-options": "Activar opciones de desarrollador", + "activate-developer-options-instructions-1": "1. Abre el menú de configuración y escribe 'versión' en la barra de búsqueda.", + "activate-developer-options-instructions-2": "2. En la siguiente pantalla, busca 'Número de compilación' y toca 7 veces sobre él.", + "activate-usb-debugging": "Activar depuración USB", + "activate-usb-debugging-instructions-1": "1. Regresa al menú de configuración y escribe 'depuración USB' en la barra de búsqueda.", + "activate-usb-debugging-instructions-2": "2. En este punto deberías estar en la pantalla 'Opciones de desarrollador'. Ahora toca en 'Depuración USB' para activarla (en algunos dispositivos se llama 'Depuración de Android').", + "bootloader-to-recovery-manually": "Gestor de arranque a recovery", + "bootloader-to-recovery-manually-instructions": "Ahora reiniciaremos tu dispositivo en modo Recovery. Por favor, sigue los siguientes pasos:", + "bootloader-to-recovery-manually-instructions-1": "1. En el gestor de arranque, selecciona recovery usando Subir volumen y Bajar volumen para navegar", + "bootloader-to-recovery-manually-instructions-2": "2. Presiona Encender para confirmar", + "check-update-android-version": "Verifica y actualiza tu versión de Android", + "check-update-android-version-caution": "Precaución: antes de proceder con la instalación, verifica si el último firmware de Android está disponible para tu dispositivo.", + "connect": "Conectar", + "connect-bootloader": "Conexión del gestor de arranque", + "connect-bootloader-instructions-1": "Tu teléfono se reiniciará ahora en modo gestor de arranque", + "connect-bootloader-instructions-2": "Si tu teléfono esté encendido, conéctalo en modo gestor de arranque tocando en el botón abajo", + "connect-your-phone": "Conecta tu teléfono", + "connect-your-phone-instructions": "Conecta el teléfono a tu computadora con un cable USB. Detectaremos tu teléfono automáticamente para instalar /e/OS.", + "connect-your-phone-instructions-notes": "Nota: la 'depuración USB' se requiere para que la detección automática funcione. Si aún no la has habilitado, te ayudaremos en los siguientes pasos.", + "device-detection": "Detección del dispositivo", + "device-detection-detected": "Se ha detectado un dispositivo.", + "device-detection-instructions-1": "Ahora conectaremos tu teléfono al navegador. Cuando aparezca esta ventana, selecciona tu teléfono de la lista.", + "device-detection-instructions-2": "Aparecerá una ventana emergente en tu teléfono. Marca siempre permitir desde esta computadora antes de presionar OK.", + "device-detection-instructions-3": "Toca el botón de abajo para iniciar la conexión", + "device-model-not-supported": "Dispositivo no compatible", + "device-model-not-supported-instructions": "no puedes instalar /e/OS usando esta herramienta", + "device-model-not-supported-title": "Tu teléfono {{product-name}} no es compatible", + "dissatisfied": "Insatisfecho", + "donate": "Donar", + "enable-usb-file-transfer": "Activar transferencia de archivos USB", + "enable-usb-file-transfer-instructions-1": "Dentro de 'Opciones de desarrollador', desliza hacia abajo hasta encontrar 'Configuración USB predeterminada' y tócala.", + "enable-usb-file-transfer-instructions-2": "Ahora selecciona la opción 'Transferencia de archivos' (también llamada 'modo MTP (protocolo de transferencia de medios)').", + "format-device": "Formatear dispositivo", + "format-device-instructions-1": "1. Selecciona Reinicio de fábrica", + "format-device-instructions-2": "2. Selecciona Formatear datos / Reinicio de fábrica", + "format-device-instructions-3": "3. La siguiente pantalla mostrará una advertencia que esta acción no se puede deshacer", + "format-device-instructions-4": "4. Selecciona Formatear datos para continuar", + "format-device-instructions-5": "5. Espera que finalice el proceso de formateo", + "format-device-instructions-6": "6. La pantalla ahora volverá a la página de Reinicio de fábrica", + "go-to-apply-update": "¡Casi terminas!", + "go-to-apply-update-instructions-1": "1. Selecciona Aplicar actualización.", + "go-to-apply-update-instructions-2": "2. Y luego Aplicar actualización desde adb.", + "go-to-apply-update-instructions-3": "3. El dispositivo ahora está en modo sideload, listo para el siguiente paso.", + "help": "Ayuda", + "help-us-improve-the-tool": "Ayúdanos a mejorar esta herramienta", + "help-us-improve-the-tool-instructions-1": "Por favor, califica tu experiencia con el /e/OS Installer.", + "help-us-improve-the-tool-instructions-2": "¿Tienes sugerencias cómo podríamos mejorar este software?", + "i-already-have-an-account": "Ya tengo una cuenta", + "i-m-ready": "¡Estoy listo!", + "installation-complete": "¡La instalación está completa!", + "installation-complete-instructions-1": "¡Felicidades! Mientras tu teléfono se inicia, deberías ver el siguiente logo. Esto tarda un poco, ten paciencia.", + "installation-complete-instructions-2": "Consejo: sigue las instrucciones en tu teléfono para configurarlo. Ahora puedes volver a agregar tus archivos al teléfono.", + "let-s-get-started": "Empecemos", + "let-s-get-started-instruction-1": "El proceso completo de instalación tarda alrededor de 1 hora. ¡Ten \npaciencia!", + "let-s-get-started-instruction-2": "Necesitarás al menos 6GB de espacio libre en tu computadora para descargar e instalar /e/OS. Asegúrate de tener suficiente espacio libre en tu disco.", + "let-s-get-started-instruction-3": "Antes de instalar /e/OS, asegúrate que tu teléfono este cargado al menos 50%", + "let-s-get-started-instruction-4": "Todos los datos en tu teléfono se borrarán durante la instalación, por lo que te recomendamos que hagas una copia de seguridad.", + "let-s-get-started-instruction-5": "Se requiere un cable USB en buen estado. ¡Los cables de recargue no transfieren datos y no funcionarán! Recomendamos USB 3.x o más nuevo.", + "let-s-get-started-instruction-title-1": "1. Tómate algo de tiempo", + "let-s-get-started-instruction-title-2": "2. Libera espacio en tu disco", + "let-s-get-started-instruction-title-3": "3. Carga tu teléfono", + "let-s-get-started-instruction-title-4": "4. Haz una copia de seguridad de tus datos", + "let-s-get-started-instruction-title-5": "5. Toma un cable de datos USB", + "locking": "Bloqueo", + "locking-instructions-1": "Tu teléfono está pidiendo un desbloqueo. Selecciona lock bootloader", + "locking-instructions-2": "Si tu dispositivo no se reinicia automáticamente, reinícialo", + "murena-workspace-account": "Cuenta Murena Workspace", + "murena-workspace-account-instructions": "Mantén tus datos seguros y sincroniza este dispositivo con tu cuenta personal de Murena Workspace. 1GB gratis y planes de pago disponibles para más almacenamiento.", + "navigator-detection": "Detectando el navegador", + "navigator-not-supported": "Tu navegador no es compatible", + "navigator-not-supported-instructions": "Puedes usar los siguientes navegadores", + "neutral": "Neutral", + "next": "Siguiente", + "ready-to-install-e-os": "Estás listo para instalar /e/OS.", + "recovery-to-bootloader": "Recovery a Gestor de arranque", + "recovery-to-bootloader-instructions": "En el menú principal", + "recovery-to-bootloader-instructions-1": "1. Selecciona Avanzado", + "recovery-to-bootloader-instructions-2": "2. Selecciona Reiniciar en gestor de arranque", + "satisfied": "Satisfecho", + "send-to-e-team": "Enviar al equipo Murena", + "sideload": "Instalación en progreso", + "sideload-instructions-1": "La pantalla mostrará el progreso... ", + "sideload-instructions-2": "Esto puede tardar varios minutos, dale algo de tiempo.", + "sideload-instructions-3": "Una vez que la instalación concluya, el teléfono regresará a la pantalla principal.", + "sideload-instructions-4": "Solo entonces puedes hacer clic en Siguiente.", + "sign-up-free": "Regístrate GRATIS", + "skip": "Saltar", + "start": "Comenzar", + "this-might-take-some-time-please-be-patient": "Esto puede tomar algo de tiempo, ten paciencia", + "unlocking-instructions-1": "El teléfono solicita un desbloqueo. Selecciona desbloquear gestor de arranque usando Volumen arriba y Volumen abajo para navegar.", + "unlocking-instructions-2": "Si tu dispositivo no se reinicia automáticamente, reinícialo.", + "unlocking-instructions-3": "Como el dispositivo se reinicia completamente, necesitarás reactivar la depuración USB.", + "unlocking-instructions-4": "Después de la configuración haz clic en siguiente", + "very-dissatisfied": "Muy insatisfecho", + "very-satisfied": "Muy satisfecho", + "format-device-instructions-7": "7. Pulsa la flecha Atrás y haz clic en Siguiente", + "locking-instructions-3": "A continuación, haz clic en Siguiente", + "android-version-not-supported": "Versión de Android no actualizada", + "android-version-not-supported-instructions": "Actualiza tu sistema a la versión mínima requerida {{android-version-required}}", + "android-version-not-supported-title": "Tu versión de Android {{android-version}} no es compatible", + "bootloader-to-recovery-manually-instructions-3": "3. Espera que tu teléfono se reinicie en modo recuperación", + "go-to-apply-update-instructions-4": "Nota: Para el siguiente paso, es posible que tu navegador necesite volver a conectarse con tu teléfono. Si aparece una ventana emergente, selecciona tu teléfono de la lista.", + "installing": "Instalando", + "unlocking-instructions-1-a": "Usa el botón Encender para confirmar.", + "unlocking-instructions-2-a": "Tu dispositivo se reiniciará. Espera hasta que la pantalla del gestor de arranque sea visible otra vez antes de ir al siguiente paso" } diff --git a/app/public/assets/languages/fr.json b/app/public/assets/languages/fr.json index d93a0dcfe08052549ea9d09c4c927066fcc61366..7cf0d56c2e6d97026388248b0c8ca56ef5fe62d5 100644 --- a/app/public/assets/languages/fr.json +++ b/app/public/assets/languages/fr.json @@ -1,110 +1,110 @@ { - "_err_01": "Erreur", - "_err_02": "Votre navigateur ne supporte pas Web USB", - "Ex 1: before installing /e/OS Android 12, you should update to the latest stock Android 12": "Ex 1 : avant d'installer /e/OS Android 12, vous devez mettre à jour vers la dernière version stock d'Android 12", - "Ex 2: or if you're installing /e/OS Android 11, make sure to update to the latest stock Android 11": "Ex 2 : ou si vous installez /e/OS Android 11, assurez-vous de mettre à jour vers la dernière version stock d'Android 11", - "Ex 3: similarly, if you're installing /e/OS Android 11, it should be the latest stock Android 10": "Ex 3 : de même, si vous installez /e/OS Android 11, il doit s'agir de la dernière version stock d'Android 10", - "activate-developer-options": "Activer les options pour les développeurs", - "activate-developer-options-instructions-1": "1. Ouvrez le menu des paramètres et tapez 'build' dans la barre de recherche.", - "activate-developer-options-instructions-2": "2. Sur l'écran suivant, trouvez 'Numéro de build' et appuyez dessus 7 fois.", - "activate-oem-unlock":"OEM unlock", - "activate-oem-unlock-instruction":"Si ce n'est pas déjà le cas, déverrouillez la fonction OEM", - "activate-usb-debugging": "Activer le débogage USB", - "activate-usb-debugging-instructions-1": "Retournez au menu des paramètres et tapez 'débogage USB' dans la barre de recherche.", - "activate-usb-debugging-instructions-2": "À ce stade, vous devriez être dans l'écran 'Options pour les développeurs'. Appuyez maintenant sur 'Débogage USB' pour l'activer (sur certains appareils, cela s'appelle 'Débogage Android').", - "bootloader-to-recovery-manually": "Bootloader à recovery", - "bootloader-to-recovery-manually-instructions": "Nous allons maintenant redémarrer votre appareil en mode Recovery. Veuillez suivre les étapes ci-dessous :", - "bootloader-to-recovery-manually-instructions-1": "1. Dans le bootloader, sélectionnez recovery en utilisant Volume Haut et Volume Bas pour naviguer", - "bootloader-to-recovery-manually-instructions-2": "2. Appuyez sur Power pour confirmer", - "bootloader-to-recovery-manually-instructions-3": "3. Attendez que votre téléphone démarre en recovery", - "check-update-android-version": "Vérifiez et mettez à jour votre version d'Android", - "check-update-android-version-caution": "Attention : avant de procéder à l'installation, vérifiez si le dernier firmware Android est disponible pour votre appareil.", - "connect": "Connecter", - "connect-bootloader": "Connexion au bootloader", - "connect-bootloader-instructions-1": "Votre téléphone va maintenant redémarrer en mode bootloader", - "connect-bootloader-instructions-2": "Lorsque votre téléphone est allumé, connectez-le en mode bootloader en cliquant sur le bouton ci-dessous", - "connect-your-phone": "Connectez votre téléphone", - "connect-your-phone-instructions": "Connectez votre téléphone à votre ordinateur avec un câble USB. Nous détecterons automatiquement votre téléphone pour installer /e/OS.", - "connect-your-phone-instructions-notes": "Remarque : le 'débogage USB' est requis pour que la détection automatique de l'appareil fonctionne. Si vous ne l'avez pas encore activé, nous vous aiderons dans les étapes suivantes.", - "device-detection": "Détection de l'appareil", - "device-detection-detected": "Un appareil a été détecté.", - "device-detection-instructions-1": "Nous allons maintenant connecter votre téléphone au navigateur. Lorsque cette fenêtre contextuelle apparaît, sélectionnez votre téléphone dans la liste.", - "device-detection-instructions-2": "Une fenêtre contextuelle apparaîtra ensuite sur votre téléphone. Vous devrez cocher toujours autoriser depuis cet ordinateur avant d'appuyer sur OK.", - "device-detection-instructions-3": "Cliquez sur le bouton ci-dessous pour commencer la connexion", - "device-model-not-supported": "Modèle d'appareil non pris en charge", - "device-model-not-supported-instructions": "vous ne pouvez pas installer /e/OS en utilisant cet outil", - "device-model-not-supported-title": "Votre téléphone {{product-name}} n'est pas compatible", - "dissatisfied": "Insatisfait", - "donate": "Faire un don", - "enable-usb-file-transfer": "Activer le transfert de fichiers USB", - "enable-usb-file-transfer-instructions-1": "Toujours dans les 'Options pour les développeurs', faites défiler vers le bas pour trouver 'Configuration USB par défaut' et appuyez dessus.", - "enable-usb-file-transfer-instructions-2": "Sélectionnez maintenant l'option 'Transfert de fichiers' (sur certains appareils, cela s'appelle 'mode MTP (Media Transfer Protocol)').", - "format-device": "Formater l'appareil", - "format-device-instructions-1": "1. Sélectionnez Réinitialisation d'usine", - "format-device-instructions-2": "2. Sélectionnez l'option Formater les données / Réinitialisation d'usine", - "format-device-instructions-3": "3. L'écran suivant affichera un avertissement que cette action ne peut pas être annulée", - "format-device-instructions-4": "4. Sélectionnez Formater les données pour continuer ou Annuler si vous souhaitez revenir en arrière", - "format-device-instructions-5": "5. Si vous avez sélectionné Formater les données, le processus de formatage se terminera", - "format-device-instructions-6": "6. L'écran reviendra maintenant à la page Réinitialisation d'usine", - "format-device-instructions-7": "7. Cliquez sur la fléche Back, puis Next", - "go-to-apply-update": "Presque terminé !", - "go-to-apply-update-instructions-1": "1. Sélectionnez Appliquer la mise à jour", - "go-to-apply-update-instructions-2": "2. Appliquer la mise à jour depuis adb", - "go-to-apply-update-instructions-3": "L'appareil est maintenant en mode sideload", - "go-to-apply-update-instructions-4": "Note: Pour l'étape suivante, il se peut que votre navigateur doive reconnecter votre téléphone. Si une fenêtre contextuelle apparaît, sélectionnez votre téléphone dans la liste.", - "help": "Aide", - "i-already-have-an-account": "J'ai déjà un compte", - "i-m-ready": "Je suis prêt !", - "installation-complete": "L'installation est terminée !", - "installation-complete-instructions-1": "Félicitations ! Pendant que votre téléphone démarre, vous devriez voir le logo ci-dessous. Cela prend du temps, soyez patient.", - "installation-complete-instructions-2": "Astuce : suivez les instructions sur votre téléphone pour configurer votre appareil. Vous pouvez maintenant ajouter vos fichiers à nouveau sur votre téléphone.", - "let-s-get-started": "Commençons", - "let-s-get-started-instruction-1": "Le processus d'installation complet prend environ 1 heure. Soyez patient !", - "let-s-get-started-instruction-2": "Vous aurez besoin d'au moins 6 Go d'espace libre sur votre ordinateur pour télécharger et installer /e/OS. Assurez-vous d'avoir suffisamment d'espace libre sur le disque.", - "let-s-get-started-instruction-3": "Avant d'installer /e/OS, assurez-vous que votre téléphone a au moins 50 % de batterie", - "let-s-get-started-instruction-4": "Toutes les données seront effacées de votre smartphone pendant l'installation, nous vous recommandons donc de sauvegarder vos données.", - "let-s-get-started-instruction-5": "Un câble de données USB fonctionnel est requis. Les câbles d'alimentation ne transfèrent pas de données et ne fonctionneront pas ! Nous recommandons USB 3.x ou plus récent.", - "let-s-get-started-instruction-title-1": "1. Libérez du temps", - "let-s-get-started-instruction-title-2": "2. Libérez de l'espace disque", - "let-s-get-started-instruction-title-3": "3. Chargez votre téléphone", - "let-s-get-started-instruction-title-4": "4. Sauvegardez vos données", - "let-s-get-started-instruction-title-5": "5. Prenez un câble de données USB", - "locking": "Verrouillage", - "locking-instructions-1": "Votre téléphone demande un verrouillage. Sélectionnez lock bootloader", - "locking-instructions-2": "L'appareil va redémarrer", - "locking-instructions-3": "Cliquer sur suivant", - "locking-instructions-4": "Sur le téléphone appuyez sur le bouton start", - "locking-instructions-1-teracube": "Votre téléphone demande un verrouillage. Sélectionnez lock bootloader en utilisant le bouton Volume Up.", - "locking-instructions-1-teracube-a": "Ensuite cliquez sur Suivant.", - "murena-workspace-account": "Compte Murena Workspace", - "murena-workspace-account-instructions": "Gardez vos données en sécurité et synchronisez cet appareil avec votre compte personnel Murena Workspace. 1 Go gratuit et des plans payants disponibles pour plus de stockage.", - "navigator-detection": "Détection du navigateur", - "navigator-not-supported": "Votre navigateur n'est pas pris en charge", - "navigator-not-supported-instructions": "Vous pouvez utiliser les navigateurs suivants", - "neutral": "Neutre", - "next": "Suivant", - "ready-to-install-e-os": "Vous êtes maintenant prêt à installer /e/OS.", - "recovery-to-bootloader": "Recovery vers Bootloader", - "recovery-to-bootloader-instructions": "Sélectionnez Avancé", - "recovery-to-bootloader-instructions-1": "1. Sélectionnez Advanced", - "recovery-to-bootloader-instructions-2": "2. Sélectionnez Reboot to bootloader", - "satisfied": "Satisfait", - "send-to-e-team": "Envoyer à l'équipe Murena", - "sideload": "Installation en cours", - "sideload-instructions-3": "Une fois l'installation terminée, le téléphone revient à l'écran principal du recovery.", - "sign-up-free": "Inscrivez-vous GRATUITEMENT", - "skip": "Passer", - "start": "Commencer", - "this-might-take-some-time-please-be-patient": "Cela peut prendre du temps, veuillez être patient", - "unlocking-instructions-1": "Votre téléphone demande un déverrouillage. Sélectionnez unlock bootloader en utilisant les boutons Volume Up and Volume Down pour naviguer.", - "unlocking-instructions-1-a": "Utiliser le bouton Power pour confirmer.", - "unlocking-instructions-1-b": "Votre téléphone demade à être déverrouilé. Selectionner unlock bootloader en utilisant le bouton Volume Up.", - "unlocking-instructions-2": "L'appareil va redémarrer. Il devrait maintenant être déverrouillé.", - "unlocking-instructions-2-a": "Attendez que l'écran du bootloader soir à nouveau visible avant d'aller à l'étape suivante.", - "unlocking-instructions-3": "Comme l'appareil réinitialise complètement, vous devrez réactiver le débogage USB.", - "unlocking-instructions-4": "Passez la configuration et cliquez sur suivant", - "unlocking-instructions-1-teracube": "Votre téléphone demande un déverrouillage. Sélectionnez unlock bootloader en utilisant le bouton Volume Up.", - "unlocking-instructions-1-teracube-a": "Ensuite cliquez sur Suivant.", - "very-dissatisfied": "Très insatisfait", - "very-satisfied": "Très satisfait" + "_err_01": "Erreur", + "_err_02": "Votre navigateur ne supporte pas Web USB", + "Ex 1: before installing /e/OS Android 12, you should update to the latest stock Android 12": "Ex 1 : avant d'installer /e/OS Android 12, vous devez mettre à jour vers la dernière version stock d'Android 12", + "Ex 2: or if you're installing /e/OS Android 11, make sure to update to the latest stock Android 11": "Ex 2 : ou si vous installez /e/OS Android 11, assurez-vous de mettre à jour vers la dernière version stock d'Android 11", + "Ex 3: similarly, if you're installing /e/OS Android 11, it should be the latest stock Android 10": "Ex 3 : de même, si vous installez /e/OS Android 11, il doit s'agir de la dernière version stock d'Android 10", + "activate-developer-options": "Activer les options pour les développeurs", + "activate-developer-options-instructions-1": "1. Ouvrez le menu des paramètres et tapez 'build' dans la barre de recherche.", + "activate-developer-options-instructions-2": "2. Sur l'écran suivant, trouvez 'Numéro de build' et appuyez dessus 7 fois.", + "activate-oem-unlock": "OEM unlock", + "activate-oem-unlock-instruction": "Si ce n'est pas déjà le cas, déverrouillez la fonction OEM", + "activate-usb-debugging": "Activer le débogage USB", + "activate-usb-debugging-instructions-1": "Retournez au menu des paramètres et tapez 'débogage USB' dans la barre de recherche.", + "activate-usb-debugging-instructions-2": "À ce stade, vous devriez être dans l'écran 'Options pour les développeurs'. Appuyez maintenant sur 'Débogage USB' pour l'activer (sur certains appareils, cela s'appelle 'Débogage Android').", + "bootloader-to-recovery-manually": "Bootloader à recovery", + "bootloader-to-recovery-manually-instructions": "Nous allons maintenant redémarrer votre appareil en mode Recovery. Veuillez suivre les étapes ci-dessous :", + "bootloader-to-recovery-manually-instructions-1": "1. Dans le bootloader, sélectionnez recovery en utilisant Volume Haut et Volume Bas pour naviguer", + "bootloader-to-recovery-manually-instructions-2": "2. Appuyez sur Power pour confirmer", + "bootloader-to-recovery-manually-instructions-3": "3. Attendez que votre téléphone démarre en recovery", + "check-update-android-version": "Vérifiez et mettez à jour votre version d'Android", + "check-update-android-version-caution": "Attention : avant de procéder à l'installation, vérifiez si le dernier firmware Android est disponible pour votre appareil.", + "connect": "Connecter", + "connect-bootloader": "Connexion au bootloader", + "connect-bootloader-instructions-1": "Votre téléphone va maintenant redémarrer en mode bootloader", + "connect-bootloader-instructions-2": "Lorsque votre téléphone est allumé, connectez-le en mode bootloader en cliquant sur le bouton ci-dessous", + "connect-your-phone": "Connectez votre téléphone", + "connect-your-phone-instructions": "Connectez votre téléphone à votre ordinateur avec un câble USB. Nous détecterons automatiquement votre téléphone pour installer /e/OS.", + "connect-your-phone-instructions-notes": "Remarque : le 'débogage USB' est requis pour que la détection automatique de l'appareil fonctionne. Si vous ne l'avez pas encore activé, nous vous aiderons dans les étapes suivantes.", + "device-detection": "Détection de l'appareil", + "device-detection-detected": "Un appareil a été détecté.", + "device-detection-instructions-1": "Nous allons maintenant connecter votre téléphone au navigateur. Lorsque cette fenêtre contextuelle apparaît, sélectionnez votre téléphone dans la liste.", + "device-detection-instructions-2": "Une fenêtre contextuelle apparaîtra ensuite sur votre téléphone. Vous devrez cocher toujours autoriser depuis cet ordinateur avant d'appuyer sur OK.", + "device-detection-instructions-3": "Cliquez sur le bouton ci-dessous pour commencer la connexion", + "device-model-not-supported": "Modèle d'appareil non pris en charge", + "device-model-not-supported-instructions": "vous ne pouvez pas installer /e/OS en utilisant cet outil", + "device-model-not-supported-title": "Votre téléphone {{product-name}} n'est pas compatible", + "dissatisfied": "Insatisfait", + "donate": "Faire un don", + "enable-usb-file-transfer": "Activer le transfert de fichiers USB", + "enable-usb-file-transfer-instructions-1": "Toujours dans les 'Options pour les développeurs', faites défiler vers le bas pour trouver 'Configuration USB par défaut' et appuyez dessus.", + "enable-usb-file-transfer-instructions-2": "Sélectionnez maintenant l'option 'Transfert de fichiers' (sur certains appareils, cela s'appelle 'mode MTP (Media Transfer Protocol)').", + "format-device": "Formater l'appareil", + "format-device-instructions-1": "1. Sélectionnez Réinitialisation d'usine", + "format-device-instructions-2": "2. Sélectionnez l'option Formater les données / Réinitialisation d'usine", + "format-device-instructions-3": "3. L'écran suivant affichera un avertissement que cette action ne peut pas être annulée", + "format-device-instructions-4": "4. Sélectionnez Formater les données pour continuer ou Annuler si vous souhaitez revenir en arrière", + "format-device-instructions-5": "5. Si vous avez sélectionné Formater les données, le processus de formatage se terminera", + "format-device-instructions-6": "6. L'écran reviendra maintenant à la page Réinitialisation d'usine", + "format-device-instructions-7": "7. Cliquez sur la fléche Back, puis Next", + "go-to-apply-update": "Presque terminé !", + "go-to-apply-update-instructions-1": "1. Sélectionnez Appliquer la mise à jour", + "go-to-apply-update-instructions-2": "2. Appliquer la mise à jour depuis adb", + "go-to-apply-update-instructions-3": "L'appareil est maintenant en mode sideload", + "go-to-apply-update-instructions-4": "Note: Pour l'étape suivante, il se peut que votre navigateur doive reconnecter votre téléphone. Si une fenêtre contextuelle apparaît, sélectionnez votre téléphone dans la liste.", + "help": "Aide", + "i-already-have-an-account": "J'ai déjà un compte", + "i-m-ready": "Je suis prêt !", + "installation-complete": "L'installation est terminée !", + "installation-complete-instructions-1": "Félicitations ! Pendant que votre téléphone démarre, vous devriez voir le logo ci-dessous. Cela prend du temps, soyez patient.", + "installation-complete-instructions-2": "Astuce : suivez les instructions sur votre téléphone pour configurer votre appareil. Vous pouvez maintenant ajouter vos fichiers à nouveau sur votre téléphone.", + "let-s-get-started": "Commençons", + "let-s-get-started-instruction-1": "Le processus d'installation complet prend environ 1 heure. Soyez patient !", + "let-s-get-started-instruction-2": "Vous aurez besoin d'au moins 6 Go d'espace libre sur votre ordinateur pour télécharger et installer /e/OS. Assurez-vous d'avoir suffisamment d'espace libre sur le disque.", + "let-s-get-started-instruction-3": "Avant d'installer /e/OS, assurez-vous que votre téléphone a au moins 50 % de batterie", + "let-s-get-started-instruction-4": "Toutes les données seront effacées de votre smartphone pendant l'installation, nous vous recommandons donc de sauvegarder vos données.", + "let-s-get-started-instruction-5": "Un câble de données USB fonctionnel est requis. Les câbles d'alimentation ne transfèrent pas de données et ne fonctionneront pas ! Nous recommandons USB 3.x ou plus récent.", + "let-s-get-started-instruction-title-1": "1. Libérez du temps", + "let-s-get-started-instruction-title-2": "2. Libérez de l'espace disque", + "let-s-get-started-instruction-title-3": "3. Chargez votre téléphone", + "let-s-get-started-instruction-title-4": "4. Sauvegardez vos données", + "let-s-get-started-instruction-title-5": "5. Prenez un câble de données USB", + "locking": "Verrouillage", + "locking-instructions-1": "Votre téléphone demande un verrouillage. Sélectionnez lock bootloader", + "locking-instructions-2": "L'appareil va redémarrer", + "locking-instructions-3": "Cliquer sur suivant", + "locking-instructions-4": "Sur le téléphone appuyez sur le bouton start", + "locking-instructions-1-teracube": "Votre téléphone demande un verrouillage. Sélectionnez lock bootloader en utilisant le bouton Volume Up.", + "locking-instructions-1-teracube-a": "Ensuite cliquez sur Suivant.", + "murena-workspace-account": "Compte Murena Workspace", + "murena-workspace-account-instructions": "Gardez vos données en sécurité et synchronisez cet appareil avec votre compte personnel Murena Workspace. 1 Go gratuit et des plans payants disponibles pour plus de stockage.", + "navigator-detection": "Détection du navigateur", + "navigator-not-supported": "Votre navigateur n'est pas pris en charge", + "navigator-not-supported-instructions": "Vous pouvez utiliser les navigateurs suivants", + "neutral": "Neutre", + "next": "Suivant", + "ready-to-install-e-os": "Vous êtes maintenant prêt à installer /e/OS.", + "recovery-to-bootloader": "Recovery vers Bootloader", + "recovery-to-bootloader-instructions": "Sélectionnez Avancé", + "recovery-to-bootloader-instructions-1": "1. Sélectionnez Advanced", + "recovery-to-bootloader-instructions-2": "2. Sélectionnez Reboot to bootloader", + "satisfied": "Satisfait", + "send-to-e-team": "Envoyer à l'équipe Murena", + "sideload": "Installation en cours", + "sideload-instructions-3": "Une fois l'installation terminée, le téléphone revient à l'écran principal du recovery.", + "sign-up-free": "Inscrivez-vous GRATUITEMENT", + "skip": "Passer", + "start": "Commencer", + "this-might-take-some-time-please-be-patient": "Cela peut prendre du temps, veuillez être patient", + "unlocking-instructions-1": "Votre téléphone demande un déverrouillage. Sélectionnez unlock bootloader en utilisant les boutons Volume Up and Volume Down pour naviguer.", + "unlocking-instructions-1-a": "Utiliser le bouton Power pour confirmer.", + "unlocking-instructions-1-b": "Votre téléphone demade à être déverrouilé. Selectionner unlock bootloader en utilisant le bouton Volume Up.", + "unlocking-instructions-2": "L'appareil va redémarrer. Il devrait maintenant être déverrouillé.", + "unlocking-instructions-2-a": "Attendez que l'écran du bootloader soir à nouveau visible avant d'aller à l'étape suivante.", + "unlocking-instructions-3": "Comme l'appareil réinitialise complètement, vous devrez réactiver le débogage USB.", + "unlocking-instructions-4": "Passez la configuration et cliquez sur suivant", + "unlocking-instructions-1-teracube": "Votre téléphone demande un déverrouillage. Sélectionnez unlock bootloader en utilisant le bouton Volume Up.", + "unlocking-instructions-1-teracube-a": "Ensuite cliquez sur Suivant.", + "very-dissatisfied": "Très insatisfait", + "very-satisfied": "Très satisfait" } diff --git a/app/public/assets/languages/is.json b/app/public/assets/languages/is.json index 8c133e7402ae160a96c205617afd79ac5d13912a..9b11476ed0c5e85e4f36b71f452940e7d03be83d 100644 --- a/app/public/assets/languages/is.json +++ b/app/public/assets/languages/is.json @@ -1,75 +1,75 @@ { - "activate-usb-debugging": "Virkjaðu USB-villuleit", - "next": "Næsta", - "ready-to-install-e-os": "Núna er allt tilbúið til uppsetningar á /e/OS.", - "recovery-to-bootloader-instructions": "Í aðalvalmyndinni", - "satisfied": "Ánægð/ur", - "send-to-e-team": "Senda til Murena-teymisins", - "sideload": "Uppsetning í gangi", - "sign-up-free": "Skráðu þig ókeypis", - "skip": "Sleppa", - "start": "Byrja", - "this-might-take-some-time-please-be-patient": "Þetta gæti tekið drjúga stund, sýndu þolinmæði", - "very-dissatisfied": "Mjög óánægð/ur", - "very-satisfied": "Mjög ánægð/ur", - "bootloader-to-recovery-manually-instructions-2": "2. Ýttu á aflrofann til að staðfesta", - "connect": "Tengjast", - "connect-your-phone": "Tengdu símann þinn", - "device-detection": "Greining tækis", - "device-detection-detected": "Tæki hefur fundist.", - "dissatisfied": "Óánægð/ur", - "donate": "Styrkja", - "enable-usb-file-transfer": "Virkjaðu USB-skráaflutning", - "format-device": "Forsníða tækið", - "format-device-instructions-1": "1. Veldu Núllstilla á verksmiðjustillingar", - "format-device-instructions-2": "2. Veldu Forsníða gögn / Núllstilla á verksmiðjustillingar", - "go-to-apply-update": "Næstum því búið!", - "help": "Hjálp", - "i-already-have-an-account": "Ég er nú þegar með notandaaðgang", - "installation-complete": "Uppsetningunni er lokið!", - "let-s-get-started": "Hefjumst handa", - "let-s-get-started-instruction-title-1": "1. Taktu frá nokkurn tíma", - "let-s-get-started-instruction-title-3": "3. Hafðu símann þinn vel hlaðinn", - "let-s-get-started-instruction-title-4": "4. Taktu öryggisafrit af gögnunum þínum", - "let-s-get-started-instruction-title-5": "5. Taktu USB-gagnakapal sem virkar", - "locking": "Læsing", - "murena-workspace-account": "Murena-skýjaaðgangur", - "navigator-not-supported-instructions": "Þú getur notað eftirfarandi vafra", - "neutral": "Hlutlaus", - "let-s-get-started-instruction-title-2": "2. Losaðu um eitthvað diskapláss", - "device-detection-instructions-3": "Smelltu á hnappinn hér fyrir neðan til að ræsa tenginguna", - "device-model-not-supported": "Þessi tegund tækis er ekki studd", - "device-model-not-supported-instructions": "Þú getur ekki sett /e/OS upp með þessu verkfæri", - "device-model-not-supported-title": "{{product-name}} síminn þinn er ekki samhæfður", - "enable-usb-file-transfer-instructions-1": "Á meðan enn er verið í forritarahamnum, skaltu skruna niður og velja 'Sjálfgefnar USB-stillingar / ’Default USB Configuration'.", - "installation-complete-instructions-1": "Til hamingju! Á meðan síminn þinn er að ræsast ættirðu að sjá táknmerkið hér fyrir neðan. Þetta gæti tekið drjúga stund, sýndu þolinmæði.", - "let-s-get-started-instruction-4": "Gögnum snjallsímans verður eytt við uppsetninguna,\nþannig að við mælum með því að þú takir öryggisafrit af gögnunum þínum.", - "locking-instructions-3": "Smelltu síðan á 'Næsta'", - "navigator-detection": "Greining á vafra", - "navigator-not-supported": "Það er ekki stuðningur við vafrann þinn", - "unlocking-instructions-4": "Slepptu uppsetningunni á símanum og smelltu á 'Næsta'", - "unlocking-instructions-5": "Smelltu síðan á 'Næsta'", - "activate-developer-options": "Virkjaðu 'Stillingar fyrir forritara", - "activate-developer-options-instructions-1": "1. Opnaðu stillingavalmyndina og skrifaðu 'build' í leitarstikuna.", - "activate-developer-options-instructions-2": "2. Á næsta skjá skaltu finna ‘Build number’ og banka 7 sinnum á það.", - "activate-usb-debugging-instructions-1": "1. Farðu aftur í stillingavalmyndina og skrifaðu '‘USB debugging’' í leitarstikuna.", - "check-update-android-version": "Athugaðu og uppfærðu Android-útgáfuna þína", - "connect-bootloader-instructions-1": "Síminn þinn mun núna endurræsast í bootloader-ræsistjóraham", - "connect-your-phone-instructions": "Tengdu símann þinn við tölvuna með USB-kapli. Síminn þinn á að finnast sjálfvirkt svo hægt sé að setja upp /e/OS.", - "enable-usb-file-transfer-instructions-2": "Veldu núna 'Skráaflutningur / File Transfer' (á sumum tækjum er þetta kallað 'MTP-hamur (media transfer protocol)').", - "format-device-instructions-3": "3. Næsti skjár mun birta aðvörun um að ekki sé hægt að afturkalla við þessa aðgerð", - "format-device-instructions-4": "4. Veldu Forsníða gögn til að halda áfram", - "format-device-instructions-5": "5. Bíddu eftir að forsníðingarferlinu ljúki", - "go-to-apply-update-instructions-1": "1. Veldu Beita uppfærslu.", - "go-to-apply-update-instructions-2": "2. Og síðan Virkja uppfærslu frá ADB.", - "help-us-improve-the-tool": "Hjálpaðu okkur að endurbæta verkfærið", - "help-us-improve-the-tool-instructions-1": "Gefðu reynslu þinni af /e/OS Installer einkunn.", - "help-us-improve-the-tool-instructions-2": "Ertu með einhverjar hugmyndir um hvernig hægt sé að betrumbæta þennan hugbúnað?", - "i-m-ready": "Ég er tilbúin/n!", - "let-s-get-started-instruction-1": "Uppsetningarferlið tekur í heildina u.þ.b. 1 klukkustund.\nSýndu þolinmæði!", - "recovery-to-bootloader-instructions-1": "1. Veldu Ítarlegt", - "recovery-to-bootloader-instructions-2": "2. Veldu að enduræsa inn í ræsistjórann", - "sideload-instructions-1": "Skjárinn mun sýna framvinduna... ", - "sideload-instructions-2": "Þetta gæti tekið nokkrar mínútur, sýndu þolinmæði.", - "sideload-instructions-4": "Aðeins þá geturðu smellt á Næsta." + "activate-usb-debugging": "Virkjaðu USB-villuleit", + "next": "Næsta", + "ready-to-install-e-os": "Núna er allt tilbúið til uppsetningar á /e/OS.", + "recovery-to-bootloader-instructions": "Í aðalvalmyndinni", + "satisfied": "Ánægð/ur", + "send-to-e-team": "Senda til Murena-teymisins", + "sideload": "Uppsetning í gangi", + "sign-up-free": "Skráðu þig ókeypis", + "skip": "Sleppa", + "start": "Byrja", + "this-might-take-some-time-please-be-patient": "Þetta gæti tekið drjúga stund, sýndu þolinmæði", + "very-dissatisfied": "Mjög óánægð/ur", + "very-satisfied": "Mjög ánægð/ur", + "bootloader-to-recovery-manually-instructions-2": "2. Ýttu á aflrofann til að staðfesta", + "connect": "Tengjast", + "connect-your-phone": "Tengdu símann þinn", + "device-detection": "Greining tækis", + "device-detection-detected": "Tæki hefur fundist.", + "dissatisfied": "Óánægð/ur", + "donate": "Styrkja", + "enable-usb-file-transfer": "Virkjaðu USB-skráaflutning", + "format-device": "Forsníða tækið", + "format-device-instructions-1": "1. Veldu Núllstilla á verksmiðjustillingar", + "format-device-instructions-2": "2. Veldu Forsníða gögn / Núllstilla á verksmiðjustillingar", + "go-to-apply-update": "Næstum því búið!", + "help": "Hjálp", + "i-already-have-an-account": "Ég er nú þegar með notandaaðgang", + "installation-complete": "Uppsetningunni er lokið!", + "let-s-get-started": "Hefjumst handa", + "let-s-get-started-instruction-title-1": "1. Taktu frá nokkurn tíma", + "let-s-get-started-instruction-title-3": "3. Hafðu símann þinn vel hlaðinn", + "let-s-get-started-instruction-title-4": "4. Taktu öryggisafrit af gögnunum þínum", + "let-s-get-started-instruction-title-5": "5. Taktu USB-gagnakapal sem virkar", + "locking": "Læsing", + "murena-workspace-account": "Murena-skýjaaðgangur", + "navigator-not-supported-instructions": "Þú getur notað eftirfarandi vafra", + "neutral": "Hlutlaus", + "let-s-get-started-instruction-title-2": "2. Losaðu um eitthvað diskapláss", + "device-detection-instructions-3": "Smelltu á hnappinn hér fyrir neðan til að ræsa tenginguna", + "device-model-not-supported": "Þessi tegund tækis er ekki studd", + "device-model-not-supported-instructions": "Þú getur ekki sett /e/OS upp með þessu verkfæri", + "device-model-not-supported-title": "{{product-name}} síminn þinn er ekki samhæfður", + "enable-usb-file-transfer-instructions-1": "Á meðan enn er verið í forritarahamnum, skaltu skruna niður og velja 'Sjálfgefnar USB-stillingar / ’Default USB Configuration'.", + "installation-complete-instructions-1": "Til hamingju! Á meðan síminn þinn er að ræsast ættirðu að sjá táknmerkið hér fyrir neðan. Þetta gæti tekið drjúga stund, sýndu þolinmæði.", + "let-s-get-started-instruction-4": "Gögnum snjallsímans verður eytt við uppsetninguna,\nþannig að við mælum með því að þú takir öryggisafrit af gögnunum þínum.", + "locking-instructions-3": "Smelltu síðan á 'Næsta'", + "navigator-detection": "Greining á vafra", + "navigator-not-supported": "Það er ekki stuðningur við vafrann þinn", + "unlocking-instructions-4": "Slepptu uppsetningunni á símanum og smelltu á 'Næsta'", + "unlocking-instructions-5": "Smelltu síðan á 'Næsta'", + "activate-developer-options": "Virkjaðu 'Stillingar fyrir forritara", + "activate-developer-options-instructions-1": "1. Opnaðu stillingavalmyndina og skrifaðu 'build' í leitarstikuna.", + "activate-developer-options-instructions-2": "2. Á næsta skjá skaltu finna ‘Build number’ og banka 7 sinnum á það.", + "activate-usb-debugging-instructions-1": "1. Farðu aftur í stillingavalmyndina og skrifaðu '‘USB debugging’' í leitarstikuna.", + "check-update-android-version": "Athugaðu og uppfærðu Android-útgáfuna þína", + "connect-bootloader-instructions-1": "Síminn þinn mun núna endurræsast í bootloader-ræsistjóraham", + "connect-your-phone-instructions": "Tengdu símann þinn við tölvuna með USB-kapli. Síminn þinn á að finnast sjálfvirkt svo hægt sé að setja upp /e/OS.", + "enable-usb-file-transfer-instructions-2": "Veldu núna 'Skráaflutningur / File Transfer' (á sumum tækjum er þetta kallað 'MTP-hamur (media transfer protocol)').", + "format-device-instructions-3": "3. Næsti skjár mun birta aðvörun um að ekki sé hægt að afturkalla við þessa aðgerð", + "format-device-instructions-4": "4. Veldu Forsníða gögn til að halda áfram", + "format-device-instructions-5": "5. Bíddu eftir að forsníðingarferlinu ljúki", + "go-to-apply-update-instructions-1": "1. Veldu Beita uppfærslu.", + "go-to-apply-update-instructions-2": "2. Og síðan Virkja uppfærslu frá ADB.", + "help-us-improve-the-tool": "Hjálpaðu okkur að endurbæta verkfærið", + "help-us-improve-the-tool-instructions-1": "Gefðu reynslu þinni af /e/OS Installer einkunn.", + "help-us-improve-the-tool-instructions-2": "Ertu með einhverjar hugmyndir um hvernig hægt sé að betrumbæta þennan hugbúnað?", + "i-m-ready": "Ég er tilbúin/n!", + "let-s-get-started-instruction-1": "Uppsetningarferlið tekur í heildina u.þ.b. 1 klukkustund.\nSýndu þolinmæði!", + "recovery-to-bootloader-instructions-1": "1. Veldu Ítarlegt", + "recovery-to-bootloader-instructions-2": "2. Veldu að enduræsa inn í ræsistjórann", + "sideload-instructions-1": "Skjárinn mun sýna framvinduna... ", + "sideload-instructions-2": "Þetta gæti tekið nokkrar mínútur, sýndu þolinmæði.", + "sideload-instructions-4": "Aðeins þá geturðu smellt á Næsta." } diff --git a/app/public/assets/languages/it.json b/app/public/assets/languages/it.json index 42d4be026bebcb25b385829ad49b5187c2d5deb9..3fe4b27079487f427a07e5a3e6e4a4033e280e87 100644 --- a/app/public/assets/languages/it.json +++ b/app/public/assets/languages/it.json @@ -1,101 +1,101 @@ { - "Ex 1: before installing /e/OS Android 12, you should update to the latest stock Android 12": "Es 1: prima di installare /e/OS Android 12, dovresti aggiornare all'ultima versione di stock di Android 12", - "Ex 2: or if you're installing /e/OS Android 11, make sure to update to the latest stock Android 11": "Es 2: o se stai installando /e/OS Android 11, assicurati di aggiornare all'ultima versione di stock di Android 11", - "Ex 3: similarly, if you're installing /e/OS Android 11, it should be the latest stock Android 10": "Es 3: allo stesso modo, se stai installando /e/OS Android 11, dovrebbe essere l'ultima versione di stock di Android 10", - "activate-developer-options": "Attiva le opzioni sviluppatore", - "activate-developer-options-instructions-1": "1. Apri il menu delle impostazioni e digita ‘build’ nella barra di ricerca.", - "activate-developer-options-instructions-2": "2. Nella schermata successiva, trova ‘Numero di build’ e tocca 7 volte su di esso.", - "activate-usb-debugging": "Attiva il debug USB", - "activate-usb-debugging-instructions-1": "Torna al menu delle impostazioni e digita ‘debug USB’ nella barra di ricerca.", - "activate-usb-debugging-instructions-2": "A questo punto dovresti essere nella schermata ‘Opzioni sviluppatore’. Ora tocca ‘Debug USB’ per attivarlo (su alcuni dispositivi si chiama ‘Debug Android’).", - "bootloader-to-recovery-manually": "Bootloader a recovery", - "bootloader-to-recovery-manually-instructions": "Ora riavvieremo il tuo dispositivo in modalità Recovery. Per favore, segui i passaggi qui sotto:", - "bootloader-to-recovery-manually-instructions-1": "1. Nel bootloader, seleziona recovery usando Volume su e Volume giù per navigare", - "bootloader-to-recovery-manually-instructions-2": "2. Premi Accensione per confermare", - "bootloader-to-recovery-manually-instructions-3": "3. Se hai saltato questo passaggio, spegni il telefono e avvia in modalità Recovery premendo contemporaneamente Accensione e Volume su fino a quando il dispositivo si accende.", - "check-update-android-version": "Controlla e aggiorna la tua versione di Android", - "check-update-android-version-caution": "Attenzione: prima di procedere con l'installazione, verifica se è disponibile l'ultimo firmware Android per il tuo dispositivo.", - "connect": "Connetti", - "connect-bootloader": "Connessione del bootloader", - "connect-bootloader-instructions-1": "Il tuo telefono ora si riavvierà in modalità bootloader", - "connect-bootloader-instructions-2": "Quando il telefono è acceso, connettiti in modalità bootloader cliccando sul pulsante qui sotto", - "connect-your-phone": "Connetti il tuo telefono", - "connect-your-phone-instructions": "Connetti il tuo telefono al computer con un cavo USB. Rileveremo automaticamente il tuo telefono per installare /e/OS.", - "connect-your-phone-instructions-notes": "Nota: il 'debug USB' è necessario affinché la rilevazione automatica del dispositivo funzioni. Se non l'hai ancora abilitato, ti aiuteremo nei prossimi passaggi.", - "device-detection": "Rilevamento del dispositivo", - "device-detection-detected": "È stato rilevato un dispositivo.", - "device-detection-instructions-1": "Ora connetteremo il tuo telefono al browser. Quando appare questo pop-up, seleziona il tuo telefono dall'elenco.", - "device-detection-instructions-2": "Poi apparirà una finestra pop-up sul tuo telefono. Dovrai selezionare consenti sempre da questo computer prima di premere OK.", - "device-detection-instructions-3": "Clicca sul pulsante qui sotto per avviare la connessione", - "device-model-not-supported": "Modello di dispositivo non supportato", - "device-model-not-supported-instructions": "non puoi installare /e/OS usando questo strumento", - "device-model-not-supported-title": "Il tuo telefono {{product-name}} non è compatibile", - "dissatisfied": "Insoddisfatto", - "donate": "Dona", - "enable-usb-file-transfer": "Abilita il trasferimento di file USB", - "enable-usb-file-transfer-instructions-1": "Sempre all'interno delle 'Opzioni sviluppatore', scorri verso il basso per trovare 'Configurazione USB predefinita' e toccala.", - "enable-usb-file-transfer-instructions-2": "Ora seleziona l'opzione 'Trasferimento di file' (su alcuni dispositivi si chiama 'modalità MTP (protocollo di trasferimento multimediale)').", - "format-device": "Formatta il dispositivo", - "format-device-instructions-1": "1. Seleziona Ripristino dati di fabbrica", - "format-device-instructions-2": "2. Seleziona l'opzione Formatta dati / Ripristino dati di fabbrica", - "format-device-instructions-3": "3. La schermata successiva mostrerà un avviso che questa azione non può essere annullata", - "format-device-instructions-4": "4. Seleziona Formatta dati per procedere o Annulla se vuoi tornare indietro", - "format-device-instructions-5": "5. Se hai selezionato Formatta dati, il processo di formattazione verrà completato", - "format-device-instructions-6": "6. Lo schermo ora tornerà alla schermata di Ripristino dati di fabbrica", - "go-to-apply-update": "Quasi fatto!", - "go-to-apply-update-instructions-1": "1. Seleziona Applica aggiornamento", - "go-to-apply-update-instructions-2": "2. Applica aggiornamento da adb", - "go-to-apply-update-instructions-3": "Il dispositivo è ora in modalità sideload", - "help": "Aiuto", - "help-us-improve-the-tool": "Aiutaci a migliorare lo strumento", - "help-us-improve-the-tool-instructions-1": "Per favore, valuta la tua esperienza con l'/e/OS Installer.", - "help-us-improve-the-tool-instructions-2": "Hai qualche idea su come migliorare questo software?", - "i-already-have-an-account": "Ho già un account", - "i-m-ready": "Sono pronto!", - "installation-complete": "L'installazione è completa!", - "installation-complete-instructions-1": "Congratulazioni! Mentre il tuo telefono si avvia, dovresti vedere il logo qui sotto. Questo richiede tempo, sii paziente.", - "installation-complete-instructions-2": "Consiglio: segui le istruzioni sul tuo telefono per configurare il tuo dispositivo. Ora puoi aggiungere di nuovo i tuoi file al telefono.", - "let-s-get-started": "Iniziamo", - "let-s-get-started-instruction-1": "Il processo completo di installazione richiede circa 1 ora. \nSii paziente!", - "let-s-get-started-instruction-2": "Avrai bisogno di almeno 6GB di spazio libero sul tuo computer per\nscaricare e installare /e/OS. Assicurati di avere abbastanza spazio libero sul disco.", - "let-s-get-started-instruction-3": "Prima di installare /e/OS, assicurati che il tuo telefono abbia almeno il 50% di batteria", - "let-s-get-started-instruction-4": "Tutti i dati verranno cancellati dal tuo smartphone durante l'installazione\nquindi ti consigliamo di eseguire il backup dei tuoi dati.", - "let-s-get-started-instruction-5": "È necessario un cavo dati USB funzionante. I cavi di alimentazione non trasferiscono dati\ne non funzioneranno! Raccomandiamo USB 3.x o successivi.", - "let-s-get-started-instruction-title-1": "1. Libera un po' di tempo", - "let-s-get-started-instruction-title-2": "2. Libera spazio sul disco", - "let-s-get-started-instruction-title-3": "3. Carica il tuo telefono", - "let-s-get-started-instruction-title-4": "4. Esegui il backup dei tuoi dati", - "let-s-get-started-instruction-title-5": "5. Prendi un cavo dati USB", - "locking": "Blocco", - "locking-instructions-1": "Il tuo telefono chiede uno sblocco. Seleziona lock bootloader", - "locking-instructions-2": "Se il dispositivo non si riavvia automaticamente, riavvialo", - "murena-workspace-account": "Account Murena Workspace", - "murena-workspace-account-instructions": "Mantieni i tuoi dati al sicuro e sincronizza questo dispositivo con il tuo account personale Murena Workspace. 1GB gratuito e piani a pagamento disponibili per più spazio di archiviazione.", - "navigator-detection": "Rilevamento del browser", - "navigator-not-supported": "Il tuo browser non è supportato", - "navigator-not-supported-instructions": "Puoi usare i seguenti browser", - "neutral": "Neutro", - "next": "Successivo", - "ready-to-install-e-os": "Ora sei pronto per installare /e/OS.", - "recovery-to-bootloader": "Recovery a Bootloader", - "recovery-to-bootloader-instructions": "Seleziona Avanzato", - "recovery-to-bootloader-instructions-1": "1. Seleziona Advanced", - "recovery-to-bootloader-instructions-2": "2. Seleziona Reboot to bootloader", - "satisfied": "Soddisfatto", - "send-to-e-team": "Invia al team di /e/", - "sideload": "Installazione in corso", - "sideload-instructions-1": "Lo schermo mostrerà la percentuale di completamento... ", - "sideload-instructions-2": "Questo potrebbe fermarsi al 47%, dagli tempo.", - "sideload-instructions-3": "Una volta che l'installazione è terminata, il telefono tornerà alla schermata principale.", - "sideload-instructions-4": "Solo allora puoi cliccare su Next.", - "sign-up-free": "Iscriviti GRATIS", - "skip": "Salta", - "start": "Inizia", - "this-might-take-some-time-please-be-patient": "Questo potrebbe richiedere del tempo, per favore sii paziente", - "unlocking-instructions-1": "Il tuo telefono chiede uno sblocco. Seleziona unlock bootloader", - "unlocking-instructions-2": "Se il dispositivo non si riavvia automaticamente, riavvialo. Ora dovrebbe essere sbloccato.", - "unlocking-instructions-3": "Poiché il dispositivo si resetta completamente, dovrai riattivare il debug USB.", - "unlocking-instructions-4": "Supera la configurazione e fai clic su successivo", - "very-dissatisfied": "Molto insoddisfatto", - "very-satisfied": "Molto soddisfatto" + "Ex 1: before installing /e/OS Android 12, you should update to the latest stock Android 12": "Es 1: prima di installare /e/OS Android 12, dovresti aggiornare all'ultima versione di stock di Android 12", + "Ex 2: or if you're installing /e/OS Android 11, make sure to update to the latest stock Android 11": "Es 2: o se stai installando /e/OS Android 11, assicurati di aggiornare all'ultima versione di stock di Android 11", + "Ex 3: similarly, if you're installing /e/OS Android 11, it should be the latest stock Android 10": "Es 3: allo stesso modo, se stai installando /e/OS Android 11, dovrebbe essere l'ultima versione di stock di Android 10", + "activate-developer-options": "Attiva le opzioni sviluppatore", + "activate-developer-options-instructions-1": "1. Apri il menu delle impostazioni e digita ‘build’ nella barra di ricerca.", + "activate-developer-options-instructions-2": "2. Nella schermata successiva, trova ‘Numero di build’ e tocca 7 volte su di esso.", + "activate-usb-debugging": "Attiva il debug USB", + "activate-usb-debugging-instructions-1": "Torna al menu delle impostazioni e digita ‘debug USB’ nella barra di ricerca.", + "activate-usb-debugging-instructions-2": "A questo punto dovresti essere nella schermata ‘Opzioni sviluppatore’. Ora tocca ‘Debug USB’ per attivarlo (su alcuni dispositivi si chiama ‘Debug Android’).", + "bootloader-to-recovery-manually": "Bootloader a recovery", + "bootloader-to-recovery-manually-instructions": "Ora riavvieremo il tuo dispositivo in modalità Recovery. Per favore, segui i passaggi qui sotto:", + "bootloader-to-recovery-manually-instructions-1": "1. Nel bootloader, seleziona recovery usando Volume su e Volume giù per navigare", + "bootloader-to-recovery-manually-instructions-2": "2. Premi Accensione per confermare", + "bootloader-to-recovery-manually-instructions-3": "3. Se hai saltato questo passaggio, spegni il telefono e avvia in modalità Recovery premendo contemporaneamente Accensione e Volume su fino a quando il dispositivo si accende.", + "check-update-android-version": "Controlla e aggiorna la tua versione di Android", + "check-update-android-version-caution": "Attenzione: prima di procedere con l'installazione, verifica se è disponibile l'ultimo firmware Android per il tuo dispositivo.", + "connect": "Connetti", + "connect-bootloader": "Connessione del bootloader", + "connect-bootloader-instructions-1": "Il tuo telefono ora si riavvierà in modalità bootloader", + "connect-bootloader-instructions-2": "Quando il telefono è acceso, connettiti in modalità bootloader cliccando sul pulsante qui sotto", + "connect-your-phone": "Connetti il tuo telefono", + "connect-your-phone-instructions": "Connetti il tuo telefono al computer con un cavo USB. Rileveremo automaticamente il tuo telefono per installare /e/OS.", + "connect-your-phone-instructions-notes": "Nota: il 'debug USB' è necessario affinché la rilevazione automatica del dispositivo funzioni. Se non l'hai ancora abilitato, ti aiuteremo nei prossimi passaggi.", + "device-detection": "Rilevamento del dispositivo", + "device-detection-detected": "È stato rilevato un dispositivo.", + "device-detection-instructions-1": "Ora connetteremo il tuo telefono al browser. Quando appare questo pop-up, seleziona il tuo telefono dall'elenco.", + "device-detection-instructions-2": "Poi apparirà una finestra pop-up sul tuo telefono. Dovrai selezionare consenti sempre da questo computer prima di premere OK.", + "device-detection-instructions-3": "Clicca sul pulsante qui sotto per avviare la connessione", + "device-model-not-supported": "Modello di dispositivo non supportato", + "device-model-not-supported-instructions": "non puoi installare /e/OS usando questo strumento", + "device-model-not-supported-title": "Il tuo telefono {{product-name}} non è compatibile", + "dissatisfied": "Insoddisfatto", + "donate": "Dona", + "enable-usb-file-transfer": "Abilita il trasferimento di file USB", + "enable-usb-file-transfer-instructions-1": "Sempre all'interno delle 'Opzioni sviluppatore', scorri verso il basso per trovare 'Configurazione USB predefinita' e toccala.", + "enable-usb-file-transfer-instructions-2": "Ora seleziona l'opzione 'Trasferimento di file' (su alcuni dispositivi si chiama 'modalità MTP (protocollo di trasferimento multimediale)').", + "format-device": "Formatta il dispositivo", + "format-device-instructions-1": "1. Seleziona Ripristino dati di fabbrica", + "format-device-instructions-2": "2. Seleziona l'opzione Formatta dati / Ripristino dati di fabbrica", + "format-device-instructions-3": "3. La schermata successiva mostrerà un avviso che questa azione non può essere annullata", + "format-device-instructions-4": "4. Seleziona Formatta dati per procedere o Annulla se vuoi tornare indietro", + "format-device-instructions-5": "5. Se hai selezionato Formatta dati, il processo di formattazione verrà completato", + "format-device-instructions-6": "6. Lo schermo ora tornerà alla schermata di Ripristino dati di fabbrica", + "go-to-apply-update": "Quasi fatto!", + "go-to-apply-update-instructions-1": "1. Seleziona Applica aggiornamento", + "go-to-apply-update-instructions-2": "2. Applica aggiornamento da adb", + "go-to-apply-update-instructions-3": "Il dispositivo è ora in modalità sideload", + "help": "Aiuto", + "help-us-improve-the-tool": "Aiutaci a migliorare lo strumento", + "help-us-improve-the-tool-instructions-1": "Per favore, valuta la tua esperienza con l'/e/OS Installer.", + "help-us-improve-the-tool-instructions-2": "Hai qualche idea su come migliorare questo software?", + "i-already-have-an-account": "Ho già un account", + "i-m-ready": "Sono pronto!", + "installation-complete": "L'installazione è completa!", + "installation-complete-instructions-1": "Congratulazioni! Mentre il tuo telefono si avvia, dovresti vedere il logo qui sotto. Questo richiede tempo, sii paziente.", + "installation-complete-instructions-2": "Consiglio: segui le istruzioni sul tuo telefono per configurare il tuo dispositivo. Ora puoi aggiungere di nuovo i tuoi file al telefono.", + "let-s-get-started": "Iniziamo", + "let-s-get-started-instruction-1": "Il processo completo di installazione richiede circa 1 ora. \nSii paziente!", + "let-s-get-started-instruction-2": "Avrai bisogno di almeno 6GB di spazio libero sul tuo computer per\nscaricare e installare /e/OS. Assicurati di avere abbastanza spazio libero sul disco.", + "let-s-get-started-instruction-3": "Prima di installare /e/OS, assicurati che il tuo telefono abbia almeno il 50% di batteria", + "let-s-get-started-instruction-4": "Tutti i dati verranno cancellati dal tuo smartphone durante l'installazione\nquindi ti consigliamo di eseguire il backup dei tuoi dati.", + "let-s-get-started-instruction-5": "È necessario un cavo dati USB funzionante. I cavi di alimentazione non trasferiscono dati\ne non funzioneranno! Raccomandiamo USB 3.x o successivi.", + "let-s-get-started-instruction-title-1": "1. Libera un po' di tempo", + "let-s-get-started-instruction-title-2": "2. Libera spazio sul disco", + "let-s-get-started-instruction-title-3": "3. Carica il tuo telefono", + "let-s-get-started-instruction-title-4": "4. Esegui il backup dei tuoi dati", + "let-s-get-started-instruction-title-5": "5. Prendi un cavo dati USB", + "locking": "Blocco", + "locking-instructions-1": "Il tuo telefono chiede uno sblocco. Seleziona lock bootloader", + "locking-instructions-2": "Se il dispositivo non si riavvia automaticamente, riavvialo", + "murena-workspace-account": "Account Murena Workspace", + "murena-workspace-account-instructions": "Mantieni i tuoi dati al sicuro e sincronizza questo dispositivo con il tuo account personale Murena Workspace. 1GB gratuito e piani a pagamento disponibili per più spazio di archiviazione.", + "navigator-detection": "Rilevamento del browser", + "navigator-not-supported": "Il tuo browser non è supportato", + "navigator-not-supported-instructions": "Puoi usare i seguenti browser", + "neutral": "Neutro", + "next": "Successivo", + "ready-to-install-e-os": "Ora sei pronto per installare /e/OS.", + "recovery-to-bootloader": "Recovery a Bootloader", + "recovery-to-bootloader-instructions": "Seleziona Avanzato", + "recovery-to-bootloader-instructions-1": "1. Seleziona Advanced", + "recovery-to-bootloader-instructions-2": "2. Seleziona Reboot to bootloader", + "satisfied": "Soddisfatto", + "send-to-e-team": "Invia al team di /e/", + "sideload": "Installazione in corso", + "sideload-instructions-1": "Lo schermo mostrerà la percentuale di completamento... ", + "sideload-instructions-2": "Questo potrebbe fermarsi al 47%, dagli tempo.", + "sideload-instructions-3": "Una volta che l'installazione è terminata, il telefono tornerà alla schermata principale.", + "sideload-instructions-4": "Solo allora puoi cliccare su Next.", + "sign-up-free": "Iscriviti GRATIS", + "skip": "Salta", + "start": "Inizia", + "this-might-take-some-time-please-be-patient": "Questo potrebbe richiedere del tempo, per favore sii paziente", + "unlocking-instructions-1": "Il tuo telefono chiede uno sblocco. Seleziona unlock bootloader", + "unlocking-instructions-2": "Se il dispositivo non si riavvia automaticamente, riavvialo. Ora dovrebbe essere sbloccato.", + "unlocking-instructions-3": "Poiché il dispositivo si resetta completamente, dovrai riattivare il debug USB.", + "unlocking-instructions-4": "Supera la configurazione e fai clic su successivo", + "very-dissatisfied": "Molto insoddisfatto", + "very-satisfied": "Molto soddisfatto" } diff --git a/app/public/assets/languages/nb-NO.json b/app/public/assets/languages/nb-NO.json index 478d64be615b6febd89b4a52771fc05e0a8ee6df..fa415a308ca6680a9fb1c7f2964157025fa3a893 100644 --- a/app/public/assets/languages/nb-NO.json +++ b/app/public/assets/languages/nb-NO.json @@ -1,44 +1,44 @@ { - "Ex 1: before installing /e/OS Android 12, you should update to the latest stock Android 12": "Eks. 1: før du installerer /e/OS Android 12, bør du oppdatere til den nyeste Android 12", - "Ex 2: or if you're installing /e/OS Android 11, make sure to update to the latest stock Android 11": "Eks. 2: eller hvis du installerer /e/OS Android 11, må du sørge for å oppdatere til den nyeste Android 11", - "Ex 3: similarly, if you're installing /e/OS Android 11, it should be the latest stock Android 10": "Eks. 3: likeså, hvis du installerer /e/OS Android 11, bør det være den nyeste Android 10", - "activate-developer-options": "Aktiver utvikleralternativer", - "activate-usb-debugging": "Aktiver USB-feilsøking", - "activate-developer-options-instructions-1": "1. Åpne menyen Innstillinger, og skriv \"bygg\" i søkefeltet.", - "activate-developer-options-instructions-2": "2. På neste skjermbilde finner du \"Byggnummer\" og trykker 7 ganger på det.", - "activate-usb-debugging-instructions-1": "Gå tilbake til menyen Innstillinger og skriv \"USB-feilsøking\" i søkefeltet.", - "activate-usb-debugging-instructions-2": "På dette tidspunktet bør du være i skjermbildet \"Utvikleralternativer\". Trykk nå på \"USB-feilsøking\" for å aktivere den (på noen enheter kalles den \"Android-feilsøking\").", - "check-update-android-version-caution": "Advarsel: Før du fortsetter med installasjonen, må du kontrollere at den nyeste Android-versjonen er tilgjengelig for enheten din.", - "enable-usb-file-transfer-instructions-1": "Fortsatt inne i \"Utvikleralternativer\", bla nedover for å finne \"Standard USB-konfigurasjon\" og trykk på den.", - "connect-bootloader-instructions-2": "Når telefonen er på, kan du aktivere bootloader-modus ved å klikke på knappen nedenfor", - "connect-your-phone-instructions-notes": "Husk: \"USB-feilsøking\" må være aktivert for at automatisk enhetsgjenkjenning skal fungere. Hvis du ikke har aktivert det ennå, vil vi hjelpe deg i de neste trinnene.", - "format-device-instructions-3": "3. Neste skjermbilde viser en advarsel om at denne handlingen ikke kan angres", - "bootloader-to-recovery-manually": "Bootloader til gjenoppretting", - "bootloader-to-recovery-manually-instructions": "Nå starter vi enheten på nytt i gjenopprettingsmodus. Vennligst følg trinnene nedenfor:", - "bootloader-to-recovery-manually-instructions-1": "1. I bootloader, velger du gjenoppretting ved å bruke Volum opp og Volum ned for å navigere", - "bootloader-to-recovery-manually-instructions-3": "3. Hvis du gikk glipp av dette trinnet, kan du slå av enheten og starte den på nytt i gjenopprettingsmodus ved å trykke på og holde inne Av/På-knappen og Volum opp samtidig, til enheten slås på.", - "bootloader-to-recovery-manually-instructions-2": "2. Trykk på Av/På-knappen for å bekrefte", - "check-update-android-version": "Sjekk og oppdater Android-versjonen", - "connect": "Koble til", - "connect-bootloader": "Bootloader-tilkobling", - "connect-bootloader-instructions-1": "Telefonen vil nå starte på nytt i bootloader-modus", - "connect-your-phone": "Koble til telefonen din", - "connect-your-phone-instructions": "Koble telefonen til datamaskinen med en USB-kabel. Vi vil automatisk oppdage telefonen din for å installere /e/OS.", - "device-detection": "Enhetsgjenkjenning", - "device-detection-detected": "En enhet har blitt oppdaget.", - "device-detection-instructions-1": "Vi kobler nå telefonen din til nettleseren. Når dette popup-vinduet vises, velger du telefonen din fra listen.", - "device-detection-instructions-2": "Et popup-vindu vises deretter på telefonen din. Du må krysse av for Tillat alltid fra denne datamaskinen før du trykker Ok.", - "device-detection-instructions-3": "Klikk på knappen nedenfor for å koble til", - "device-model-not-supported": "Enhetsmodellen støttes ikke", - "device-model-not-supported-instructions": "du kan ikke installere /e/OS ved hjelp av dette programmet", - "device-model-not-supported-title": "Telefonen din {{product-name}} er ikke kompatibel", - "dissatisfied": "Misfornøyd", - "donate": "Doner", - "enable-usb-file-transfer": "Aktiver USB-filoverføring", - "enable-usb-file-transfer-instructions-2": "Velg alternativet \"Filoverføring\" (på noen enheter kalles det \"MTP-modus (media transfer protocol)\").", - "format-device": "Formater enheten", - "format-device-instructions-1": "1. Velg Fabrikkinnstillinger", - "format-device-instructions-2": "2. Velg alternativet Formater data / Tilbakestill til fabrikkinnstillinger", - "format-device-instructions-4": "4. Velg Formater data for å fortsette eller Avbryt hvis du vil gå tilbake", - "format-device-instructions-5": "5. Hvis du har valgt Formater data, fullføres formateringsprosessen" + "Ex 1: before installing /e/OS Android 12, you should update to the latest stock Android 12": "Eks. 1: før du installerer /e/OS Android 12, bør du oppdatere til den nyeste Android 12", + "Ex 2: or if you're installing /e/OS Android 11, make sure to update to the latest stock Android 11": "Eks. 2: eller hvis du installerer /e/OS Android 11, må du sørge for å oppdatere til den nyeste Android 11", + "Ex 3: similarly, if you're installing /e/OS Android 11, it should be the latest stock Android 10": "Eks. 3: likeså, hvis du installerer /e/OS Android 11, bør det være den nyeste Android 10", + "activate-developer-options": "Aktiver utvikleralternativer", + "activate-usb-debugging": "Aktiver USB-feilsøking", + "activate-developer-options-instructions-1": "1. Åpne menyen Innstillinger, og skriv \"bygg\" i søkefeltet.", + "activate-developer-options-instructions-2": "2. På neste skjermbilde finner du \"Byggnummer\" og trykker 7 ganger på det.", + "activate-usb-debugging-instructions-1": "Gå tilbake til menyen Innstillinger og skriv \"USB-feilsøking\" i søkefeltet.", + "activate-usb-debugging-instructions-2": "På dette tidspunktet bør du være i skjermbildet \"Utvikleralternativer\". Trykk nå på \"USB-feilsøking\" for å aktivere den (på noen enheter kalles den \"Android-feilsøking\").", + "check-update-android-version-caution": "Advarsel: Før du fortsetter med installasjonen, må du kontrollere at den nyeste Android-versjonen er tilgjengelig for enheten din.", + "enable-usb-file-transfer-instructions-1": "Fortsatt inne i \"Utvikleralternativer\", bla nedover for å finne \"Standard USB-konfigurasjon\" og trykk på den.", + "connect-bootloader-instructions-2": "Når telefonen er på, kan du aktivere bootloader-modus ved å klikke på knappen nedenfor", + "connect-your-phone-instructions-notes": "Husk: \"USB-feilsøking\" må være aktivert for at automatisk enhetsgjenkjenning skal fungere. Hvis du ikke har aktivert det ennå, vil vi hjelpe deg i de neste trinnene.", + "format-device-instructions-3": "3. Neste skjermbilde viser en advarsel om at denne handlingen ikke kan angres", + "bootloader-to-recovery-manually": "Bootloader til gjenoppretting", + "bootloader-to-recovery-manually-instructions": "Nå starter vi enheten på nytt i gjenopprettingsmodus. Vennligst følg trinnene nedenfor:", + "bootloader-to-recovery-manually-instructions-1": "1. I bootloader, velger du gjenoppretting ved å bruke Volum opp og Volum ned for å navigere", + "bootloader-to-recovery-manually-instructions-3": "3. Hvis du gikk glipp av dette trinnet, kan du slå av enheten og starte den på nytt i gjenopprettingsmodus ved å trykke på og holde inne Av/På-knappen og Volum opp samtidig, til enheten slås på.", + "bootloader-to-recovery-manually-instructions-2": "2. Trykk på Av/På-knappen for å bekrefte", + "check-update-android-version": "Sjekk og oppdater Android-versjonen", + "connect": "Koble til", + "connect-bootloader": "Bootloader-tilkobling", + "connect-bootloader-instructions-1": "Telefonen vil nå starte på nytt i bootloader-modus", + "connect-your-phone": "Koble til telefonen din", + "connect-your-phone-instructions": "Koble telefonen til datamaskinen med en USB-kabel. Vi vil automatisk oppdage telefonen din for å installere /e/OS.", + "device-detection": "Enhetsgjenkjenning", + "device-detection-detected": "En enhet har blitt oppdaget.", + "device-detection-instructions-1": "Vi kobler nå telefonen din til nettleseren. Når dette popup-vinduet vises, velger du telefonen din fra listen.", + "device-detection-instructions-2": "Et popup-vindu vises deretter på telefonen din. Du må krysse av for Tillat alltid fra denne datamaskinen før du trykker Ok.", + "device-detection-instructions-3": "Klikk på knappen nedenfor for å koble til", + "device-model-not-supported": "Enhetsmodellen støttes ikke", + "device-model-not-supported-instructions": "du kan ikke installere /e/OS ved hjelp av dette programmet", + "device-model-not-supported-title": "Telefonen din {{product-name}} er ikke kompatibel", + "dissatisfied": "Misfornøyd", + "donate": "Doner", + "enable-usb-file-transfer": "Aktiver USB-filoverføring", + "enable-usb-file-transfer-instructions-2": "Velg alternativet \"Filoverføring\" (på noen enheter kalles det \"MTP-modus (media transfer protocol)\").", + "format-device": "Formater enheten", + "format-device-instructions-1": "1. Velg Fabrikkinnstillinger", + "format-device-instructions-2": "2. Velg alternativet Formater data / Tilbakestill til fabrikkinnstillinger", + "format-device-instructions-4": "4. Velg Formater data for å fortsette eller Avbryt hvis du vil gå tilbake", + "format-device-instructions-5": "5. Hvis du har valgt Formater data, fullføres formateringsprosessen" } diff --git a/app/public/assets/languages/ru.json b/app/public/assets/languages/ru.json index 2d1a4379d797ddef0309c0517ae9305d29b82368..325927c563062495a0dacec460e179682728232f 100644 --- a/app/public/assets/languages/ru.json +++ b/app/public/assets/languages/ru.json @@ -1,14 +1,14 @@ { - "Ex 1: before installing /e/OS Android 12, you should update to the latest stock Android 12": "Вывод 1: перед установкой /e/OS Android 12 необходимо обновить до последней стоковой версии Android 12", - "activate-developer-options-instructions-1": "1. Откройте меню настроек и введите \"build\" в строке поиска.", - "activate-usb-debugging-instructions-2": "2. В этот момент вы должны оказаться на экране \"Параметры разработчика\". Теперь нажмите на \"Отладка USB\", чтобы активировать ее (на некоторых устройствах она называется \"Отладка Android\").", - "Ex 3: similarly, if you're installing /e/OS Android 11, it should be the latest stock Android 10": "Вывод 3: Аналогично, если вы устанавливаете /e/OS Android 11, это должна быть последняя стоковая версия Android 10", - "activate-developer-options": "Активируйте Опции разработчика", - "activate-developer-options-instructions-2": "2. На следующем экране найдите \"Build number\" и нажмите на него 7 раз.", - "activate-usb-debugging": "Активируйте отладку по USB", - "activate-usb-debugging-instructions-1": "1. Вернитесь в меню настроек и введите в строке поиска \"Отладка USB\".", - "android-version-not-supported": "Устаревшая версия Android", - "android-version-not-supported-instructions": "Обновите свою систему до минимально необходимой версии {{android-version-required}}", - "android-version-not-supported-title": "Ваша версия Android {{android-version}} не поддерживается", - "Ex 2: or if you're installing /e/OS Android 11, make sure to update to the latest stock Android 11": "Вывод 2: или если вы устанавливаете /e/OS Android 11, обязательно обновитесь до последней стоковой версии Android 11" + "Ex 1: before installing /e/OS Android 12, you should update to the latest stock Android 12": "Вывод 1: перед установкой /e/OS Android 12 необходимо обновить до последней стоковой версии Android 12", + "activate-developer-options-instructions-1": "1. Откройте меню настроек и введите \"build\" в строке поиска.", + "activate-usb-debugging-instructions-2": "2. В этот момент вы должны оказаться на экране \"Параметры разработчика\". Теперь нажмите на \"Отладка USB\", чтобы активировать ее (на некоторых устройствах она называется \"Отладка Android\").", + "Ex 3: similarly, if you're installing /e/OS Android 11, it should be the latest stock Android 10": "Вывод 3: Аналогично, если вы устанавливаете /e/OS Android 11, это должна быть последняя стоковая версия Android 10", + "activate-developer-options": "Активируйте Опции разработчика", + "activate-developer-options-instructions-2": "2. На следующем экране найдите \"Build number\" и нажмите на него 7 раз.", + "activate-usb-debugging": "Активируйте отладку по USB", + "activate-usb-debugging-instructions-1": "1. Вернитесь в меню настроек и введите в строке поиска \"Отладка USB\".", + "android-version-not-supported": "Устаревшая версия Android", + "android-version-not-supported-instructions": "Обновите свою систему до минимально необходимой версии {{android-version-required}}", + "android-version-not-supported-title": "Ваша версия Android {{android-version}} не поддерживается", + "Ex 2: or if you're installing /e/OS Android 11, make sure to update to the latest stock Android 11": "Вывод 2: или если вы устанавливаете /e/OS Android 11, обязательно обновитесь до последней стоковой версии Android 11" } diff --git a/app/public/assets/languages/sv.json b/app/public/assets/languages/sv.json index fc2805ef63cbbd0059878ba6c40241bf3302f626..4c33d7d583030cb582f9b3e35164eedfe577c0b4 100644 --- a/app/public/assets/languages/sv.json +++ b/app/public/assets/languages/sv.json @@ -1,110 +1,110 @@ { - "donate": "Donera", - "connect": "Anslut", - "connect-your-phone": "Anslut din telefon", - "Ex 1: before installing /e/OS Android 12, you should update to the latest stock Android 12": "Exempel 1: innan installation av /e/OS Android 12 bör du uppgradera till den senaste standardversionen av Android 12", - "Ex 2: or if you're installing /e/OS Android 11, make sure to update to the latest stock Android 11": "Exempel 2: eller om du installerar /e/OS Android 11, se till att uppgradera till den senaste standardversionen av Android 11", - "next": "Nästa", - "connect-bootloader": "Anslutning starthanteraren", - "connect-bootloader-instructions-2": "När din telefon är på ansluter du telefonen i läget starthanteraren genom att klicka på knappen nedan", - "connect-your-phone-instructions-notes": "Obs! \"USB-felsökning\" krävs för att automatisk enhetsupptäckt ska fungera. Om du inte har aktiverat det än kommer vi hjälpa dig i de kommande stegen.", - "device-detection": "Enhetsupptäckt", - "device-detection-detected": "En enhet har upptäckts.", - "device-detection-instructions-1": "Vi kommer nu ansluta din telefon till webbläsaren. När du ser en popupp väljer du din telefon från listan.", - "device-detection-instructions-3": "Klicka på knappen nedan för att starta anslutningen", - "device-model-not-supported": "Enhetens modell stöds inte", - "device-model-not-supported-instructions": "du kan inte installera /e/OS med detta program", - "device-model-not-supported-title": "Din telefon {{product-name}} är inte kompatibel", - "dissatisfied": "Inte nöjd", - "enable-usb-file-transfer": "Aktivera filöverföring via USB", - "connect-bootloader-instructions-1": "Din telefon kommer nu att starta om i läget starthanteraren", - "connect-your-phone-instructions": "Anslut din telefon till din dator med en USB-kabel. Vi kommer automatiskt upptäcka din telefon för att installera /e/OS.", - "device-detection-instructions-2": "Ett popupp-fönster kommer synas på din telefon. Du behöver markera tillåt alltid från denna dator innan du trycker ok.", - "Ex 3: similarly, if you're installing /e/OS Android 11, it should be the latest stock Android 10": "Exempel 3: och om du installerar /e/OS Android 11 bör det vara den senaste standardversionen av Android 10", - "activate-developer-options": "Aktivera utvecklaralternativ", - "activate-developer-options-instructions-1": "1. Öppna inställningsmenyn och skriv \"build\" i sökfältet.", - "activate-developer-options-instructions-2": "2. På nästa skärm letar du upp \"Build number\" och trycker 7 gånger på det.", - "activate-usb-debugging": "Aktivera USB-felsökning", - "activate-usb-debugging-instructions-2": "2. Nu bör du vara i \"Utvecklaralternativ\". Tryck nu på \"USB-felsökning\" för att aktivera det (på vissa enheter kan det kallas (Android-felsökning\").", - "activate-usb-debugging-instructions-1": "1. Gå tillbaka till inställningsmenyn och skriv \"USB-felsökning\" i sökfältet.", - "bootloader-to-recovery-manually": "Starthanterare till återställning", - "bootloader-to-recovery-manually-instructions": "Nu ska vi starta om din enhet i Återställningsläget. Följ nedan steg:", - "bootloader-to-recovery-manually-instructions-1": "1. Välj Återställningsläge i starthanteraren genom att navigera med Volum upp och Volym ned", - "bootloader-to-recovery-manually-instructions-2": "2. Tryck på Av/På-knappen för att bekräfta", - "check-update-android-version": "Kontrollera och uppdatera din Androidversion", - "check-update-android-version-caution": "Varning: innan du fortsätter med installationen, kontrollera om den senaste Androidversionen finns tillgänglig för din enhet.", - "enable-usb-file-transfer-instructions-1": "Medan du fortfarande är inne i \"Utvecklaralternativ\" skrollar du ner för att hitta \"USB standardkonfiguration\" och trycker på det.", - "format-device": "Formatera enheten", - "format-device-instructions-1": "1. Välj fabriksåterställning", - "format-device-instructions-2": "2. Välj alternativet Formatera data/Fabriksåterställning", - "format-device-instructions-3": "3. Nästa skärm kommer visa en varning om att denna åtgärd inte kan göras ogjord", - "format-device-instructions-4": "4. Välj Formatera data för att fortsätta", - "format-device-instructions-5": "5. Vänta medan formateringsprocessen slutförs", - "format-device-instructions-6": "6. Skärmen kommer nu gå tillbaka till skärmen Fabriksåterställning", - "help": "Hjälp", - "help-us-improve-the-tool": "Hjälp oss förbättra verktyget", - "help-us-improve-the-tool-instructions-1": "Vänligen betygsätt upplevelsen med /e/OS Installer.", - "help-us-improve-the-tool-instructions-2": "Har du några tankar om hur programvaran skulle kunna förbättras?", - "i-already-have-an-account": "Jag har redan ett konto", - "i-m-ready": "Jag är redo!", - "installation-complete": "Installationen är klar!", - "installation-complete-instructions-1": "Grattis! Medan din telefon startar bör du se loggan nedan. Detta tar tid, vänligen var tålmodig.", - "go-to-apply-update": "Nästan där!", - "go-to-apply-update-instructions-1": "1. Välj applicera uppdatering.", - "go-to-apply-update-instructions-2": "2. Sedan Applicera uppdatering från adb.", - "installation-complete-instructions-2": "Tips: följ instruktionerna på din telefon för att ställa in din enhet. Du kan nu föra över dina filer tillbaka till din telefon.", - "let-s-get-started-instruction-1": "Hela installationsprocessen kräver cirka 1 timme. Var\n tålmodig!", - "enable-usb-file-transfer-instructions-2": "Välj nu alternativet Filöverföring (på en del enheter kallas det \"MTP-läge (media transfer protocol)\").", - "format-device-instructions-7": "7. Tryck på bakåtpilen och tryck på Nästa", - "locking-instructions-3": "Klicka sedan på nästa", - "murena-workspace-account": "Murena Workspace-konto", - "murena-workspace-account-instructions": "Håll din data säker och synkronisera denna enheten med ditt personliga Murena Workspace-konto. 1 GB gratis och det finns betalplaner för mer utrymme.", - "navigator-detection": "Navigatorupptäckt", - "navigator-not-supported": "Din navigator stöds inte", - "navigator-not-supported-instructions": "Du kan använda följande webbläsare", - "neutral": "Neutral", - "unlocking-instructions-1-a": "Använd Av/På-knappen för att bekräfta.", - "android-version-not-supported": "Androidversionen är utdaterad", - "android-version-not-supported-title": "Din Androidverson {{android-version}} stöds inte", - "android-version-not-supported-instructions": "Uppdatera ditt system till den version som är minimikravet {{android-version-required}}", - "go-to-apply-update-instructions-3": "3. Enheten är nu i \"sideload\"-läge, du är nu redo för nästa steg.", - "let-s-get-started": "Nu sätter vi igång", - "let-s-get-started-instruction-2": "Du behöver minst 6 GB ledigt utrymme på din dator\n för att hämta och installera /e/OS. Se till att du har tillräckligt med ledigt utrymme på hårddisken.", - "let-s-get-started-instruction-3": "Se till att telefonens batteri har minst 50% laddning kvar innan du installerar /e/OS", - "let-s-get-started-instruction-4": "All data kommer raderas från din smarta telefon under installationen,\n vi rekommenderar att du tar en säkerhetskopia av din data.", - "let-s-get-started-instruction-5": "Det krävs en fungerande USB-datakabel. Laddkablar överför inte data\n och kommer inte att fungera! Vi rekommenderar USB 3.x eller senare.", - "let-s-get-started-instruction-title-1": "1. Frigör lite tid", - "let-s-get-started-instruction-title-2": "2. Frigör lagringsutrymme", - "let-s-get-started-instruction-title-3": "3. Ladda din telefon", - "let-s-get-started-instruction-title-4": "4. Säkerhetskopiera din data", - "let-s-get-started-instruction-title-5": "5. Ta en USB-datakabel", - "locking": "Låser", - "locking-instructions-1": "Din telefon frågar om att låsas upp. Välj lås starthanteraren", - "locking-instructions-2": "Starta om din telefon om den inte startar om automatiskt", - "ready-to-install-e-os": "Du är nu redo att installera /e/OS.", - "recovery-to-bootloader": "Återställning till Starthanteraren", - "recovery-to-bootloader-instructions": "I huvudmenyn", - "recovery-to-bootloader-instructions-1": "1. Välj Avancerad", - "recovery-to-bootloader-instructions-2": "2. Välj Starta om till starthanteraren", - "satisfied": "Nöjd", - "send-to-e-team": "Skicka till Murena-teamet", - "sideload": "Installation pågår", - "sideload-instructions-1": "Skärmen kommer visa processen ... ", - "sideload-instructions-2": "Detta kan ta flera minuter, ge det lite tid.", - "sideload-instructions-3": "När installationen är klar kommer telefonen att gå tillbaka till huvudskärmen.", - "sideload-instructions-4": "Endast då kan du klicka på Nästa.", - "skip": "Hoppa över", - "start": "Starta", - "this-might-take-some-time-please-be-patient": "Detta kan ta lite tid, vänligen ha tålamod", - "unlocking-instructions-1": "Din telefon frågaor om upplåsning. Välj lås upp starthanteraren genom att navigera med Volym upp och Volym ned.", - "unlocking-instructions-2": "Starta om enheten om den inte startar om automatiskt.", - "bootloader-to-recovery-manually-instructions-3": "3. Vänta på att telefonen startar i återställning", - "go-to-apply-update-instructions-4": "Observera! Inför nästa steg kanske webbläsaren behöver återansluta till din telefon. Om ett popup-fönster dyker upp, välj din telefon från listan.", - "installing": "Installerar", - "unlocking-instructions-2-a": "Din enhet kommer starta om. Vänta till Starthanterarens skärm visas igen innan du går vidare till nästa steg", - "very-satisfied": "Mycket nöjd", - "unlocking-instructions-3": "Eftersom enheter helt återställs kommer du behöva aktivera USB-felsökning igen.", - "unlocking-instructions-4": "Hoppa över inställningen på telefonen och klicka på nästa", - "very-dissatisfied": "Mycket missnöjd", - "sign-up-free": "Registrera dig GRATIS" + "donate": "Donera", + "connect": "Anslut", + "connect-your-phone": "Anslut din telefon", + "Ex 1: before installing /e/OS Android 12, you should update to the latest stock Android 12": "Exempel 1: innan installation av /e/OS Android 12 bör du uppgradera till den senaste standardversionen av Android 12", + "Ex 2: or if you're installing /e/OS Android 11, make sure to update to the latest stock Android 11": "Exempel 2: eller om du installerar /e/OS Android 11, se till att uppgradera till den senaste standardversionen av Android 11", + "next": "Nästa", + "connect-bootloader": "Anslutning starthanteraren", + "connect-bootloader-instructions-2": "När din telefon är på ansluter du telefonen i läget starthanteraren genom att klicka på knappen nedan", + "connect-your-phone-instructions-notes": "Obs! \"USB-felsökning\" krävs för att automatisk enhetsupptäckt ska fungera. Om du inte har aktiverat det än kommer vi hjälpa dig i de kommande stegen.", + "device-detection": "Enhetsupptäckt", + "device-detection-detected": "En enhet har upptäckts.", + "device-detection-instructions-1": "Vi kommer nu ansluta din telefon till webbläsaren. När du ser en popupp väljer du din telefon från listan.", + "device-detection-instructions-3": "Klicka på knappen nedan för att starta anslutningen", + "device-model-not-supported": "Enhetens modell stöds inte", + "device-model-not-supported-instructions": "du kan inte installera /e/OS med detta program", + "device-model-not-supported-title": "Din telefon {{product-name}} är inte kompatibel", + "dissatisfied": "Inte nöjd", + "enable-usb-file-transfer": "Aktivera filöverföring via USB", + "connect-bootloader-instructions-1": "Din telefon kommer nu att starta om i läget starthanteraren", + "connect-your-phone-instructions": "Anslut din telefon till din dator med en USB-kabel. Vi kommer automatiskt upptäcka din telefon för att installera /e/OS.", + "device-detection-instructions-2": "Ett popupp-fönster kommer synas på din telefon. Du behöver markera tillåt alltid från denna dator innan du trycker ok.", + "Ex 3: similarly, if you're installing /e/OS Android 11, it should be the latest stock Android 10": "Exempel 3: och om du installerar /e/OS Android 11 bör det vara den senaste standardversionen av Android 10", + "activate-developer-options": "Aktivera utvecklaralternativ", + "activate-developer-options-instructions-1": "1. Öppna inställningsmenyn och skriv \"build\" i sökfältet.", + "activate-developer-options-instructions-2": "2. På nästa skärm letar du upp \"Build number\" och trycker 7 gånger på det.", + "activate-usb-debugging": "Aktivera USB-felsökning", + "activate-usb-debugging-instructions-2": "2. Nu bör du vara i \"Utvecklaralternativ\". Tryck nu på \"USB-felsökning\" för att aktivera det (på vissa enheter kan det kallas (Android-felsökning\").", + "activate-usb-debugging-instructions-1": "1. Gå tillbaka till inställningsmenyn och skriv \"USB-felsökning\" i sökfältet.", + "bootloader-to-recovery-manually": "Starthanterare till återställning", + "bootloader-to-recovery-manually-instructions": "Nu ska vi starta om din enhet i Återställningsläget. Följ nedan steg:", + "bootloader-to-recovery-manually-instructions-1": "1. Välj Återställningsläge i starthanteraren genom att navigera med Volum upp och Volym ned", + "bootloader-to-recovery-manually-instructions-2": "2. Tryck på Av/På-knappen för att bekräfta", + "check-update-android-version": "Kontrollera och uppdatera din Androidversion", + "check-update-android-version-caution": "Varning: innan du fortsätter med installationen, kontrollera om den senaste Androidversionen finns tillgänglig för din enhet.", + "enable-usb-file-transfer-instructions-1": "Medan du fortfarande är inne i \"Utvecklaralternativ\" skrollar du ner för att hitta \"USB standardkonfiguration\" och trycker på det.", + "format-device": "Formatera enheten", + "format-device-instructions-1": "1. Välj fabriksåterställning", + "format-device-instructions-2": "2. Välj alternativet Formatera data/Fabriksåterställning", + "format-device-instructions-3": "3. Nästa skärm kommer visa en varning om att denna åtgärd inte kan göras ogjord", + "format-device-instructions-4": "4. Välj Formatera data för att fortsätta", + "format-device-instructions-5": "5. Vänta medan formateringsprocessen slutförs", + "format-device-instructions-6": "6. Skärmen kommer nu gå tillbaka till skärmen Fabriksåterställning", + "help": "Hjälp", + "help-us-improve-the-tool": "Hjälp oss förbättra verktyget", + "help-us-improve-the-tool-instructions-1": "Vänligen betygsätt upplevelsen med /e/OS Installer.", + "help-us-improve-the-tool-instructions-2": "Har du några tankar om hur programvaran skulle kunna förbättras?", + "i-already-have-an-account": "Jag har redan ett konto", + "i-m-ready": "Jag är redo!", + "installation-complete": "Installationen är klar!", + "installation-complete-instructions-1": "Grattis! Medan din telefon startar bör du se loggan nedan. Detta tar tid, vänligen var tålmodig.", + "go-to-apply-update": "Nästan där!", + "go-to-apply-update-instructions-1": "1. Välj applicera uppdatering.", + "go-to-apply-update-instructions-2": "2. Sedan Applicera uppdatering från adb.", + "installation-complete-instructions-2": "Tips: följ instruktionerna på din telefon för att ställa in din enhet. Du kan nu föra över dina filer tillbaka till din telefon.", + "let-s-get-started-instruction-1": "Hela installationsprocessen kräver cirka 1 timme. Var\n tålmodig!", + "enable-usb-file-transfer-instructions-2": "Välj nu alternativet Filöverföring (på en del enheter kallas det \"MTP-läge (media transfer protocol)\").", + "format-device-instructions-7": "7. Tryck på bakåtpilen och tryck på Nästa", + "locking-instructions-3": "Klicka sedan på nästa", + "murena-workspace-account": "Murena Workspace-konto", + "murena-workspace-account-instructions": "Håll din data säker och synkronisera denna enheten med ditt personliga Murena Workspace-konto. 1 GB gratis och det finns betalplaner för mer utrymme.", + "navigator-detection": "Navigatorupptäckt", + "navigator-not-supported": "Din navigator stöds inte", + "navigator-not-supported-instructions": "Du kan använda följande webbläsare", + "neutral": "Neutral", + "unlocking-instructions-1-a": "Använd Av/På-knappen för att bekräfta.", + "android-version-not-supported": "Androidversionen är utdaterad", + "android-version-not-supported-title": "Din Androidverson {{android-version}} stöds inte", + "android-version-not-supported-instructions": "Uppdatera ditt system till den version som är minimikravet {{android-version-required}}", + "go-to-apply-update-instructions-3": "3. Enheten är nu i \"sideload\"-läge, du är nu redo för nästa steg.", + "let-s-get-started": "Nu sätter vi igång", + "let-s-get-started-instruction-2": "Du behöver minst 6 GB ledigt utrymme på din dator\n för att hämta och installera /e/OS. Se till att du har tillräckligt med ledigt utrymme på hårddisken.", + "let-s-get-started-instruction-3": "Se till att telefonens batteri har minst 50% laddning kvar innan du installerar /e/OS", + "let-s-get-started-instruction-4": "All data kommer raderas från din smarta telefon under installationen,\n vi rekommenderar att du tar en säkerhetskopia av din data.", + "let-s-get-started-instruction-5": "Det krävs en fungerande USB-datakabel. Laddkablar överför inte data\n och kommer inte att fungera! Vi rekommenderar USB 3.x eller senare.", + "let-s-get-started-instruction-title-1": "1. Frigör lite tid", + "let-s-get-started-instruction-title-2": "2. Frigör lagringsutrymme", + "let-s-get-started-instruction-title-3": "3. Ladda din telefon", + "let-s-get-started-instruction-title-4": "4. Säkerhetskopiera din data", + "let-s-get-started-instruction-title-5": "5. Ta en USB-datakabel", + "locking": "Låser", + "locking-instructions-1": "Din telefon frågar om att låsas upp. Välj lås starthanteraren", + "locking-instructions-2": "Starta om din telefon om den inte startar om automatiskt", + "ready-to-install-e-os": "Du är nu redo att installera /e/OS.", + "recovery-to-bootloader": "Återställning till Starthanteraren", + "recovery-to-bootloader-instructions": "I huvudmenyn", + "recovery-to-bootloader-instructions-1": "1. Välj Avancerad", + "recovery-to-bootloader-instructions-2": "2. Välj Starta om till starthanteraren", + "satisfied": "Nöjd", + "send-to-e-team": "Skicka till Murena-teamet", + "sideload": "Installation pågår", + "sideload-instructions-1": "Skärmen kommer visa processen ... ", + "sideload-instructions-2": "Detta kan ta flera minuter, ge det lite tid.", + "sideload-instructions-3": "När installationen är klar kommer telefonen att gå tillbaka till huvudskärmen.", + "sideload-instructions-4": "Endast då kan du klicka på Nästa.", + "skip": "Hoppa över", + "start": "Starta", + "this-might-take-some-time-please-be-patient": "Detta kan ta lite tid, vänligen ha tålamod", + "unlocking-instructions-1": "Din telefon frågaor om upplåsning. Välj lås upp starthanteraren genom att navigera med Volym upp och Volym ned.", + "unlocking-instructions-2": "Starta om enheten om den inte startar om automatiskt.", + "bootloader-to-recovery-manually-instructions-3": "3. Vänta på att telefonen startar i återställning", + "go-to-apply-update-instructions-4": "Observera! Inför nästa steg kanske webbläsaren behöver återansluta till din telefon. Om ett popup-fönster dyker upp, välj din telefon från listan.", + "installing": "Installerar", + "unlocking-instructions-2-a": "Din enhet kommer starta om. Vänta till Starthanterarens skärm visas igen innan du går vidare till nästa steg", + "very-satisfied": "Mycket nöjd", + "unlocking-instructions-3": "Eftersom enheter helt återställs kommer du behöva aktivera USB-felsökning igen.", + "unlocking-instructions-4": "Hoppa över inställningen på telefonen och klicka på nästa", + "very-dissatisfied": "Mycket missnöjd", + "sign-up-free": "Registrera dig GRATIS" } diff --git a/app/public/assets/languages/tr.json b/app/public/assets/languages/tr.json index 845989ed65c2fb242df94d5d94f3e995fd4b80f9..d0cd844271b458379d0a9365a450d6cff95bca58 100644 --- a/app/public/assets/languages/tr.json +++ b/app/public/assets/languages/tr.json @@ -1,22 +1,22 @@ { - "Ex 1: before installing /e/OS Android 12, you should update to the latest stock Android 12": "Örnek 1: /e/OS Android 12'yi yüklemeden önce, en son stok Android 12'ye güncellemelisiniz", - "Ex 2: or if you're installing /e/OS Android 11, make sure to update to the latest stock Android 11": "Ex 2: veya /e/OS Android 11 yüklüyorsanız, en son stok Android 11'e güncellediğinizden emin olun", - "Ex 3: similarly, if you're installing /e/OS Android 11, it should be the latest stock Android 10": "Ex 3: benzer şekilde, /e/OS Android 11 yüklüyorsanız, en son stok Android 10 olmalıdır", - "activate-developer-options": "Geliştirici seçeneklerini etkinleştirin", - "activate-developer-options-instructions-1": "1. Ayarlar menüsünü açın ve arama çubuğuna 'sürüm' yazın.", - "activate-developer-options-instructions-2": "2. Bir sonraki ekranda 'Yapı numarası'nı bulun ve üzerine 7 kez dokunun.", - "activate-usb-debugging": "USB Hata Ayıklamayı Etkinleştir", - "activate-usb-debugging-instructions-1": "1. Ayarlar menüsüne geri dönün ve arama çubuğuna 'USB hata ayıklama' yazın.", - "android-version-not-supported": "Android sürümü güncel değil", - "android-version-not-supported-instructions": "Sisteminizi gereken minimum sürüme güncelleyin {{android-version-required}}", - "android-version-not-supported-title": "Android sürümünüz {{android-version}} desteklenmiyor", - "activate-usb-debugging-instructions-2": "2. Bu noktada 'Geliştirici seçenekleri ekranında' olmalısınız. Şimdi etkinleştirmek için 'USB hata ayıklama' üzerine dokunun (bazı cihazlarda 'Android Hata Ayıklama' olarak adlandırılır).", - "bootloader-to-recovery-manually": "Önyükleyiciden kurtarmaya", - "bootloader-to-recovery-manually-instructions": "Şimdi cihazınızı Kurtarma modunda yeniden başlatacağız. Lütfen aşağıdaki adımları takip edin:", - "bootloader-to-recovery-manually-instructions-2": "2. Onaylamak için Güç düğmesine basın", - "bootloader-to-recovery-manually-instructions-3": "3. Telefonunuzun kurtarma işleminde başlamasını bekleyin", - "check-update-android-version": "Android sürümünüzü kontrol edin ve güncelleyin", - "connect": "Bağlan", - "connect-bootloader": "Önyükleyici bağlantısı", - "bootloader-to-recovery-manually-instructions-1": "1. Önyükleyicide, Ses Açma ve Ses Kısma düğmelerini kullanarak kurtarma modunu seçin" + "Ex 1: before installing /e/OS Android 12, you should update to the latest stock Android 12": "Örnek 1: /e/OS Android 12'yi yüklemeden önce, en son stok Android 12'ye güncellemelisiniz", + "Ex 2: or if you're installing /e/OS Android 11, make sure to update to the latest stock Android 11": "Ex 2: veya /e/OS Android 11 yüklüyorsanız, en son stok Android 11'e güncellediğinizden emin olun", + "Ex 3: similarly, if you're installing /e/OS Android 11, it should be the latest stock Android 10": "Ex 3: benzer şekilde, /e/OS Android 11 yüklüyorsanız, en son stok Android 10 olmalıdır", + "activate-developer-options": "Geliştirici seçeneklerini etkinleştirin", + "activate-developer-options-instructions-1": "1. Ayarlar menüsünü açın ve arama çubuğuna 'sürüm' yazın.", + "activate-developer-options-instructions-2": "2. Bir sonraki ekranda 'Yapı numarası'nı bulun ve üzerine 7 kez dokunun.", + "activate-usb-debugging": "USB Hata Ayıklamayı Etkinleştir", + "activate-usb-debugging-instructions-1": "1. Ayarlar menüsüne geri dönün ve arama çubuğuna 'USB hata ayıklama' yazın.", + "android-version-not-supported": "Android sürümü güncel değil", + "android-version-not-supported-instructions": "Sisteminizi gereken minimum sürüme güncelleyin {{android-version-required}}", + "android-version-not-supported-title": "Android sürümünüz {{android-version}} desteklenmiyor", + "activate-usb-debugging-instructions-2": "2. Bu noktada 'Geliştirici seçenekleri ekranında' olmalısınız. Şimdi etkinleştirmek için 'USB hata ayıklama' üzerine dokunun (bazı cihazlarda 'Android Hata Ayıklama' olarak adlandırılır).", + "bootloader-to-recovery-manually": "Önyükleyiciden kurtarmaya", + "bootloader-to-recovery-manually-instructions": "Şimdi cihazınızı Kurtarma modunda yeniden başlatacağız. Lütfen aşağıdaki adımları takip edin:", + "bootloader-to-recovery-manually-instructions-2": "2. Onaylamak için Güç düğmesine basın", + "bootloader-to-recovery-manually-instructions-3": "3. Telefonunuzun kurtarma işleminde başlamasını bekleyin", + "check-update-android-version": "Android sürümünüzü kontrol edin ve güncelleyin", + "connect": "Bağlan", + "connect-bootloader": "Önyükleyici bağlantısı", + "bootloader-to-recovery-manually-instructions-1": "1. Önyükleyicide, Ses Açma ve Ses Kısma düğmelerini kullanarak kurtarma modunu seçin" } diff --git a/app/public/css/loader.css b/app/public/css/loader.css index 1f8e84aaece1954efe250881af3f8b2924418fd9..56c05e1b4fb2b504d93015910c2f7ab3ac549466 100644 --- a/app/public/css/loader.css +++ b/app/public/css/loader.css @@ -1,21 +1,25 @@ button.next { - display: inline-flex; - align-items: center; - justify-content: center; + display: inline-flex; + align-items: center; + justify-content: center; } .btn-loader { - border: 2px solid #d4d4d4; - border-top: 2px solid white; - border-radius: 50%; - width: 12px; - height: 12px; - margin-left: 10px; - animation: spin 1s linear infinite; - display: none; + border: 2px solid #d4d4d4; + border-top: 2px solid white; + border-radius: 50%; + width: 12px; + height: 12px; + margin-left: 10px; + animation: spin 1s linear infinite; + display: none; } @keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} \ No newline at end of file + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} diff --git a/app/public/css/styles.css b/app/public/css/styles.css index 3d6230b200fbcb07369caeac2b06f319996cc210..7a1c98d03e03ae2cffaf492c0fc07e5383f80383 100644 --- a/app/public/css/styles.css +++ b/app/public/css/styles.css @@ -1,210 +1,219 @@ @import "theme.css"; - #compatibility-check { - display: none; - position: fixed; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - background-color: #fff; - padding: 20px; - border: 2px solid #ccc; - z-index: 1000; + display: none; + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background-color: #fff; + padding: 20px; + border: 2px solid #ccc; + z-index: 1000; } button.connect { - background: var(--success-color); - color: var(--button-text-color); - border: none; + background: var(--success-color); + color: var(--button-text-color); + border: none; } button.next { - background: var(--button-color); - color: var(--button-text-color); - border: none; + background: var(--button-color); + color: var(--button-text-color); + border: none; } button.next:disabled { - background: rgba(2, 127, 254, 0.6); - cursor: auto; + background: rgba(2, 127, 254, 0.6); + cursor: auto; } #error-message { - color: red; + color: red; } /* */ #banner { - top: 0; - position: fixed; - width: 100%; + top: 0; + position: fixed; + width: 100%; } #top-banner { - background: var(--top-banner-color); - color: var(--white); - height: 50px; - display: flex; - width: 100%; - flex-wrap: wrap; - gap: 10px; - align-content: center; - justify-content: center; + background: var(--top-banner-color); + color: var(--white); + height: 50px; + display: flex; + width: 100%; + flex-wrap: wrap; + gap: 10px; + align-content: center; + justify-content: center; } #sub-banner { - display: flex; - justify-content: space-between; - padding: 5px 10px; + display: flex; + justify-content: space-between; + padding: 5px 10px; } #error-message-state { - max-height: 100px; - overflow: auto; - padding: 5px; - border: 1px solid var(--top-banner-color); - background-color:#fff; -} -#donate, #help { - display: flex; - align-items: center; - gap : 8px; - padding: 0.2rem 1.5rem; -} -#donate img, #help img{ - width: 24px; - height: 24px; -} -#donate{ - background: var(--green); - border: var(--green); - color: var(--white); -} -#help{ - background: transparent; - border-color: var(--blue); - color: var(--blue); + max-height: 100px; + overflow: auto; + padding: 5px; + border: 1px solid var(--top-banner-color); + background-color: #fff; +} +#donate, +#help { + display: flex; + align-items: center; + gap: 8px; + padding: 0.2rem 1.5rem; +} +#donate img, +#help img { + width: 24px; + height: 24px; +} +#donate { + background: var(--green); + border: var(--green); + color: var(--white); +} +#help { + background: transparent; + border-color: var(--blue); + color: var(--blue); } /* */ /*
*/ #process-ctn { - background: linear-gradient(to bottom, var(--top-background-color) 500px, transparent 500px); - padding-top: 250px; - position: relative; - width: 100%; + background: linear-gradient( + to bottom, + var(--top-background-color) 500px, + transparent 500px + ); + padding-top: 250px; + position: relative; + width: 100%; } .ready-to-install-e-os { - color : var(--info-color); - font-size: 28px; - display: none; + color: var(--info-color); + font-size: 28px; + display: none; } #logo-ctn { - max-width: 780px; - margin:auto; - display: flex; - gap: 16px; - color : #F7F7F7; - align-items: center; + max-width: 780px; + margin: auto; + display: flex; + gap: 16px; + color: #f7f7f7; + align-items: center; } #logo { - max-width: 80px; + max-width: 80px; } /*
*/ /* */ .card { - scroll-margin-top: 65px; - box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1); - max-width: 780px; - border-radius: 6px; - background: var(--white); - margin: 25px auto 50px auto; - padding: 32px; + scroll-margin-top: 65px; + box-shadow: + 0 1px 3px 0 rgba(0, 0, 0, 0.1), + 0 1px 2px -1px rgba(0, 0, 0, 0.1); + max-width: 780px; + border-radius: 6px; + background: var(--white); + margin: 25px auto 50px auto; + padding: 32px; } .card-header { - font-size: 24px; - font-family: 'Century Gothic'; - font-weight: 600; + font-size: 24px; + font-family: "Century Gothic"; + font-weight: 600; } -.card-body, .large-padding { - padding-top: 16px; - padding-bottom: 16px; +.card-body, +.large-padding { + padding-top: 16px; + padding-bottom: 16px; } .card-footer { - text-align : right; + text-align: right; } .flashing.done progress { - -webkit-appearance: none; - height: 2px; + -webkit-appearance: none; + height: 2px; } .flashing.done progress::-webkit-progress-bar { - -webkit-appearance: none; - background-color: var(--green); + -webkit-appearance: none; + background-color: var(--green); } /* */ .instruction-title { - font-size: 18px; - font-weight: 600; + font-size: 18px; + font-weight: 600; } .normal-padding { - margin-bottom : 20px; - margin-top : 20px; + margin-bottom: 20px; + margin-top: 20px; } .enable-usb-file-transfer .instruction-img { - max-width: 225px; + max-width: 225px; } -.device-detection .instruction-img, .connect-your-phone .instruction-img { - max-width: 300px; +.device-detection .instruction-img, +.connect-your-phone .instruction-img { + max-width: 300px; } .activate-developer-options .instruction-img, .activate-usb-debugging .instruction-img, -.connect-your-phone .instruction-img { - max-width: 350px; +.connect-your-phone .instruction-img { + max-width: 350px; } #overlay-background { - position: absolute; - background: #0000004f; - display: flex; - align-items: center; - justify-content: center; - top: 0; - left: 0; - right: 0; - bottom:0; + position: absolute; + background: #0000004f; + display: flex; + align-items: center; + justify-content: center; + top: 0; + left: 0; + right: 0; + bottom: 0; } progress { - height: 3px; - width: 50%; - min-width: 300px; + height: 3px; + width: 50%; + min-width: 300px; } progress[value] { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - border: none; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + border: none; } progress[value]::-webkit-progress-bar { - background-color: #d0d0d0; + background-color: #d0d0d0; } progress[value]::-webkit-progress-value { - background-color: var(--downloading-color); + background-color: var(--downloading-color); } progress[value].success::-webkit-progress-value { - background-color: var(--green); + background-color: var(--green); } /* */ /* */ .let-s-get-started .instruction-ctn { - padding : 16px 0; - display : flex; - align-items: center; - gap : 24px; + padding: 16px 0; + display: flex; + align-items: center; + gap: 24px; } .let-s-get-started .instruction-title { - padding-bottom: 8px; + padding-bottom: 8px; } /* */ .navigator-not-supported .instructions-ctn { - display: grid; - grid-template-columns: repeat(4, 1fr); - gap: 22px; - text-align:center; - font-size:14px; - padding: 16px 0; -} \ No newline at end of file + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 22px; + text-align: center; + font-size: 14px; + padding: 16px 0; +} diff --git a/app/public/css/theme.css b/app/public/css/theme.css index d9802d33bff3e0f142a2458beff0e7550dddd2e5..0261db803e982ca809558f6160776f3b59eabc86 100644 --- a/app/public/css/theme.css +++ b/app/public/css/theme.css @@ -1,94 +1,98 @@ -@font-face { - font-family: "Century Gothic"; - src: url("../assets/fonts/century-gothic/Century-Gothic.ttf") format("truetype"); -} -@font-face { - font-family: "Century Gothic Bold"; - src: url("../assets/fonts/century-gothic/Century-Gothic.ttf") format("truetype"); -} -:root { - --top-banner-color: #191823; - --top-background-color: #0f0f0f; - --background-color: #f7f7f7; - --text-color: #111111; - --info-color: #027ffe; - --base-color: #dedee5; - --secondary-color: #898989; - --base-color-alt: #f5f5f7; - --blue: #2a7ae2; - --white: white; - --green: #00b13c; - --success-color: #61CE70; - --downloading-color: #027ffe; - --button-color: #027ffe; - --button-text-color: white; - --warning-background-color: #fff1c9; - --warning-text-color: #795917; - --info-background-color: #cbe9ee; - --info-text-color: #104a55; -} -html, body { - margin: 0px; - background: var(--background-color); - font-family: 'Century Gothic', 'Lato'; - font-size : 14px; -} -button { - border-radius: 100px; - padding: 0.4rem 1.5rem; - cursor: pointer; - transition: background-color 0.25s ease-in-out; -} -kbd { - padding: .2rem .4rem; - font-size: 87.5%; - color: #fff; - background-color: #212529; - border-radius: .2rem; -} -code { - border: 1px solid #e8e8e8; - border-radius: 3px; - background-color: #eef; - font-size: 87.5%; - color: #e83e8c; - word-wrap: break-word; -} -.warning { - background: var(--warning-background-color); - color: var(--warning-text-color); -} -.info { - background: var(--info-background-color); - color: var(--info-text-color); -} -.warning, .info { - padding: 0.625rem; - border-radius: 4px; -} -.secondary { - color : var(--secondary-color); -} -.text-center { - text-align: center; -} -.inactive { - display: none !important; -} - -.active { - display: block !important; -} -.icon { - width: 2.5rem; - height: 2.5rem; -} -.gap-4 { - gap: 1.5rem !important; -} -.flex { - display: flex; -} -.align-items-center { - align-items: center; -} \ No newline at end of file +@font-face { + font-family: "Century Gothic"; + src: url("../assets/fonts/century-gothic/Century-Gothic.ttf") + format("truetype"); +} +@font-face { + font-family: "Century Gothic Bold"; + src: url("../assets/fonts/century-gothic/Century-Gothic.ttf") + format("truetype"); +} +:root { + --top-banner-color: #191823; + --top-background-color: #0f0f0f; + --background-color: #f7f7f7; + --text-color: #111111; + --info-color: #027ffe; + --base-color: #dedee5; + --secondary-color: #898989; + --base-color-alt: #f5f5f7; + --blue: #2a7ae2; + --white: white; + --green: #00b13c; + --success-color: #61ce70; + --downloading-color: #027ffe; + --button-color: #027ffe; + --button-text-color: white; + --warning-background-color: #fff1c9; + --warning-text-color: #795917; + --info-background-color: #cbe9ee; + --info-text-color: #104a55; +} +html, +body { + margin: 0px; + background: var(--background-color); + font-family: "Century Gothic", "Lato"; + font-size: 14px; +} +button { + border-radius: 100px; + padding: 0.4rem 1.5rem; + cursor: pointer; + transition: background-color 0.25s ease-in-out; +} +kbd { + padding: 0.2rem 0.4rem; + font-size: 87.5%; + color: #fff; + background-color: #212529; + border-radius: 0.2rem; +} +code { + border: 1px solid #e8e8e8; + border-radius: 3px; + background-color: #eef; + font-size: 87.5%; + color: #e83e8c; + word-wrap: break-word; +} +.warning { + background: var(--warning-background-color); + color: var(--warning-text-color); +} +.info { + background: var(--info-background-color); + color: var(--info-text-color); +} +.warning, +.info { + padding: 0.625rem; + border-radius: 4px; +} +.secondary { + color: var(--secondary-color); +} +.text-center { + text-align: center; +} +.inactive { + display: none !important; +} + +.active { + display: block !important; +} +.icon { + width: 2.5rem; + height: 2.5rem; +} +.gap-4 { + gap: 1.5rem !important; +} +.flex { + display: flex; +} +.align-items-center { + align-items: center; +} diff --git a/app/public/resources/-Nord.json b/app/public/resources/-Nord.json index ea93fc8fc018bff0de2fdff6fbe623714003678f..8bd275beb687c224f247cb46f1bf04ef7165e5e6 100644 --- a/app/public/resources/-Nord.json +++ b/app/public/resources/-Nord.json @@ -6,10 +6,7 @@ }, { "id": "connect-bootloader", - "command": [ - "connect bootloader", - "oem unlock" - ], + "command": ["connect bootloader", "oem unlock"], "needUserGesture": true }, { @@ -69,10 +66,7 @@ }, { "id": "connect-bootloader", - "command": [ - "connect bootloader", - "reboot" - ], + "command": ["connect bootloader", "reboot"], "needUserGesture": true }, { diff --git a/app/public/resources/FP3.json b/app/public/resources/FP3.json index b4a50a9fc433efd1bb8c03a2432a9c9309d63b35..3e3bda91b56fef485a51b7f1a9cb75091db5941b 100644 --- a/app/public/resources/FP3.json +++ b/app/public/resources/FP3.json @@ -3,7 +3,7 @@ { "mode": "bootloader", "id": "connect-bootloader", - "command": ["connect bootloader","oem unlock unlocked"], + "command": ["connect bootloader", "oem unlock unlocked"], "needUserGesture": true }, { @@ -31,7 +31,7 @@ }, { "id": "flashing", - "command" : [ + "command": [ "flash modem_a modem.img", "flash modem_a modem.img", "flash modem_b modem.img", diff --git a/app/public/resources/FP4-safe.json b/app/public/resources/FP4-safe.json index 6646670ab59ecdee6ce9ad9815a973253b64911d..1f267bbc34bbd55796aa33cc50dc2fe9a2f629aa 100644 --- a/app/public/resources/FP4-safe.json +++ b/app/public/resources/FP4-safe.json @@ -110,7 +110,8 @@ "flash core_nhlos_a core_nhlos.img --set-active=a", "erase userdata", "erase metadata", - "reboot"] + "reboot" + ] }, { "id": "murena-workspace-account", @@ -124,7 +125,7 @@ { "name": "FP4 installer", "unzip": true, - "path": "https://images.ecloud.global/official/FP4/IMG-e-latest-u-official-FP4.zip" + "path": "https://images.ecloud.global/official/FP4/IMG-e-latest-t-official-FP4.zip" } ] } diff --git a/app/public/resources/FP4.json b/app/public/resources/FP4.json index fa9e4d3e21c02fd9ad5bbc83ebe4cd980d6abfae..036fcfb7bf47e042d6ffa0b66ab2ec75900fa808 100644 --- a/app/public/resources/FP4.json +++ b/app/public/resources/FP4.json @@ -64,54 +64,55 @@ { "id": "flashing", "command": [ - "flash bluetooth_a bluetooth.img", - "flash bluetooth_b bluetooth.img", - "flash devcfg_a devcfg.img", - "flash devcfg_b devcfg.img", - "flash dsp_a dsp.img", - "flash dsp_b dsp.img", - "flash modem_a modem.img", - "flash modem_b modem.img", - "flash xbl_a xbl.img", - "flash xbl_b xbl.img", - "flash tz_a tz.img", - "flash tz_b tz.img", - "flash hyp_a hyp.img", - "flash hyp_b hyp.img", - "flash keymaster_a keymaster.img", - "flash keymaster_b keymaster.img", - "flash abl_a abl.img", - "flash abl_b abl.img", - "flash boot_a boot.img", - "flash boot_b boot.img", - "flash recovery_a recovery.img", - "flash recovery_b recovery.img", - "flash dtbo_a dtbo.img", - "flash dtbo_b dtbo.img", - "flash vbmeta_system_a vbmeta_system.img", - "flash vbmeta_system_b vbmeta_system.img", - "flash vbmeta_a vbmeta.img", - "flash vbmeta_b vbmeta.img", - "flash super super.img", - "flash aop_a aop.img", - "flash aop_b aop.img", - "flash featenabler_a featenabler.img", - "flash featenabler_b featenabler.img", - "flash imagefv_a imagefv.img", - "flash imagefv_b imagefv.img", - "flash multiimgoem_a multiimgoem.img", - "flash multiimgoem_b multiimgoem.img", - "flash qupfw_a qupfw.img", - "flash qupfw_b qupfw.img", - "flash uefisecapp_a uefisecapp.img", - "flash uefisecapp_b uefisecapp.img", - "flash xbl_config_a xbl_config.img", - "flash xbl_config_b xbl_config.img", - "flash core_nhlos_b core_nhlos.img", - "flash core_nhlos_a core_nhlos.img --set-active=a", - "erase userdata", - "erase metadata", - "flashing lock"] + "flash bluetooth_a bluetooth.img", + "flash bluetooth_b bluetooth.img", + "flash devcfg_a devcfg.img", + "flash devcfg_b devcfg.img", + "flash dsp_a dsp.img", + "flash dsp_b dsp.img", + "flash modem_a modem.img", + "flash modem_b modem.img", + "flash xbl_a xbl.img", + "flash xbl_b xbl.img", + "flash tz_a tz.img", + "flash tz_b tz.img", + "flash hyp_a hyp.img", + "flash hyp_b hyp.img", + "flash keymaster_a keymaster.img", + "flash keymaster_b keymaster.img", + "flash abl_a abl.img", + "flash abl_b abl.img", + "flash boot_a boot.img", + "flash boot_b boot.img", + "flash recovery_a recovery.img", + "flash recovery_b recovery.img", + "flash dtbo_a dtbo.img", + "flash dtbo_b dtbo.img", + "flash vbmeta_system_a vbmeta_system.img", + "flash vbmeta_system_b vbmeta_system.img", + "flash vbmeta_a vbmeta.img", + "flash vbmeta_b vbmeta.img", + "flash super super.img", + "flash aop_a aop.img", + "flash aop_b aop.img", + "flash featenabler_a featenabler.img", + "flash featenabler_b featenabler.img", + "flash imagefv_a imagefv.img", + "flash imagefv_b imagefv.img", + "flash multiimgoem_a multiimgoem.img", + "flash multiimgoem_b multiimgoem.img", + "flash qupfw_a qupfw.img", + "flash qupfw_b qupfw.img", + "flash uefisecapp_a uefisecapp.img", + "flash uefisecapp_b uefisecapp.img", + "flash xbl_config_a xbl_config.img", + "flash xbl_config_b xbl_config.img", + "flash core_nhlos_b core_nhlos.img", + "flash core_nhlos_a core_nhlos.img --set-active=a", + "erase userdata", + "erase metadata", + "flashing lock" + ] }, { "id": "locking-fp4", @@ -156,7 +157,7 @@ { "name": "FP4 installer", "unzip": true, - "path": "https://images.ecloud.global/official/FP4/IMG-e-latest-u-official-FP4.zip" + "path": "https://images.ecloud.global/official/FP4/IMG-e-latest-t-official-FP4.zip" } ] } diff --git a/app/public/resources/GS290.json b/app/public/resources/GS290.json index f8cd8cb95817baecaff5ba2877b3dbf884f4ff21..281dfe4ef7e0d2ba6a68b07a9143cc9d1fb5cd06 100644 --- a/app/public/resources/GS290.json +++ b/app/public/resources/GS290.json @@ -1,9 +1,9 @@ { "steps": [ - { + { "mode": "bootloader", "id": "connect-bootloader", - "command": ["connect bootloader","flashing unlock unlocked"], + "command": ["connect bootloader", "flashing unlock unlocked"], "needUserGesture": true }, { diff --git a/app/public/resources/OnePlus7.json b/app/public/resources/OnePlus7.json index 6a9562a41e43f0c571c424d59287df09d3b4c16f..747b217c3f0dfc8ff1709094445fb28591b57278 100644 --- a/app/public/resources/OnePlus7.json +++ b/app/public/resources/OnePlus7.json @@ -6,10 +6,7 @@ }, { "id": "connect-bootloader", - "command": [ - "connect bootloader", - "oem unlock" - ], + "command": ["connect bootloader", "oem unlock"], "needUserGesture": true }, { @@ -65,10 +62,7 @@ }, { "id": "connect-bootloader", - "command": [ - "connect bootloader", - "reboot" - ], + "command": ["connect bootloader", "reboot"], "needUserGesture": true }, { diff --git a/app/public/resources/OnePlus7Pro.json b/app/public/resources/OnePlus7Pro.json index f123030a45affc2f65ffc7e40ae8bf5cad01dffb..f427d92b978c1404b084031a1539e83cd032047b 100644 --- a/app/public/resources/OnePlus7Pro.json +++ b/app/public/resources/OnePlus7Pro.json @@ -6,10 +6,7 @@ }, { "id": "connect-bootloader", - "command": [ - "connect bootloader", - "oem unlock" - ], + "command": ["connect bootloader", "oem unlock"], "needUserGesture": true }, { @@ -65,10 +62,7 @@ }, { "id": "connect-bootloader", - "command": [ - "connect bootloader", - "reboot" - ], + "command": ["connect bootloader", "reboot"], "needUserGesture": true }, { diff --git a/app/public/resources/OnePlus7T.json b/app/public/resources/OnePlus7T.json index 4365250a4c42c3ce21f99b02156c63fe53954398..6c607036c9705613bd7ac7b8d214c839a10ed1b7 100644 --- a/app/public/resources/OnePlus7T.json +++ b/app/public/resources/OnePlus7T.json @@ -6,10 +6,7 @@ }, { "id": "connect-bootloader", - "command": [ - "connect bootloader", - "oem unlock" - ], + "command": ["connect bootloader", "oem unlock"], "needUserGesture": true }, { @@ -65,10 +62,7 @@ }, { "id": "connect-bootloader", - "command": [ - "connect bootloader", - "reboot" - ], + "command": ["connect bootloader", "reboot"], "needUserGesture": true }, { diff --git a/app/public/resources/OnePlus8.json b/app/public/resources/OnePlus8.json index caf17ff1f42ebcac5ab3e7e4a99ee8ee4125ac3a..a8da9f43e8db1659f8752781eb66bd5f7de35ae1 100644 --- a/app/public/resources/OnePlus8.json +++ b/app/public/resources/OnePlus8.json @@ -6,10 +6,7 @@ }, { "id": "connect-bootloader", - "command": [ - "connect bootloader", - "oem unlock" - ], + "command": ["connect bootloader", "oem unlock"], "needUserGesture": true }, { @@ -65,10 +62,7 @@ }, { "id": "connect-bootloader", - "command": [ - "connect bootloader", - "reboot" - ], + "command": ["connect bootloader", "reboot"], "needUserGesture": true }, { diff --git a/app/public/resources/OnePlus8Pro.json b/app/public/resources/OnePlus8Pro.json index db34b444ee67a3baae695e207c4d37f6924f14d0..fbb5890bd06c9b50f1a2f6acbcbfbafee415f506 100644 --- a/app/public/resources/OnePlus8Pro.json +++ b/app/public/resources/OnePlus8Pro.json @@ -6,10 +6,7 @@ }, { "id": "connect-bootloader", - "command": [ - "connect bootloader", - "oem unlock" - ], + "command": ["connect bootloader", "oem unlock"], "needUserGesture": true }, { @@ -65,10 +62,7 @@ }, { "id": "connect-bootloader", - "command": [ - "connect bootloader", - "reboot" - ], + "command": ["connect bootloader", "reboot"], "needUserGesture": true }, { diff --git a/app/public/resources/Teracube_2e.json b/app/public/resources/Teracube_2e.json index 1a4ecf878976486ae16e8d14d8f078518dc3e551..be88089a099604e3b44d657778ca56e07475e462 100644 --- a/app/public/resources/Teracube_2e.json +++ b/app/public/resources/Teracube_2e.json @@ -1,6 +1,6 @@ { "UNUSED___security_patch_level": "2020-04-05", - "description" : "Teracube 2e (2020)", + "description": "Teracube 2e (2020)", "steps": [ { "mode": "bootloader", @@ -13,10 +13,10 @@ "needUserGesture": true }, { - "id": "flashing", + "id": "flashing", "command": [ "erase userdata", - + "flash preloader preloader_zirconia.bin", "flash lk lk.img", "flash md1img md1img.img", @@ -48,9 +48,9 @@ ], "folder": [ { - "path": "https://images.ecloud.global/official/zirconia/IMG-e-latest-s-official-zirconia.zip", - "name": "Teracube 2e (2020) installer", - "unzip": true + "path": "https://images.ecloud.global/official/zirconia/IMG-e-latest-s-official-zirconia.zip", + "name": "Teracube 2e (2020) installer", + "unzip": true } ] } diff --git a/app/public/resources/coral.json b/app/public/resources/coral.json index 52a28c4830e4977f0974a82874b78fb0aecaca68..2634a5aa16c3e67a4cc02bc6bbeffc0ae1c9f8fc 100644 --- a/app/public/resources/coral.json +++ b/app/public/resources/coral.json @@ -6,7 +6,7 @@ }, { "id": "connect-bootloader", - "command": ["connect bootloader", "flashing unlock unlocked" ], + "command": ["connect bootloader", "flashing unlock unlocked"], "needUserGesture": true }, { @@ -16,10 +16,7 @@ }, { "id": "flashing", - "command": [ - "flash dtbo dtbo.img", - "flash boot recovery.img" - ] + "command": ["flash dtbo dtbo.img", "flash boot recovery.img"] }, { "id": "bootloader-to-recovery-manually", @@ -43,10 +40,7 @@ }, { "id": "connect-bootloader", - "command": [ - "connect bootloader", - "reboot" - ], + "command": ["connect bootloader", "reboot"], "needUserGesture": true }, { diff --git a/app/public/resources/emerald-safe.json b/app/public/resources/emerald-safe.json index 5587166fc3c03ecf1cfb791b2d1f68c63c8cf6fc..853abb0e66139e7567fcdd31f2be7956e04cef77 100644 --- a/app/public/resources/emerald-safe.json +++ b/app/public/resources/emerald-safe.json @@ -1,5 +1,5 @@ { - "description" : "Teracube 2e (2021 emerald) Safe", + "description": "Teracube 2e (2021 emerald) Safe", "steps": [ { "mode": "bootloader", @@ -12,9 +12,8 @@ "needUserGesture": true }, { - "id": "flashing", + "id": "flashing", "command": [ - "erase userdata", "format md_udc", "flash boot_a boot.img", diff --git a/app/public/resources/emerald.json b/app/public/resources/emerald.json index 4576d107de41701bfb7ddaabb73dacd5c9e3e524..7ca01e0129938ea1943785d250237fd172daaced 100644 --- a/app/public/resources/emerald.json +++ b/app/public/resources/emerald.json @@ -1,6 +1,6 @@ { "UNUSED___security_patch_level": "2020-04-05", - "description" : "Teracube 2e (2021 emerald)", + "description": "Teracube 2e (2021 emerald)", "steps": [ { "mode": "bootloader", @@ -13,9 +13,8 @@ "needUserGesture": true }, { - "id": "flashing", + "id": "flashing", "command": [ - "erase userdata", "format md_udc", "flash boot_a boot.img", @@ -56,9 +55,9 @@ ], "folder": [ { - "path": "https://images.ecloud.global/official/emerald/IMG-e-latest-s-official-emerald.zip", - "name": "Teracube 2e (2021 emerald) installer", - "unzip": true + "path": "https://images.ecloud.global/official/emerald/IMG-e-latest-s-official-emerald.zip", + "name": "Teracube 2e (2021 emerald) installer", + "unzip": true } ] } diff --git a/app/public/resources/flame.json b/app/public/resources/flame.json index 18557d829c36e591b4453fa42a782c9efb038f94..b56188dcbf3683a03cefcd3b44d05d89f5bd3009 100644 --- a/app/public/resources/flame.json +++ b/app/public/resources/flame.json @@ -6,7 +6,7 @@ }, { "id": "connect-bootloader", - "command": ["connect bootloader", "flashing unlock unlocked" ], + "command": ["connect bootloader", "flashing unlock unlocked"], "needUserGesture": true }, { @@ -16,10 +16,7 @@ }, { "id": "flashing", - "command": [ - "flash dtbo dtbo.img", - "flash boot recovery.img" - ] + "command": ["flash dtbo dtbo.img", "flash boot recovery.img"] }, { "id": "bootloader-to-recovery-manually", @@ -43,10 +40,7 @@ }, { "id": "connect-bootloader", - "command": [ - "connect bootloader", - "reboot" - ], + "command": ["connect bootloader", "reboot"], "needUserGesture": true }, { diff --git a/app/public/resources/redfin.json b/app/public/resources/redfin.json index 38f909bce70356cf012012be87d356f48f4af659..ca9fd8ec45abea5bca75c9d811663b18fad55050 100644 --- a/app/public/resources/redfin.json +++ b/app/public/resources/redfin.json @@ -6,7 +6,7 @@ }, { "id": "connect-bootloader", - "command": ["connect bootloader", "flashing unlock unlocked" ], + "command": ["connect bootloader", "flashing unlock unlocked"], "needUserGesture": true }, { diff --git a/app/public/resources/shiba.json b/app/public/resources/shiba.json index b41bb830bceddd55d05dd9ce0c25ce7c5079d96e..f40c91fc66cdb12bca96dff2242fe548409c9365 100644 --- a/app/public/resources/shiba.json +++ b/app/public/resources/shiba.json @@ -87,5 +87,3 @@ } ] } - - diff --git a/app/public/resources/sunfish.json b/app/public/resources/sunfish.json index b2a793c30f7409f453aa710fc405e48989504a32..5febd2f7cfd6781d6df243f0119d0fcf8b74d6c2 100644 --- a/app/public/resources/sunfish.json +++ b/app/public/resources/sunfish.json @@ -6,7 +6,7 @@ }, { "id": "connect-bootloader", - "command": ["connect bootloader", "flashing unlock unlocked" ], + "command": ["connect bootloader", "flashing unlock unlocked"], "needUserGesture": true }, { @@ -16,10 +16,7 @@ }, { "id": "flashing", - "command": [ - "flash dtbo dtbo.img", - "flash boot recovery.img" - ] + "command": ["flash dtbo dtbo.img", "flash boot recovery.img"] }, { "id": "bootloader-to-recovery-manually", @@ -43,10 +40,7 @@ }, { "id": "connect-bootloader", - "command": [ - "connect bootloader", - "reboot" - ], + "command": ["connect bootloader", "reboot"], "needUserGesture": true }, { diff --git a/app/public/resources/tetris.json b/app/public/resources/tetris.json index 0486ebba6bb576f61263a68cc2eec11e5618c638..2d619b2234b68d3eb5152963ec07d81ec07b7fce 100644 --- a/app/public/resources/tetris.json +++ b/app/public/resources/tetris.json @@ -1,20 +1,20 @@ { "android": 14, "steps": [ - { + { "mode": "bootloader", "id": "connect-bootloader", - "command": ["connect bootloader","flashing unlock"], + "command": ["connect bootloader", "flashing unlock"], "needUserGesture": true }, { "id": "unlocking-gs290", "needUserGesture": true }, - { + { "mode": "bootloader", "id": "connect-bootloader", - "command": ["connect bootloader","flashing unlock_critical"], + "command": ["connect bootloader", "flashing unlock_critical"], "needUserGesture": true }, { diff --git a/app/src/before-leave-app.js b/app/src/before-leave-app.js index bbd81c38378b9a05f47b107c1194144f9811020d..04b72ff150ed86e40da007f740c4998db6d258e2 100644 --- a/app/src/before-leave-app.js +++ b/app/src/before-leave-app.js @@ -1,3 +1,3 @@ -window.addEventListener('beforeunload', function (event) { - event.preventDefault(); -}); \ No newline at end of file +window.addEventListener("beforeunload", function (event) { + event.preventDefault(); +}); diff --git a/app/src/controller.manager.js b/app/src/controller.manager.js index 73a05a4ee45c3317d12bd8af312c792ff08f09fc..990540e1873f99347d8c57606f468dd10b210b58 100644 --- a/app/src/controller.manager.js +++ b/app/src/controller.manager.js @@ -1,371 +1,428 @@ -import {DeviceManager} from "./controller/device.manager.js"; -import {Command} from "./controller/device/command.class.js"; -import {Step} from "./controller/utils/step.class.js"; -import {WDebug} from "./debug.js"; -/* -* Class to manage process -* Check and display the steps, interact with deviceManager -*/ -export class Controller { - constructor() { - this.steps = [ - new Step("let-s-get-started", undefined, true), - new Step("connect-your-phone", undefined, true), - new Step("activate-developer-options", undefined, true), - new Step("activate-oem-unlock", undefined, true), - new Step("activate-usb-debugging", undefined, true), - new Step("enable-usb-file-transfer", undefined, true), - new Step("device-detection", 'connect adb', true), - ]; - this.currentIndex = 0; - } - - - async init(view) { - this.deviceManager = new DeviceManager(); - await this.deviceManager.init(); - this.view = view; - } - - async next() { - - let current = this.steps[this.currentIndex]; - let next = this.steps[this.currentIndex + 1]; - - WDebug.log("Controller Manager Next", next); - - if (next) { - //K1ZFP check this - if (next.mode) { //if next step require another mode [adb|fastboot|bootloader] - if (this.deviceManager.isConnected() && !this.inInMode(next.mode)) { - //we need reboot - await this.deviceManager.reboot(next.mode); - } - if (!this.deviceManager.isConnected()) { - await this.deviceManager.connect(next.mode); - } - } - this.currentIndex++; - current = this.steps[this.currentIndex]; - this.view.onStepStarted(this.currentIndex, current); - if (!current.needUserGesture) { - await this.executeStep(current.name); - } - } - } - - async executeStep(stepName, loader) { - const current = this.steps[this.currentIndex]; - let this_command; - WDebug.log("ControllerManager Execute step", current) - document.getElementById('error-message-state').style.display = 'none'; - if (current.name === stepName) { - let res = true; - let i; - try { - for (i= 0; i < current.commands.length && res; i++) { - this_command = current.commands[i]; - res = await this.runCommand(this_command, loader); - WDebug.log("run command > ", this_command , "returns ", res); - - } - const next = this.steps[this.currentIndex + 1]; - let previous = this.steps[this.currentIndex - 1]; - if (res) { - if (next) { - this.view.onStepFinished(current, next); - await this.next(); - } - } else { - this.view.onStepFailed(current, previous); - if (!current.needUserGesture) { - this.currentIndex--; - } - throw new Error('command failed'); - } - } catch (e) { - throw new Error(`Cannot execute command ${this_command.command}
${e.message || e}`); - } - } else { - throw new Error('this is not the current step ' + current.name + ' is not equals to ' + stepName) - } - } - - /** - * - * @param mode - * @returns {boolean} - * Check if device is connected to a mode - */ - inInMode(mode) { - return this.deviceManager.isInMode(mode); - } - - /* - * run a command - this throw new error if something went wwrong. - error should contain a proposal to solve the issue. - */ - async runCommand(cmd, loader) { - WDebug.log("ControllerManager run command:", cmd); - switch (cmd.type) { - case Command.CMD_TYPE.download: - let res = false; - try { - await this.deviceManager.downloadAll((loaded, total, name) => { - this.view.onDownloading(name, loaded, total); - }, (loaded, total, name) => { - this.view.onUnzip(name, loaded, total); - }); - this.view.onDownloadingEnd(); - return true; - } catch (e) { - const proposal = "Proposal: Retry by refreshing this page."; - throw new Error(`Cannot download
${e.message || e}
${proposal}`); - } - return false; - case Command.CMD_TYPE.reboot: - try { - await this.deviceManager.reboot(cmd.mode); - } catch (e) { - console.error(e); - //K1ZFP TODO - return false; - } - return true; - case Command.CMD_TYPE.connect: - const proposal = "Proposal: Check connection and that no other program is using the phone and retry."; - try { - const res = await this.deviceManager.connect(cmd.mode); - if (res) { - await this.onDeviceConnected(); - if(loader) { - loader.style.display = 'none'; - } - return true; - } - } catch (e) { - throw new Error(`The device is not connected ${e.message || e}
${proposal}`); - } - throw new Error(`Cannot connect the device
${proposal}`); - case Command.CMD_TYPE.erase: - return this.deviceManager.erase(cmd.partition); - case Command.CMD_TYPE.flash: - return this.deviceManager.flash(cmd.file, cmd.partition, (done, total) => { - this.view.onInstalling(cmd.file, done, total); - }); - case Command.CMD_TYPE.unlock: - //check if unlocked to avoid unnecessary command - let isUnlocked = false; - let gotoStep = ""; - if (cmd.partition) { - try { - if (cmd.partition.startsWith("goto_")) { - gotoStep = cmd.partition.substring(5); - WDebug.log("goto step", gotoStep); - isUnlocked = await this.deviceManager.getUnlocked('unlocked'); - } else { - isUnlocked = await this.deviceManager.getUnlocked(cmd.partition); - } - } catch (e) {} - } - WDebug.log("ControllerManager unlock: ", this.deviceManager.adb.getProductName() + " isUnlocked = " + isUnlocked); - if (!isUnlocked) { - try { - this.deviceManager.unlock(cmd.command); // Do not await thus display unlocking screen - } catch (e) { - //on some device, check unlocked does not work but when we try the command, it throws an error with "already unlocked" - if (e.bootloaderMessage?.includes("already")) { - - } else if (e.bootloaderMessage?.includes("not allowed")) { - //K1ZFP TODO - } - } - } else { - WDebug.log("The phone is not locked - bypass lock process"); - if (gotoStep=="") { // Goto the next step. - this.currentIndex++; - } else { // Goto the maned step. - do { - this.currentIndex++; - WDebug.log("Bypass step", this.steps[this.currentIndex].name + " " + (this.steps[this.currentIndex].name == gotoStep)); - } while ( !(this.steps[this.currentIndex].name == gotoStep) ); - this.currentIndex--; - } - } - return true; - case Command.CMD_TYPE.lock: - let isLocked = false; - if (cmd.partition) { - try { - isLocked = !(await this.deviceManager.getUnlocked(cmd.partition)); - } catch (e) { - } - } - if (!isLocked) { - try { - this.deviceManager.lock(cmd.command); // Do not await thus display unlocking screen - } catch (e) { - //on some device, check unlocked does not work but when we try the command, it throws an error with "already locked" - if (e.bootloaderMessage?.includes("already")) { - isLocked = true; - } else { - console.error(e); //K1ZFP TODO - } - } - } - return true; - case Command.CMD_TYPE.sideload: - try { - await this.deviceManager.connect('recovery'); - await this.deviceManager.sideload(cmd.file); - return true; - } catch (e) { - console.error(e); // K1ZFP TODO - return false; - } - case Command.CMD_TYPE.format: - try { - this.deviceManager.for(cmd.partition); - } catch (e) { - console.error(e); // K1ZFP TODO - } - return true; - case Command.CMD_TYPE.delay: - await new Promise(resolve => setTimeout(resolve, cmd.partition)); - return true; - - default: - WDebug.log(`try unknown command ${cmd.command}`); - try { - await this.deviceManager.runCommand(cmd.command); - } catch(e) { - // K1ZFP TODO... - } - return true; - } - } - - async onDeviceConnected() { - - const productName = this.deviceManager.getProductName(); - const wasAlreadyConnected = this.deviceManager.wasAlreadyConnected(); - if (!wasAlreadyConnected) { - this.view.updateData('product-name', productName); - this.model = productName; - WDebug.log("ControllerManager Model:", this.model); - try { - const resources = await this.getResources(); - - if(resources.android){ - this.view.updateData('android-version-required', resources.android); - await this.checkAndroidVersion(resources.android); - } - this.setResources(resources); - } catch(e) { - this.steps.push(new Step(e.message)); - this.view.updateTotalStep(this.steps.length); - // Don not throw this error, as it is handled by the UI directly. - } - } - } - async checkAndroidVersion(versionRequired){ - const android = await this.deviceManager.getAndroidVersion(); - WDebug.log("current android version:", android); - if( android) { - this.view.updateData('android-version', android); - if(android < versionRequired){ - throw Error('android-version-not-supported'); - } - } - } - async getResources(){ - - let resources = null; - try { - let current_security_path_level = null; - try { - const security_patch = await this.deviceManager.adb.webusb.getProp("ro.build.version.security_patch"); - //WDebug.log('security_patch', security_patch) - current_security_path_level = parseInt(security_patch.replace(/-/g, ''), 10); - WDebug.log("current_security_path_level", current_security_path_level); - - } catch(ee) { - WDebug.log("Security patch Error"); - current_security_path_level = null; - } - - let this_model = this.deviceManager.adb.webusb.device; - // https://gitlab.e.foundation/e/os/backlog/-/issues/2604#note_609234 - const model = this.deviceManager.adb.webusb.model; - if (model.includes("Teracube") && model.includes("2e")) { - try { - const serial = await this.deviceManager.adb.getSerialNumber(); - WDebug.log("serial numer:", serial); - if (serial.startsWith("2021")) { - this_model = "emerald"; - } else if (serial.startsWith("2020")) { - this_model = "Teracube_2e"; - } else { - const id = - "model "+this.deviceManager.adb.webusb.model + " " + - "product "+this.deviceManager.adb.webusb.product + " " + - "name "+this.deviceManager.adb.webusb.name + " " + - "device "+this.deviceManager.adb.webusb.device; - throw new Error("Cannot find device resource", id); - } - } catch (e) { - const id = - "model "+this.deviceManager.adb.webusb.model + " " + - "product "+this.deviceManager.adb.webusb.product + " " + - "name "+this.deviceManager.adb.webusb.name + " " + - "device "+this.deviceManager.adb.webusb.device; - throw new Error("Error on getting devcice resource", id); - } - - } - - if (model.includes("A015")) { - try { - this_model = "tetris"; - } catch (e) { - const id = - "model "+this.deviceManager.adb.webusb.model + " " + - "product "+this.deviceManager.adb.webusb.product + " " + - "name "+this.deviceManager.adb.webusb.name + " " + - "device "+this.deviceManager.adb.webusb.device; - throw new Error("Error on getting devcice resource", id); - } - - } - - resources = await (await fetch(`resources/${this_model}.json`)).json(); - if (current_security_path_level != null && typeof resources.security_patch_level != 'undefined') { - WDebug.log("EOS Rom has security patch "); - const new_security_path_level = parseInt(resources.security_patch_level.replace(/-/g, ''), 10); - if (current_security_path_level > new_security_path_level) { - WDebug.log("Bypass lock procedure", `resources/${this_model}-safe.json`); - resources = await (await fetch(`resources/${this_model}-safe.json`)).json(); - } - } - } catch (e) { - resources = null; - WDebug.log("getRessources Error"); - throw Error('device-model-not-supported'); - } - - return resources; - } - - setResources(resources){ - this.resources = resources; - if (this.resources.steps) { - this.steps.push(new Step("downloading", 'download', false)); - this.steps.push(...this.resources.steps.map((step) => { - return new Step(step.id, step.command, step.needUserGesture ?? false, step.mode); - })); - this.view.updateTotalStep(this.steps.length); - } - this.deviceManager.setResources(this.resources.folder, this.steps); - } -} +import { DeviceManager } from "./controller/device.manager.js"; +import { Command } from "./controller/device/command.class.js"; +import { Step } from "./controller/utils/step.class.js"; +import { WDebug } from "./debug.js"; +/* + * Class to manage process + * Check and display the steps, interact with deviceManager + */ +export class Controller { + constructor() { + this.steps = [ + new Step("let-s-get-started", undefined, true), + new Step("connect-your-phone", undefined, true), + new Step("activate-developer-options", undefined, true), + new Step("activate-oem-unlock", undefined, true), + new Step("activate-usb-debugging", undefined, true), + new Step("enable-usb-file-transfer", undefined, true), + new Step("device-detection", "connect adb", true), + ]; + this.currentIndex = 0; + } + + async init(view) { + this.deviceManager = new DeviceManager(); + await this.deviceManager.init(); + this.view = view; + } + + async next() { + let current = this.steps[this.currentIndex]; + let next = this.steps[this.currentIndex + 1]; + + WDebug.log("Controller Manager Next", next); + + if (next) { + //K1ZFP check this + if (next.mode) { + //if next step require another mode [adb|fastboot|bootloader] + if (this.deviceManager.isConnected() && !this.inInMode(next.mode)) { + //we need reboot + await this.deviceManager.reboot(next.mode); + } + if (!this.deviceManager.isConnected()) { + await this.deviceManager.connect(next.mode); + } + } + this.currentIndex++; + current = this.steps[this.currentIndex]; + this.view.onStepStarted(this.currentIndex, current); + if (!current.needUserGesture) { + await this.executeStep(current.name); + } + } + } + + async executeStep(stepName, loader) { + const current = this.steps[this.currentIndex]; + let this_command; + WDebug.log("ControllerManager Execute step", current); + document.getElementById("error-message-state").style.display = "none"; + if (current.name === stepName) { + let res = true; + let i; + try { + for (i = 0; i < current.commands.length && res; i++) { + this_command = current.commands[i]; + res = await this.runCommand(this_command, loader); + WDebug.log("run command > ", this_command, "returns ", res); + } + const next = this.steps[this.currentIndex + 1]; + let previous = this.steps[this.currentIndex - 1]; + if (res) { + if (next) { + this.view.onStepFinished(current, next); + await this.next(); + } + } else { + this.view.onStepFailed(current, previous); + if (!current.needUserGesture) { + this.currentIndex--; + } + throw new Error("command failed"); + } + } catch (e) { + throw new Error( + `Cannot execute command ${this_command.command}
${e.message || e}`, + ); + } + } else { + throw new Error( + "this is not the current step " + + current.name + + " is not equals to " + + stepName, + ); + } + } + + /** + * + * @param mode + * @returns {boolean} + * Check if device is connected to a mode + */ + inInMode(mode) { + return this.deviceManager.isInMode(mode); + } + + /* + * run a command + this throw new error if something went wwrong. + error should contain a proposal to solve the issue. + */ + async runCommand(cmd, loader) { + WDebug.log("ControllerManager run command:", cmd); + switch (cmd.type) { + case Command.CMD_TYPE.download: + try { + await this.deviceManager.downloadAll( + (loaded, total, name) => { + this.view.onDownloading(name, loaded, total); + }, + (loaded, total, name) => { + this.view.onUnzip(name, loaded, total); + }, + ); + this.view.onDownloadingEnd(); + return true; + } catch (e) { + const proposal = "Proposal: Retry by refreshing this page."; + throw new Error( + `Cannot download
${e.message || e}
${proposal}`, + ); + } + case Command.CMD_TYPE.reboot: + try { + await this.deviceManager.reboot(cmd.mode); + } catch (e) { + console.error(e); + //K1ZFP TODO + return false; + } + return true; + case Command.CMD_TYPE.connect: { + const proposal = + "Proposal: Check connection and that no other program is using the phone and retry."; + try { + await this.deviceManager.connect(cmd.mode); + await this.onDeviceConnected(); + if (loader) { + loader.style.display = "none"; + } + return true; + } catch (e) { + throw new Error( + `The device is not connected ${e.message || e}
${proposal}`, + ); + } + } + case Command.CMD_TYPE.erase: + return this.deviceManager.erase(cmd.partition); + case Command.CMD_TYPE.flash: + return this.deviceManager.flash( + cmd.file, + cmd.partition, + (done, total) => { + this.view.onInstalling(cmd.file, done, total); + }, + ); + case Command.CMD_TYPE.unlock: { + //check if unlocked to avoid unnecessary command + let isUnlocked = false; + let gotoStep = ""; + if (cmd.partition) { + if (cmd.partition.startsWith("goto_")) { + gotoStep = cmd.partition.substring(5); + WDebug.log("goto step", gotoStep); + isUnlocked = await this.deviceManager.getUnlocked("unlocked"); + } else { + isUnlocked = await this.deviceManager.getUnlocked(cmd.partition); + } + } + WDebug.log( + "ControllerManager unlock: ", + this.deviceManager.adb.getProductName() + + " isUnlocked = " + + isUnlocked, + ); + if (!isUnlocked) { + try { + this.deviceManager.unlock(cmd.command); // Do not await thus display unlocking screen + } catch (e) { + //on some device, check unlocked does not work but when we try the command, it throws an error with "already unlocked" + if (e.bootloaderMessage?.includes("already")) { + WDebug.log("device already unlocked"); + } else if (e.bootloaderMessage?.includes("not allowed")) { + WDebug.log("device unlock is not allowed"); + } + } + } else { + WDebug.log("The phone is not locked - bypass lock process"); + if (gotoStep == "") { + // Goto the next step. + this.currentIndex++; + } else { + // Goto the maned step. + do { + this.currentIndex++; + WDebug.log( + "Bypass step", + this.steps[this.currentIndex].name + + " " + + (this.steps[this.currentIndex].name == gotoStep), + ); + } while (!(this.steps[this.currentIndex].name == gotoStep)); + this.currentIndex--; + } + } + return true; + } + case Command.CMD_TYPE.lock: { + let isLocked = false; + if (cmd.partition) { + isLocked = !(await this.deviceManager.getUnlocked(cmd.partition)); + } + if (!isLocked) { + try { + this.deviceManager.lock(cmd.command); // Do not await thus display unlocking screen + } catch (e) { + //on some device, check unlocked does not work but when we try the command, it throws an error with "already locked" + if (e.bootloaderMessage?.includes("already")) { + isLocked = true; + } else { + console.error(e); //K1ZFP TODO + } + } + } + return true; + } + case Command.CMD_TYPE.sideload: + try { + await this.deviceManager.connect("recovery"); + await this.deviceManager.sideload(cmd.file); + return true; + } catch (e) { + console.error(e); // K1ZFP TODO + return false; + } + case Command.CMD_TYPE.format: + try { + this.deviceManager.for(cmd.partition); + } catch (e) { + console.error(e); // K1ZFP TODO + } + return true; + case Command.CMD_TYPE.delay: + await new Promise((resolve) => setTimeout(resolve, cmd.partition)); + return true; + + default: + WDebug.log(`try unknown command ${cmd.command}`); + await this.deviceManager.runCommand(cmd.command); + return true; + } + } + + async onDeviceConnected() { + const productName = this.deviceManager.getProductName(); + const wasAlreadyConnected = this.deviceManager.wasAlreadyConnected(); + if (!wasAlreadyConnected) { + this.view.updateData("product-name", productName); + this.model = productName; + WDebug.log("ControllerManager Model:", this.model); + try { + const resources = await this.getResources(); + + if (resources.android) { + this.view.updateData("android-version-required", resources.android); + await this.checkAndroidVersion(resources.android); + } + this.setResources(resources); + } catch (e) { + this.steps.push(new Step(e.message)); + this.view.updateTotalStep(this.steps.length); + // Don not throw this error, as it is handled by the UI directly. + } + } + } + async checkAndroidVersion(versionRequired) { + const android = await this.deviceManager.getAndroidVersion(); + WDebug.log("current android version:", android); + if (android) { + this.view.updateData("android-version", android); + if (android < versionRequired) { + throw Error("android-version-not-supported"); + } + } + } + async getResources() { + let resources = null; + try { + let current_security_path_level = null; + try { + const security_patch = await this.deviceManager.adb.webusb.getProp( + "ro.build.version.security_patch", + ); + //WDebug.log('security_patch', security_patch) + current_security_path_level = parseInt( + security_patch.replace(/-/g, ""), + 10, + ); + WDebug.log("current_security_path_level", current_security_path_level); + } catch { + WDebug.log("Security patch Error"); + current_security_path_level = null; + } + + let this_model = this.deviceManager.adb.webusb.device; + // https://gitlab.e.foundation/e/os/backlog/-/issues/2604#note_609234 + const model = this.deviceManager.adb.webusb.model; + if (model.includes("Teracube") && model.includes("2e")) { + try { + const serial = await this.deviceManager.adb.getSerialNumber(); + WDebug.log("serial numer:", serial); + if (serial.startsWith("2021")) { + this_model = "emerald"; + } else if (serial.startsWith("2020")) { + this_model = "Teracube_2e"; + } else { + const id = + "model " + + this.deviceManager.adb.webusb.model + + " " + + "product " + + this.deviceManager.adb.webusb.product + + " " + + "name " + + this.deviceManager.adb.webusb.name + + " " + + "device " + + this.deviceManager.adb.webusb.device; + throw new Error("Cannot find device resource", id); + } + } catch { + const id = + "model " + + this.deviceManager.adb.webusb.model + + " " + + "product " + + this.deviceManager.adb.webusb.product + + " " + + "name " + + this.deviceManager.adb.webusb.name + + " " + + "device " + + this.deviceManager.adb.webusb.device; + throw new Error("Error on getting device resource", id); + } + } + + if (model.includes("A015")) { + try { + this_model = "tetris"; + } catch { + const id = + "model " + + this.deviceManager.adb.webusb.model + + " " + + "product " + + this.deviceManager.adb.webusb.product + + " " + + "name " + + this.deviceManager.adb.webusb.name + + " " + + "device " + + this.deviceManager.adb.webusb.device; + throw new Error("Error on getting devcice resource", id); + } + } + + resources = await (await fetch(`resources/${this_model}.json`)).json(); + if ( + current_security_path_level != null && + typeof resources.security_patch_level != "undefined" + ) { + WDebug.log("EOS Rom has security patch "); + const new_security_path_level = parseInt( + resources.security_patch_level.replace(/-/g, ""), + 10, + ); + if (current_security_path_level > new_security_path_level) { + WDebug.log( + "Bypass lock procedure", + `resources/${this_model}-safe.json`, + ); + resources = await ( + await fetch(`resources/${this_model}-safe.json`) + ).json(); + } + } + } catch (e) { + resources = null; + WDebug.log("getResources Error: " + e); + throw Error("device-model-not-supported"); + } + + return resources; + } + + setResources(resources) { + this.resources = resources; + if (this.resources.steps) { + this.steps.push(new Step("downloading", "download", false)); + this.steps.push( + ...this.resources.steps.map((step) => { + return new Step( + step.id, + step.command, + step.needUserGesture ?? false, + step.mode, + ); + }), + ); + this.view.updateTotalStep(this.steps.length); + } + this.deviceManager.setResources(this.resources.folder, this.steps); + } +} diff --git a/app/src/controller/device.manager.js b/app/src/controller/device.manager.js index bf600b1b2458625c67ea0c410bd432f5e353ee87..981d2c6865dd05dbad8ec5eaf587ea34fade8eae 100644 --- a/app/src/controller/device.manager.js +++ b/app/src/controller/device.manager.js @@ -1,199 +1,200 @@ -import {Bootloader} from "./device/bootloader.class.js"; -import {Downloader} from "./downloader.manager.js"; -import {ADB} from "./device/adb.class.js"; -import {Recovery} from "./device/recovery.class.js"; -import {Device} from "./device/device.class.js"; -const MODE = { - adb: 'adb', - recovery: 'recovery', - bootloader: 'bootloader', -} - -/** - * wrap device functions - * */ -export class DeviceManager { - constructor() { - this.model = ''; - this.rom = undefined; - this.key = undefined; - this.patch = []; - this.oem = undefined; - this.device = new Device(); - this.bootloader = new Bootloader(); - this.recovery = new Recovery(); - this.adb = new ADB(); - this.downloader = new Downloader(); - this.wasConnected = false; - } - - async init() { - await this.bootloader.init(); - await this.adb.init(); - await this.recovery.init(); - await this.downloader.init(); - } - - - wasAlreadyConnected() { - if (this.wasConnected == false) { - this.wasConnected = true; - return false; - } - return true; - } - - setResources(folder, steps ) { - this.folder = folder; - this.files = steps.map(s => { - return s.commands.map(c => { - return c.file; - }) - }).flat(); - } - - async getUnlocked(variable) { - return this.bootloader.isUnlocked(variable); - } - async getAndroidVersion() { - return await this.device.getAndroidVersion(); - } - async isDetected(){ - const serial = this.serialNumber; - if(serial) { - const devices = await navigator.usb.getDevices(); - return !!devices.length; - } - return false; - } - - - /** - * @param mode - * @returns {any} - * - * We set the device to the mode manager we went to connect to - * And we connect the device - * - */ - async setMode(mode) { - switch (mode) { - case MODE.bootloader : - this.device = this.bootloader; - break; - case MODE.adb : - this.device = this.adb; - break; - case MODE.recovery : - this.device = this.recovery; - break; - } - } - async connect(mode) { - await this.setMode(mode); - try { - return await this.device.connect(); - } catch(e) { - throw new Error(`Failed to connect: ${e.message || e}`); - } - } - - isConnected() { - return this.device.isConnected(); - } - /** - * @param mode - * @returns {boolean} - * - */ - isInMode(mode) { - if(this.isConnected()){ - switch (mode) { - case 'bootloader': - return this.device.isBootloader(); - case 'adb': - return this.device.isADB(); - case 'recovery': - return this.device.isRecovery(); - } - } - return false; - } - - erase(partition) { - return this.bootloader.runCommand(`erase:${partition}`); - } - - format(argument) { - return true; -// return this.bootloader.runCommand(`format ${argument}`); -// the fastboot format md_udc is not supported evne by the official fastboot program - } - - unlock(command) { - return this.bootloader.runCommand(command); - } - - lock(command) { - return this.bootloader.runCommand(command); - } - - async flash(file, partition, onProgress) { - let blob = await this.downloader.getFile(file); - if (!blob) { - throw new Error(`error getting blob file ${file}`); - } - let flashed = false; - try { - flashed = await this.bootloader.flashBlob(partition, blob, onProgress); - } - catch (e) { - throw new Error(`error flashing file ${file} ${e.message || e}`); - } - return flashed; - } - - - getProductName() { - return this.device.getProductName(); - } - - getSerialNumber() { - return this.device.getSerialNumber(); - } - - - - async reboot(mode) { - const res = await this.device.reboot(mode); - if(res) { - this.setMode(mode); - } - return res; - } - - async sideload(file) { - let blob = await this.downloader.getFile(file); - if (!blob) { - throw new Error(`error getting blob file ${file}`); - } - - return await this.device.sideload(blob); - } - - async runCommand(command) { - try { - return this.device.runCommand(command); - } catch (e) { - throw new Error(`error ${command} failed
${e.message || e}`); - } - } - - async downloadAll(onProgress, onUnzip) { - try { - await this.downloader.downloadAndUnzipFolder(this.files, this.folder, onProgress, onUnzip); - } catch (e) { - throw new Error(`downloadAll error ${e.message || e}`); - } - } -} \ No newline at end of file +import { Bootloader } from "./device/bootloader.class.js"; +import { Downloader } from "./downloader.manager.js"; +import { ADB } from "./device/adb.class.js"; +import { Recovery } from "./device/recovery.class.js"; +import { Device } from "./device/device.class.js"; +const MODE = { + adb: "adb", + recovery: "recovery", + bootloader: "bootloader", +}; + +/** + * wrap device functions + * */ +export class DeviceManager { + constructor() { + this.model = ""; + this.rom = undefined; + this.key = undefined; + this.patch = []; + this.oem = undefined; + this.device = new Device(); + this.bootloader = new Bootloader(); + this.recovery = new Recovery(); + this.adb = new ADB(); + this.downloader = new Downloader(); + this.wasConnected = false; + } + + async init() { + await this.bootloader.init(); + await this.adb.init(); + await this.recovery.init(); + await this.downloader.init(); + } + + wasAlreadyConnected() { + if (this.wasConnected == false) { + this.wasConnected = true; + return false; + } + return true; + } + + setResources(folder, steps) { + this.folder = folder; + this.files = steps + .map((s) => { + return s.commands.map((c) => { + return c.file; + }); + }) + .flat(); + } + + async getUnlocked(variable) { + return this.bootloader.isUnlocked(variable); + } + async getAndroidVersion() { + return await this.device.getAndroidVersion(); + } + async isDetected() { + const serial = this.serialNumber; + if (serial) { + const devices = await navigator.usb.getDevices(); + return !!devices.length; + } + return false; + } + + /** + * @param mode + * @returns {any} + * + * We set the device to the mode manager we went to connect to + * And we connect the device + * + */ + async setMode(mode) { + switch (mode) { + case MODE.bootloader: + this.device = this.bootloader; + break; + case MODE.adb: + this.device = this.adb; + break; + case MODE.recovery: + this.device = this.recovery; + break; + } + } + async connect(mode) { + await this.setMode(mode); + try { + return await this.device.connect(); + } catch (e) { + throw new Error(`Failed to connect: ${e.message || e}`); + } + } + + isConnected() { + return this.device.isConnected(); + } + /** + * @param mode + * @returns {boolean} + * + */ + isInMode(mode) { + if (this.isConnected()) { + switch (mode) { + case "bootloader": + return this.device.isBootloader(); + case "adb": + return this.device.isADB(); + case "recovery": + return this.device.isRecovery(); + } + } + return false; + } + + erase(partition) { + return this.bootloader.runCommand(`erase:${partition}`); + } + + format() { + return true; + // return this.bootloader.runCommand(`format ${argument}`); + // the fastboot format md_udc is not supported evne by the official fastboot program + } + + unlock(command) { + return this.bootloader.runCommand(command); + } + + lock(command) { + return this.bootloader.runCommand(command); + } + + async flash(file, partition, onProgress) { + let blob = await this.downloader.getFile(file); + if (!blob) { + throw new Error(`error getting blob file ${file}`); + } + let flashed = false; + try { + flashed = await this.bootloader.flashBlob(partition, blob, onProgress); + } catch (e) { + throw new Error(`error flashing file ${file} ${e.message || e}`); + } + return flashed; + } + + getProductName() { + return this.device.getProductName(); + } + + getSerialNumber() { + return this.device.getSerialNumber(); + } + + async reboot(mode) { + const res = await this.device.reboot(mode); + if (res) { + this.setMode(mode); + } + return res; + } + + async sideload(file) { + let blob = await this.downloader.getFile(file); + if (!blob) { + throw new Error(`error getting blob file ${file}`); + } + + return await this.device.sideload(blob); + } + + async runCommand(command) { + try { + return this.device.runCommand(command); + } catch (e) { + throw new Error(`error ${command} failed
${e.message || e}`); + } + } + + async downloadAll(onProgress, onUnzip) { + try { + await this.downloader.downloadAndUnzipFolder( + this.files, + this.folder, + onProgress, + onUnzip, + ); + } catch (e) { + throw new Error(`downloadAll error ${e.message || e}`); + } + } +} diff --git a/app/src/controller/device/adb.class.js b/app/src/controller/device/adb.class.js index 28adebcd9e28356d2a98ae75258d82b3c91c9c41..86bd536d4e2c6e94e97e4e4487bfb963dd1b1379 100644 --- a/app/src/controller/device/adb.class.js +++ b/app/src/controller/device/adb.class.js @@ -1,79 +1,70 @@ -import {Device} from "./device.class.js"; -import {WDebug} from "../../debug.js"; -import {AdbWebBackend, Adb2} from "../../lib/webadb/adb.bundle.js"; - -export class ADB extends Device { - constructor(device) { - super(device); - this.webusb = null; - } - - async isConnected() { - if (!this.device) { - return false; - } - try { - return this.device.getDevice(); - } catch (e) { - return false; - } - } - - isADB() { - return true; - } - - async connect(cb) { - let res = false; - try { - console.log("debug adb connect") - let adbWebBackend = await AdbWebBackend.requestDevice(); - if (adbWebBackend) { - let adbDevice = new Adb2(adbWebBackend, null); //adb.bundle.js - await adbDevice.connect(); - this.device = adbWebBackend._device; - this.webusb = adbDevice; - - WDebug.log("----------------------------------"); - WDebug.log("Model", adbDevice.model); - WDebug.log("product", adbDevice.product); - WDebug.log("Name", adbDevice.name); - WDebug.log(">Device (codename)", adbDevice.device); // codemane - WDebug.log("----------------------------------"); - - res = true; - } - } catch (e) { - this.device = null; - throw new Error(`Cannot connect ADB ${e.message || e}`); - } finally { - return res; - } - } - - getProductName() { - return this.webusb.name; - } - - async getAndroidVersion() { - return this.webusb.getProp('ro.build.version.release'); - } - - async getSerialNumber() { - return this.webusb.getProp("ro.boot.serialno"); - } - - async runCommand(cmd) { - WDebug.log("ADB Run command>", cmd); - return await this.webusb.exec(cmd); - } - - async reboot(mode) { - const res = await this.webusb.createStreamAndReadAll(`reboot:${mode}`); - return res; - - } - - - -} +import { Device } from "./device.class.js"; +import { WDebug } from "../../debug.js"; +import { AdbWebBackend, Adb2 } from "../../lib/webadb/adb.bundle.js"; + +export class ADB extends Device { + constructor(device) { + super(device); + this.webusb = null; + } + + async isConnected() { + if (!this.device) { + return false; + } + try { + return this.device.getDevice(); + } catch { + return false; + } + } + + isADB() { + return true; + } + + async connect() { + try { + console.log("debug adb connect"); + let adbWebBackend = await AdbWebBackend.requestDevice(); + if (adbWebBackend) { + let adbDevice = new Adb2(adbWebBackend, null); //adb.bundle.js + await adbDevice.connect(); + this.device = adbWebBackend._device; + this.webusb = adbDevice; + + WDebug.log("----------------------------------"); + WDebug.log("Model", adbDevice.model); + WDebug.log("product", adbDevice.product); + WDebug.log("Name", adbDevice.name); + WDebug.log(">Device (codename)", adbDevice.device); // codemane + WDebug.log("----------------------------------"); + } + } catch (e) { + this.device = null; + throw new Error(`Cannot connect ADB ${e.message || e}`); + } + } + + getProductName() { + return this.webusb.name; + } + + async getAndroidVersion() { + return this.webusb.getProp("ro.build.version.release"); + } + + async getSerialNumber() { + return this.webusb.getProp("ro.boot.serialno"); + } + + async runCommand(cmd) { + WDebug.log("ADB Run command>", cmd); + return await this.webusb.exec(cmd); + } + + async reboot(mode) { + const res = await this.webusb.createStreamAndReadAll(`reboot:${mode}`); + return res; + } +} diff --git a/app/src/controller/device/bootloader.class.js b/app/src/controller/device/bootloader.class.js index 8e9e48a21a82c6e704d867f3751723056381ffce..86df50c2869f37e59b3d0a77524cca7734605807 100644 --- a/app/src/controller/device/bootloader.class.js +++ b/app/src/controller/device/bootloader.class.js @@ -1,153 +1,134 @@ -import * as fastboot from "../../lib/fastboot/fastboot.js"; -import {TimeoutError} from "../../lib/fastboot/fastboot.js"; -import {Device} from "./device.class.js"; -import { WDebug } from "../../debug.js"; - -/** - * wrap fastboot interactions - * */ -export class Bootloader extends Device { - - constructor() { - super(new fastboot.FastbootDevice()); - } - - async init() { - //await this.blobStore.init(); - fastboot.configureZip({ - workerScripts: { - inflate: ["../dist/vendor/z-worker-pako.js", "pako_inflate.min.js"], - }, - }); - // Enable verbose debug logging - fastboot.setDebugLevel(2); - } - - reboot(mode) { - return this.device.reboot(mode); - } - - runCommand(command) { - return this.device.runCommand(command); - } - - isConnected() { - return this.device.isConnected; - } - - isBootloader() { - return true; - } - - async connect() { - let connected = false; - try { - await this.device.connect(); - connected = true; - } catch (e) { - throw new Error("Cannot connect Bootloader", `${e.message || e}`); - } finally { - return connected; - } - } - - getProductName() { - return this.device.device.productName; - } - - getSerialNumber() { - return this.device.device.serialNumber; - } - - async flashFactoryZip(blob, onProgress, onReconnect) { - try { - await this.device.flashFactoryZip( - blob, - false, - onReconnect, - // Progress callback - (action, item, progress) => { - let userAction = fastboot.USER_ACTION_MAP[action]; - onProgress(userAction, item, progress); - } - ); - } catch (e) { - throw e; - } - } - - async flashBlob(partition, blob, onProgress) { - try { - await this.device.flashBlob( - partition, - blob, - (progress) => { - onProgress(progress * blob.size, blob.size, partition); - } - ); - onProgress(blob.size, blob.size, partition); - return true; - } catch (e) { - if (e instanceof TimeoutError) { - WDebug.log("Timeout on flashblob >" + partition); - return await this.flashBlob(partition, blob, onProgress); - } else { - console.log("flashBlob error", e); - throw new Error(`Bootloader error: ${e.message || e}`); - } - } - } - - bootBlob(blob) { - return this.device.bootBlob(blob); - } - - async isUnlocked(variable) { - if (this.device && this.device.isConnected) { - try { - const unlocked = await this.device.getVariable(variable); - return !(!unlocked || unlocked === 'no'); - } catch (e) { - console.error(e); // K1ZFP TODO - throw e; - } - } - return false; - } - - async isLocked(variable) { - if (this.device && this.device.isConnected) { - try { - const unlocked = await this.device.getVariable(variable); - return !unlocked || unlocked === 'no'; - } catch (e) { - console.error(e); //K1ZFP TODO - throw e; - } - } - return false; - } - - async unlock(command) { - if (command) { - const res = await this.device.runCommand(command); - } else { - throw Error('no unlock command configured'); //K1ZFP TODO - } - } - - async lock(command) { - if (command) { - try { - const res = await this.device.runCommand(command); - return !(await this.isUnlocked()); - } catch (e) { - throw e; - } - } else { - throw Error('no lock command configured'); //K1ZFP TODO - } - } - - -} \ No newline at end of file +import * as fastboot from "../../lib/fastboot/fastboot.js"; +import { TimeoutError } from "../../lib/fastboot/fastboot.js"; +import { Device } from "./device.class.js"; +import { WDebug } from "../../debug.js"; + +/** + * wrap fastboot interactions + * */ +export class Bootloader extends Device { + constructor() { + super(new fastboot.FastbootDevice()); + } + + async init() { + //await this.blobStore.init(); + fastboot.configureZip({ + workerScripts: { + inflate: ["../dist/vendor/z-worker-pako.js", "pako_inflate.min.js"], + }, + }); + // Enable verbose debug logging + fastboot.setDebugLevel(2); + } + + reboot(mode) { + return this.device.reboot(mode); + } + + runCommand(command) { + return this.device.runCommand(command); + } + + isConnected() { + return this.device.isConnected; + } + + isBootloader() { + return true; + } + + async connect() { + try { + await this.device.connect(); + } catch (e) { + throw new Error("Cannot connect Bootloader", `${e.message || e}`); + } + } + + getProductName() { + return this.device.device.productName; + } + + getSerialNumber() { + return this.device.device.serialNumber; + } + + async flashFactoryZip(blob, onProgress, onReconnect) { + await this.device.flashFactoryZip( + blob, + false, + onReconnect, + // Progress callback + (action, item, progress) => { + let userAction = fastboot.USER_ACTION_MAP[action]; + onProgress(userAction, item, progress); + }, + ); + } + + async flashBlob(partition, blob, onProgress) { + try { + await this.device.flashBlob(partition, blob, (progress) => { + onProgress(progress * blob.size, blob.size, partition); + }); + onProgress(blob.size, blob.size, partition); + return true; + } catch (e) { + if (e instanceof TimeoutError) { + WDebug.log("Timeout on flashblob >" + partition); + return await this.flashBlob(partition, blob, onProgress); + } else { + console.log("flashBlob error", e); + throw new Error(`Bootloader error: ${e.message || e}`); + } + } + } + + bootBlob(blob) { + return this.device.bootBlob(blob); + } + + async isUnlocked(variable) { + if (this.device && this.device.isConnected) { + try { + const unlocked = await this.device.getVariable(variable); + return !(!unlocked || unlocked === "no"); + } catch (e) { + console.error(e); // K1ZFP TODO + throw e; + } + } + return false; + } + + async isLocked(variable) { + if (this.device && this.device.isConnected) { + try { + const unlocked = await this.device.getVariable(variable); + return !unlocked || unlocked === "no"; + } catch (e) { + console.error(e); //K1ZFP TODO + throw e; + } + } + return false; + } + + async unlock(command) { + if (command) { + await this.device.runCommand(command); + } else { + throw Error("no unlock command configured"); //K1ZFP TODO + } + } + + async lock(command) { + if (command) { + await this.device.runCommand(command); + return !(await this.isUnlocked()); + } else { + throw Error("no lock command configured"); //K1ZFP TODO + } + } +} diff --git a/app/src/controller/device/command.class.js b/app/src/controller/device/command.class.js index 5faf6c3c2e5363158e81abd1111c48bbda5825ea..b572d2df9caf6be8fec19da68fb4746d1ba4fbdd 100644 --- a/app/src/controller/device/command.class.js +++ b/app/src/controller/device/command.class.js @@ -1,74 +1,77 @@ -import { WDebug } from "../../debug.js"; - -export class Command { - static CMD_TYPE = { - flash: 'flash', - sideload: 'sideload', - erase: 'erase', - unlock: 'unlock', - lock: 'lock', - connect: 'connect', - reboot: 'reboot', - download: 'download', - format: 'format', - delay: 'delay' - }; - - constructor(cmd) { - this.command = cmd; - this.type = undefined; - this.mode = undefined; - this.partition = undefined; - this.file = undefined; - this.parseCommand(cmd); - } - - parseCommand(cmd) { - const res = cmd.split(' ').map(m => m.trim()).filter(m => m != ''); - WDebug.log(`command.class parseCommand : ${cmd}`); - switch (res[0]) { - case 'download': - this.type = Command.CMD_TYPE.download; - break - case 'connect': - this.type = Command.CMD_TYPE.connect; - this.mode = res[1]; // adb or fastboot; - break - case 'flash': - this.type = Command.CMD_TYPE.flash; - this.partition = res[1]; - this.file = res[2]; - break; - case 'sideload': - this.type = Command.CMD_TYPE.sideload; - this.file = res[1]; - break; - case 'erase': - this.type = Command.CMD_TYPE.erase; - this.partition = res[1]; - break; - case 'reboot': - this.type = Command.CMD_TYPE.reboot; - this.mode = res[1]; - break; - case 'flashing': - case 'oem': - this.command = `${res[0]} ${res[1]}`; - this.partition = res[2]; - if (res[1].startsWith('unlock')) { - this.type = Command.CMD_TYPE.unlock; - } else if (res[1].startsWith('lock')) { - this.type = Command.CMD_TYPE.lock; - } - break; - case 'delay' : - this.type = Command.CMD_TYPE.delay; - this.partition = parseInt(res[1], 10)*1000; - break; - case 'format': - this.partition = res[1]; - this.type = Command.CMD_TYPE.format; - break; - } - } -} \ No newline at end of file +import { WDebug } from "../../debug.js"; + +export class Command { + static CMD_TYPE = { + flash: "flash", + sideload: "sideload", + erase: "erase", + unlock: "unlock", + lock: "lock", + connect: "connect", + reboot: "reboot", + download: "download", + format: "format", + delay: "delay", + }; + + constructor(cmd) { + this.command = cmd; + this.type = undefined; + this.mode = undefined; + this.partition = undefined; + this.file = undefined; + this.parseCommand(cmd); + } + + parseCommand(cmd) { + const res = cmd + .split(" ") + .map((m) => m.trim()) + .filter((m) => m != ""); + WDebug.log(`command.class parseCommand : ${cmd}`); + switch (res[0]) { + case "download": + this.type = Command.CMD_TYPE.download; + break; + case "connect": + this.type = Command.CMD_TYPE.connect; + this.mode = res[1]; // adb or fastboot; + break; + case "flash": + this.type = Command.CMD_TYPE.flash; + this.partition = res[1]; + this.file = res[2]; + break; + case "sideload": + this.type = Command.CMD_TYPE.sideload; + this.file = res[1]; + break; + case "erase": + this.type = Command.CMD_TYPE.erase; + this.partition = res[1]; + break; + case "reboot": + this.type = Command.CMD_TYPE.reboot; + this.mode = res[1]; + break; + case "flashing": + case "oem": + this.command = `${res[0]} ${res[1]}`; + this.partition = res[2]; + if (res[1].startsWith("unlock")) { + this.type = Command.CMD_TYPE.unlock; + } else if (res[1].startsWith("lock")) { + this.type = Command.CMD_TYPE.lock; + } + break; + case "delay": + this.type = Command.CMD_TYPE.delay; + this.partition = parseInt(res[1], 10) * 1000; + break; + case "format": + this.partition = res[1]; + this.type = Command.CMD_TYPE.format; + break; + } + } +} diff --git a/app/src/controller/device/device.class.js b/app/src/controller/device/device.class.js index ee68e8b91e09c0619b885569101728c823b0a88d..10bcdb9882dd7e4de92809440db167f9f4fdb40b 100644 --- a/app/src/controller/device/device.class.js +++ b/app/src/controller/device/device.class.js @@ -1,60 +1,56 @@ -export class Device { - constructor(device) { - this.device = device; - } - - async init() { - - } - - async connect() { - return false; - } - - isConnected() { - return false; - } - - isADB() { - return false; - } - - isBootloader() { - return false; - } - - isFastboot() { - return false; - } - - isRecovery() { - return false; - } - - async flashBlob(partition, blob, onProgress) { - return false; - } - - async runCommand(cmd) { - return false; - } - - getProductName() { - return undefined; - } - - getSerialNumber() { - return undefined; - } - async getAndroidVersion() { - return undefined; - } - - reboot(mode) { - return undefined; - } - - async bootBlob(blob) { - return false; - } -} \ No newline at end of file +export class Device { + constructor(device) { + this.device = device; + } + + async init() {} + + async connect() {} + + isConnected() { + return false; + } + + isADB() { + return false; + } + + isBootloader() { + return false; + } + + isFastboot() { + return false; + } + + isRecovery() { + return false; + } + + async flashBlob() { + return false; + } + + async runCommand() { + return false; + } + + getProductName() { + return undefined; + } + + getSerialNumber() { + return undefined; + } + async getAndroidVersion() { + return undefined; + } + + reboot() { + return undefined; + } + + async bootBlob() { + return false; + } +} diff --git a/app/src/controller/device/recovery.class.js b/app/src/controller/device/recovery.class.js index 3114594770f59d51cc500de1c5c1fa5b88fc34ed..d786ba178194729103cf1cf5d5d1f6d134d8bee4 100644 --- a/app/src/controller/device/recovery.class.js +++ b/app/src/controller/device/recovery.class.js @@ -1,432 +1,158 @@ -import {MessageClass} from "../../lib/webadb/message.class.js"; -import {MessageHeader} from "../../lib/webadb/message-header.class.js"; -import {Device} from "./device.class.js"; -import {WDebug} from "../../debug.js"; -import {AdbWebBackend3, Adb3} from "../../lib/webadb/adb.bundle.js"; - -export class Recovery extends Device { - constructor(device) { - super(device); - this.webusb = null; - this.count = 0; - this.adbWebBackend = null; - } - - async isConnected() { - if (!this.device) { - return false; - } - try { - return this.device.getDevice(); - } catch (e) { - return false; - } - } - - isRecovery() { - return true; - } - - async connect() { - let res = false; - try { - if (this.device && this.device.isConnected) { - WDebug.log("Connect recovery the device is connected"); - } else { - const adbWebBackend = await AdbWebBackend3.requestDevice(); - WDebug.log("adbWebBackend = ", adbWebBackend); - const adbDevice = new Adb3(adbWebBackend, null); //adb.bundle.js - WDebug.log("adbDevice = ", adbDevice); - await adbDevice.connect(); - WDebug.log("adbDevice connected"); - this.device = adbWebBackend._device; - this.webusb = adbDevice; - this.adbWebBackend = adbWebBackend; - res = true; - } - return true; - } catch (e) { - this.device = null; - throw new Error(`Cannot connect Recovery ${e.message || e}`); - } finally { - return res; - } - } - - async sideload(blob, onProgress) { - let res = false; - try { - await this.adbOpen(blob, true); - res = true; - } catch (e) { - throw new Error(`Sideload fails ${e.message || e}`); - } finally { - return res; - } - } - - async reboot(mode) { - return await this.device.shell(`reboot ${mode}`); - } - - getProductName() { - return this.webusb.name; - } - - getSerialNumber() { - return this.webusb.product; - } - - async _______adbOpen_DEPRECATED(blob, useChecksum ) { -// K1ZFP this one is used by the webadb.js lib that does not works on MacOS - const transport = this.device.transport; - if (transport == null) - return; - - const encoder = new TextEncoder(); - const decoder = new TextDecoder(); - - const MAX_PAYLOAD = this.device.max_payload; - const fileSize = blob.size; - const service = `sideload-host:${fileSize}:${MAX_PAYLOAD}`; //sideload-host:1381604186:262144 - - let data = new DataView(encoder.encode('' + service + '\0').buffer); - this.stream = await Adb.Stream.open(this.device, service); // Send OPEN message and receive OKAY - - let checksum = 0; - if (useChecksum) { - checksum = MessageClass.checksum(data); - } - const localId = this.stream.local_id; - const remoteId = this.stream.remote_id; - - - let header = new MessageHeader('OKAY', localId, remoteId, 0, checksum); - let receivedData; - const hh = header.toDataView().buffer - /* - Index Valeur (Int8) - 0 79 - 1 75 - 2 65 - 3 89 - 4 1 - 5 0 - 6 0 - 7 0 - 8 1 - 9 0 - 10 0 - 11 0 - 12 0 - 13 0 - 14 0 - 15 0 - 16 -35 - 17 8 - 18 0 - 19 0 - 20 -80 - 21 -76 - 22 -66 - 23 -90 - */ - await this.write(hh); - - let response_h = await this.read(24); - /* - Index Valeur (Int8) Interprétation ASCII - 0 87 W - 1 82 R - 2 84 T - 3 69 E - 4 1 - 5 0 - 6 0 - 7 0 - 8 1 - 9 0 - 10 0 - 11 0 - 12 8 - 13 0 - 14 0 - 15 0 - 16 -114 - 17 1 - 18 0 - 19 0 - 20 -88 - 21 -83 - 22 -85 - 23 -70 - */ - - header = MessageHeader.parse(response_h, useChecksum); - switch (header.cmd) { - default: { - if (header.length > 0) { //=8 - receivedData = await this.read(header.length); //READ... - /* - Int8Array(8) - 0 : 48 - 1 : 48 - 2 : 48 - 3 : 48 - 4 : 53 - 5 : 50 - 6 : 55 - 7 : 48 - */ - } - } - } - - let message = new MessageClass(header, receivedData); - if (message.header.cmd !== 'WRTE') { - throw new Error('WRTE Failed'); - } - - while (true) { - let res = decoder.decode(message.data); //1pass 1 2pass 0 // 5270 - const block = Number(res); - - if (isNaN(block) && res === 'DONEDONE') { - break; - } - - const offset = block * MAX_PAYLOAD; //1381498880 - if (offset >= fileSize) { //1381604186 - throw new Error(`adb: failed to read block ${block} past end`); - } - - let to_write = MAX_PAYLOAD; //105306 - if ((offset + MAX_PAYLOAD) > fileSize) { - to_write = fileSize - offset; - } - - const slice = blob.slice(offset, offset + to_write); //K1ZFP type? - //cons ole.log("offset to_write", offset, to_write); // 1 179 254 784 - //cons ole.log("to_write(" + to_write + ") offset(" + offset + ") " + (await slice.arrayBuffer()).byteLength); - - let header = new MessageHeader('WRTE', localId, remoteId, to_write, checksum); - let hhh = header.toDataView().buffer; - /* - 0 87 W - 1 82 R - 2 84 T - 3 69 E - 4 1 - 5 0 - 6 0 - 7 0 - 8 1 - 9 0 - 10 0 - 11 0 - 12 90 Z - 13 -101 - 14 1 - 15 0 - 16 -35 - 17 8 - 18 0 - 19 0 - 20 -88 - 21 -83 - 22 -85 - 23 -70 */ - await this.write(hhh); - let hhhh = await slice.arrayBuffer(); - await this.write(hhhh); - /* - byteLength: 105306 - detached: false - maxByteLength: 105306 - resizable : false*/ - - /////// - - response_h = await this.read(24); - /* - Index Valeur (Int8) Interprétation ASCII - 0 79 O - 1 75 K - 2 65 A - 3 89 Y - 4 1 - 5 0 - 6 0 - 7 0 - 8 1 - 9 0 - 10 0 - 11 0 - 12 0 - 13 0 - 14 0 - 15 0 - 16 0 - 17 0 - 18 0 - 19 0 - 20 -80 - 21 -76 - 22 -66 - 23 -90 */ - header = MessageHeader.parse(response_h, useChecksum); - switch (header.cmd) { - default: { - if (header.length > 0) { - receivedData = await this.read(header.length); - } else { - receivedData = new DataView(encoder.encode("0").buffer); // 1pass Here 2nd... - } - } - } - message = new MessageClass(header, receivedData); - - if (message.header.cmd !== 'OKAY') { - throw new Error('WRTE Failed'); - } - - header = new MessageHeader('OKAY', localId, remoteId, 0, checksum); - await this.write(header.toDataView().buffer); - - response_h = await this.read(24); - /* - - Index Valeur (Int8) Interprétation ASCII - 0 87 W - 1 82 R - 2 84 T - 3 69 E - 4 1 - 5 0 - 6 0 - 7 0 - 8 1 - 9 0 - 10 0 - 11 0 - 12 8 - 13 0 - 14 0 - 15 0 - 16 -128 - 17 1 - 18 0 - 19 0 - 20 -88 - 21 -83 - 22 -85 - 23 -70 */ - header = MessageHeader.parse(response_h, useChecksum); - switch (header.cmd) { - default: { - if (header.length > 0) { // 1pass 8 - receivedData = await this.read(header.length); - /* - 0 48 0 - 1 48 0 - 2 48 0 - 3 48 0 - 4 48 0 - 5 48 0 - 6 48 0 - 7 48 0*/ - } - } - } - - message = new MessageClass(header, receivedData); - - if (message.header.cmd !== 'WRTE') { - throw new Error('WRTE Failed'); - } - } - return true; - } - - async adbOpen(blob, useChecksum) { - // This one is used by the adb.bundle.js - - const encoder = new TextEncoder(); - const decoder = new TextDecoder(); - - const MAX_PAYLOAD = 0x40000; - const fileSize = blob.size; - const service = `sideload-host:${fileSize}:${MAX_PAYLOAD}`; //sideload-host:1381604186:262144 - - let data = new DataView(encoder.encode('' + service + '\0').buffer); - this.stream = await this.webusb.createStream(service); // Send Open message and receive OKAY. - - let checksum = 0; - if (useChecksum) { - checksum = MessageClass.checksum(data); - } - const localId = this.stream.localId; - const remoteId = this.stream.remoteId; - - let header = new MessageHeader('OKAY', localId, remoteId, 0, checksum); - let receivedData, message; - await this.adbWebBackend.write(header.toDataView().buffer); - let r = await this.adbWebBackend.read(24); - let v = Array.from(new Uint8Array(r)).map(byte => String.fromCharCode(byte)).join(''); - if (v[0]=='W' && v[1]=='R' && v[2]=='T' && v[3]=='E') { - receivedData = await this.adbWebBackend.read(8); - message = new MessageClass(header, receivedData); - } else { - throw new Error('Write OKAY Failed (init)'); - } - - while (true) { - const res = decoder.decode(message.data); - const block = Number(res); - - if (isNaN(block) && res === 'DONEDONE') { - break; - } else { - if ((block%10)==0) { - WDebug.log("Sideloading " + block); - } - } - - const offset = block * MAX_PAYLOAD; - if (offset >= fileSize) { - throw new Error(`adb: failed to read block ${block} past end`); - } - - let to_write = MAX_PAYLOAD; - if ((offset + MAX_PAYLOAD) > fileSize) { - to_write = fileSize - offset; - } - - let slice = blob.slice(offset, offset + to_write); - header = new MessageHeader('WRTE', localId, remoteId, to_write, checksum); - let buff = await slice.arrayBuffer(); - - await this.adbWebBackend.write(header.toDataView().buffer) - await this.adbWebBackend.write(buff); - r = await this.adbWebBackend.read(24); - v = Array.from(new Uint8Array(r)).map(byte => String.fromCharCode(byte)).join(''); - //test OKAY - if (v[0]=='O' && v[1]=='K' && v[2]=='A' && v[3]=='Y') { - header = new MessageHeader('OKAY', localId, remoteId, 0, checksum); - await this.adbWebBackend.write(header.toDataView().buffer); - r = await this.adbWebBackend.read(24); - v = Array.from(new Uint8Array(r)).map(byte => String.fromCharCode(byte)).join(''); - //Test WRTE - if (v[0]=='W' && v[1]=='R' && v[2]=='T' && v[3]=='E') { - receivedData = await this.adbWebBackend.read(8); - message = new MessageClass(header, receivedData); - } else { - throw new Error(`WRTE Failed ${block}`); - } - } else { - throw new Error(`OKAY Failed ${block}`); - } - } - return true; - } -} +import { MessageClass } from "../../lib/webadb/message.class.js"; +import { MessageHeader } from "../../lib/webadb/message-header.class.js"; +import { Device } from "./device.class.js"; +import { WDebug } from "../../debug.js"; +import { AdbWebBackend3, Adb3 } from "../../lib/webadb/adb.bundle.js"; + +export class Recovery extends Device { + constructor(device) { + super(device); + this.webusb = null; + this.count = 0; + this.adbWebBackend = null; + } + + async isConnected() { + if (!this.device) { + return false; + } + try { + return this.device.getDevice(); + } catch { + return false; + } + } + + isRecovery() { + return true; + } + + async connect() { + try { + if (this.device && this.device.isConnected) { + WDebug.log("Connect recovery the device is connected"); + } else { + const adbWebBackend = await AdbWebBackend3.requestDevice(); + WDebug.log("adbWebBackend = ", adbWebBackend); + const adbDevice = new Adb3(adbWebBackend, null); //adb.bundle.js + WDebug.log("adbDevice = ", adbDevice); + await adbDevice.connect(); + WDebug.log("adbDevice connected"); + this.device = adbWebBackend._device; + this.webusb = adbDevice; + this.adbWebBackend = adbWebBackend; + } + } catch (e) { + this.device = null; + throw new Error(`Cannot connect Recovery ${e.message || e}`); + } + } + + async sideload(blob) { + try { + await this.adbOpen(blob, true); + } catch (e) { + throw new Error(`Sideload fails ${e.message || e}`); + } + } + + async reboot(mode) { + return await this.device.shell(`reboot ${mode}`); + } + + getProductName() { + return this.webusb.name; + } + + getSerialNumber() { + return this.webusb.product; + } + + async adbOpen(blob, useChecksum) { + // This one is used by the adb.bundle.js + + const encoder = new TextEncoder(); + const decoder = new TextDecoder(); + + const MAX_PAYLOAD = 0x40000; + const fileSize = blob.size; + const service = `sideload-host:${fileSize}:${MAX_PAYLOAD}`; //sideload-host:1381604186:262144 + + let data = new DataView(encoder.encode("" + service + "\0").buffer); + this.stream = await this.webusb.createStream(service); // Send Open message and receive OKAY. + + let checksum = 0; + if (useChecksum) { + checksum = MessageClass.checksum(data); + } + const localId = this.stream.localId; + const remoteId = this.stream.remoteId; + + let header = new MessageHeader("OKAY", localId, remoteId, 0, checksum); + let receivedData, message; + await this.adbWebBackend.write(header.toDataView().buffer); + let r = await this.adbWebBackend.read(24); + let v = Array.from(new Uint8Array(r)) + .map((byte) => String.fromCharCode(byte)) + .join(""); + if (v[0] == "W" && v[1] == "R" && v[2] == "T" && v[3] == "E") { + receivedData = await this.adbWebBackend.read(8); + message = new MessageClass(header, receivedData); + } else { + throw new Error("Write OKAY Failed (init)"); + } + + while (true) { + const res = decoder.decode(message.data); + const block = Number(res); + + if (isNaN(block) && res === "DONEDONE") { + break; + } else { + if (block % 10 == 0) { + WDebug.log("Sideloading " + block); + } + } + + const offset = block * MAX_PAYLOAD; + if (offset >= fileSize) { + throw new Error(`adb: failed to read block ${block} past end`); + } + + let to_write = MAX_PAYLOAD; + if (offset + MAX_PAYLOAD > fileSize) { + to_write = fileSize - offset; + } + + let slice = blob.slice(offset, offset + to_write); + header = new MessageHeader("WRTE", localId, remoteId, to_write, checksum); + let buff = await slice.arrayBuffer(); + + await this.adbWebBackend.write(header.toDataView().buffer); + await this.adbWebBackend.write(buff); + r = await this.adbWebBackend.read(24); + v = Array.from(new Uint8Array(r)) + .map((byte) => String.fromCharCode(byte)) + .join(""); + //test OKAY + if (v[0] == "O" && v[1] == "K" && v[2] == "A" && v[3] == "Y") { + header = new MessageHeader("OKAY", localId, remoteId, 0, checksum); + await this.adbWebBackend.write(header.toDataView().buffer); + r = await this.adbWebBackend.read(24); + v = Array.from(new Uint8Array(r)) + .map((byte) => String.fromCharCode(byte)) + .join(""); + //Test WRTE + if (v[0] == "W" && v[1] == "R" && v[2] == "T" && v[3] == "E") { + receivedData = await this.adbWebBackend.read(8); + message = new MessageClass(header, receivedData); + } else { + throw new Error(`WRTE Failed ${block}`); + } + } else { + throw new Error(`OKAY Failed ${block}`); + } + } + return true; + } +} diff --git a/app/src/controller/downloader.manager.js b/app/src/controller/downloader.manager.js index c8d6a561d625aac6dc01db28464d17c675278c1e..8940e777ba5e8af86c27a8bb7b8f65b30d89717e 100644 --- a/app/src/controller/downloader.manager.js +++ b/app/src/controller/downloader.manager.js @@ -1,9 +1,8 @@ const DB_NAME = "MurenaBlobStore"; const DB_VERSION = 1; -import ky from 'ky'; -import {ZipReader, BlobReader, BlobWriter} from "@zip.js/zip.js"; -import { WDebug } from "../debug.js"; +import ky from "ky"; +import { ZipReader, BlobReader, BlobWriter } from "@zip.js/zip.js"; /** * Download Manager @@ -12,238 +11,253 @@ import { WDebug } from "../debug.js"; * Blobs are in this.files[filename] */ export class Downloader { - constructor() { - this.db = null; - this.stored = {}; - } + constructor() { + this.db = null; + this.stored = {}; + } - async init() { - if (this.db) return; // Already initialized + async init() { + if (this.db) return; // Already initialized - this.db = await this.openDBStore(); - await this.clearDBStore(); - this.quota = await navigator.storage.estimate(); - } + this.db = await this.openDBStore(); + await this.clearDBStore(); + this.quota = await navigator.storage.estimate(); + } - /* - * */ - async downloadAndUnzipFolder(filesRequired, folder, onDownloadProgress, onUnzipProgress) { - let current_file ; - try { - for (let i = 0; i < folder.length; i++) { - const file = folder[i]; - current_file = file.path; - if(filesRequired.includes(file.name) || file.unzip){ - const blob = await this.download(file.path, (value, total) => { - onDownloadProgress(value, total, file.name); - }); - if(file.unzip){ - const zipReader = new ZipReader(new BlobReader(blob)); - const filesEntries = await zipReader.getEntries(); - for(let i= 0 ; i < filesEntries.length; i++) { - const unzippedEntry = await this.getFileFromZip(filesEntries[i], (value, total) => { - onUnzipProgress(value, total, filesEntries[i].filename); - }); - let filename = this.getMappedName(filesEntries[i].filename, file.mapping); - if(filesRequired.includes(filename)){ - await this.setInDBStore(unzippedEntry.blob, filename); - this.stored[filename] = true; - } - } - await zipReader.close(); - - } else { - await this.setInDBStore(blob, file.name); - this.stored[file.name] = true; - } - } + /* + * */ + async downloadAndUnzipFolder( + filesRequired, + folder, + onDownloadProgress, + onUnzipProgress, + ) { + let current_file; + try { + for (let i = 0; i < folder.length; i++) { + const file = folder[i]; + current_file = file.path; + if (filesRequired.includes(file.name) || file.unzip) { + const blob = await this.download(file.path, (value, total) => { + onDownloadProgress(value, total, file.name); + }); + if (file.unzip) { + const zipReader = new ZipReader(new BlobReader(blob)); + const filesEntries = await zipReader.getEntries(); + for (let i = 0; i < filesEntries.length; i++) { + const unzippedEntry = await this.getFileFromZip( + filesEntries[i], + (value, total) => { + onUnzipProgress(value, total, filesEntries[i].filename); + }, + ); + let filename = this.getMappedName( + filesEntries[i].filename, + file.mapping, + ); + if (filesRequired.includes(filename)) { + await this.setInDBStore(unzippedEntry.blob, filename); + this.stored[filename] = true; + } } - } catch (e) { - throw new Error(`downloadAndUnzipFolder Error
current_file ${current_file}
${e.message || e}`); - } - } - - async getFileFromZip(file, onProgress) { - const name = file.filename; - const blob = await file.getData(new BlobWriter(), { - onprogress: (value, total) => { - onProgress(value, total, name); - }, - useWebWorkers: false, - }); - return { - name, - blob + await zipReader.close(); + } else { + await this.setInDBStore(blob, file.name); + this.stored[file.name] = true; + } } + } + } catch (e) { + throw new Error( + `downloadAndUnzipFolder Error
current_file ${current_file}
${e.message || e}`, + ); } + } - getMappedName(filename, map) { - if (!map) { - return filename; - } + async getFileFromZip(file, onProgress) { + const name = file.filename; + const blob = await file.getData(new BlobWriter(), { + onprogress: (value, total) => { + onProgress(value, total, name); + }, + useWebWorkers: false, + }); + return { + name, + blob, + }; + } - console.log(map); - for (const [regex, newFilename] of Object.entries(map)) { - let re = new RegExp(regex); - if (filename.match(re)) { - return newFilename; - } - } - return filename; + getMappedName(filename, map) { + if (!map) { + return filename; } - - /** - * @param name - * @returns {} - * It does not launch download (downloads are launched with downloadFolder) - * this function retrieve the promise linked to the fileName - */ - async getFile(name) { - const file = this.stored[name]; - if(!file){ - throw new Error(`File ${name} was not previously downloaded`) - } - return await this.getFromDBStore(name); + console.log(map); + for (const [regex, newFilename] of Object.entries(map)) { + let re = new RegExp(regex); + if (filename.match(re)) { + return newFilename; + } } + return filename; + } - /* - * getData from a zip file - * */ - async getData(dbFile, fileEntry, onProgress) { - const _zip = new BlobWriter(); - const blob = await fileEntry.getData(_zip, { - onprogress: (value, total) => { - onProgress(value, total, dbFile); - }, - onend: () => {}, - useWebWorkers: true, - }); - return blob; + /** + * @param name + * @returns {} + * It does not launch download (downloads are launched with downloadFolder) + * this function retrieve the promise linked to the fileName + */ + async getFile(name) { + const file = this.stored[name]; + if (!file) { + throw new Error(`File ${name} was not previously downloaded`); } + return await this.getFromDBStore(name); + } - async download(path, onProgress) { - try { - const buffers = await this.fetch({ - url: path, - chunkSize: 16 * 1024 * 1024, - poolLimit: 1, - }, onProgress); - - //let totalSize = buffers.reduce((sum, buffer) => sum + buffer.byteLength, 0); - const ret = new Blob(buffers); - return ret; - } catch (e) { - throw new Error(`${e.message || e}`); - } - } + /* + * getData from a zip file + * */ + async getData(dbFile, fileEntry, onProgress) { + const _zip = new BlobWriter(); + const blob = await fileEntry.getData(_zip, { + onprogress: (value, total) => { + onProgress(value, total, dbFile); + }, + onend: () => {}, + useWebWorkers: true, + }); + return blob; + } + + async download(path, onProgress) { + try { + const buffers = await this.fetch( + { + url: path, + chunkSize: 16 * 1024 * 1024, + poolLimit: 1, + }, + onProgress, + ); - async clearDBStore() { - const store = this.db.transaction(DB_NAME, "readwrite").objectStore(DB_NAME); - store.clear(); + //let totalSize = buffers.reduce((sum, buffer) => sum + buffer.byteLength, 0); + const ret = new Blob(buffers); + return ret; + } catch (e) { + throw new Error(`${e.message || e}`); } + } - async setInDBStore(blob, key) { - return new Promise((resolve, reject) => { - const transaction = this.db.transaction(DB_NAME, 'readwrite'); - const store = transaction.objectStore(DB_NAME); - const request = store.put(blob, key); + async clearDBStore() { + const store = this.db + .transaction(DB_NAME, "readwrite") + .objectStore(DB_NAME); + store.clear(); + } - request.onsuccess = () => { - resolve(); - }; + async setInDBStore(blob, key) { + return new Promise((resolve, reject) => { + const transaction = this.db.transaction(DB_NAME, "readwrite"); + const store = transaction.objectStore(DB_NAME); + const request = store.put(blob, key); - request.onerror = (event) => { - reject(event.target.error); - }; - }); - } + request.onsuccess = () => { + resolve(); + }; - async getFromDBStore(key) { - return new Promise((resolve, reject) => { - const transaction = this.db.transaction(DB_NAME, 'readonly'); - const store = transaction.objectStore(DB_NAME); - const request = store.get(key); - request.onsuccess = function (event) { - const result = event.target.result; - if (result) { - resolve(result); - } else { - resolve(null); - } - }; - request.onerror = function (event) { - reject(event.target.error); - }; - }); - } + request.onerror = (event) => { + reject(event.target.error); + }; + }); + } - async openDBStore() { - return new Promise((resolve, reject) => { - const request = indexedDB.open(DB_NAME, DB_VERSION); - request.onerror = reject; - request.onupgradeneeded = function (event) { - const db = event.target.result; - db.createObjectStore(DB_NAME, {autoIncrement: false}); - }; - request.onsuccess = function (event) { - resolve(event.target.result); - } - }); - } + async getFromDBStore(key) { + return new Promise((resolve, reject) => { + const transaction = this.db.transaction(DB_NAME, "readonly"); + const store = transaction.objectStore(DB_NAME); + const request = store.get(key); + request.onsuccess = function (event) { + const result = event.target.result; + if (result) { + resolve(result); + } else { + resolve(null); + } + }; + request.onerror = function (event) { + reject(event.target.error); + }; + }); + } + async openDBStore() { + return new Promise((resolve, reject) => { + const request = indexedDB.open(DB_NAME, DB_VERSION); + request.onerror = reject; + request.onupgradeneeded = function (event) { + const db = event.target.result; + db.createObjectStore(DB_NAME, { autoIncrement: false }); + }; + request.onsuccess = function (event) { + resolve(event.target.result); + }; + }); + } - concatenate(arrays) { - if (!arrays.length) return null; - let totalLength = arrays.reduce((acc, value) => acc + value.length, 0); - let result = new Uint8Array(totalLength); - let length = 0; - for (let array of arrays) { - result.set(array, length); - length += array.length; - } - return result; + concatenate(arrays) { + if (!arrays.length) return null; + let totalLength = arrays.reduce((acc, value) => acc + value.length, 0); + let result = new Uint8Array(totalLength); + let length = 0; + for (let array of arrays) { + result.set(array, length); + length += array.length; } + return result; + } - async getContentLength(url) { - const response = await ky.head(url) - const contentLength = response.headers.get("content-length"); - return parseInt(contentLength, 10); - } + async getContentLength(url) { + const response = await ky.head(url); + const contentLength = response.headers.get("content-length"); + return parseInt(contentLength, 10); + } - async fetch({url, chunkSize}, onProgress) { + async fetch({ url, chunkSize }, onProgress) { + try { + const contentLength = await this.getContentLength(url); + const totalChunks = Math.ceil(contentLength / chunkSize); + const buffers = []; + + for (let i = 0; i < totalChunks; i++) { + const start = i * chunkSize; + const end = Math.min(start + chunkSize - 1, contentLength - 1); try { - const contentLength = await this.getContentLength(url); - const totalChunks = Math.ceil(contentLength / chunkSize); - const buffers = []; - - for (let i = 0; i < totalChunks; i++) { - const start = i * chunkSize; - const end = Math.min(start + chunkSize - 1, contentLength - 1); - try { - const response = await ky.get(url, { - headers: { - 'Range': `bytes=${start}-${end}` - } - }); - if (!response.ok) { - throw new Error(`Cannot download chunk (1) ${i + 1}: ${response.status} ${response.statusText}`); - } - - const chunk = await response.arrayBuffer(); - buffers.push(chunk); - onProgress(start + chunk.byteLength, contentLength); - - } catch (chunkError) { - throw new Error(`Cannot download chunk (2) ${i + 1} ${chunkError.message || chunkError}`); - } - } - return buffers; - - } catch (error) { - throw new Error(`Download fails ${error.message || error}`); + const response = await ky.get(url, { + headers: { + Range: `bytes=${start}-${end}`, + }, + }); + if (!response.ok) { + throw new Error( + `Cannot download chunk (1) ${i + 1}: ${response.status} ${response.statusText}`, + ); + } + + const chunk = await response.arrayBuffer(); + buffers.push(chunk); + onProgress(start + chunk.byteLength, contentLength); + } catch (chunkError) { + throw new Error( + `Cannot download chunk (2) ${i + 1} ${chunkError.message || chunkError}`, + ); } + } + return buffers; + } catch (error) { + throw new Error(`Download fails ${error.message || error}`); } - - + } } diff --git a/app/src/controller/utils/step.class.js b/app/src/controller/utils/step.class.js index f023094529b9cd29c0091df00a23c594a37ec220..f5dfdb3ed856b656c3a11951a6c6f512b18959f0 100644 --- a/app/src/controller/utils/step.class.js +++ b/app/src/controller/utils/step.class.js @@ -1,21 +1,20 @@ -import {Command} from "../device/command.class.js"; - -export class Step { - constructor(name, command, needUserGesture,mode) { - this.name = name; - this.id = new Date().getTime() + Math.round((Math.random() * 1000)); - this.needUserGesture = needUserGesture; - this.commands = []; - if(command) { - if(Array.isArray(command)){ - this.commands = command.map(m => { - return new Command(m) - }); - } else { - this.commands = [new Command(command)]; - } - } - this.mode = mode; - } - -} \ No newline at end of file +import { Command } from "../device/command.class.js"; + +export class Step { + constructor(name, command, needUserGesture, mode) { + this.name = name; + this.id = new Date().getTime() + Math.round(Math.random() * 1000); + this.needUserGesture = needUserGesture; + this.commands = []; + if (command) { + if (Array.isArray(command)) { + this.commands = command.map((m) => { + return new Command(m); + }); + } else { + this.commands = [new Command(command)]; + } + } + this.mode = mode; + } +} diff --git a/app/src/debug.js b/app/src/debug.js index a90c247467da791d9d10a95fed411e2977a8d4e9..96d0e9d40711c3826e64890b4522e84f4a7bf7a1 100644 --- a/app/src/debug.js +++ b/app/src/debug.js @@ -1,10 +1,10 @@ export class WDebug { - constructor() {} - - static log(...args) { - console.log('[DEBUG]', ...args); - } - static error(...args) { - console.error('[ERROR]', ...args); - } - } \ No newline at end of file + constructor() {} + + static log(...args) { + console.log("[DEBUG]", ...args); + } + static error(...args) { + console.error("[ERROR]", ...args); + } +} diff --git a/app/src/errorManager.js b/app/src/errorManager.js index 162bf02293d571f3f40fb3b3816723206078cad5..d55b7baaa2607ce70f102a1944b0ad9f5b0ccbc3 100644 --- a/app/src/errorManager.js +++ b/app/src/errorManager.js @@ -1,11 +1,11 @@ /* - * Copyright 2024 - ECORP SAS + * Copyright 2024 - ECORP SAS * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -16,24 +16,22 @@ */ /* -* Class to manage errors -* The Error are NOT translated, as the may not be predicted in all the case -*/ + * Class to manage errors + * The Error are NOT translated, as the may not be predicted in all the case + */ export class ErrorManager { - constructor() { - } - - // Display a message relative to when the installer is (Step) - static displayError_state(caption, message) { - document.getElementById('error-message-state').style.display = 'block'; - console.log("-------------------DISPLAY ERROR ----------------"); - console.log(caption); - console.log(message); - console.log("-------------------------------------------------"); - const errorCaption = document.getElementById('error-caption-state'); - const errorText = document.getElementById('error-text-state'); - errorCaption.innerHTML = caption; - errorText.innerHTML = message; - } + constructor() {} -} \ No newline at end of file + // Display a message relative to when the installer is (Step) + static displayError_state(caption, message) { + document.getElementById("error-message-state").style.display = "block"; + console.log("-------------------DISPLAY ERROR ----------------"); + console.log(caption); + console.log(message); + console.log("-------------------------------------------------"); + const errorCaption = document.getElementById("error-caption-state"); + const errorText = document.getElementById("error-text-state"); + errorCaption.innerHTML = caption; + errorText.innerHTML = message; + } +} diff --git a/app/src/viewManager.js b/app/src/viewManager.js index f9ed2141ab8cee899f6a210e0868afea1f86d624..f6f7e02beda3d4efd55bbc884716b17d0939f067 100644 --- a/app/src/viewManager.js +++ b/app/src/viewManager.js @@ -1,209 +1,221 @@ -import {WDebug} from './debug.js' -import {ErrorManager} from './errorManager.js' -import {Controller} from './controller.manager.js'; -import {TranslationManager} from './vue/translation.manager.js'; - -/* -* Class to manage events -* from the buttons events to the event of the controller and fastboot -* it's just log for now, but maybe it will be more usefull for dynamic display -*/ - -export default class ViewManager { - - constructor() { - - } - - async init() { - this.WDebug = WDebug; - this.ErrorManager = ErrorManager; - this.controller = new Controller(); - await this.controller.init(this); - this.translationManager = new TranslationManager(); - await this.translationManager.init(); - window.scroll(0,0); - } - - selectStep(currentIndex, step) { - const $stepIndex = document.getElementById('current-step'); - $stepIndex.innerText = currentIndex+1; - - const $step = document.getElementById(step.name); - if ($step) { - const $copyStep = $step.cloneNode(true); - $copyStep.id = step.id; - $copyStep.classList.add('active'); - $copyStep.classList.remove('inactive'); - $copyStep.addEventListener('click', async () => { - this.executeStep($copyStep, step.name); - }); - let $processCtn = document.getElementById('process-ctn'); - if($processCtn){ - $processCtn.appendChild($copyStep); - setTimeout(() => { - $copyStep.scrollIntoView({ behavior: "smooth", block: "start"}); - }, 100); - } - } - } - - updateTotalStep(total){ - const $total = document.getElementById('total-step'); - $total.innerText = total; - } - // BUTTON EVENTS - - async onNext($button) { - $button.disabled = true; - try { - await this.controller.next(); - } catch (e) { - this.ErrorManager.displayError_state('Error on next', `${e.message || e}`); - $button.disabled = false; - } finally { - } - } - async executeStep($button, stepName) { - $button.disabled = true; - let loader = $button.querySelector('.btn-loader'); - if(loader) { - loader.style.display = 'inline-block'; - } - - try { - await this.controller.executeStep(stepName, loader); - } catch (e) { - this.ErrorManager.displayError_state(`Error on step: ${stepName}`, `${e.message || e}`); - $button.disabled = false; - } finally { - if(loader) { - loader.style.display = 'none'; - } - } - - } - onStepStarted(currentIndex, currentStep) { - this.selectStep(currentIndex, currentStep); - } - - onStepFinished(currentStep, nextStep) { - if (currentStep) { - const $currentStep = document.getElementById(currentStep.id); - if($currentStep){ - const $button = $currentStep.getElementsByClassName('next'); - const $check = document.createElement('IMG'); - $check.src = "assets/images/icons/check.svg"; - if($button[0]){ - $button[0].replaceWith($check); - } - - $currentStep.classList.add('done'); - $currentStep.classList.remove('active'); - } - } - if (nextStep) { - /*const $next = document.getElementById(nextStep.id); - $next.disabled = !nextStep.needUser;*/ - } - } - onStepFailed(step){ - - } - - // /BUTTON EVENTS - - /* - * STEP 1 : Connect - */ - onADBConnect() { - this.WDebug.log(`Device connected !`); - } - - async onWaiting() { - this.WDebug.log(`.`); - } - - onDownloading(name, loaded, total) { - const v = Math.round(loaded / total * 100) ; - let $progressBar = document.querySelector(`.active .downloading-progress-bar`); - let $progress = document.querySelector(`.active .downloading-progress`); - if ($progressBar) { - $progressBar.value = v; - } - if ($progress) { - $progress.innerText = `Downloading ${name}: ${v}/${100}`; - } - this.WDebug.log(`Downloading ${name}: ${v}/${100}`, `downloading-${name}`); - } - - onUnzip(name, loaded, total) { - const v = Math.round(loaded / total * 100) ; - let $progressBar = document.querySelector(`.active .downloading-progress-bar`); - let $progress = document.querySelector(`.active .downloading-progress`); - if ($progressBar) { - $progressBar.value = v; - } - if ($progress) { - $progress.innerText = `Extracting ${name}: ${v}/${100}`; - } - this.WDebug.log(`Unzipping ${name}: ${v}/${100}`, `Unzipping-${name}`); - } - onDownloadingEnd() { - let $progressBar = document.querySelector(`.active .downloading-progress-bar`); - if ($progressBar) { - $progressBar.classList.add('success'); - } - let $progress = document.querySelector(`.active .downloading-progress`); - if ($progress) { - $progress.innerText = `Download is complete!`; - } - let $ready = document.querySelector(`.active .ready-to-install-e-os `); - if ($ready) { - $ready.style.display = `block`; - } - } - - async onInstalling(name, loaded, total) { - const v = Math.round(loaded / total * 100) ; - let $progressBar = document.querySelector(`.active .installing-progress-bar`); - let $progress = document.querySelector(`.active .installing-progress`); - if ($progressBar) { - $progressBar.value = v; - } - if ($progress) { - $progress.innerText = `Installing ${name}: ${v}/${100}`; - } - this.WDebug.log(`Installing ${name}: ${Math.round(v * 100)}/${100}`, `installing-${name}`); - } - updateData(key, value){ - let $subscribers = document.querySelectorAll(`[data-subscribe="${key}"]`); - this.WDebug.log($subscribers); - this.WDebug.log({ - [key] : value - }); - for(let i = 0 ; i< $subscribers.length; i++) { - this.translationManager.translateElement($subscribers[i], { - [key] : value - }) - } - } - - // /CONTROLLER EVENTS -} - -document.addEventListener('DOMContentLoaded', async () => { - var VIEW = new ViewManager(); - await VIEW.init(); - - let elts = document.querySelectorAll(".card button") - for(let elt of elts) { - if (elt.parentElement.parentElement.className.includes("inactive")) { - continue; - } - elt.addEventListener('click', async () => { - VIEW.executeStep(elt, elt.parentElement.parentElement.id); - }) - } - -}); +import { WDebug } from "./debug.js"; +import { ErrorManager } from "./errorManager.js"; +import { Controller } from "./controller.manager.js"; +import { TranslationManager } from "./vue/translation.manager.js"; + +/* + * Class to manage events + * from the buttons events to the event of the controller and fastboot + * it's just log for now, but maybe it will be more useful for dynamic display + */ + +export default class ViewManager { + constructor() {} + + async init() { + this.WDebug = WDebug; + this.ErrorManager = ErrorManager; + this.controller = new Controller(); + await this.controller.init(this); + this.translationManager = new TranslationManager(); + await this.translationManager.init(); + window.scroll(0, 0); + } + + selectStep(currentIndex, step) { + const $stepIndex = document.getElementById("current-step"); + $stepIndex.innerText = currentIndex + 1; + + const $step = document.getElementById(step.name); + if ($step) { + const $copyStep = $step.cloneNode(true); + $copyStep.id = step.id; + $copyStep.classList.add("active"); + $copyStep.classList.remove("inactive"); + $copyStep.addEventListener("click", async () => { + this.executeStep($copyStep, step.name); + }); + let $processCtn = document.getElementById("process-ctn"); + if ($processCtn) { + $processCtn.appendChild($copyStep); + setTimeout(() => { + $copyStep.scrollIntoView({ + behavior: "smooth", + block: "start", + }); + }, 100); + } + } + } + + updateTotalStep(total) { + const $total = document.getElementById("total-step"); + $total.innerText = total; + } + // BUTTON EVENTS + + async onNext($button) { + $button.disabled = true; + try { + await this.controller.next(); + } catch (e) { + this.ErrorManager.displayError_state( + "Error on next", + `${e.message || e}`, + ); + $button.disabled = false; + } + } + async executeStep($button, stepName) { + $button.disabled = true; + let loader = $button.querySelector(".btn-loader"); + if (loader) { + loader.style.display = "inline-block"; + } + + try { + await this.controller.executeStep(stepName, loader); + } catch (e) { + this.ErrorManager.displayError_state( + `Error on step: ${stepName}`, + `${e.message || e}`, + ); + $button.disabled = false; + } finally { + if (loader) { + loader.style.display = "none"; + } + } + } + onStepStarted(currentIndex, currentStep) { + this.selectStep(currentIndex, currentStep); + } + + onStepFinished(currentStep, nextStep) { + if (currentStep) { + const $currentStep = document.getElementById(currentStep.id); + if ($currentStep) { + const $button = $currentStep.getElementsByClassName("next"); + const $check = document.createElement("IMG"); + $check.src = "assets/images/icons/check.svg"; + if ($button[0]) { + $button[0].replaceWith($check); + } + + $currentStep.classList.add("done"); + $currentStep.classList.remove("active"); + } + } + if (nextStep) { + /*const $next = document.getElementById(nextStep.id); + $next.disabled = !nextStep.needUser;*/ + } + } + onStepFailed() {} + + // /BUTTON EVENTS + + /* + * STEP 1 : Connect + */ + onADBConnect() { + this.WDebug.log(`Device connected !`); + } + + async onWaiting() { + this.WDebug.log(`.`); + } + + onDownloading(name, loaded, total) { + const v = Math.round((loaded / total) * 100); + let $progressBar = document.querySelector( + `.active .downloading-progress-bar`, + ); + let $progress = document.querySelector(`.active .downloading-progress`); + if ($progressBar) { + $progressBar.value = v; + } + if ($progress) { + $progress.innerText = `Downloading ${name}: ${v}/${100}`; + } + this.WDebug.log(`Downloading ${name}: ${v}/${100}`, `downloading-${name}`); + } + + onUnzip(name, loaded, total) { + const v = Math.round((loaded / total) * 100); + let $progressBar = document.querySelector( + `.active .downloading-progress-bar`, + ); + let $progress = document.querySelector(`.active .downloading-progress`); + if ($progressBar) { + $progressBar.value = v; + } + if ($progress) { + $progress.innerText = `Extracting ${name}: ${v}/${100}`; + } + this.WDebug.log(`Unzipping ${name}: ${v}/${100}`, `Unzipping-${name}`); + } + onDownloadingEnd() { + let $progressBar = document.querySelector( + `.active .downloading-progress-bar`, + ); + if ($progressBar) { + $progressBar.classList.add("success"); + } + let $progress = document.querySelector(`.active .downloading-progress`); + if ($progress) { + $progress.innerText = `Download is complete!`; + } + let $ready = document.querySelector(`.active .ready-to-install-e-os `); + if ($ready) { + $ready.style.display = `block`; + } + } + + async onInstalling(name, loaded, total) { + const v = Math.round((loaded / total) * 100); + let $progressBar = document.querySelector( + `.active .installing-progress-bar`, + ); + let $progress = document.querySelector(`.active .installing-progress`); + if ($progressBar) { + $progressBar.value = v; + } + if ($progress) { + $progress.innerText = `Installing ${name}: ${v}/${100}`; + } + this.WDebug.log( + `Installing ${name}: ${Math.round(v * 100)}/${100}`, + `installing-${name}`, + ); + } + updateData(key, value) { + let $subscribers = document.querySelectorAll(`[data-subscribe="${key}"]`); + this.WDebug.log($subscribers); + this.WDebug.log({ + [key]: value, + }); + for (let i = 0; i < $subscribers.length; i++) { + this.translationManager.translateElement($subscribers[i], { + [key]: value, + }); + } + } + + // /CONTROLLER EVENTS +} + +document.addEventListener("DOMContentLoaded", async () => { + var VIEW = new ViewManager(); + await VIEW.init(); + + let elts = document.querySelectorAll(".card button"); + for (let elt of elts) { + if (elt.parentElement.parentElement.className.includes("inactive")) { + continue; + } + elt.addEventListener("click", async () => { + VIEW.executeStep(elt, elt.parentElement.parentElement.id); + }); + } +}); diff --git a/app/src/vue/translation.manager.js b/app/src/vue/translation.manager.js index d6de409d5df5f89a6f9b02801f2ea63bb9ad77fe..46afc00681d4d44c7bc16e8e9d4fdc4c5f2931c7 100644 --- a/app/src/vue/translation.manager.js +++ b/app/src/vue/translation.manager.js @@ -1,141 +1,141 @@ -/* -* Class to manage translation -* fetch translation file & use the correct language for the user -* also change single Node text if needed -* [data-translate] is used to find Nodes needing translation -*/ -import {WDebug} from "../debug.js"; - -export class TranslationManager { - static DEFAULT = 'en'; //if user languages not found, fallback to 'en' - constructor() { - this.translation = {}; - this.values = {}; - this.languages = TranslationManager.getAcceptedLanguages(); - this.languageIndex = 0; - } - - async init() { - await this.loadCurrentTranslation(); // fetch translation - await this.translateDOM();// use it for DOM - } - /** - * @returns string - * using the current languageIndex, we retrieve the string language - * ex 'fr-FR' - */ - getCurrentLanguage() { - return this.languages[this.languageIndex]; - } - async loadCurrentTranslation() { - const language = this.getCurrentLanguage(); - const shortLanguage = TranslationManager.getShortLanguage(language); - try { - this.translation = await TranslationManager.fetchTranslation(shortLanguage); - } catch(e) { - //if language not found, fallback to next language - if(this.languageIndex < this.languages.length) { - this.languageIndex++; - await this.loadCurrentTranslation(); - } else { - //as the last language is the default app one, this should never happen... Right ? - this.translation = {}; - } - } - } - /** - * select DOM elements using data-translate key - * translate each DOM element elected - */ - translateDOM() { - const elems = document.querySelectorAll('[data-translate]'); - for (let i = 0; i < elems.length; i++) { - this.translateElement(elems[i]); - } - } - - - /** - * get the translation using data-translate value - * replace DOM HTML with the translation - */ - translateElement($el, values) { - if($el.dataset.translate) { - $el.innerHTML = this.translate($el.dataset.translate, values); - } - } - /** - * @param key : string - * @param values : object? - * @returns string - * using key to retrieve the wanted string in the translations - * if values is a defined object, we use it to set value in the translation - * ex: if values = { "hello" : "Hallo" } and translation = "{{hello}} Welt !" - * returned text is "Hallo Welt !" - */ - translate(key, values) { - let text = this.translation[key]; - if (!text) { - console.warn(`translation of ${key} not found`) - text = key; - } - //I have to choose tags, so I'm using Mustache tags - //I'm not adding the lib since it's not necessary - //But if one day it is, the translation does not have to change :> - if (typeof values === 'object') { - Object.keys(values).forEach(k => { - text = text.replaceAll(`{{${k}}}`, values[k]); - }); - } - return text; - } - - /** - * @param language : string - * @returns string - * return the short version of a language - * ex: 'en-US' return 'en' - */ - static getShortLanguage(language) { - let shortLang = language; - if (shortLang.indexOf('-') !== -1){ - shortLang = shortLang.split('-')[0]; - } - if (shortLang.indexOf('_') !== -1){ - shortLang = shortLang.split('_')[0]; - } - return shortLang; - } - - /** - * @param language : string - * @returns JSON - * fetch translation file and return its JSON content - * throw error in case of file not found or invalid JSON content - */ - static async fetchTranslation(language) { - const response = await fetch(`assets/languages/${language}.json`); - if(response.ok) { - try { - return await response.json(); - } catch (e) { - WDebug.error("translation file is not a valid JSON: ", language); - throw Error(`${language} translation file is not a valid JSON`); - } - } else { //Most likely a 404 - throw Error(`${language} not found`); - } - } - /** - * @returns string[] - * get user's preferred languages - * and add default translation app as the last one in case none of user's preferred languages are usable - * ex ['ay', 'fr-FR', 'en-US', 'en'] - */ - static getAcceptedLanguages() { - let languages = [...window.navigator.languages]; //use copy as window.navigator.languages is not editable - languages.push(TranslationManager.DEFAULT); //add default language app as the last resort - return languages; - } - -} \ No newline at end of file +/* + * Class to manage translation + * fetch translation file & use the correct language for the user + * also change single Node text if needed + * [data-translate] is used to find Nodes needing translation + */ +import { WDebug } from "../debug.js"; + +export class TranslationManager { + static DEFAULT = "en"; //if user languages not found, fallback to 'en' + constructor() { + this.translation = {}; + this.values = {}; + this.languages = TranslationManager.getAcceptedLanguages(); + this.languageIndex = 0; + } + + async init() { + await this.loadCurrentTranslation(); // fetch translation + await this.translateDOM(); // use it for DOM + } + /** + * @returns string + * using the current languageIndex, we retrieve the string language + * ex 'fr-FR' + */ + getCurrentLanguage() { + return this.languages[this.languageIndex]; + } + async loadCurrentTranslation() { + const language = this.getCurrentLanguage(); + const shortLanguage = TranslationManager.getShortLanguage(language); + try { + this.translation = + await TranslationManager.fetchTranslation(shortLanguage); + } catch { + //if language not found, fallback to next language + if (this.languageIndex < this.languages.length) { + this.languageIndex++; + await this.loadCurrentTranslation(); + } else { + //as the last language is the default app one, this should never happen... Right ? + this.translation = {}; + } + } + } + /** + * select DOM elements using data-translate key + * translate each DOM element elected + */ + translateDOM() { + const elems = document.querySelectorAll("[data-translate]"); + for (let i = 0; i < elems.length; i++) { + this.translateElement(elems[i]); + } + } + + /** + * get the translation using data-translate value + * replace DOM HTML with the translation + */ + translateElement($el, values) { + if ($el.dataset.translate) { + $el.innerHTML = this.translate($el.dataset.translate, values); + } + } + /** + * @param key : string + * @param values : object? + * @returns string + * using key to retrieve the wanted string in the translations + * if values is a defined object, we use it to set value in the translation + * ex: if values = { "hello" : "Hallo" } and translation = "{{hello}} Welt !" + * returned text is "Hallo Welt !" + */ + translate(key, values) { + let text = this.translation[key]; + if (!text) { + console.warn(`translation of ${key} not found`); + text = key; + } + //I have to choose tags, so I'm using Mustache tags + //I'm not adding the lib since it's not necessary + //But if one day it is, the translation does not have to change :> + if (typeof values === "object") { + Object.keys(values).forEach((k) => { + text = text.replaceAll(`{{${k}}}`, values[k]); + }); + } + return text; + } + + /** + * @param language : string + * @returns string + * return the short version of a language + * ex: 'en-US' return 'en' + */ + static getShortLanguage(language) { + let shortLang = language; + if (shortLang.indexOf("-") !== -1) { + shortLang = shortLang.split("-")[0]; + } + if (shortLang.indexOf("_") !== -1) { + shortLang = shortLang.split("_")[0]; + } + return shortLang; + } + + /** + * @param language : string + * @returns JSON + * fetch translation file and return its JSON content + * throw error in case of file not found or invalid JSON content + */ + static async fetchTranslation(language) { + const response = await fetch(`assets/languages/${language}.json`); + if (response.ok) { + try { + return await response.json(); + } catch { + WDebug.error("translation file is not a valid JSON: ", language); + throw Error(`${language} translation file is not a valid JSON`); + } + } else { + //Most likely a 404 + throw Error(`${language} not found`); + } + } + /** + * @returns string[] + * get user's preferred languages + * and add default translation app as the last one in case none of user's preferred languages are usable + * ex ['ay', 'fr-FR', 'en-US', 'en'] + */ + static getAcceptedLanguages() { + let languages = [...window.navigator.languages]; //use copy as window.navigator.languages is not editable + languages.push(TranslationManager.DEFAULT); //add default language app as the last resort + return languages; + } +} diff --git a/app/vite.config.js b/app/vite.config.js index c5d471f453b92dea5499b0a7abf9984fdbfbc456..16ef1eca2b4fff59ccabfa1c7372cbb52c18d7fc 100644 --- a/app/vite.config.js +++ b/app/vite.config.js @@ -1,5 +1,5 @@ -import { defineConfig } from 'vite' +import { defineConfig } from "vite"; export default defineConfig({ - base: '', -}) + base: "", +});