diff --git a/.eslintrc.js b/.eslintrc.js index 069a67e511..fc82e75ce2 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,15 +1,3 @@ -const path = require('path'); - -// get the path of the js-sdk so we can extend the config -// eslint supports loading extended configs by module, -// but only if they come from a module that starts with eslint-config- -// So we load the filename directly (and it could be in node_modules/ -// or or ../node_modules/ etc) -// -// We add a `..` to the end because the js-sdk lives out of lib/, but the eslint -// config is at the project root. -const matrixJsSdkPath = path.join(path.dirname(require.resolve('matrix-js-sdk')), '..'); - module.exports = { extends: ["matrix-org", "matrix-org/react-legacy"], parser: "babel-eslint", @@ -31,7 +19,7 @@ module.exports = { }, overrides: [{ - files: ["src/**/*.{ts, tsx}"], + "files": ["src/**/*.{ts, tsx}"], "extends": ["matrix-org/ts"], "rules": { // We disable this while we're transitioning @@ -41,6 +29,6 @@ module.exports = { "quotes": "off", "no-extra-boolean-cast": "off", - } + }, }], }; diff --git a/CHANGELOG.md b/CHANGELOG.md index e08b2ad612..d944d58f36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,125 @@ +Changes in [3.0.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.0.0) (2020-07-27) +=================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v2.10.1...v3.0.0) + +BREAKING CHANGES +--- + + * The room list components have been replaced as part of this release, so the list, tiles, and other associated components now use a different prop / state contract. + + +All Changes +--- + + * Upgrade to JS SDK 8.0.0 + * Update from Weblate + [\#5053](https://github.com/matrix-org/matrix-react-sdk/pull/5053) + * RoomList listen to notificationState updates for bolding + [\#5051](https://github.com/matrix-org/matrix-react-sdk/pull/5051) + * Ensure notification badges stop listening when they unmount + [\#5049](https://github.com/matrix-org/matrix-react-sdk/pull/5049) + * Improve RoomTile performance + [\#5048](https://github.com/matrix-org/matrix-react-sdk/pull/5048) + * Reward users for using stable ordering in their room list + [\#5047](https://github.com/matrix-org/matrix-react-sdk/pull/5047) + * Fix autocomplete suggesting a different thing mid-composition + [\#5030](https://github.com/matrix-org/matrix-react-sdk/pull/5030) + * Put low priority xor toggle back in the room list context menu + [\#5026](https://github.com/matrix-org/matrix-react-sdk/pull/5026) + * Fix autocompletion of Community IDs + [\#5040](https://github.com/matrix-org/matrix-react-sdk/pull/5040) + * Use OpenType tabular numbers in timestamps + [\#5042](https://github.com/matrix-org/matrix-react-sdk/pull/5042) + * Update packages to modern versions + [\#5046](https://github.com/matrix-org/matrix-react-sdk/pull/5046) + * Add dismiss button to rebrand toast + [\#5044](https://github.com/matrix-org/matrix-react-sdk/pull/5044) + * Fix Firefox composer regression exception + [\#5039](https://github.com/matrix-org/matrix-react-sdk/pull/5039) + * Fix BaseAvatar wrongly using Buttons when it needs not + [\#5037](https://github.com/matrix-org/matrix-react-sdk/pull/5037) + * Performance improvements round 2: Maps, freezing, dispatching, and flexbox + obliteration + [\#5038](https://github.com/matrix-org/matrix-react-sdk/pull/5038) + * Mixed bag of performance improvements: ScrollPanel and notifications + [\#5034](https://github.com/matrix-org/matrix-react-sdk/pull/5034) + * Update message previews + [\#5025](https://github.com/matrix-org/matrix-react-sdk/pull/5025) + * Translate create room buttons + [\#5035](https://github.com/matrix-org/matrix-react-sdk/pull/5035) + * Escape single quotes in composer placeholder + [\#5033](https://github.com/matrix-org/matrix-react-sdk/pull/5033) + * Don't hammer on the layout engine with avatar updates for the background + [\#5032](https://github.com/matrix-org/matrix-react-sdk/pull/5032) + * Ensure incremental updates to the ImportanceAlgorithm trigger A-Z order + [\#5031](https://github.com/matrix-org/matrix-react-sdk/pull/5031) + * don't syntax highlight languages that begin with "_" + [\#5029](https://github.com/matrix-org/matrix-react-sdk/pull/5029) + * Convert Modal to TypeScript + [\#4956](https://github.com/matrix-org/matrix-react-sdk/pull/4956) + * Use new eslint dependency and remove tslint + [\#4815](https://github.com/matrix-org/matrix-react-sdk/pull/4815) + * Support custom tags in the room list again + [\#5024](https://github.com/matrix-org/matrix-react-sdk/pull/5024) + * Fix the tag panel context menu + [\#5028](https://github.com/matrix-org/matrix-react-sdk/pull/5028) + * Tag Watcher don't create new filter if not needed, confuses references + [\#5021](https://github.com/matrix-org/matrix-react-sdk/pull/5021) + * Convert editor to TypeScript + [\#4978](https://github.com/matrix-org/matrix-react-sdk/pull/4978) + * Query Matcher use unhomoglyph for a little bit more leniency + [\#4977](https://github.com/matrix-org/matrix-react-sdk/pull/4977) + * Fix Breadcrumbs2 ending up with 2 tabIndexes on Firefox + [\#5017](https://github.com/matrix-org/matrix-react-sdk/pull/5017) + * Add min-width to floating Jitsi + [\#5023](https://github.com/matrix-org/matrix-react-sdk/pull/5023) + * Update crypto event icon to match rest of app styling + [\#5020](https://github.com/matrix-org/matrix-react-sdk/pull/5020) + * Fix Reactions Row Button vertical misalignment due to forced height + [\#5019](https://github.com/matrix-org/matrix-react-sdk/pull/5019) + * Use mouseleave instead of mouseout for hover events. Fix tooltip flicker + [\#5016](https://github.com/matrix-org/matrix-react-sdk/pull/5016) + * Fix slash commands null guard + [\#5015](https://github.com/matrix-org/matrix-react-sdk/pull/5015) + * Fix field tooltips + [\#5014](https://github.com/matrix-org/matrix-react-sdk/pull/5014) + * Fix community right panel button regression + [\#5022](https://github.com/matrix-org/matrix-react-sdk/pull/5022) + * [BREAKING] Remove the old room list + [\#5013](https://github.com/matrix-org/matrix-react-sdk/pull/5013) + * ellipse senders for images and videos + [\#4990](https://github.com/matrix-org/matrix-react-sdk/pull/4990) + * Sprinkle and consolidate some tooltips + [\#5012](https://github.com/matrix-org/matrix-react-sdk/pull/5012) + * Hopefully make cancel dialog a bit less weird + [\#4833](https://github.com/matrix-org/matrix-react-sdk/pull/4833) + * Fix emoji filterString + [\#5011](https://github.com/matrix-org/matrix-react-sdk/pull/5011) + * Fix size call for devtools state events + [\#5008](https://github.com/matrix-org/matrix-react-sdk/pull/5008) + * Fix `this` context in _setupHomeserverManagers for IntegrationManagers + [\#5010](https://github.com/matrix-org/matrix-react-sdk/pull/5010) + * Sync recently used reactions list across sessions + [\#4993](https://github.com/matrix-org/matrix-react-sdk/pull/4993) + * Null guard no e2ee for UserInfo + [\#5009](https://github.com/matrix-org/matrix-react-sdk/pull/5009) + * stop Inter from clobbering Twemoji + [\#5007](https://github.com/matrix-org/matrix-react-sdk/pull/5007) + * use a proper HTML sanitizer to strip , rather than a regexp + [\#5006](https://github.com/matrix-org/matrix-react-sdk/pull/5006) + * Convert room list log setting to a real setting + [\#5005](https://github.com/matrix-org/matrix-react-sdk/pull/5005) + * Bump lodash from 4.17.15 to 4.17.19 in /test/end-to-end-tests + [\#5003](https://github.com/matrix-org/matrix-react-sdk/pull/5003) + * Bump lodash from 4.17.15 to 4.17.19 + [\#5004](https://github.com/matrix-org/matrix-react-sdk/pull/5004) + * Convert devtools dialog to use new room state format + [\#4936](https://github.com/matrix-org/matrix-react-sdk/pull/4936) + * Update checkbox + [\#5000](https://github.com/matrix-org/matrix-react-sdk/pull/5000) + * Increase width for country code dropdown + [\#5001](https://github.com/matrix-org/matrix-react-sdk/pull/5001) + Changes in [2.10.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v2.10.1) (2020-07-16) ===================================================================================================== [Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v2.10.0...v2.10.1) diff --git a/docs/local-echo-dev.md b/docs/local-echo-dev.md new file mode 100644 index 0000000000..e4725a9b07 --- /dev/null +++ b/docs/local-echo-dev.md @@ -0,0 +1,39 @@ +# Local echo (developer docs) + +The React SDK provides some local echo functionality to allow for components to do something +quickly and fall back when it fails. This is all available in the `local-echo` directory within +`stores`. + +Echo is handled in EchoChambers, with `GenericEchoChamber` being the base implementation for all +chambers. The `EchoChamber` class is provided as semantic access to a `GenericEchoChamber` +implementation, such as the `RoomEchoChamber` (which handles echoable details of a room). + +Anything that can be locally echoed will be provided by the `GenericEchoChamber` implementation. +The echo chamber will also need to deal with external changes, and has full control over whether +or not something has successfully been echoed. + +An `EchoContext` is provided to echo chambers (usually with a matching type: `RoomEchoContext` +gets provided to a `RoomEchoChamber` for example) with details about their intended area of +effect, as well as manage `EchoTransaction`s. An `EchoTransaction` is simply a unit of work that +needs to be locally echoed. + +The `EchoStore` manages echo chamber instances, builds contexts, and is generally less semantically +accessible than the `EchoChamber` class. For separation of concerns, and to try and keep things +tidy, this is an intentional design decision. + +**Note**: The local echo stack uses a "whenable" pattern, which is similar to thenables and +`EventEmitter`. Whenables are ways of actioning a changing condition without having to deal +with listeners being torn down. Once the reference count of the Whenable causes garbage collection, +the Whenable's listeners will also be torn down. This is accelerated by the `IDestroyable` interface +usage. + +## Audit functionality + +The UI supports a "Server isn't responding" dialog which includes a partial audit log-like +structure to it. This is partially the reason for added complexity of `EchoTransaction`s +and `EchoContext`s - this information feeds the UI states which then provide direct retry +mechanisms. + +The `EchoStore` is responsible for ensuring that the appropriate non-urgent toast (lower left) +is set up, where the dialog then drives through the contexts and transactions. + diff --git a/package.json b/package.json index 997e46257d..61a9a21815 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "2.10.1", + "version": "3.0.0", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { @@ -53,119 +53,117 @@ "test:e2e": "./test/end-to-end-tests/run.sh --riot-url http://localhost:8080" }, "dependencies": { - "@babel/runtime": "^7.8.3", + "@babel/runtime": "^7.10.5", "await-lock": "^2.0.1", - "blueimp-canvas-to-blob": "^3.5.0", + "blueimp-canvas-to-blob": "^3.27.0", "browser-encrypt-attachment": "^0.3.0", "browser-request": "^0.3.3", - "classnames": "^2.1.2", - "commonmark": "^0.28.1", - "counterpart": "^0.18.0", - "create-react-class": "^15.6.0", - "diff-dom": "^4.1.3", - "diff-match-patch": "^1.0.4", + "classnames": "^2.2.6", + "commonmark": "^0.29.1", + "counterpart": "^0.18.6", + "create-react-class": "^15.6.3", + "diff-dom": "^4.1.6", + "diff-match-patch": "^1.0.5", "emojibase-data": "^5.0.1", "emojibase-regex": "^4.0.1", "escape-html": "^1.0.3", - "file-saver": "^1.3.3", - "filesize": "3.5.6", + "file-saver": "^1.3.8", + "filesize": "3.6.1", "flux": "2.1.1", - "focus-visible": "^5.0.2", - "fuse.js": "^2.2.0", - "gfm.css": "^1.1.1", + "focus-visible": "^5.1.0", + "fuse.js": "^2.7.4", + "gfm.css": "^1.1.2", "glob-to-regexp": "^0.4.1", - "highlight.js": "^9.15.8", - "html-entities": "^1.2.1", + "highlight.js": "^10.1.2", + "html-entities": "^1.3.1", "is-ip": "^2.0.0", - "linkifyjs": "^2.1.6", - "lodash": "^4.17.14", + "linkifyjs": "^2.1.9", + "lodash": "^4.17.19", "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop", - "minimist": "^1.2.0", - "pako": "^1.0.5", + "minimist": "^1.2.5", + "pako": "^1.0.11", "parse5": "^5.1.1", "png-chunks-extract": "^1.0.0", "project-name-generator": "^2.1.7", - "prop-types": "^15.5.8", + "prop-types": "^15.7.2", "qrcode": "^1.4.4", - "qs": "^6.6.0", - "re-resizable": "^6.5.2", - "react": "^16.9.0", + "qs": "^6.9.4", + "re-resizable": "^6.5.4", + "react": "^16.13.1", "react-beautiful-dnd": "^4.0.1", - "react-dom": "^16.9.0", - "react-focus-lock": "^2.2.1", + "react-dom": "^16.13.1", + "react-focus-lock": "^2.4.1", "react-transition-group": "^4.4.1", - "resize-observer-polyfill": "^1.5.0", - "sanitize-html": "^1.18.4", - "text-encoding-utf-8": "^1.0.1", + "resize-observer-polyfill": "^1.5.1", + "sanitize-html": "^1.27.1", + "text-encoding-utf-8": "^1.0.2", "url": "^0.11.0", "velocity-animate": "^1.5.2", - "what-input": "^5.2.6", + "what-input": "^5.2.10", "zxcvbn": "^4.4.2" }, "devDependencies": { - "@babel/cli": "^7.7.5", - "@babel/core": "^7.7.5", - "@babel/plugin-proposal-class-properties": "^7.7.4", - "@babel/plugin-proposal-decorators": "^7.7.4", - "@babel/plugin-proposal-export-default-from": "^7.7.4", - "@babel/plugin-proposal-numeric-separator": "^7.7.4", - "@babel/plugin-proposal-object-rest-spread": "^7.7.4", - "@babel/plugin-transform-flow-comments": "^7.7.4", - "@babel/plugin-transform-runtime": "^7.8.3", - "@babel/preset-env": "^7.7.6", - "@babel/preset-flow": "^7.7.4", - "@babel/preset-react": "^7.7.4", - "@babel/preset-typescript": "^7.7.4", - "@babel/register": "^7.7.4", - "@peculiar/webcrypto": "^1.0.22", + "@babel/cli": "^7.10.5", + "@babel/core": "^7.10.5", + "@babel/parser": "^7.11.0", + "@babel/plugin-proposal-class-properties": "^7.10.4", + "@babel/plugin-proposal-decorators": "^7.10.5", + "@babel/plugin-proposal-export-default-from": "^7.10.4", + "@babel/plugin-proposal-numeric-separator": "^7.10.4", + "@babel/plugin-proposal-object-rest-spread": "^7.10.4", + "@babel/plugin-transform-flow-comments": "^7.10.4", + "@babel/plugin-transform-runtime": "^7.10.5", + "@babel/preset-env": "^7.10.4", + "@babel/preset-flow": "^7.10.4", + "@babel/preset-react": "^7.10.4", + "@babel/preset-typescript": "^7.10.4", + "@babel/register": "^7.10.5", + "@babel/traverse": "^7.11.0", + "@peculiar/webcrypto": "^1.1.2", "@types/classnames": "^2.2.10", "@types/counterpart": "^0.18.1", "@types/flux": "^3.1.9", "@types/linkifyjs": "^2.1.3", - "@types/lodash": "^4.14.152", + "@types/lodash": "^4.14.158", "@types/modernizr": "^3.5.3", - "@types/node": "^12.12.41", + "@types/node": "^12.12.51", "@types/qrcode": "^1.3.4", "@types/react": "^16.9", "@types/react-dom": "^16.9.8", "@types/react-transition-group": "^4.4.0", "@types/sanitize-html": "^1.23.3", "@types/zxcvbn": "^4.4.0", - "@typescript-eslint/eslint-plugin": "^3.4.0", - "@typescript-eslint/parser": "^3.4.0", - "babel-eslint": "^10.0.3", + "@typescript-eslint/eslint-plugin": "^3.7.0", + "@typescript-eslint/parser": "^3.7.0", + "babel-eslint": "^10.1.0", "babel-jest": "^24.9.0", - "chokidar": "^3.3.1", - "concurrently": "^4.0.1", - "enzyme": "^3.10.0", - "enzyme-adapter-react-16": "^1.15.1", - "eslint": "7.3.1", - "eslint-config-google": "^0.7.1", + "chokidar": "^3.4.1", + "concurrently": "^4.1.2", + "enzyme": "^3.11.0", + "enzyme-adapter-react-16": "^1.15.2", + "eslint": "7.5.0", "eslint-config-matrix-org": "^0.1.2", - "eslint-plugin-babel": "^5.2.1", - "eslint-plugin-flowtype": "^2.30.0", - "eslint-plugin-jest": "^23.0.4", - "eslint-plugin-react": "^7.7.0", - "eslint-plugin-react-hooks": "^2.0.1", - "estree-walker": "^0.5.0", + "eslint-plugin-babel": "^5.3.1", + "eslint-plugin-flowtype": "^2.50.3", + "eslint-plugin-react": "^7.20.3", + "eslint-plugin-react-hooks": "^2.5.1", "file-loader": "^3.0.1", - "flow-parser": "^0.57.3", - "glob": "^5.0.14", + "glob": "^5.0.15", "jest": "^24.9.0", "jest-canvas-mock": "^2.2.0", "lolex": "^5.1.2", "matrix-mock-request": "^1.2.3", "matrix-react-test-utils": "^0.2.2", - "react-test-renderer": "^16.9.0", - "rimraf": "^2.4.3", - "source-map-loader": "^0.2.3", + "react-test-renderer": "^16.13.1", + "rimraf": "^2.7.1", + "source-map-loader": "^0.2.4", "stylelint": "^9.10.1", - "stylelint-config-standard": "^18.2.0", - "stylelint-scss": "^3.9.0", - "typescript": "^3.7.3", - "walk": "^2.3.9", - "webpack": "^4.20.2", - "webpack-cli": "^3.1.1" + "stylelint-config-standard": "^18.3.0", + "stylelint-scss": "^3.18.0", + "typescript": "^3.9.7", + "walk": "^2.3.14", + "webpack": "^4.43.0", + "webpack-cli": "^3.3.12" }, "jest": { "testMatch": [ diff --git a/res/css/_components.scss b/res/css/_components.scss index 23e4af780a..fcc87e2061 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -15,6 +15,7 @@ @import "./structures/_MainSplit.scss"; @import "./structures/_MatrixChat.scss"; @import "./structures/_MyGroups.scss"; +@import "./structures/_NonUrgentToastContainer.scss"; @import "./structures/_NotificationPanel.scss"; @import "./structures/_RightPanel.scss"; @import "./structures/_RoomDirectory.scss"; @@ -75,6 +76,7 @@ @import "./views/dialogs/_RoomSettingsDialogBridges.scss"; @import "./views/dialogs/_RoomUpgradeDialog.scss"; @import "./views/dialogs/_RoomUpgradeWarningDialog.scss"; +@import "./views/dialogs/_ServerOfflineDialog.scss"; @import "./views/dialogs/_SetEmailDialog.scss"; @import "./views/dialogs/_SetMxIdDialog.scss"; @import "./views/dialogs/_SetPasswordDialog.scss"; @@ -215,6 +217,7 @@ @import "./views/settings/tabs/user/_SecurityUserSettingsTab.scss"; @import "./views/settings/tabs/user/_VoiceUserSettingsTab.scss"; @import "./views/terms/_InlineTermsAgreement.scss"; +@import "./views/toasts/_NonUrgentEchoFailureToast.scss"; @import "./views/verification/_VerificationShowSas.scss"; @import "./views/voip/_CallContainer.scss"; @import "./views/voip/_CallView.scss"; diff --git a/res/css/structures/_CustomRoomTagPanel.scss b/res/css/structures/_CustomRoomTagPanel.scss index 135a51c7cd..3feb2565be 100644 --- a/res/css/structures/_CustomRoomTagPanel.scss +++ b/res/css/structures/_CustomRoomTagPanel.scss @@ -54,5 +54,5 @@ limitations under the License. position: absolute; left: -9px; border-radius: 0 3px 3px 0; - top: 12px; // just feels right (see comment above about designs needing to be updated) + top: 5px; // just feels right (see comment above about designs needing to be updated) } diff --git a/res/css/structures/_FilePanel.scss b/res/css/structures/_FilePanel.scss index 859ee28035..50b01b4a14 100644 --- a/res/css/structures/_FilePanel.scss +++ b/res/css/structures/_FilePanel.scss @@ -109,3 +109,7 @@ limitations under the License. .mx_FilePanel .mx_EventTile:hover .mx_EventTile_line { background-color: $primary-bg-color; } + +.mx_FilePanel_empty::before { + mask-image: url('$(res)/img/element-icons/room/files.svg'); +} diff --git a/res/css/structures/_LeftPanel.scss b/res/css/structures/_LeftPanel.scss index 1673092c9e..db531cf088 100644 --- a/res/css/structures/_LeftPanel.scss +++ b/res/css/structures/_LeftPanel.scss @@ -135,12 +135,7 @@ $tagPanelWidth: 56px; // only applies in this file, used for calculations } .mx_LeftPanel_roomListWrapper { - // Create a flexbox to ensure the containing items cause appropriate overflow. - display: flex; - - flex-grow: 1; overflow: hidden; - min-height: 0; margin-top: 10px; // so we're not up against the search/filter &.mx_LeftPanel_roomListWrapper_stickyBottom { @@ -153,14 +148,8 @@ $tagPanelWidth: 56px; // only applies in this file, used for calculations } .mx_LeftPanel_actualRoomListContainer { - flex-grow: 1; // fill the available space - overflow-y: auto; - width: 100%; - max-width: 100%; position: relative; // for sticky headers - - // Create a flexbox to trick the layout engine - display: flex; + height: 100%; // ensure scrolling still works } } diff --git a/res/css/structures/_MainSplit.scss b/res/css/structures/_MainSplit.scss index 25e1153fce..aee7b5a154 100644 --- a/res/css/structures/_MainSplit.scss +++ b/res/css/structures/_MainSplit.scss @@ -21,8 +21,20 @@ limitations under the License. height: 100%; } -// move hit area 5px to the right so it doesn't overlap with the timeline scrollbar -.mx_MainSplit > .mx_ResizeHandle.mx_ResizeHandle_horizontal { - margin: 0 -10px 0 0; - padding: 0 10px 0 0; +.mx_MainSplit > .mx_RightPanel_ResizeWrapper { + padding: 5px; + + &:hover .mx_RightPanel_ResizeHandle { + // Need to use important to override element style attributes + // set by re-resizable + top: 50% !important; + transform: translate(0, -50%); + + height: 64px !important; // to match width of the ones on roomlist + width: 4px !important; + border-radius: 4px !important; + + background-color: $primary-fg-color; + opacity: 0.8; + } } diff --git a/res/css/structures/_MatrixChat.scss b/res/css/structures/_MatrixChat.scss index 88b29a96e8..af6f6c79e9 100644 --- a/res/css/structures/_MatrixChat.scss +++ b/res/css/structures/_MatrixChat.scss @@ -78,3 +78,24 @@ limitations under the License. */ height: 100%; } + +.mx_MatrixChat > .mx_LeftPanel2:hover + .mx_ResizeHandle_horizontal, +.mx_MatrixChat > .mx_ResizeHandle_horizontal:hover { + position: relative; + + &::before { + position: absolute; + left: 6px; + top: 50%; + transform: translate(0, -50%); + + height: 64px; // to match width of the ones on roomlist + width: 4px; + border-radius: 4px; + + content: ' '; + + background-color: $primary-fg-color; + opacity: 0.8; + } +} diff --git a/src/stores/room-list/previews/CreationEventPreview.ts b/res/css/structures/_NonUrgentToastContainer.scss similarity index 51% rename from src/stores/room-list/previews/CreationEventPreview.ts rename to res/css/structures/_NonUrgentToastContainer.scss index 62bb5fe53a..826a812406 100644 --- a/src/stores/room-list/previews/CreationEventPreview.ts +++ b/res/css/structures/_NonUrgentToastContainer.scss @@ -14,18 +14,22 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { IPreview } from "./IPreview"; -import { TagID } from "../models"; -import { MatrixEvent } from "matrix-js-sdk/src/models/event"; -import { getSenderName, isSelf } from "./utils"; -import { _t } from "../../../languageHandler"; +.mx_NonUrgentToastContainer { + position: absolute; + bottom: 30px; + left: 28px; + z-index: 101; // same level as other toasts -export class CreationEventPreview implements IPreview { - public getTextFor(event: MatrixEvent, tagId?: TagID): string { - if (isSelf(event)) { - return _t("You created the room"); - } else { - return _t("%(senderName)s created the room", {senderName: getSenderName(event)}); - } + .mx_NonUrgentToastContainer_toast { + padding: 10px 12px; + border-radius: 8px; + width: 320px; + font-size: $font-13px; + margin-top: 8px; + + // We don't use variables on the colours because we want it to be the same + // in all themes. + background-color: #17191c; + color: #fff; } } diff --git a/res/css/structures/_NotificationPanel.scss b/res/css/structures/_NotificationPanel.scss index 561ab1446f..715a94fe2c 100644 --- a/res/css/structures/_NotificationPanel.scss +++ b/res/css/structures/_NotificationPanel.scss @@ -99,3 +99,7 @@ limitations under the License. .mx_NotificationPanel .mx_EventTile_content { margin-right: 0px; } + +.mx_NotificationPanel_empty::before { + mask-image: url('$(res)/img/element-icons/notifications.svg'); +} diff --git a/res/css/structures/_RightPanel.scss b/res/css/structures/_RightPanel.scss index 2fe7aac3b2..120f44db90 100644 --- a/res/css/structures/_RightPanel.scss +++ b/res/css/structures/_RightPanel.scss @@ -19,13 +19,12 @@ limitations under the License. overflow-x: hidden; flex: 0 0 auto; position: relative; - min-width: 264px; - max-width: 50%; display: flex; flex-direction: column; border-radius: 8px; - margin: 5px; padding: 4px 0; + box-sizing: border-box; + height: 100%; .mx_RoomView_MessageList { padding: 14px 18px; // top and bottom is 4px smaller to balance with the padding set above @@ -145,3 +144,28 @@ limitations under the License. order: 2; margin: auto; } + +.mx_RightPanel_empty { + margin-right: -42px; + + h2 { + font-weight: 700; + margin: 16px 0; + } + + h2, p { + font-size: $font-14px; + } + + &::before { + content: ''; + display: block; + margin: 11px auto 29px auto; + height: 42px; + width: 42px; + background-color: $rightpanel-button-color; + mask-repeat: no-repeat; + mask-size: contain; + mask-position: center; + } +} diff --git a/res/css/views/dialogs/_RebrandDialog.scss b/res/css/views/dialogs/_RebrandDialog.scss index 6c916e0f1d..534584ae2a 100644 --- a/res/css/views/dialogs/_RebrandDialog.scss +++ b/res/css/views/dialogs/_RebrandDialog.scss @@ -53,11 +53,12 @@ limitations under the License. .mx_RebrandDialog_chevron::after { content: ''; display: inline-block; - width: 24px; - height: 24px; + width: 30px; + height: 30px; mask-position: center; mask-size: contain; mask-repeat: no-repeat; background-color: $muted-fg-color; - mask-image: url('$(res)/img/feather-customised/chevron-right.svg'); + mask-image: url('$(res)/img/feather-customised/chevron-down.svg'); + transform: rotate(-90deg); } diff --git a/res/css/views/dialogs/_ServerOfflineDialog.scss b/res/css/views/dialogs/_ServerOfflineDialog.scss new file mode 100644 index 0000000000..ae4b70beb3 --- /dev/null +++ b/res/css/views/dialogs/_ServerOfflineDialog.scss @@ -0,0 +1,72 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_ServerOfflineDialog { + .mx_ServerOfflineDialog_content { + padding-right: 85px; + color: $primary-fg-color; + + hr { + border-color: $primary-fg-color; + opacity: 0.1; + border-bottom: none; + } + + ul { + padding: 16px; + + li:nth-child(n + 2) { + margin-top: 16px; + } + } + + .mx_ServerOfflineDialog_content_context { + .mx_ServerOfflineDialog_content_context_timestamp { + display: inline-block; + width: 115px; + color: $muted-fg-color; + line-height: 24px; // same as avatar + vertical-align: top; + } + + .mx_ServerOfflineDialog_content_context_timeline { + display: inline-block; + width: calc(100% - 155px); // 115px timestamp width + 40px right margin + + .mx_ServerOfflineDialog_content_context_timeline_header { + span { + margin-left: 8px; + vertical-align: middle; + } + } + + .mx_ServerOfflineDialog_content_context_txn { + position: relative; + margin-top: 8px; + + .mx_ServerOfflineDialog_content_context_txn_desc { + width: calc(100% - 100px); // 100px is an arbitrary margin for the button + } + + .mx_AccessibleButton { + float: right; + padding: 0; + } + } + } + } + } +} diff --git a/res/css/views/directory/_NetworkDropdown.scss b/res/css/views/directory/_NetworkDropdown.scss index bd5c67c7ed..ae0927386a 100644 --- a/res/css/views/directory/_NetworkDropdown.scss +++ b/res/css/views/directory/_NetworkDropdown.scss @@ -145,13 +145,14 @@ limitations under the License. &::after { content: ""; position: absolute; - width: 24px; - height: 24px; - right: -28px; // - (24 + 4) + width: 26px; + height: 26px; + right: -27.5px; // - (width: 26 + spacing to align with X above: 1.5) + top: -3px; mask-repeat: no-repeat; mask-position: center; mask-size: contain; - mask-image: url('$(res)/img/feather-customised/chevron-down.svg'); + mask-image: url('$(res)/img/feather-customised/chevron-down-thin.svg'); background-color: $primary-fg-color; } diff --git a/res/css/views/elements/_ResizeHandle.scss b/res/css/views/elements/_ResizeHandle.scss index 5544799a34..5189f80b30 100644 --- a/res/css/views/elements/_ResizeHandle.scss +++ b/res/css/views/elements/_ResizeHandle.scss @@ -34,7 +34,7 @@ limitations under the License. .mx_MatrixChat > .mx_ResizeHandle.mx_ResizeHandle_horizontal { margin: 0 -10px 0 0; - padding: 0 10px 0 0; + padding: 0 8px 0 0; } .mx_ResizeHandle > div { diff --git a/res/css/views/messages/_MessageTimestamp.scss b/res/css/views/messages/_MessageTimestamp.scss index f8d91cc083..85c910296a 100644 --- a/res/css/views/messages/_MessageTimestamp.scss +++ b/res/css/views/messages/_MessageTimestamp.scss @@ -17,4 +17,5 @@ limitations under the License. .mx_MessageTimestamp { color: $event-timestamp-color; font-size: $font-10px; + font-variant-numeric: tabular-nums; } diff --git a/res/css/views/rooms/_JumpToBottomButton.scss b/res/css/views/rooms/_JumpToBottomButton.scss index cb3803fe5b..6cb3b6bce9 100644 --- a/res/css/views/rooms/_JumpToBottomButton.scss +++ b/res/css/views/rooms/_JumpToBottomButton.scss @@ -67,8 +67,8 @@ limitations under the License. bottom: 0; left: 0; right: 0; - mask: url('$(res)/img/icon-jump-to-bottom.svg'); + mask-image: url('$(res)/img/feather-customised/chevron-down-thin.svg'); mask-repeat: no-repeat; - mask-position: 9px 14px; + mask-size: contain; background: $muted-fg-color; } diff --git a/res/css/views/rooms/_RoomList.scss b/res/css/views/rooms/_RoomList.scss index 690ed0646e..89ab85e146 100644 --- a/res/css/views/rooms/_RoomList.scss +++ b/res/css/views/rooms/_RoomList.scss @@ -15,11 +15,5 @@ limitations under the License. */ .mx_RoomList { - width: calc(100% - 16px); // 16px of artificial right-side margin (8px is overflowed from the sublists) - - // Create a column-based flexbox for the sublists. That's pretty much all we have to - // worry about in this stylesheet. - display: flex; - flex-direction: column; - flex-wrap: nowrap; // let the column overflow + padding-right: 7px; // width of the scrollbar, to line things up } diff --git a/res/css/views/rooms/_RoomPreviewBar.scss b/res/css/views/rooms/_RoomPreviewBar.scss index 8708f13ada..0b1da7a41c 100644 --- a/res/css/views/rooms/_RoomPreviewBar.scss +++ b/res/css/views/rooms/_RoomPreviewBar.scss @@ -58,11 +58,6 @@ limitations under the License. } } -.mx_RoomPreviewBar_dark { - background-color: $tagpanel-bg-color; - color: $accent-fg-color; -} - .mx_RoomPreviewBar_actions { display: flex; } diff --git a/res/css/views/rooms/_RoomSublist.scss b/res/css/views/rooms/_RoomSublist.scss index 3ec4d114af..d3c9b79c69 100644 --- a/res/css/views/rooms/_RoomSublist.scss +++ b/res/css/views/rooms/_RoomSublist.scss @@ -15,15 +15,8 @@ limitations under the License. */ .mx_RoomSublist { - // The sublist is a column of rows, essentially - display: flex; - flex-direction: column; - margin-left: 8px; margin-bottom: 4px; - width: 100%; - - flex-shrink: 0; // to convince safari's layout engine the flexbox is fine .mx_RoomSublist_headerContainer { // Create a flexbox to make alignment easy @@ -149,26 +142,24 @@ limitations under the License. .mx_RoomSublist_collapseBtn { display: inline-block; position: relative; - width: 12px; - height: 12px; - margin-right: 8px; + width: 14px; + height: 14px; + margin-right: 6px; &::before { content: ''; - width: 12px; - height: 12px; + width: 18px; + height: 18px; position: absolute; - top: 1px; - left: 1px; mask-position: center; mask-size: contain; mask-repeat: no-repeat; - background-color: $primary-fg-color; + background-color: $roomlist-header-color; mask-image: url('$(res)/img/feather-customised/chevron-down.svg'); } &.mx_RoomSublist_collapseBtn_collapsed::before { - mask-image: url('$(res)/img/feather-customised/chevron-right.svg'); + transform: rotate(-90deg); } } } @@ -258,22 +249,24 @@ limitations under the License. .mx_RoomSublist_showNButtonChevron { position: relative; - width: 16px; - height: 16px; + width: 18px; + height: 18px; margin-left: 12px; - margin-right: 18px; + margin-right: 16px; mask-position: center; mask-size: contain; mask-repeat: no-repeat; - background: $roomtile-preview-color; + background: $roomlist-header-color; + left: -1px; // adjust for image position } - .mx_RoomSublist_showMoreButtonChevron { + .mx_RoomSublist_showMoreButtonChevron, + .mx_RoomSublist_showLessButtonChevron { mask-image: url('$(res)/img/feather-customised/chevron-down.svg'); } .mx_RoomSublist_showLessButtonChevron { - mask-image: url('$(res)/img/feather-customised/chevron-up.svg'); + transform: rotate(180deg); } } diff --git a/res/css/views/rooms/_RoomTile.scss b/res/css/views/rooms/_RoomTile.scss index 9afbd44b20..f22228602d 100644 --- a/res/css/views/rooms/_RoomTile.scss +++ b/res/css/views/rooms/_RoomTile.scss @@ -221,10 +221,6 @@ limitations under the License. mask-image: url('$(res)/img/element-icons/roomlist/favorite.svg'); } - .mx_RoomTile_iconFavorite::before { - mask-image: url('$(res)/img/feather-customised/favourites.svg'); - } - .mx_RoomTile_iconArrowDown::before { mask-image: url('$(res)/img/element-icons/roomlist/low-priority.svg'); } diff --git a/res/css/views/rooms/_TopUnreadMessagesBar.scss b/res/css/views/rooms/_TopUnreadMessagesBar.scss index c0545660c2..8841b042a0 100644 --- a/res/css/views/rooms/_TopUnreadMessagesBar.scss +++ b/res/css/views/rooms/_TopUnreadMessagesBar.scss @@ -28,7 +28,7 @@ limitations under the License. content: ""; position: absolute; top: -8px; - left: 11px; + left: 10.5px; width: 4px; height: 4px; border-radius: 16px; @@ -49,12 +49,13 @@ limitations under the License. .mx_TopUnreadMessagesBar_scrollUp::before { content: ""; position: absolute; - width: 38px; - height: 38px; - mask-image: url('$(res)/img/icon-jump-to-first-unread.svg'); + width: 36px; + height: 36px; + mask-image: url('$(res)/img/feather-customised/chevron-down-thin.svg'); mask-repeat: no-repeat; - mask-position: 9px 13px; + mask-size: contain; background: $muted-fg-color; + transform: rotate(180deg); } .mx_TopUnreadMessagesBar_markAsRead { diff --git a/src/stores/room-list/previews/NameEventPreview.ts b/res/css/views/toasts/_NonUrgentEchoFailureToast.scss similarity index 50% rename from src/stores/room-list/previews/NameEventPreview.ts rename to res/css/views/toasts/_NonUrgentEchoFailureToast.scss index 4197abacfb..9a8229b38e 100644 --- a/src/stores/room-list/previews/NameEventPreview.ts +++ b/res/css/views/toasts/_NonUrgentEchoFailureToast.scss @@ -14,18 +14,24 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { IPreview } from "./IPreview"; -import { TagID } from "../models"; -import { MatrixEvent } from "matrix-js-sdk/src/models/event"; -import { getSenderName, isSelf } from "./utils"; -import { _t } from "../../../languageHandler"; +.mx_NonUrgentEchoFailureToast { + .mx_NonUrgentEchoFailureToast_icon { + display: inline-block; + width: $font-18px; + height: $font-18px; + mask-position: center; + mask-size: contain; + mask-repeat: no-repeat; + background-color: #fff; // we know that non-urgent toasts are always styled the same + mask-image: url('$(res)/img/element-icons/cloud-off.svg'); + margin-right: 8px; + } -export class NameEventPreview implements IPreview { - public getTextFor(event: MatrixEvent, tagId?: TagID): string { - if (isSelf(event)) { - return _t("You changed the room name"); - } else { - return _t("%(senderName)s changed the room name", {senderName: getSenderName(event)}); - } + span { // includes the i18n block + vertical-align: middle; + } + + .mx_AccessibleButton { + padding: 0; } } diff --git a/res/img/attach.png b/res/img/attach.png deleted file mode 100644 index 1bcb70045d..0000000000 Binary files a/res/img/attach.png and /dev/null differ diff --git a/res/img/button-text-block-quote-on.svg b/res/img/button-text-block-quote-on.svg deleted file mode 100644 index f8a86125c9..0000000000 --- a/res/img/button-text-block-quote-on.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - 3B24B8C7-64BE-4B3E-A748-94DB72E1210F - Created with sketchtool. - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/button-text-block-quote.svg b/res/img/button-text-block-quote.svg deleted file mode 100644 index d70c261f5d..0000000000 --- a/res/img/button-text-block-quote.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - BFC0418B-9081-4789-A231-B75953157748 - Created with sketchtool. - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/button-text-bold-on.svg b/res/img/button-text-bold-on.svg deleted file mode 100644 index 161e740e90..0000000000 --- a/res/img/button-text-bold-on.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - 01F3F9B2-8F38-4BAF-A345-AECAC3D88E79 - Created with sketchtool. - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/button-text-bold.svg b/res/img/button-text-bold.svg deleted file mode 100644 index 0fd0baa07e..0000000000 --- a/res/img/button-text-bold.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - 9BC64A5B-F157-43FF-BCC4-02D30CDF520B - Created with sketchtool. - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/button-text-bulleted-list-on.svg b/res/img/button-text-bulleted-list-on.svg deleted file mode 100644 index d4a40e889c..0000000000 --- a/res/img/button-text-bulleted-list-on.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - 654917CF-20A4-49B6-B0A1-9875D7B733C8 - Created with sketchtool. - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/button-text-bulleted-list.svg b/res/img/button-text-bulleted-list.svg deleted file mode 100644 index ae3e640d8e..0000000000 --- a/res/img/button-text-bulleted-list.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - B7D94619-44BC-4184-A60A-DBC5BB54E5F9 - Created with sketchtool. - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/button-text-deleted-on.svg b/res/img/button-text-deleted-on.svg deleted file mode 100644 index 2914fcabe6..0000000000 --- a/res/img/button-text-deleted-on.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - 69B11088-0F3A-4E14-BD9F-4FEF4115E99B - Created with sketchtool. - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/button-text-deleted.svg b/res/img/button-text-deleted.svg deleted file mode 100644 index 5f262dc350..0000000000 --- a/res/img/button-text-deleted.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - A34F2223-34C6-46AE-AA47-38EC8984E9B3 - Created with sketchtool. - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/button-text-formatting.svg b/res/img/button-text-formatting.svg deleted file mode 100644 index d697010d40..0000000000 --- a/res/img/button-text-formatting.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - diff --git a/res/img/button-text-inline-code-on.svg b/res/img/button-text-inline-code-on.svg deleted file mode 100644 index 8d1439c97b..0000000000 --- a/res/img/button-text-inline-code-on.svg +++ /dev/null @@ -1,25 +0,0 @@ - - - - B76754AB-42E6-48D2-9443-80CBC0DE02ED - Created with sketchtool. - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/button-text-inline-code.svg b/res/img/button-text-inline-code.svg deleted file mode 100644 index 24026cb709..0000000000 --- a/res/img/button-text-inline-code.svg +++ /dev/null @@ -1,25 +0,0 @@ - - - - 4CAFF494-61AE-4916-AFE8-D1E62F7CF0DE - Created with sketchtool. - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/button-text-italic-on.svg b/res/img/button-text-italic-on.svg deleted file mode 100644 index 15fe588596..0000000000 --- a/res/img/button-text-italic-on.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - 116426C2-0B55-480E-92B3-57D4B3ABAB90 - Created with sketchtool. - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/button-text-italic.svg b/res/img/button-text-italic.svg deleted file mode 100644 index b5722e827b..0000000000 --- a/res/img/button-text-italic.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - 9FBC844D-96CF-4DCB-B545-FCD23727218B - Created with sketchtool. - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/button-text-numbered-list-on.svg b/res/img/button-text-numbered-list-on.svg deleted file mode 100644 index 869a2c2cc2..0000000000 --- a/res/img/button-text-numbered-list-on.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - 294F929B-31AA-4D0C-98B3-9CA96764060D - Created with sketchtool. - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/button-text-numbered-list.svg b/res/img/button-text-numbered-list.svg deleted file mode 100644 index 8e5b8b87b6..0000000000 --- a/res/img/button-text-numbered-list.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - F0F58459-A13A-48C5-9332-ABFB96726F05 - Created with sketchtool. - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/button-text-underlined-on.svg b/res/img/button-text-underlined-on.svg deleted file mode 100644 index 870be3ce6a..0000000000 --- a/res/img/button-text-underlined-on.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - FD84FF7C-43E4-4312-90AB-5A59AD018377 - Created with sketchtool. - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/button-text-underlined.svg b/res/img/button-text-underlined.svg deleted file mode 100644 index 26f448539c..0000000000 --- a/res/img/button-text-underlined.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - 13E7EE68-9B16-4A3D-8F9F-31E4BAB7E438 - Created with sketchtool. - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/call.png b/res/img/call.png deleted file mode 100644 index a7805e0596..0000000000 Binary files a/res/img/call.png and /dev/null differ diff --git a/res/img/cancel-black.png b/res/img/cancel-black.png deleted file mode 100644 index 87dcfd41a8..0000000000 Binary files a/res/img/cancel-black.png and /dev/null differ diff --git a/res/img/cancel-black2.png b/res/img/cancel-black2.png deleted file mode 100644 index a928c61b09..0000000000 Binary files a/res/img/cancel-black2.png and /dev/null differ diff --git a/res/img/cancel.png b/res/img/cancel.png deleted file mode 100644 index 2bda8ff5bf..0000000000 Binary files a/res/img/cancel.png and /dev/null differ diff --git a/res/img/chevron-left.png b/res/img/chevron-left.png deleted file mode 100644 index efb0065de9..0000000000 Binary files a/res/img/chevron-left.png and /dev/null differ diff --git a/res/img/chevron-right.png b/res/img/chevron-right.png deleted file mode 100644 index 18a4684e47..0000000000 Binary files a/res/img/chevron-right.png and /dev/null differ diff --git a/res/img/chevron.png b/res/img/chevron.png deleted file mode 100644 index 81236f91bc..0000000000 Binary files a/res/img/chevron.png and /dev/null differ diff --git a/res/img/close-white.png b/res/img/close-white.png deleted file mode 100644 index d8752ed9fe..0000000000 Binary files a/res/img/close-white.png and /dev/null differ diff --git a/res/img/create-big.png b/res/img/create-big.png deleted file mode 100644 index b7307a11c7..0000000000 Binary files a/res/img/create-big.png and /dev/null differ diff --git a/res/img/create-big.svg b/res/img/create-big.svg deleted file mode 100644 index 2450542b63..0000000000 --- a/res/img/create-big.svg +++ /dev/null @@ -1,26 +0,0 @@ - - - - icons_create_room - Created with sketchtool. - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/create.png b/res/img/create.png deleted file mode 100644 index 2d6107ac50..0000000000 Binary files a/res/img/create.png and /dev/null differ diff --git a/res/img/delete.png b/res/img/delete.png deleted file mode 100644 index 8ff20a116d..0000000000 Binary files a/res/img/delete.png and /dev/null differ diff --git a/res/img/directory-big.png b/res/img/directory-big.png deleted file mode 100644 index 03cab69c4a..0000000000 Binary files a/res/img/directory-big.png and /dev/null differ diff --git a/res/img/download.png b/res/img/download.png deleted file mode 100644 index 1999ebf7ab..0000000000 Binary files a/res/img/download.png and /dev/null differ diff --git a/res/img/e2e/blacklisted.svg b/res/img/e2e/blacklisted.svg deleted file mode 100644 index ac99d23f05..0000000000 --- a/res/img/e2e/blacklisted.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/res/img/e2e/lock-verified.svg b/res/img/e2e/lock-verified.svg deleted file mode 100644 index 819dfacc49..0000000000 --- a/res/img/e2e/lock-verified.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/res/img/e2e/lock-warning.svg b/res/img/e2e/lock-warning.svg deleted file mode 100644 index de2bded7f8..0000000000 --- a/res/img/e2e/lock-warning.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/res/img/edit.png b/res/img/edit.png deleted file mode 100644 index 6f373d3f3d..0000000000 Binary files a/res/img/edit.png and /dev/null differ diff --git a/res/img/edit.svg b/res/img/edit.svg deleted file mode 100644 index 9674b31690..0000000000 --- a/res/img/edit.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/res/img/element-icons/cloud-off.svg b/res/img/element-icons/cloud-off.svg new file mode 100644 index 0000000000..7faea7d3b5 --- /dev/null +++ b/res/img/element-icons/cloud-off.svg @@ -0,0 +1,3 @@ + + + diff --git a/res/img/element-icons/room/composer/send.svg b/res/img/element-icons/room/composer/send.svg deleted file mode 100644 index b255a9b23b..0000000000 --- a/res/img/element-icons/room/composer/send.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/res/img/element-icons/roomlist/clear-input.svg b/res/img/element-icons/roomlist/clear-input.svg deleted file mode 100644 index 29fc097600..0000000000 --- a/res/img/element-icons/roomlist/clear-input.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/res/img/element-icons/roomlist/direct-chat.svg b/res/img/element-icons/roomlist/direct-chat.svg deleted file mode 100644 index 4b92dd9521..0000000000 --- a/res/img/element-icons/roomlist/direct-chat.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/res/img/element-icons/roomlist/e2ee-default.svg b/res/img/element-icons/roomlist/e2ee-default.svg deleted file mode 100644 index 76525f48b2..0000000000 --- a/res/img/element-icons/roomlist/e2ee-default.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/res/img/element-icons/roomlist/e2ee-error.svg b/res/img/element-icons/roomlist/e2ee-error.svg deleted file mode 100644 index 7f1a761dde..0000000000 --- a/res/img/element-icons/roomlist/e2ee-error.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/res/img/element-icons/roomlist/e2ee-none.svg b/res/img/element-icons/roomlist/e2ee-none.svg deleted file mode 100644 index cfafe6d09d..0000000000 --- a/res/img/element-icons/roomlist/e2ee-none.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/res/img/element-icons/roomlist/e2ee-trusted.svg b/res/img/element-icons/roomlist/e2ee-trusted.svg deleted file mode 100644 index 577d6a31e1..0000000000 --- a/res/img/element-icons/roomlist/e2ee-trusted.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/res/img/element-icons/roomlist/explore-rooms.svg b/res/img/element-icons/roomlist/explore-rooms.svg deleted file mode 100644 index 3786ce1153..0000000000 --- a/res/img/element-icons/roomlist/explore-rooms.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/res/img/element-icons/roomlist/search.svg b/res/img/element-icons/roomlist/search.svg deleted file mode 100644 index 3786ce1153..0000000000 --- a/res/img/element-icons/roomlist/search.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/res/img/explore.svg b/res/img/explore.svg deleted file mode 100644 index 3956e912ac..0000000000 --- a/res/img/explore.svg +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - diff --git a/res/img/feather-customised/archive.svg b/res/img/feather-customised/archive.svg deleted file mode 100644 index 428882c87b..0000000000 --- a/res/img/feather-customised/archive.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/res/img/feather-customised/arrow-down.svg b/res/img/feather-customised/arrow-down.svg deleted file mode 100644 index 4f84f627bd..0000000000 --- a/res/img/feather-customised/arrow-down.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/res/img/feather-customised/bell-crossed.svg b/res/img/feather-customised/bell-crossed.svg deleted file mode 100644 index 3ca24662b9..0000000000 --- a/res/img/feather-customised/bell-crossed.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/res/img/feather-customised/bell-mentions.custom.svg b/res/img/feather-customised/bell-mentions.custom.svg deleted file mode 100644 index fcc02f337f..0000000000 --- a/res/img/feather-customised/bell-mentions.custom.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/res/img/feather-customised/bell-notification.custom.svg b/res/img/feather-customised/bell-notification.custom.svg deleted file mode 100644 index 7bfd551f97..0000000000 --- a/res/img/feather-customised/bell-notification.custom.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/res/img/feather-customised/bell.svg b/res/img/feather-customised/bell.svg deleted file mode 100644 index b6bc5ec502..0000000000 --- a/res/img/feather-customised/bell.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/res/img/feather-customised/brush.svg b/res/img/feather-customised/brush.svg deleted file mode 100644 index d7f2738629..0000000000 --- a/res/img/feather-customised/brush.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/res/img/feather-customised/chevron-down-thin.svg b/res/img/feather-customised/chevron-down-thin.svg new file mode 100644 index 0000000000..109c83def6 --- /dev/null +++ b/res/img/feather-customised/chevron-down-thin.svg @@ -0,0 +1,3 @@ + + + diff --git a/res/img/feather-customised/chevron-down.svg b/res/img/feather-customised/chevron-down.svg index bcb185ede7..a091913b42 100644 --- a/res/img/feather-customised/chevron-down.svg +++ b/res/img/feather-customised/chevron-down.svg @@ -1,3 +1,3 @@ - - + + diff --git a/res/img/feather-customised/chevron-right.svg b/res/img/feather-customised/chevron-right.svg deleted file mode 100644 index 258de414a1..0000000000 --- a/res/img/feather-customised/chevron-right.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/res/img/feather-customised/chevron-up.svg b/res/img/feather-customised/chevron-up.svg deleted file mode 100644 index 4eb5ecc33e..0000000000 --- a/res/img/feather-customised/chevron-up.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/res/img/feather-customised/emoji3.custom.svg b/res/img/feather-customised/emoji3.custom.svg deleted file mode 100644 index d91ba1c132..0000000000 --- a/res/img/feather-customised/emoji3.custom.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/res/img/feather-customised/face.svg b/res/img/feather-customised/face.svg deleted file mode 100644 index a8ca856b67..0000000000 --- a/res/img/feather-customised/face.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/res/img/feather-customised/favourites.svg b/res/img/feather-customised/favourites.svg deleted file mode 100644 index 80f08f6e55..0000000000 --- a/res/img/feather-customised/favourites.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/res/img/feather-customised/flag.svg b/res/img/feather-customised/flag.svg deleted file mode 100644 index 983c02762b..0000000000 --- a/res/img/feather-customised/flag.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/res/img/feather-customised/flair.svg b/res/img/feather-customised/flair.svg deleted file mode 100644 index ce3a5ed6ad..0000000000 --- a/res/img/feather-customised/flair.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/res/img/feather-customised/grid.svg b/res/img/feather-customised/grid.svg deleted file mode 100644 index 4f7ab30d97..0000000000 --- a/res/img/feather-customised/grid.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/res/img/feather-customised/lock-solid.svg b/res/img/feather-customised/lock-solid.svg deleted file mode 100644 index 9eb8b6a4c5..0000000000 --- a/res/img/feather-customised/lock-solid.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/res/img/feather-customised/lock.svg b/res/img/feather-customised/lock.svg deleted file mode 100644 index 1330903b30..0000000000 --- a/res/img/feather-customised/lock.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/res/img/feather-customised/more-horizontal.svg b/res/img/feather-customised/more-horizontal.svg deleted file mode 100644 index dc6a85564e..0000000000 --- a/res/img/feather-customised/more-horizontal.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/res/img/feather-customised/notifications.svg b/res/img/feather-customised/notifications.svg deleted file mode 100644 index a590031ac3..0000000000 --- a/res/img/feather-customised/notifications.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/res/img/feather-customised/paperclip.svg b/res/img/feather-customised/paperclip.svg deleted file mode 100644 index 74a90e0fa3..0000000000 --- a/res/img/feather-customised/paperclip.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/res/img/feather-customised/phone.svg b/res/img/feather-customised/phone.svg deleted file mode 100644 index 85661c5320..0000000000 --- a/res/img/feather-customised/phone.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/res/img/feather-customised/search.svg b/res/img/feather-customised/search.svg deleted file mode 100644 index 9ce0724ea7..0000000000 --- a/res/img/feather-customised/search.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/res/img/feather-customised/share.svg b/res/img/feather-customised/share.svg deleted file mode 100644 index 7098af58aa..0000000000 --- a/res/img/feather-customised/share.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/res/img/feather-customised/sliders.svg b/res/img/feather-customised/sliders.svg deleted file mode 100644 index 5b5ec8656c..0000000000 --- a/res/img/feather-customised/sliders.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/res/img/feather-customised/star.svg b/res/img/feather-customised/star.svg deleted file mode 100644 index bcdc31aa47..0000000000 --- a/res/img/feather-customised/star.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/res/img/feather-customised/sticker.custom.svg b/res/img/feather-customised/sticker.custom.svg deleted file mode 100644 index 691e3b3925..0000000000 --- a/res/img/feather-customised/sticker.custom.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/res/img/feather-customised/sun.svg b/res/img/feather-customised/sun.svg deleted file mode 100644 index 7f51b94d1c..0000000000 --- a/res/img/feather-customised/sun.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/res/img/feather-customised/upload.svg b/res/img/feather-customised/upload.svg deleted file mode 100644 index 30c89d3819..0000000000 --- a/res/img/feather-customised/upload.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/res/img/feather-customised/user-add.svg b/res/img/feather-customised/user-add.svg deleted file mode 100644 index 6b5210c1d6..0000000000 --- a/res/img/feather-customised/user-add.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/res/img/feather-customised/users-sm.svg b/res/img/feather-customised/users-sm.svg deleted file mode 100644 index 6098be38c3..0000000000 --- a/res/img/feather-customised/users-sm.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/res/img/feather-customised/users.svg b/res/img/feather-customised/users.svg deleted file mode 100644 index b90aafdd4a..0000000000 --- a/res/img/feather-customised/users.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/res/img/feather-customised/video.svg b/res/img/feather-customised/video.svg deleted file mode 100644 index da77b6c57a..0000000000 --- a/res/img/feather-customised/video.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/res/img/filegrid.png b/res/img/filegrid.png deleted file mode 100644 index c2c2799f37..0000000000 Binary files a/res/img/filegrid.png and /dev/null differ diff --git a/res/img/filelist.png b/res/img/filelist.png deleted file mode 100644 index 3cf6cb494e..0000000000 Binary files a/res/img/filelist.png and /dev/null differ diff --git a/res/img/fullscreen.svg b/res/img/fullscreen.svg deleted file mode 100644 index e333abb6fb..0000000000 --- a/res/img/fullscreen.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - Zoom - Created with Sketch. - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/hide.png b/res/img/hide.png deleted file mode 100644 index c5aaf0dd0d..0000000000 Binary files a/res/img/hide.png and /dev/null differ diff --git a/res/img/icon-jump-to-bottom.svg b/res/img/icon-jump-to-bottom.svg deleted file mode 100644 index c4210b4ebe..0000000000 --- a/res/img/icon-jump-to-bottom.svg +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/res/img/icon-jump-to-first-unread.svg b/res/img/icon-jump-to-first-unread.svg deleted file mode 100644 index 652ccec20d..0000000000 --- a/res/img/icon-jump-to-first-unread.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - diff --git a/res/img/icon-text-cancel.svg b/res/img/icon-text-cancel.svg deleted file mode 100644 index ce28d128aa..0000000000 --- a/res/img/icon-text-cancel.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - 28D80248-63BA-4A5F-9216-4CFE72784BAC - Created with sketchtool. - - - - - - - - - - \ No newline at end of file diff --git a/res/img/icons-pin.svg b/res/img/icons-pin.svg deleted file mode 100644 index a6fbf13baa..0000000000 --- a/res/img/icons-pin.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/res/img/icons-room-nobg.svg b/res/img/icons-room-nobg.svg deleted file mode 100644 index 8ca7ab272b..0000000000 --- a/res/img/icons-room-nobg.svg +++ /dev/null @@ -1,28 +0,0 @@ - -image/svg+xml - - - - - - - \ No newline at end of file diff --git a/res/img/icons-share.svg b/res/img/icons-share.svg deleted file mode 100644 index aac19080f4..0000000000 --- a/res/img/icons-share.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/res/img/info.png b/res/img/info.png deleted file mode 100644 index 699fd64e01..0000000000 Binary files a/res/img/info.png and /dev/null differ diff --git a/res/img/leave.svg b/res/img/leave.svg deleted file mode 100644 index 1acbe59313..0000000000 --- a/res/img/leave.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/res/img/list-close.png b/res/img/list-close.png deleted file mode 100644 index 82b322f9d4..0000000000 Binary files a/res/img/list-close.png and /dev/null differ diff --git a/res/img/list-open.png b/res/img/list-open.png deleted file mode 100644 index f8c8063197..0000000000 Binary files a/res/img/list-open.png and /dev/null differ diff --git a/res/img/matrix-m.svg b/res/img/matrix-m.svg deleted file mode 100644 index ccb1df0fc5..0000000000 --- a/res/img/matrix-m.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - diff --git a/res/img/menu.png b/res/img/menu.png deleted file mode 100755 index b45f88950f..0000000000 Binary files a/res/img/menu.png and /dev/null differ diff --git a/res/img/network-matrix.svg b/res/img/network-matrix.svg deleted file mode 100644 index bb8278ae39..0000000000 --- a/res/img/network-matrix.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - diff --git a/res/img/newmessages.png b/res/img/newmessages.png deleted file mode 100644 index a22156ab21..0000000000 Binary files a/res/img/newmessages.png and /dev/null differ diff --git a/res/img/placeholder.png b/res/img/placeholder.png deleted file mode 100644 index 7da32f259c..0000000000 Binary files a/res/img/placeholder.png and /dev/null differ diff --git a/res/img/react.svg b/res/img/react.svg deleted file mode 100644 index dd23c41c2c..0000000000 --- a/res/img/react.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/res/img/reply.svg b/res/img/reply.svg deleted file mode 100644 index 540e228883..0000000000 --- a/res/img/reply.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/res/img/search.png b/res/img/search.png deleted file mode 100644 index 2f98d29048..0000000000 Binary files a/res/img/search.png and /dev/null differ diff --git a/res/img/selected.png b/res/img/selected.png deleted file mode 100644 index 8931cba75f..0000000000 Binary files a/res/img/selected.png and /dev/null differ diff --git a/res/img/settings-big.png b/res/img/settings-big.png deleted file mode 100644 index cb2e0a62d0..0000000000 Binary files a/res/img/settings-big.png and /dev/null differ diff --git a/res/img/settings.png b/res/img/settings.png deleted file mode 100644 index 264b3c9bc3..0000000000 Binary files a/res/img/settings.png and /dev/null differ diff --git a/res/img/sound-indicator.svg b/res/img/sound-indicator.svg deleted file mode 100644 index 9b8de53d81..0000000000 --- a/res/img/sound-indicator.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - sound_indicator - Created with Sketch. - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/trans.png b/res/img/trans.png deleted file mode 100644 index 8ba2310a06..0000000000 Binary files a/res/img/trans.png and /dev/null differ diff --git a/res/img/typing.png b/res/img/typing.png deleted file mode 100644 index 066a0ce8fd..0000000000 Binary files a/res/img/typing.png and /dev/null differ diff --git a/res/img/upload-big.png b/res/img/upload-big.png deleted file mode 100644 index c11c0c452d..0000000000 Binary files a/res/img/upload-big.png and /dev/null differ diff --git a/res/img/upload.png b/res/img/upload.png deleted file mode 100644 index 7457bcd0f1..0000000000 Binary files a/res/img/upload.png and /dev/null differ diff --git a/res/img/video-mute.svg b/res/img/video-mute.svg deleted file mode 100644 index 6de60ba39b..0000000000 --- a/res/img/video-mute.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - icons_video copy - Created with Sketch. - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/video-unmute.svg b/res/img/video-unmute.svg deleted file mode 100644 index a6c6c3b681..0000000000 --- a/res/img/video-unmute.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - icons_video copy - Created with Sketch. - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/img/video.png b/res/img/video.png deleted file mode 100644 index 2a788f6fa4..0000000000 Binary files a/res/img/video.png and /dev/null differ diff --git a/res/img/voice-mute.svg b/res/img/voice-mute.svg deleted file mode 100644 index 336641078e..0000000000 --- a/res/img/voice-mute.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - Audio - Created with Sketch. - - - - - - - - - \ No newline at end of file diff --git a/res/img/voice-unmute.svg b/res/img/voice-unmute.svg deleted file mode 100644 index 0d7e6f429f..0000000000 --- a/res/img/voice-unmute.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - Audio - Created with Sketch. - - - - - - - - - - \ No newline at end of file diff --git a/res/img/voice.png b/res/img/voice.png deleted file mode 100644 index 5ba765b0f4..0000000000 Binary files a/res/img/voice.png and /dev/null differ diff --git a/res/img/voip-chevron.svg b/res/img/voip-chevron.svg deleted file mode 100644 index 5f7cbe7153..0000000000 --- a/res/img/voip-chevron.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - Triangle 1 - Created with Sketch. - - - - - - - \ No newline at end of file diff --git a/res/img/voip-mute.png b/res/img/voip-mute.png deleted file mode 100644 index a16d1001e5..0000000000 Binary files a/res/img/voip-mute.png and /dev/null differ diff --git a/res/img/voip.png b/res/img/voip.png deleted file mode 100644 index e8f05bcc37..0000000000 Binary files a/res/img/voip.png and /dev/null differ diff --git a/res/img/warning.png b/res/img/warning.png deleted file mode 100644 index c5553530a8..0000000000 Binary files a/res/img/warning.png and /dev/null differ diff --git a/res/img/warning2.png b/res/img/warning2.png deleted file mode 100644 index db0fd4a897..0000000000 Binary files a/res/img/warning2.png and /dev/null differ diff --git a/res/img/zoom.png b/res/img/zoom.png deleted file mode 100644 index f05ea959b4..0000000000 Binary files a/res/img/zoom.png and /dev/null differ diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index 15155ba854..e39bb29044 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -18,6 +18,10 @@ $primary-fg-color: $text-primary-color; $primary-bg-color: $bg-color; $muted-fg-color: $header-panel-text-primary-color; +// additional text colors +$secondary-fg-color: #A9B2BC; +$tertiary-fg-color: #8E99A4; + // used for dialog box text $light-fg-color: $header-panel-text-secondary-color; @@ -112,10 +116,10 @@ $theme-button-bg-color: #e3e8f0; $roomlist-button-bg-color: rgba(141, 151, 165, 0.2); // Buttons include the filter box, explore button, and sublist buttons $roomlist-bg-color: rgba(33, 38, 44, 0.90); -$roomlist-header-color: #8E99A4; +$roomlist-header-color: $tertiary-fg-color; $roomsublist-divider-color: $primary-fg-color; -$roomtile-preview-color: #A9B2BC; +$roomtile-preview-color: $secondary-fg-color; $roomtile-default-badge-bg-color: #61708b; $roomtile-selected-bg-color: rgba(141, 151, 165, 0.2); diff --git a/res/themes/light/css/_light.scss b/res/themes/light/css/_light.scss index e317683963..e67bcdf89a 100644 --- a/res/themes/light/css/_light.scss +++ b/res/themes/light/css/_light.scss @@ -19,8 +19,8 @@ $accent-bg-color: rgba(3, 179, 129, 0.16); $notice-primary-color: #ff4b55; $notice-primary-bg-color: rgba(255, 75, 85, 0.16); $primary-fg-color: #2e2f32; -$roomlist-header-color: $primary-fg-color; -$notice-secondary-color: $roomlist-header-color; +$secondary-fg-color: #737D8C; +$tertiary-fg-color: #8D99A5; $header-panel-bg-color: #f3f8fd; // typical text (dark-on-white in light skin) @@ -52,10 +52,6 @@ $info-bg-color: #2A9EDF; $mention-user-pill-bg-color: $warning-color; $other-user-pill-bg-color: rgba(0, 0, 0, 0.1); -// pinned events indicator -$pinned-unread-color: $notice-primary-color; -$pinned-color: $notice-secondary-color; - // informational plinth $info-plinth-bg-color: #f7f7f7; $info-plinth-fg-color: #888; @@ -178,9 +174,10 @@ $theme-button-bg-color: #e3e8f0; $roomlist-button-bg-color: #fff; // Buttons include the filter box, explore button, and sublist buttons $roomlist-bg-color: rgba(245, 245, 245, 0.90); +$roomlist-header-color: $tertiary-fg-color; $roomsublist-divider-color: $primary-fg-color; -$roomtile-preview-color: #737D8C; +$roomtile-preview-color: $secondary-fg-color; $roomtile-default-badge-bg-color: #61708b; $roomtile-selected-bg-color: #FFF; @@ -199,8 +196,14 @@ $username-variant6-color: #2dc2c5; $username-variant7-color: #5c56f5; $username-variant8-color: #74d12c; +$notice-secondary-color: $roomlist-header-color; + $panel-divider-color: transparent; +// pinned events indicator +$pinned-unread-color: $notice-primary-color; +$pinned-color: $notice-secondary-color; + // ******************** $widget-menu-bar-bg-color: $secondary-accent-color; diff --git a/scripts/gen-i18n.js b/scripts/gen-i18n.js index a1823cdf50..c30ac62e3b 100755 --- a/scripts/gen-i18n.js +++ b/scripts/gen-i18n.js @@ -18,7 +18,7 @@ limitations under the License. /** * Regenerates the translations en_EN file by walking the source tree and - * parsing each file with flow-parser. Emits a JSON file with the + * parsing each file with the appropriate parser. Emits a JSON file with the * translatable strings mapped to themselves in the order they appeared * in the files and grouped by the file they appeared in. * @@ -29,8 +29,8 @@ const path = require('path'); const walk = require('walk'); -const flowParser = require('flow-parser'); -const estreeWalker = require('estree-walker'); +const parser = require("@babel/parser"); +const traverse = require("@babel/traverse"); const TRANSLATIONS_FUNCS = ['_t', '_td']; @@ -44,17 +44,9 @@ const OUTPUT_FILE = 'src/i18n/strings/en_EN.json'; // to a project that's actively maintained. const SEARCH_PATHS = ['src', 'res']; -const FLOW_PARSER_OPTS = { - esproposal_class_instance_fields: true, - esproposal_class_static_fields: true, - esproposal_decorators: true, - esproposal_export_star_as: true, - types: true, -}; - function getObjectValue(obj, key) { for (const prop of obj.properties) { - if (prop.key.type == 'Identifier' && prop.key.name == key) { + if (prop.key.type === 'Identifier' && prop.key.name === key) { return prop.value; } } @@ -62,11 +54,11 @@ function getObjectValue(obj, key) { } function getTKey(arg) { - if (arg.type == 'Literal') { + if (arg.type === 'Literal' || arg.type === "StringLiteral") { return arg.value; - } else if (arg.type == 'BinaryExpression' && arg.operator == '+') { + } else if (arg.type === 'BinaryExpression' && arg.operator === '+') { return getTKey(arg.left) + getTKey(arg.right); - } else if (arg.type == 'TemplateLiteral') { + } else if (arg.type === 'TemplateLiteral') { return arg.quasis.map((q) => { return q.value.raw; }).join(''); @@ -110,81 +102,112 @@ function getFormatStrings(str) { } function getTranslationsJs(file) { - const tree = flowParser.parse(fs.readFileSync(file, { encoding: 'utf8' }), FLOW_PARSER_OPTS); + const contents = fs.readFileSync(file, { encoding: 'utf8' }); const trs = new Set(); - estreeWalker.walk(tree, { - enter: function(node, parent) { - if ( - node.type == 'CallExpression' && - TRANSLATIONS_FUNCS.includes(node.callee.name) - ) { - const tKey = getTKey(node.arguments[0]); - // This happens whenever we call _t with non-literals (ie. whenever we've - // had to use a _td to compensate) so is expected. - if (tKey === null) return; + try { + const plugins = [ + // https://babeljs.io/docs/en/babel-parser#plugins + "classProperties", + "objectRestSpread", + "throwExpressions", + "exportDefaultFrom", + "decorators-legacy", + ]; - // check the format string against the args - // We only check _t: _td has no args - if (node.callee.name === '_t') { - try { - const placeholders = getFormatStrings(tKey); - for (const placeholder of placeholders) { - if (node.arguments.length < 2) { - throw new Error(`Placeholder found ('${placeholder}') but no substitutions given`); - } - const value = getObjectValue(node.arguments[1], placeholder); - if (value === null) { - throw new Error(`No value found for placeholder '${placeholder}'`); - } - } + if (file.endsWith(".js") || file.endsWith(".jsx")) { + // all JS is assumed to be flow or react + plugins.push("flow", "jsx"); + } else if (file.endsWith(".ts")) { + // TS can't use JSX unless it's a TSX file (otherwise angle casts fail) + plugins.push("typescript"); + } else if (file.endsWith(".tsx")) { + // When the file is a TSX file though, enable JSX parsing + plugins.push("typescript", "jsx"); + } - // Validate tag replacements - if (node.arguments.length > 2) { - const tagMap = node.arguments[2]; - for (const prop of tagMap.properties || []) { - if (prop.key.type === 'Literal') { - const tag = prop.key.value; - // RegExp same as in src/languageHandler.js - const regexp = new RegExp(`(<${tag}>(.*?)<\\/${tag}>|<${tag}>|<${tag}\\s*\\/>)`); - if (!tKey.match(regexp)) { - throw new Error(`No match for ${regexp} in ${tKey}`); + const babelParsed = parser.parse(contents, { + allowImportExportEverywhere: true, + errorRecovery: true, + sourceFilename: file, + tokens: true, + plugins, + }); + traverse.default(babelParsed, { + enter: (p) => { + const node = p.node; + if (p.isCallExpression() && node.callee && TRANSLATIONS_FUNCS.includes(node.callee.name)) { + const tKey = getTKey(node.arguments[0]); + + // This happens whenever we call _t with non-literals (ie. whenever we've + // had to use a _td to compensate) so is expected. + if (tKey === null) return; + + // check the format string against the args + // We only check _t: _td has no args + if (node.callee.name === '_t') { + try { + const placeholders = getFormatStrings(tKey); + for (const placeholder of placeholders) { + if (node.arguments.length < 2) { + throw new Error(`Placeholder found ('${placeholder}') but no substitutions given`); + } + const value = getObjectValue(node.arguments[1], placeholder); + if (value === null) { + throw new Error(`No value found for placeholder '${placeholder}'`); + } + } + + // Validate tag replacements + if (node.arguments.length > 2) { + const tagMap = node.arguments[2]; + for (const prop of tagMap.properties || []) { + if (prop.key.type === 'Literal') { + const tag = prop.key.value; + // RegExp same as in src/languageHandler.js + const regexp = new RegExp(`(<${tag}>(.*?)<\\/${tag}>|<${tag}>|<${tag}\\s*\\/>)`); + if (!tKey.match(regexp)) { + throw new Error(`No match for ${regexp} in ${tKey}`); + } } } } - } - } catch (e) { - console.log(); - console.error(`ERROR: ${file}:${node.loc.start.line} ${tKey}`); - console.error(e); - process.exit(1); - } - } - - let isPlural = false; - if (node.arguments.length > 1 && node.arguments[1].type == 'ObjectExpression') { - const countVal = getObjectValue(node.arguments[1], 'count'); - if (countVal) { - isPlural = true; - } - } - - if (isPlural) { - trs.add(tKey + "|other"); - const plurals = enPlurals[tKey]; - if (plurals) { - for (const pluralType of Object.keys(plurals)) { - trs.add(tKey + "|" + pluralType); + } catch (e) { + console.log(); + console.error(`ERROR: ${file}:${node.loc.start.line} ${tKey}`); + console.error(e); + process.exit(1); } } - } else { - trs.add(tKey); + + let isPlural = false; + if (node.arguments.length > 1 && node.arguments[1].type === 'ObjectExpression') { + const countVal = getObjectValue(node.arguments[1], 'count'); + if (countVal) { + isPlural = true; + } + } + + if (isPlural) { + trs.add(tKey + "|other"); + const plurals = enPlurals[tKey]; + if (plurals) { + for (const pluralType of Object.keys(plurals)) { + trs.add(tKey + "|" + pluralType); + } + } + } else { + trs.add(tKey); + } } - } - } - }); + }, + }); + } catch (e) { + console.error(e); + process.exit(1); + } return trs; } diff --git a/src/@types/common.ts b/src/@types/common.ts index a24d47ac9e..b887bd4090 100644 --- a/src/@types/common.ts +++ b/src/@types/common.ts @@ -14,7 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ +import { JSXElementConstructor } from "react"; + // Based on https://stackoverflow.com/a/53229857/3532235 export type Without = {[P in Exclude] ? : never}; export type XOR = (T | U) extends object ? (Without & U) | (Without & T) : T | U; export type Writeable = { -readonly [P in keyof T]: T[P] }; + +export type ComponentClass = keyof JSX.IntrinsicElements | JSXElementConstructor; diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts index 5d72061be5..cdced6df59 100644 --- a/src/@types/global.d.ts +++ b/src/@types/global.d.ts @@ -25,6 +25,7 @@ import { PlatformPeg } from "../PlatformPeg"; import RoomListLayoutStore from "../stores/room-list/RoomListLayoutStore"; import {IntegrationManagers} from "../integrations/IntegrationManagers"; import {ModalManager} from "../Modal"; +import SettingsStore from "../settings/SettingsStore"; import {ActiveRoomObserver} from "../ActiveRoomObserver"; declare global { @@ -45,6 +46,7 @@ declare global { mxPlatformPeg: PlatformPeg; mxIntegrationManagers: typeof IntegrationManagers; singletonModalManager: ModalManager; + mxSettingsStore: SettingsStore; } // workaround for https://github.com/microsoft/TypeScript/issues/30933 diff --git a/src/CallHandler.js b/src/CallHandler.js index 4414bce457..d5e058ef1e 100644 --- a/src/CallHandler.js +++ b/src/CallHandler.js @@ -62,10 +62,11 @@ import Matrix from 'matrix-js-sdk'; import dis from './dispatcher/dispatcher'; import WidgetUtils from './utils/WidgetUtils'; import WidgetEchoStore from './stores/WidgetEchoStore'; -import SettingsStore, { SettingLevel } from './settings/SettingsStore'; +import SettingsStore from './settings/SettingsStore'; import {generateHumanReadableId} from "./utils/NamingUtils"; import {Jitsi} from "./widgets/Jitsi"; import {WidgetType} from "./widgets/WidgetType"; +import {SettingLevel} from "./settings/SettingLevel"; global.mxCalls = { //room_id: MatrixCall diff --git a/src/CallMediaHandler.js b/src/CallMediaHandler.js index a0364f798a..8d56467c57 100644 --- a/src/CallMediaHandler.js +++ b/src/CallMediaHandler.js @@ -15,7 +15,8 @@ */ import * as Matrix from 'matrix-js-sdk'; -import SettingsStore, {SettingLevel} from "./settings/SettingsStore"; +import SettingsStore from "./settings/SettingsStore"; +import {SettingLevel} from "./settings/SettingLevel"; export default { hasAnyLabeledDevices: async function() { diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index 6dba041685..77a9579f2c 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -184,7 +184,7 @@ const transformTags: sanitizeHtml.IOptions["transformTags"] = { // custom to mat if (typeof attribs.class !== 'undefined') { // Filter out all classes other than ones starting with language- for syntax highlighting. const classes = attribs.class.split(/\s/).filter(function(cl) { - return cl.startsWith('language-'); + return cl.startsWith('language-') && !cl.startsWith('language-_'); }); attribs.class = classes.join(' '); } diff --git a/src/Lifecycle.js b/src/Lifecycle.js index a05392c3e9..2bebe22f14 100644 --- a/src/Lifecycle.js +++ b/src/Lifecycle.js @@ -306,6 +306,11 @@ async function _restoreFromLocalStorage(opts) { } const pickleKey = await PlatformPeg.get().getPickleKey(userId, deviceId); + if (pickleKey) { + console.log("Got pickle key"); + } else { + console.log("No pickle key available"); + } console.log(`Restoring session for ${userId}`); await _doSetLoggedIn({ @@ -364,6 +369,12 @@ export async function setLoggedIn(credentials) { ? await PlatformPeg.get().createPickleKey(credentials.userId, credentials.deviceId) : null; + if (pickleKey) { + console.log("Created pickle key"); + } else { + console.log("Pickle key not created"); + } + return _doSetLoggedIn(Object.assign({}, credentials, {pickleKey}), true); } @@ -501,6 +512,14 @@ function _persistCredentialsToLocalStorage(credentials) { localStorage.setItem("mx_access_token", credentials.accessToken); localStorage.setItem("mx_is_guest", JSON.stringify(credentials.guest)); + if (credentials.pickleKey) { + localStorage.setItem("mx_has_pickle_key", true); + } else { + if (localStorage.getItem("mx_has_pickle_key")) { + console.error("Expected a pickle key, but none provided. Encryption may not work."); + } + } + // if we didn't get a deviceId from the login, leave mx_device_id unset, // rather than setting it to "undefined". // diff --git a/src/MatrixClientPeg.ts b/src/MatrixClientPeg.ts index 5f334a639c..be16f5fe10 100644 --- a/src/MatrixClientPeg.ts +++ b/src/MatrixClientPeg.ts @@ -256,7 +256,7 @@ class _MatrixClientPeg implements IMatrixClientPeg { deviceId: creds.deviceId, pickleKey: creds.pickleKey, timelineSupport: true, - forceTURN: !SettingsStore.getValue('webRtcAllowPeerToPeer', false), + forceTURN: !SettingsStore.getValue('webRtcAllowPeerToPeer'), fallbackICEServerAllowed: !!SettingsStore.getValue('fallbackICEServerAllowed'), verificationMethods: [ verificationMethods.SAS, diff --git a/src/Notifier.js b/src/Notifier.js index c6fc7d7985..2ed302267e 100644 --- a/src/Notifier.js +++ b/src/Notifier.js @@ -27,10 +27,11 @@ import dis from './dispatcher/dispatcher'; import * as sdk from './index'; import { _t } from './languageHandler'; import Modal from './Modal'; -import SettingsStore, {SettingLevel} from "./settings/SettingsStore"; +import SettingsStore from "./settings/SettingsStore"; import { hideToast as hideNotificationsToast, } from "./toasts/DesktopNotificationsToast"; +import {SettingLevel} from "./settings/SettingLevel"; /* * Dispatches: diff --git a/src/RebrandListener.tsx b/src/RebrandListener.tsx index 283f74d743..47b883cf35 100644 --- a/src/RebrandListener.tsx +++ b/src/RebrandListener.tsx @@ -114,6 +114,11 @@ export default class RebrandListener { } }; + onOneTimeToastDismiss = async () => { + localStorage.setItem('mx_rename_dialog_dismissed', 'true'); + this.recheck(); + }; + onNagTimerFired = () => { this._reshowTimer = null; this.nagAgainAt = null; @@ -143,10 +148,14 @@ export default class RebrandListener { if (nagToast || oneTimeToast) { let description; + let rejectLabel = null; + let onReject = null; if (nagToast) { description = _t("Use your account to sign in to the latest version"); } else { description = _t("We’re excited to announce Riot is now Element"); + rejectLabel = _t("Dismiss"); + onReject = this.onOneTimeToastDismiss; } ToastStore.sharedInstance().addOrReplaceToast({ @@ -157,6 +166,8 @@ export default class RebrandListener { description, acceptLabel: _t("Learn More"), onAccept: nagToast ? this.onNagToastLearnMore : this.onOneTimeToastLearnMore, + rejectLabel, + onReject, }, component: GenericToast, priority: 20, diff --git a/src/RoomNotifs.js b/src/RoomNotifs.js index 4614bef378..a86c521ac4 100644 --- a/src/RoomNotifs.js +++ b/src/RoomNotifs.js @@ -34,27 +34,6 @@ export function shouldShowMentionBadge(roomNotifState) { return MENTION_BADGE_STATES.includes(roomNotifState); } -export function countRoomsWithNotif(rooms) { - return rooms.reduce((result, room, index) => { - const roomNotifState = getRoomNotifsState(room.roomId); - const highlight = room.getUnreadNotificationCount('highlight') > 0; - const notificationCount = room.getUnreadNotificationCount(); - - const notifBadges = notificationCount > 0 && shouldShowNotifBadge(roomNotifState); - const mentionBadges = highlight && shouldShowMentionBadge(roomNotifState); - const isInvite = room.hasMembershipState(MatrixClientPeg.get().credentials.userId, 'invite'); - const badges = notifBadges || mentionBadges || isInvite; - - if (badges) { - result.count++; - if (highlight) { - result.highlight = true; - } - } - return result; - }, {count: 0, highlight: false}); -} - export function aggregateNotificationCount(rooms) { return rooms.reduce((result, room) => { const roomNotifState = getRoomNotifsState(room.roomId); diff --git a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js index ec4b88f759..de50feaedb 100644 --- a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js +++ b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js @@ -20,9 +20,10 @@ import PropTypes from 'prop-types'; import dis from "../../../../dispatcher/dispatcher"; import { _t } from '../../../../languageHandler'; -import SettingsStore, {SettingLevel} from "../../../../settings/SettingsStore"; +import SettingsStore from "../../../../settings/SettingsStore"; import EventIndexPeg from "../../../../indexing/EventIndexPeg"; import {Action} from "../../../../dispatcher/actions"; +import {SettingLevel} from "../../../../settings/SettingLevel"; /* * Allows the user to disable the Event Index. diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js index a9dd5be34b..be3368b87b 100644 --- a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js +++ b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js @@ -19,11 +19,12 @@ import * as sdk from '../../../../index'; import PropTypes from 'prop-types'; import { _t } from '../../../../languageHandler'; import SdkConfig from '../../../../SdkConfig'; -import SettingsStore, {SettingLevel} from "../../../../settings/SettingsStore"; +import SettingsStore from "../../../../settings/SettingsStore"; import Modal from '../../../../Modal'; import {formatBytes, formatCountLong} from "../../../../utils/FormattingUtils"; import EventIndexPeg from "../../../../indexing/EventIndexPeg"; +import {SettingLevel} from "../../../../settings/SettingLevel"; /* * Allows the user to introspect the event index state and disable it. diff --git a/src/autocomplete/EmojiProvider.tsx b/src/autocomplete/EmojiProvider.tsx index c4dd3ec9cc..147d68f5ff 100644 --- a/src/autocomplete/EmojiProvider.tsx +++ b/src/autocomplete/EmojiProvider.tsx @@ -34,7 +34,8 @@ import EMOTICON_REGEX from 'emojibase-regex/emoticon'; const LIMIT = 20; // Match for ascii-style ";-)" emoticons or ":wink:" shortcodes provided by emojibase -const EMOJI_REGEX = new RegExp('(' + EMOTICON_REGEX.source + '|:[+-\\w]*:?)$', 'g'); +// anchored to only match from the start of parts otherwise it'll show emoji suggestions whilst typing matrix IDs +const EMOJI_REGEX = new RegExp('(' + EMOTICON_REGEX.source + '|(?:^|\\s):[+-\\w]*:?)$', 'g'); interface IEmojiShort { emoji: IEmoji; diff --git a/src/autocomplete/QueryMatcher.ts b/src/autocomplete/QueryMatcher.ts index f717fb11f6..9c91414556 100644 --- a/src/autocomplete/QueryMatcher.ts +++ b/src/autocomplete/QueryMatcher.ts @@ -142,7 +142,8 @@ export default class QueryMatcher { private processQuery(query: string): string { if (this._options.fuzzy !== false) { - return removeHiddenChars(query).toLowerCase(); + // lower case both the input and the output for consistency + return removeHiddenChars(query.toLowerCase()).toLowerCase(); } return query.toLowerCase(); } diff --git a/src/autocomplete/RoomProvider.tsx b/src/autocomplete/RoomProvider.tsx index f14fa3bbfa..b18b2d132c 100644 --- a/src/autocomplete/RoomProvider.tsx +++ b/src/autocomplete/RoomProvider.tsx @@ -118,7 +118,7 @@ export default class RoomProvider extends AutocompleteProvider { } getName() { - return '💬 ' + _t('Rooms'); + return _t('Rooms'); } renderCompletions(completions: React.ReactNode[]): React.ReactNode { diff --git a/src/autocomplete/UserProvider.tsx b/src/autocomplete/UserProvider.tsx index eeb6c7a522..c957b5e597 100644 --- a/src/autocomplete/UserProvider.tsx +++ b/src/autocomplete/UserProvider.tsx @@ -137,7 +137,7 @@ export default class UserProvider extends AutocompleteProvider { } getName(): string { - return '👥 ' + _t('Users'); + return _t('Users'); } _makeUsers() { diff --git a/src/components/structures/FilePanel.js b/src/components/structures/FilePanel.js index f8c03be864..d873dd4094 100644 --- a/src/components/structures/FilePanel.js +++ b/src/components/structures/FilePanel.js @@ -210,6 +210,11 @@ const FilePanel = createReactClass({ const TimelinePanel = sdk.getComponent("structures.TimelinePanel"); const Loader = sdk.getComponent("elements.Spinner"); + const emptyState = (
+

{_t('No files visible in this room')}

+

{_t('Attach files from chat or just drag and drop them anywhere in a room.')}

+
); + if (this.state.timelineSet) { // console.log("rendering TimelinePanel for timelineSet " + this.state.timelineSet.room.roomId + " " + // "(" + this.state.timelineSet._timelines.join(", ") + ")" + " with key " + this.props.roomId); @@ -223,7 +228,7 @@ const FilePanel = createReactClass({ onPaginationRequest={this.onPaginationRequest} tileShape="file_grid" resizeNotifier={this.props.resizeNotifier} - empty={_t('There are no visible files in this room')} + empty={emptyState} /> ); diff --git a/src/components/structures/LeftPanel.tsx b/src/components/structures/LeftPanel.tsx index 43e75ffe88..bc17bbe23f 100644 --- a/src/components/structures/LeftPanel.tsx +++ b/src/components/structures/LeftPanel.tsx @@ -35,6 +35,8 @@ import RoomListStore, { LISTS_UPDATE_EVENT } from "../../stores/room-list/RoomLi import {Key} from "../../Keyboard"; import IndicatorScrollbar from "../structures/IndicatorScrollbar"; import AccessibleTooltipButton from "../views/elements/AccessibleTooltipButton"; +import { OwnProfileStore } from "../../stores/OwnProfileStore"; +import { MatrixClientPeg } from "../../MatrixClientPeg"; interface IProps { isMinimized: boolean; @@ -42,7 +44,6 @@ interface IProps { } interface IState { - searchFilter: string; showBreadcrumbs: boolean; showTagPanel: boolean; } @@ -59,6 +60,7 @@ const cssClasses = [ export default class LeftPanel extends React.Component { private listContainerRef: React.RefObject = createRef(); private tagPanelWatcherRef: string; + private bgImageWatcherRef: string; private focusedElement = null; private isDoingStickyHeaders = false; @@ -66,13 +68,15 @@ export default class LeftPanel extends React.Component { super(props); this.state = { - searchFilter: "", showBreadcrumbs: BreadcrumbsStore.instance.visible, showTagPanel: SettingsStore.getValue('TagPanel.enableTagPanel'), }; BreadcrumbsStore.instance.on(UPDATE_EVENT, this.onBreadcrumbsUpdate); RoomListStore.instance.on(LISTS_UPDATE_EVENT, this.onBreadcrumbsUpdate); + OwnProfileStore.instance.on(UPDATE_EVENT, this.onBackgroundImageUpdate); + this.bgImageWatcherRef = SettingsStore.watchSetting( + "RoomList.backgroundImage", null, this.onBackgroundImageUpdate); this.tagPanelWatcherRef = SettingsStore.watchSetting("TagPanel.enableTagPanel", null, () => { this.setState({showTagPanel: SettingsStore.getValue("TagPanel.enableTagPanel")}); }); @@ -84,15 +88,13 @@ export default class LeftPanel extends React.Component { public componentWillUnmount() { SettingsStore.unwatchSetting(this.tagPanelWatcherRef); + SettingsStore.unwatchSetting(this.bgImageWatcherRef); BreadcrumbsStore.instance.off(UPDATE_EVENT, this.onBreadcrumbsUpdate); RoomListStore.instance.off(LISTS_UPDATE_EVENT, this.onBreadcrumbsUpdate); + OwnProfileStore.instance.off(UPDATE_EVENT, this.onBackgroundImageUpdate); this.props.resizeNotifier.off("middlePanelResizedNoisy", this.onResize); } - private onSearch = (term: string): void => { - this.setState({searchFilter: term}); - }; - private onExplore = () => { dis.fire(Action.ViewRoomDirectory); }; @@ -108,6 +110,20 @@ export default class LeftPanel extends React.Component { } }; + private onBackgroundImageUpdate = () => { + // Note: we do this in the LeftPanel as it uses this variable most prominently. + const avatarSize = 32; // arbitrary + let avatarUrl = OwnProfileStore.instance.getHttpAvatarUrl(avatarSize); + const settingBgMxc = SettingsStore.getValue("RoomList.backgroundImage"); + if (settingBgMxc) { + avatarUrl = MatrixClientPeg.get().mxcUrlToHttp(settingBgMxc, avatarSize, avatarSize); + } + const avatarUrlProp = `url(${avatarUrl})`; + if (document.body.style.getPropertyValue("--avatar-url") !== avatarUrlProp) { + document.body.style.setProperty("--avatar-url", avatarUrlProp); + } + }; + private handleStickyHeaders(list: HTMLDivElement) { if (this.isDoingStickyHeaders) return; this.isDoingStickyHeaders = true; @@ -344,7 +360,6 @@ export default class LeftPanel extends React.Component { onKeyDown={this.onKeyDown} > { onKeyDown={this.onKeyDown} resizeNotifier={null} collapsed={false} - searchFilter={this.state.searchFilter} onFocus={this.onFocus} onBlur={this.onBlur} isMinimized={this.props.isMinimized} diff --git a/src/components/structures/LoggedInView.tsx b/src/components/structures/LoggedInView.tsx index 1f561e68ef..48669a3721 100644 --- a/src/components/structures/LoggedInView.tsx +++ b/src/components/structures/LoggedInView.tsx @@ -54,6 +54,8 @@ import LeftPanel from "./LeftPanel"; import CallContainer from '../views/voip/CallContainer'; import { ViewRoomDeltaPayload } from "../../dispatcher/payloads/ViewRoomDeltaPayload"; import RoomListStore from "../../stores/room-list/RoomListStore"; +import NonUrgentToastContainer from "./NonUrgentToastContainer"; +import { ToggleRightPanelPayload } from "../../dispatcher/payloads/ToggleRightPanelPayload"; // We need to fetch each pinned message individually (if we don't already have it) // so each pinned message may trigger a request. Limit the number per room for sanity. @@ -472,8 +474,8 @@ class LoggedInView extends React.Component { case Key.PERIOD: if (ctrlCmdOnly && (this.props.page_type === "room_view" || this.props.page_type === "group_view")) { - dis.dispatch({ - action: 'toggle_right_panel', + dis.dispatch({ + action: Action.ToggleRightPanel, type: this.props.page_type === "room_view" ? "room" : "group", }); handled = true; @@ -687,6 +689,7 @@ class LoggedInView extends React.Component { + ); } diff --git a/src/components/structures/MainSplit.js b/src/components/structures/MainSplit.js index 7c66f21a04..800ed76bb9 100644 --- a/src/components/structures/MainSplit.js +++ b/src/components/structures/MainSplit.js @@ -16,77 +16,24 @@ limitations under the License. */ import React from 'react'; -import ResizeHandle from '../views/elements/ResizeHandle'; -import {Resizer, FixedDistributor} from '../../resizer'; +import { Resizable } from 're-resizable'; export default class MainSplit extends React.Component { - constructor(props) { - super(props); - this._setResizeContainerRef = this._setResizeContainerRef.bind(this); - this._onResized = this._onResized.bind(this); + _onResized = (event, direction, refToElement, delta) => { + window.localStorage.setItem("mx_rhs_size", this._loadSidePanelSize().width + delta.width); } - _onResized(size) { - window.localStorage.setItem("mx_rhs_size", size); - if (this.props.resizeNotifier) { - this.props.resizeNotifier.notifyRightHandleResized(); - } - } + _loadSidePanelSize() { + let rhsSize = parseInt(window.localStorage.getItem("mx_rhs_size"), 10); - _createResizer() { - const classNames = { - handle: "mx_ResizeHandle", - vertical: "mx_ResizeHandle_vertical", - reverse: "mx_ResizeHandle_reverse", - }; - const resizer = new Resizer( - this.resizeContainer, - FixedDistributor, - {onResized: this._onResized}, - ); - resizer.setClassNames(classNames); - let rhsSize = window.localStorage.getItem("mx_rhs_size"); - if (rhsSize !== null) { - rhsSize = parseInt(rhsSize, 10); - } else { + if (isNaN(rhsSize)) { rhsSize = 350; } - resizer.forHandleAt(0).resize(rhsSize); - resizer.attach(); - this.resizer = resizer; - } - - _setResizeContainerRef(div) { - this.resizeContainer = div; - } - - componentDidMount() { - if (this.props.panel) { - this._createResizer(); - } - } - - componentWillUnmount() { - if (this.resizer) { - this.resizer.detach(); - this.resizer = null; - } - } - - componentDidUpdate(prevProps) { - const wasPanelSet = this.props.panel && !prevProps.panel; - const wasPanelCleared = !this.props.panel && prevProps.panel; - - if (this.resizeContainer && wasPanelSet) { - // The resizer can only be created when **both** expanded and the panel is - // set. Once both are true, the container ref will mount, which is required - // for the resizer to work. - this._createResizer(); - } else if (this.resizer && wasPanelCleared) { - this.resizer.detach(); - this.resizer = null; - } + return { + height: "100%", + width: rhsSize, + }; } render() { @@ -97,13 +44,29 @@ export default class MainSplit extends React.Component { let children; if (hasResizer) { - children = - + children = { panelView } - ; + ; } - return
+ return
{ bodyView } { children }
; diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 920b7e4dec..a66d4c043f 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -51,14 +51,13 @@ import { getHomePageUrl } from '../../utils/pages'; import createRoom from "../../createRoom"; import {_t, _td, getCurrentLanguage} from '../../languageHandler'; -import SettingsStore, { SettingLevel } from "../../settings/SettingsStore"; +import SettingsStore from "../../settings/SettingsStore"; import ThemeController from "../../settings/controllers/ThemeController"; import { startAnyRegistrationFlow } from "../../Registration.js"; import { messageForSyncError } from '../../utils/ErrorUtils'; import ResizeNotifier from "../../utils/ResizeNotifier"; import AutoDiscoveryUtils, { ValidatedServerConfig } from "../../utils/AutoDiscoveryUtils"; import DMRoomMap from '../../utils/DMRoomMap'; -import { countRoomsWithNotif } from '../../RoomNotifs'; import ThemeWatcher from "../../settings/watchers/ThemeWatcher"; import { FontWatcher } from '../../settings/watchers/FontWatcher'; import { storeRoomAliasInCache } from '../../RoomAliasCache'; @@ -75,6 +74,8 @@ import { import {showToast as showNotificationsToast} from "../../toasts/DesktopNotificationsToast"; import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload"; import ErrorDialog from "../views/dialogs/ErrorDialog"; +import { RoomNotificationStateStore } from "../../stores/notifications/RoomNotificationStateStore"; +import { SettingLevel } from "../../settings/SettingLevel"; /** constants for MatrixChat.state.view */ export enum Views { @@ -1844,21 +1845,20 @@ export default class MatrixChat extends React.PureComponent { } updateStatusIndicator(state: string, prevState: string) { - // only count visible rooms to not torment the user with notification counts in rooms they can't see - // it will include highlights from the previous version of the room internally - const notifCount = countRoomsWithNotif(MatrixClientPeg.get().getVisibleRooms()).count; + const notificationState = RoomNotificationStateStore.instance.globalState; + const numUnreadRooms = notificationState.numUnreadStates; // we know that states === rooms here if (PlatformPeg.get()) { PlatformPeg.get().setErrorStatus(state === 'ERROR'); - PlatformPeg.get().setNotificationCount(notifCount); + PlatformPeg.get().setNotificationCount(numUnreadRooms); } this.subTitleStatus = ''; if (state === "ERROR") { this.subTitleStatus += `[${_t("Offline")}] `; } - if (notifCount > 0) { - this.subTitleStatus += `[${notifCount}]`; + if (numUnreadRooms > 0) { + this.subTitleStatus += `[${numUnreadRooms}]`; } this.setPageSubtitle(); diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index 7567786af3..230d136e04 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -346,9 +346,9 @@ export default class MessagePanel extends React.Component { } } - _isUnmounting() { + _isUnmounting = () => { return !this._isMounted; - } + }; // TODO: Implement granular (per-room) hide options _shouldShowEvent(mxEv) { @@ -571,12 +571,10 @@ export default class MessagePanel extends React.Component { const readReceipts = this._readReceiptsByEvent[eventId]; - // Dev note: `this._isUnmounting.bind(this)` is important - it ensures that - // the function is run in the context of this class and not EventTile, therefore - // ensuring the right `this._mounted` variable is used by read receipts (which - // don't update their position if we, the MessagePanel, is unmounting). + // use txnId as key if available so that we don't remount during sending ret.push( -
  • @@ -590,7 +588,7 @@ export default class MessagePanel extends React.Component { readReceipts={readReceipts} readReceiptMap={this._readReceiptMap} showUrlPreview={this.props.showUrlPreview} - checkUnmounting={this._isUnmounting.bind(this)} + checkUnmounting={this._isUnmounting} eventSendStatus={mxEv.getAssociatedStatus()} tileShape={this.props.tileShape} isTwelveHour={this.props.isTwelveHour} diff --git a/src/components/structures/NonUrgentToastContainer.tsx b/src/components/structures/NonUrgentToastContainer.tsx new file mode 100644 index 0000000000..8d415df4dd --- /dev/null +++ b/src/components/structures/NonUrgentToastContainer.tsx @@ -0,0 +1,63 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import * as React from "react"; +import { ComponentClass } from "../../@types/common"; +import NonUrgentToastStore from "../../stores/NonUrgentToastStore"; +import { UPDATE_EVENT } from "../../stores/AsyncStore"; + +interface IProps { +} + +interface IState { + toasts: ComponentClass[], +} + +export default class NonUrgentToastContainer extends React.PureComponent { + public constructor(props, context) { + super(props, context); + + this.state = { + toasts: NonUrgentToastStore.instance.components, + }; + + NonUrgentToastStore.instance.on(UPDATE_EVENT, this.onUpdateToasts); + } + + public componentWillUnmount() { + NonUrgentToastStore.instance.off(UPDATE_EVENT, this.onUpdateToasts); + } + + private onUpdateToasts = () => { + this.setState({toasts: NonUrgentToastStore.instance.components}); + }; + + public render() { + const toasts = this.state.toasts.map((t, i) => { + return ( +
    + {React.createElement(t, {})} +
    + ); + }); + + return ( +
    + {toasts} +
    + ); + } +} diff --git a/src/components/structures/NotificationPanel.js b/src/components/structures/NotificationPanel.js index c1a0ec9c4b..c1f78cffda 100644 --- a/src/components/structures/NotificationPanel.js +++ b/src/components/structures/NotificationPanel.js @@ -36,6 +36,11 @@ const NotificationPanel = createReactClass({ const TimelinePanel = sdk.getComponent("structures.TimelinePanel"); const Loader = sdk.getComponent("elements.Spinner"); + const emptyState = (
    +

    {_t('You’re all caught up')}

    +

    {_t('You have no visible notifications in this room.')}

    +
    ); + const timelineSet = MatrixClientPeg.get().getNotifTimelineSet(); if (timelineSet) { return ( @@ -46,7 +51,7 @@ const NotificationPanel = createReactClass({ timelineSet={timelineSet} showUrlPreview={false} tileShape="notif" - empty={_t('You have no visible notifications')} + empty={emptyState} />
  • ); diff --git a/src/components/structures/RightPanel.js b/src/components/structures/RightPanel.js index 776130e709..a4e3254e4c 100644 --- a/src/components/structures/RightPanel.js +++ b/src/components/structures/RightPanel.js @@ -26,7 +26,7 @@ import dis from '../../dispatcher/dispatcher'; import RateLimitedFunc from '../../ratelimitedfunc'; import { showGroupInviteDialog, showGroupAddRoomDialog } from '../../GroupAddressPicker'; import GroupStore from '../../stores/GroupStore'; -import {RIGHT_PANEL_PHASES, RIGHT_PANEL_PHASES_NO_ARGS} from "../../stores/RightPanelStorePhases"; +import {RightPanelPhases, RIGHT_PANEL_PHASES_NO_ARGS} from "../../stores/RightPanelStorePhases"; import RightPanelStore from "../../stores/RightPanelStore"; import MatrixClientContext from "../../contexts/MatrixClientContext"; import {Action} from "../../dispatcher/actions"; @@ -75,8 +75,8 @@ export default class RightPanel extends React.Component { const userForPanel = this._getUserForPanel(); if (this.props.groupId) { if (!RIGHT_PANEL_PHASES_NO_ARGS.includes(rps.groupPanelPhase)) { - dis.dispatch({action: "set_right_panel_phase", phase: RIGHT_PANEL_PHASES.GroupMemberList}); - return RIGHT_PANEL_PHASES.GroupMemberList; + dis.dispatch({action: Action.SetRightPanelPhase, phase: RightPanelPhases.GroupMemberList}); + return RightPanelPhases.GroupMemberList; } return rps.groupPanelPhase; } else if (userForPanel) { @@ -98,11 +98,11 @@ export default class RightPanel extends React.Component { ) { return rps.roomPanelPhase; } - return RIGHT_PANEL_PHASES.RoomMemberInfo; + return RightPanelPhases.RoomMemberInfo; } else { if (!RIGHT_PANEL_PHASES_NO_ARGS.includes(rps.roomPanelPhase)) { - dis.dispatch({action: "set_right_panel_phase", phase: RIGHT_PANEL_PHASES.RoomMemberList}); - return RIGHT_PANEL_PHASES.RoomMemberList; + dis.dispatch({action: Action.SetRightPanelPhase, phase: RightPanelPhases.RoomMemberList}); + return RightPanelPhases.RoomMemberList; } return rps.roomPanelPhase; } @@ -149,7 +149,7 @@ export default class RightPanel extends React.Component { onInviteToGroupButtonClick() { showGroupInviteDialog(this.props.groupId).then(() => { this.setState({ - phase: RIGHT_PANEL_PHASES.GroupMemberList, + phase: RightPanelPhases.GroupMemberList, }); }); } @@ -165,9 +165,9 @@ export default class RightPanel extends React.Component { return; } // redraw the badge on the membership list - if (this.state.phase === RIGHT_PANEL_PHASES.RoomMemberList && member.roomId === this.props.roomId) { + if (this.state.phase === RightPanelPhases.RoomMemberList && member.roomId === this.props.roomId) { this._delayedUpdate(); - } else if (this.state.phase === RIGHT_PANEL_PHASES.RoomMemberInfo && member.roomId === this.props.roomId && + } else if (this.state.phase === RightPanelPhases.RoomMemberInfo && member.roomId === this.props.roomId && member.userId === this.state.member.userId) { // refresh the member info (e.g. new power level) this._delayedUpdate(); @@ -175,7 +175,7 @@ export default class RightPanel extends React.Component { } onAction(payload) { - if (payload.action === "after_right_panel_phase_change") { + if (payload.action === Action.AfterRightPanelPhaseChange) { this.setState({ phase: payload.phase, groupRoomId: payload.groupRoomId, @@ -206,7 +206,7 @@ export default class RightPanel extends React.Component { // or the member list if we were in the member panel... phew. dis.dispatch({ action: Action.ViewUser, - member: this.state.phase === RIGHT_PANEL_PHASES.EncryptionPanel ? this.state.member : null, + member: this.state.phase === RightPanelPhases.EncryptionPanel ? this.state.member : null, }); } }; @@ -225,21 +225,21 @@ export default class RightPanel extends React.Component { let panel =
    ; switch (this.state.phase) { - case RIGHT_PANEL_PHASES.RoomMemberList: + case RightPanelPhases.RoomMemberList: if (this.props.roomId) { panel = ; } break; - case RIGHT_PANEL_PHASES.GroupMemberList: + case RightPanelPhases.GroupMemberList: if (this.props.groupId) { panel = ; } break; - case RIGHT_PANEL_PHASES.GroupRoomList: + case RightPanelPhases.GroupRoomList: panel = ; break; - case RIGHT_PANEL_PHASES.RoomMemberInfo: - case RIGHT_PANEL_PHASES.EncryptionPanel: + case RightPanelPhases.RoomMemberInfo: + case RightPanelPhases.EncryptionPanel: panel = ; break; - case RIGHT_PANEL_PHASES.Room3pidMemberInfo: + case RightPanelPhases.Room3pidMemberInfo: panel = ; break; - case RIGHT_PANEL_PHASES.GroupMemberInfo: + case RightPanelPhases.GroupMemberInfo: panel = ; break; - case RIGHT_PANEL_PHASES.GroupRoomInfo: + case RightPanelPhases.GroupRoomInfo: panel = ; break; - case RIGHT_PANEL_PHASES.NotificationPanel: + case RightPanelPhases.NotificationPanel: panel = ; break; - case RIGHT_PANEL_PHASES.FilePanel: + case RightPanelPhases.FilePanel: panel = ; break; } diff --git a/src/components/structures/RoomSearch.tsx b/src/components/structures/RoomSearch.tsx index 1451630c97..69504e9ab8 100644 --- a/src/components/structures/RoomSearch.tsx +++ b/src/components/structures/RoomSearch.tsx @@ -24,9 +24,10 @@ import { throttle } from 'lodash'; import { Key } from "../../Keyboard"; import AccessibleButton from "../views/elements/AccessibleButton"; import { Action } from "../../dispatcher/actions"; +import RoomListStore from "../../stores/room-list/RoomListStore"; +import { NameFilterCondition } from "../../stores/room-list/filters/NameFilterCondition"; interface IProps { - onQueryUpdate: (newQuery: string) => void; isMinimized: boolean; onVerticalArrow(ev: React.KeyboardEvent): void; onEnter(ev: React.KeyboardEvent): boolean; @@ -40,6 +41,7 @@ interface IState { export default class RoomSearch extends React.PureComponent { private dispatcherRef: string; private inputRef: React.RefObject = createRef(); + private searchFilter: NameFilterCondition = new NameFilterCondition(); constructor(props: IProps) { super(props); @@ -52,6 +54,21 @@ export default class RoomSearch extends React.PureComponent { this.dispatcherRef = defaultDispatcher.register(this.onAction); } + public componentDidUpdate(prevProps: Readonly, prevState: Readonly): void { + if (prevState.query !== this.state.query) { + const hadSearch = !!this.searchFilter.search.trim(); + const haveSearch = !!this.state.query.trim(); + this.searchFilter.search = this.state.query; + if (!hadSearch && haveSearch) { + // started a new filter - add the condition + RoomListStore.instance.addFilter(this.searchFilter); + } else if (hadSearch && !haveSearch) { + // cleared a filter - remove the condition + RoomListStore.instance.removeFilter(this.searchFilter); + } // else the filter hasn't changed enough for us to care here + } + } + public componentWillUnmount() { defaultDispatcher.unregister(this.dispatcherRef); } @@ -78,19 +95,8 @@ export default class RoomSearch extends React.PureComponent { private onChange = () => { if (!this.inputRef.current) return; this.setState({query: this.inputRef.current.value}); - this.onSearchUpdated(); }; - // it wants this at the top of the file, but we know better - // tslint:disable-next-line - private onSearchUpdated = throttle( - () => { - // We can't use the state variable because it can lag behind the input. - // The lag is most obvious when deleting/clearing text with the keyboard. - this.props.onQueryUpdate(this.inputRef.current.value); - }, 200, {trailing: true, leading: true}, - ); - private onFocus = (ev: React.FocusEvent) => { this.setState({focused: true}); ev.target.select(); diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 7dc2d57ff0..f585a97fde 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -48,7 +48,7 @@ import RightPanel from './RightPanel'; import RoomViewStore from '../../stores/RoomViewStore'; import RoomScrollStateStore from '../../stores/RoomScrollStateStore'; import WidgetEchoStore from '../../stores/WidgetEchoStore'; -import SettingsStore, {SettingLevel} from "../../settings/SettingsStore"; +import SettingsStore from "../../settings/SettingsStore"; import AccessibleButton from "../views/elements/AccessibleButton"; import RightPanelStore from "../../stores/RightPanelStore"; import {haveTileForEvent} from "../views/rooms/EventTile"; @@ -56,6 +56,7 @@ import RoomContext from "../../contexts/RoomContext"; import MatrixClientContext from "../../contexts/MatrixClientContext"; import { shieldStatusForRoom } from '../../utils/ShieldUtils'; import {Action} from "../../dispatcher/actions"; +import {SettingLevel} from "../../settings/SettingLevel"; const DEBUG = false; let debuglog = function() {}; diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index cb0114b243..51113f4f56 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -648,7 +648,9 @@ export default createReactClass({ if (scrollState.stuckAtBottom) { const sn = this._getScrollNode(); - sn.scrollTop = sn.scrollHeight; + if (sn.scrollTop !== sn.scrollHeight) { + sn.scrollTop = sn.scrollHeight; + } } else if (scrollState.trackedScrollToken) { const itemlist = this._itemlist.current; const trackedNode = this._getTrackedNode(); @@ -657,7 +659,10 @@ export default createReactClass({ const bottomDiff = newBottomOffset - scrollState.bottomOffset; this._bottomGrowth += bottomDiff; scrollState.bottomOffset = newBottomOffset; - itemlist.style.height = `${this._getListHeight()}px`; + const newHeight = `${this._getListHeight()}px`; + if (itemlist.style.height !== newHeight) { + itemlist.style.height = newHeight; + } debuglog("balancing height because messages below viewport grew by", bottomDiff); } } @@ -694,12 +699,16 @@ export default createReactClass({ const height = Math.max(minHeight, contentHeight); this._pages = Math.ceil(height / PAGE_SIZE); this._bottomGrowth = 0; - const newHeight = this._getListHeight(); + const newHeight = `${this._getListHeight()}px`; const scrollState = this.scrollState; if (scrollState.stuckAtBottom) { - itemlist.style.height = `${newHeight}px`; - sn.scrollTop = sn.scrollHeight; + if (itemlist.style.height !== newHeight) { + itemlist.style.height = newHeight; + } + if (sn.scrollTop !== sn.scrollHeight){ + sn.scrollTop = sn.scrollHeight; + } debuglog("updateHeight to", newHeight); } else if (scrollState.trackedScrollToken) { const trackedNode = this._getTrackedNode(); @@ -709,7 +718,9 @@ export default createReactClass({ // the currently filled piece of the timeline if (trackedNode) { const oldTop = trackedNode.offsetTop; - itemlist.style.height = `${newHeight}px`; + if (itemlist.style.height !== newHeight) { + itemlist.style.height = newHeight; + } const newTop = trackedNode.offsetTop; const topDiff = newTop - oldTop; // important to scroll by a relative amount as diff --git a/src/components/structures/UserMenu.tsx b/src/components/structures/UserMenu.tsx index c9360d7ac3..3f2e387ccb 100644 --- a/src/components/structures/UserMenu.tsx +++ b/src/components/structures/UserMenu.tsx @@ -26,7 +26,7 @@ import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload"; import RedesignFeedbackDialog from "../views/dialogs/RedesignFeedbackDialog"; import Modal from "../../Modal"; import LogoutDialog from "../views/dialogs/LogoutDialog"; -import SettingsStore, {SettingLevel} from "../../settings/SettingsStore"; +import SettingsStore from "../../settings/SettingsStore"; import {getCustomTheme} from "../../theme"; import {getHostingLink} from "../../utils/HostingLink"; import {ButtonEvent} from "../views/elements/AccessibleButton"; @@ -37,6 +37,7 @@ import { UPDATE_EVENT } from "../../stores/AsyncStore"; import BaseAvatar from '../views/avatars/BaseAvatar'; import classNames from "classnames"; import AccessibleTooltipButton from "../views/elements/AccessibleTooltipButton"; +import { SettingLevel } from "../../settings/SettingLevel"; interface IProps { isMinimized: boolean; @@ -306,9 +307,6 @@ export default class UserMenu extends React.Component { public render() { const avatarSize = 32; // should match border-radius of the avatar - const {body} = document; - const avatarUrl = OwnProfileStore.instance.getHttpAvatarUrl(avatarSize); - body.style.setProperty("--avatar-url", `url('${avatarUrl}')`); let name = {OwnProfileStore.instance.displayName}; let buttons = ( diff --git a/src/components/structures/auth/SoftLogout.js b/src/components/structures/auth/SoftLogout.js index 6577386fae..a539c8c9ee 100644 --- a/src/components/structures/auth/SoftLogout.js +++ b/src/components/structures/auth/SoftLogout.js @@ -72,7 +72,7 @@ export default class SoftLogout extends React.Component { this._initLogin(); - MatrixClientPeg.get().flagAllGroupSessionsForBackup().then(remaining => { + MatrixClientPeg.get().countSessionsNeedingBackup().then(remaining => { this.setState({keyBackupNeeded: remaining > 0}); }); } diff --git a/src/components/views/auth/LanguageSelector.js b/src/components/views/auth/LanguageSelector.js index 83db5d225b..0738ee43e4 100644 --- a/src/components/views/auth/LanguageSelector.js +++ b/src/components/views/auth/LanguageSelector.js @@ -16,10 +16,11 @@ limitations under the License. import SdkConfig from "../../../SdkConfig"; import {getCurrentLanguage} from "../../../languageHandler"; -import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; +import SettingsStore from "../../../settings/SettingsStore"; import PlatformPeg from "../../../PlatformPeg"; import * as sdk from '../../../index'; import React from 'react'; +import {SettingLevel} from "../../../settings/SettingLevel"; function onChange(newLang) { if (getCurrentLanguage() !== newLang) { diff --git a/src/components/views/avatars/BaseAvatar.tsx b/src/components/views/avatars/BaseAvatar.tsx index 7f30a7a377..4c6fde19eb 100644 --- a/src/components/views/avatars/BaseAvatar.tsx +++ b/src/components/views/avatars/BaseAvatar.tsx @@ -134,7 +134,7 @@ const BaseAvatar = (props: IProps) => { aria-hidden="true" /> ); - if (onClick !== null) { + if (onClick) { return ( { } } - if (onClick !== null) { + if (onClick) { return ( { }; export default BaseAvatar; -export type BaseAvatarType = React.FC; \ No newline at end of file +export type BaseAvatarType = React.FC; diff --git a/src/components/views/avatars/DecoratedRoomAvatar.tsx b/src/components/views/avatars/DecoratedRoomAvatar.tsx index bb737397dc..daf28400f2 100644 --- a/src/components/views/avatars/DecoratedRoomAvatar.tsx +++ b/src/components/views/avatars/DecoratedRoomAvatar.tsx @@ -44,7 +44,7 @@ export default class DecoratedRoomAvatar extends React.PureComponent u.userId !== myUserId); diff --git a/src/components/views/dialogs/ServerOfflineDialog.tsx b/src/components/views/dialogs/ServerOfflineDialog.tsx new file mode 100644 index 0000000000..f6767dcb8d --- /dev/null +++ b/src/components/views/dialogs/ServerOfflineDialog.tsx @@ -0,0 +1,124 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import * as React from 'react'; +import BaseDialog from './BaseDialog'; +import { _t } from '../../../languageHandler'; +import { EchoStore } from "../../../stores/local-echo/EchoStore"; +import { formatTime } from "../../../DateUtils"; +import SettingsStore from "../../../settings/SettingsStore"; +import { RoomEchoContext } from "../../../stores/local-echo/RoomEchoContext"; +import RoomAvatar from "../avatars/RoomAvatar"; +import { TransactionStatus } from "../../../stores/local-echo/EchoTransaction"; +import Spinner from "../elements/Spinner"; +import AccessibleButton from "../elements/AccessibleButton"; +import { UPDATE_EVENT } from "../../../stores/AsyncStore"; +import { MatrixClientPeg } from "../../../MatrixClientPeg"; + +interface IProps { + onFinished: (bool) => void; +} + +export default class ServerOfflineDialog extends React.PureComponent { + public componentDidMount() { + EchoStore.instance.on(UPDATE_EVENT, this.onEchosUpdated); + } + + public componentWillUnmount() { + EchoStore.instance.off(UPDATE_EVENT, this.onEchosUpdated); + } + + private onEchosUpdated = () => { + this.forceUpdate(); // no state to worry about + }; + + private renderTimeline(): React.ReactElement[] { + return EchoStore.instance.contexts.map((c, i) => { + if (!c.firstFailedTime) return null; // not useful + if (!(c instanceof RoomEchoContext)) throw new Error("Cannot render unknown context: " + c); + const header = ( +
    + + {c.room.name} +
    + ); + const entries = c.transactions + .filter(t => t.status === TransactionStatus.Error || t.didPreviouslyFail) + .map((t, j) => { + let button = ; + if (t.status === TransactionStatus.Error) { + button = ( + t.run()}>{_t("Resend")} + ); + } + return ( +
    + + {t.auditName} + + {button} +
    + ); + }); + return ( +
    +
    + {formatTime(c.firstFailedTime, SettingsStore.getValue("showTwelveHourTimestamps"))} +
    +
    + {header} + {entries} +
    +
    + ) + }); + } + + public render() { + let timeline = this.renderTimeline().filter(c => !!c); // remove nulls for next check + if (timeline.length === 0) { + timeline = [
    {_t("You're all caught up.")}
    ]; + } + + const serverName = MatrixClientPeg.getHomeserverName(); + return +
    +

    {_t( + "Your server isn't responding to some of your requests. " + + "Below are some of the most likely reasons.", + )}

    +
      +
    • {_t("The server (%(serverName)s) took too long to respond.", {serverName})}
    • +
    • {_t("Your firewall or anti-virus is blocking the request.")}
    • +
    • {_t("A browser extension is preventing the request.")}
    • +
    • {_t("The server is offline.")}
    • +
    • {_t("The server has denied your request.")}
    • +
    • {_t("Your area is experiencing difficulties connecting to the internet.")}
    • +
    • {_t("A connection error occurred while trying to contact the server.")}
    • +
    • {_t("The server is not configured to indicate what the problem is (CORS).")}
    • +
    +
    +

    {_t("Recent changes that have not yet been received")}

    + {timeline} +
    +
    ; + } +} diff --git a/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js b/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js index 162cb4736a..42a5304f13 100644 --- a/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js +++ b/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js @@ -17,10 +17,11 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import {_t} from "../../../languageHandler"; -import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; +import SettingsStore from "../../../settings/SettingsStore"; import * as sdk from "../../../index"; import LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; import WidgetUtils from "../../../utils/WidgetUtils"; +import {SettingLevel} from "../../../settings/SettingLevel"; export default class WidgetOpenIDPermissionsDialog extends React.Component { static propTypes = { diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index 3e4418f945..d0fc56743f 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -35,12 +35,13 @@ import dis from '../../../dispatcher/dispatcher'; import ActiveWidgetStore from '../../../stores/ActiveWidgetStore'; import classNames from 'classnames'; import {IntegrationManagers} from "../../../integrations/IntegrationManagers"; -import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; +import SettingsStore from "../../../settings/SettingsStore"; import {aboveLeftOf, ContextMenu, ContextMenuButton} from "../../structures/ContextMenu"; import PersistedElement from "./PersistedElement"; import {WidgetType} from "../../../widgets/WidgetType"; import {Capability} from "../../../widgets/WidgetApi"; import {sleep} from "../../../utils/promise"; +import {SettingLevel} from "../../../settings/SettingLevel"; const ALLOWED_APP_URL_SCHEMES = ['https:', 'http:']; const ENABLE_REACT_PERF = false; diff --git a/src/components/views/elements/IRCTimelineProfileResizer.tsx b/src/components/views/elements/IRCTimelineProfileResizer.tsx index 65140707d5..1098d0293e 100644 --- a/src/components/views/elements/IRCTimelineProfileResizer.tsx +++ b/src/components/views/elements/IRCTimelineProfileResizer.tsx @@ -15,8 +15,9 @@ limitations under the License. */ import React from 'react'; -import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; +import SettingsStore from "../../../settings/SettingsStore"; import Draggable, {ILocationState} from './Draggable'; +import { SettingLevel } from "../../../settings/SettingLevel"; interface IProps { // Current room diff --git a/src/components/views/elements/SettingsFlag.tsx b/src/components/views/elements/SettingsFlag.tsx index 4f41db51e2..03e91fac62 100644 --- a/src/components/views/elements/SettingsFlag.tsx +++ b/src/components/views/elements/SettingsFlag.tsx @@ -20,11 +20,12 @@ import SettingsStore from "../../../settings/SettingsStore"; import { _t } from '../../../languageHandler'; import ToggleSwitch from "./ToggleSwitch"; import StyledCheckbox from "./StyledCheckbox"; +import { SettingLevel } from "../../../settings/SettingLevel"; interface IProps { // The setting must be a boolean name: string; - level: string; + level: SettingLevel; roomId?: string; // for per-room settings label?: string; // untranslated isExplicit?: boolean; @@ -52,8 +53,8 @@ export default class SettingsFlag extends React.Component { }; } - private onChange = (checked: boolean): void => { - this.save(checked); + private onChange = async (checked: boolean) => { + await this.save(checked); this.setState({ value: checked }); if (this.props.onChange) this.props.onChange(checked); }; @@ -62,8 +63,8 @@ export default class SettingsFlag extends React.Component { this.onChange(e.target.checked); }; - private save = (val?: boolean): void => { - return SettingsStore.setValue( + private save = async (val?: boolean) => { + await SettingsStore.setValue( this.props.name, this.props.roomId, this.props.level, diff --git a/src/components/views/elements/TextWithTooltip.js b/src/components/views/elements/TextWithTooltip.js index 0c29e01995..b0405dc4c9 100644 --- a/src/components/views/elements/TextWithTooltip.js +++ b/src/components/views/elements/TextWithTooltip.js @@ -47,11 +47,10 @@ export default class TextWithTooltip extends React.Component { return ( {this.props.children} - + className={"mx_TextWithTooltip_tooltip"} /> } ); } diff --git a/src/components/views/groups/GroupMemberList.js b/src/components/views/groups/GroupMemberList.js index 7b643c7346..031b875409 100644 --- a/src/components/views/groups/GroupMemberList.js +++ b/src/components/views/groups/GroupMemberList.js @@ -24,8 +24,9 @@ import GroupStore from '../../../stores/GroupStore'; import PropTypes from 'prop-types'; import { showGroupInviteDialog } from '../../../GroupAddressPicker'; import AccessibleButton from '../elements/AccessibleButton'; -import {RIGHT_PANEL_PHASES} from "../../../stores/RightPanelStorePhases"; +import {RightPanelPhases} from "../../../stores/RightPanelStorePhases"; import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; +import {Action} from "../../../dispatcher/actions"; const INITIAL_LOAD_NUM_MEMBERS = 30; @@ -164,9 +165,9 @@ export default createReactClass({ onInviteToGroupButtonClick() { showGroupInviteDialog(this.props.groupId).then(() => { dis.dispatch({ - action: 'set_right_panel_phase', - phase: RIGHT_PANEL_PHASES.GroupMemberList, - groupId: this.props.groupId, + action: Action.SetRightPanelPhase, + phase: RightPanelPhases.GroupMemberList, + refireParams: { groupId: this.props.groupId }, }); }); }, diff --git a/src/components/views/messages/MKeyVerificationRequest.js b/src/components/views/messages/MKeyVerificationRequest.js index a5b1ae26bb..01a5c2663e 100644 --- a/src/components/views/messages/MKeyVerificationRequest.js +++ b/src/components/views/messages/MKeyVerificationRequest.js @@ -22,7 +22,8 @@ import { _t } from '../../../languageHandler'; import {getNameForEventRoom, userLabelForEventRoom} from '../../../utils/KeyVerificationStateObserver'; import dis from "../../../dispatcher/dispatcher"; -import {RIGHT_PANEL_PHASES} from "../../../stores/RightPanelStorePhases"; +import {RightPanelPhases} from "../../../stores/RightPanelStorePhases"; +import {Action} from "../../../dispatcher/actions"; export default class MKeyVerificationRequest extends React.Component { constructor(props) { @@ -48,8 +49,8 @@ export default class MKeyVerificationRequest extends React.Component { const {verificationRequest} = this.props.mxEvent; const member = MatrixClientPeg.get().getUser(verificationRequest.otherUserId); dis.dispatch({ - action: "set_right_panel_phase", - phase: RIGHT_PANEL_PHASES.EncryptionPanel, + action: Action.SetRightPanelPhase, + phase: RightPanelPhases.EncryptionPanel, refireParams: {verificationRequest, member}, }); }; diff --git a/src/components/views/messages/TextualBody.js b/src/components/views/messages/TextualBody.js index 87df1b8a87..5f9e5e7db1 100644 --- a/src/components/views/messages/TextualBody.js +++ b/src/components/views/messages/TextualBody.js @@ -107,7 +107,7 @@ export default createReactClass({ } else { // Only syntax highlight if there's a class starting with language- const classes = blocks[i].className.split(/\s+/).filter(function(cl) { - return cl.startsWith('language-'); + return cl.startsWith('language-') && !cl.startsWith('language-_'); }); if (classes.length != 0) { diff --git a/src/components/views/right_panel/EncryptionInfo.js b/src/components/views/right_panel/EncryptionInfo.tsx similarity index 87% rename from src/components/views/right_panel/EncryptionInfo.js rename to src/components/views/right_panel/EncryptionInfo.tsx index 007e2831ce..f62af65543 100644 --- a/src/components/views/right_panel/EncryptionInfo.js +++ b/src/components/views/right_panel/EncryptionInfo.tsx @@ -15,10 +15,10 @@ limitations under the License. */ import React from "react"; -import PropTypes from "prop-types"; import * as sdk from "../../../index"; import {_t} from "../../../languageHandler"; +import {RoomMember} from "matrix-js-sdk/src/models/room-member"; export const PendingActionSpinner = ({text}) => { const Spinner = sdk.getComponent('elements.Spinner'); @@ -28,7 +28,17 @@ export const PendingActionSpinner = ({text}) => {
    ; }; -const EncryptionInfo = ({ +interface IProps { + waitingForOtherParty: boolean; + waitingForNetwork: boolean; + member: RoomMember; + onStartVerification: () => Promise; + isRoomEncrypted: boolean; + inDialog: boolean; + isSelfVerification: boolean; +} + +const EncryptionInfo: React.FC = ({ waitingForOtherParty, waitingForNetwork, member, @@ -36,10 +46,10 @@ const EncryptionInfo = ({ isRoomEncrypted, inDialog, isSelfVerification, -}) => { - let content; +}: IProps) => { + let content: JSX.Element; if (waitingForOtherParty || waitingForNetwork) { - let text; + let text: string; if (waitingForOtherParty) { if (isSelfVerification) { text = _t("Waiting for you to accept on your other session…"); @@ -61,7 +71,7 @@ const EncryptionInfo = ({ ); } - let description; + let description: JSX.Element; if (isRoomEncrypted) { description = (
    @@ -97,10 +107,5 @@ const EncryptionInfo = ({
    ; }; -EncryptionInfo.propTypes = { - member: PropTypes.object.isRequired, - onStartVerification: PropTypes.func.isRequired, - request: PropTypes.object, -}; export default EncryptionInfo; diff --git a/src/components/views/right_panel/EncryptionPanel.js b/src/components/views/right_panel/EncryptionPanel.tsx similarity index 86% rename from src/components/views/right_panel/EncryptionPanel.js rename to src/components/views/right_panel/EncryptionPanel.tsx index e9f94729fa..df52e5cabd 100644 --- a/src/components/views/right_panel/EncryptionPanel.js +++ b/src/components/views/right_panel/EncryptionPanel.tsx @@ -15,7 +15,6 @@ limitations under the License. */ import React, {useCallback, useEffect, useState} from "react"; -import PropTypes from "prop-types"; import EncryptionInfo from "./EncryptionInfo"; import VerificationPanel from "./VerificationPanel"; @@ -26,11 +25,23 @@ import Modal from "../../../Modal"; import {PHASE_REQUESTED, PHASE_UNSENT} from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest"; import * as sdk from "../../../index"; import {_t} from "../../../languageHandler"; +import {VerificationRequest} from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest"; +import {RoomMember} from "matrix-js-sdk/src/models/room-member"; // cancellation codes which constitute a key mismatch const MISMATCHES = ["m.key_mismatch", "m.user_error", "m.mismatched_sas"]; -const EncryptionPanel = (props) => { +interface IProps { + member: RoomMember; + onClose: () => void; + verificationRequest: VerificationRequest; + verificationRequestPromise: Promise; + layout: string; + inDialog: boolean; + isRoomEncrypted: boolean; +} + +const EncryptionPanel: React.FC = (props: IProps) => { const {verificationRequest, verificationRequestPromise, member, onClose, layout, isRoomEncrypted} = props; const [request, setRequest] = useState(verificationRequest); // state to show a spinner immediately after clicking "start verification", @@ -48,10 +59,10 @@ const EncryptionPanel = (props) => { useEffect(() => { async function awaitPromise() { setRequesting(true); - const request = await verificationRequestPromise; + const requestFromPromise = await verificationRequestPromise; setRequesting(false); - setRequest(request); - setPhase(request.phase); + setRequest(requestFromPromise); + setPhase(requestFromPromise.phase); } if (verificationRequestPromise) { awaitPromise(); @@ -90,7 +101,7 @@ const EncryptionPanel = (props) => { } }, [request]); - let cancelButton; + let cancelButton: JSX.Element; if (layout !== "dialog" && request && request.pending) { const AccessibleButton = sdk.getComponent("elements.AccessibleButton"); cancelButton = ( { setRequesting(true); const cli = MatrixClientPeg.get(); const roomId = await ensureDMExists(cli, member.userId); - const verificationRequest = await cli.requestVerificationDM(member.userId, roomId); - setRequest(verificationRequest); - setPhase(verificationRequest.phase); + const verificationRequest_ = await cli.requestVerificationDM(member.userId, roomId); + setRequest(verificationRequest_); + setPhase(verificationRequest_.phase); }, [member.userId]); const requested = @@ -144,12 +155,5 @@ const EncryptionPanel = (props) => { ); } }; -EncryptionPanel.propTypes = { - member: PropTypes.object.isRequired, - onClose: PropTypes.func.isRequired, - verificationRequest: PropTypes.object, - layout: PropTypes.string, - inDialog: PropTypes.bool, -}; export default EncryptionPanel; diff --git a/src/components/views/right_panel/GroupHeaderButtons.js b/src/components/views/right_panel/GroupHeaderButtons.tsx similarity index 60% rename from src/components/views/right_panel/GroupHeaderButtons.js rename to src/components/views/right_panel/GroupHeaderButtons.tsx index 33d9325433..44237e401f 100644 --- a/src/components/views/right_panel/GroupHeaderButtons.js +++ b/src/components/views/right_panel/GroupHeaderButtons.tsx @@ -21,65 +21,68 @@ limitations under the License. import React from 'react'; import { _t } from '../../../languageHandler'; import HeaderButton from './HeaderButton'; -import HeaderButtons, {HEADER_KIND_GROUP} from './HeaderButtons'; -import {RIGHT_PANEL_PHASES} from "../../../stores/RightPanelStorePhases"; +import HeaderButtons, {HeaderKind} from './HeaderButtons'; +import {RightPanelPhases} from "../../../stores/RightPanelStorePhases"; import {Action} from "../../../dispatcher/actions"; import {ActionPayload} from "../../../dispatcher/payloads"; +import {ViewUserPayload} from "../../../dispatcher/payloads/ViewUserPayload"; const GROUP_PHASES = [ - RIGHT_PANEL_PHASES.GroupMemberInfo, - RIGHT_PANEL_PHASES.GroupMemberList, + RightPanelPhases.GroupMemberInfo, + RightPanelPhases.GroupMemberList, ]; const ROOM_PHASES = [ - RIGHT_PANEL_PHASES.GroupRoomList, - RIGHT_PANEL_PHASES.GroupRoomInfo, + RightPanelPhases.GroupRoomList, + RightPanelPhases.GroupRoomInfo, ]; +interface IProps {} + export default class GroupHeaderButtons extends HeaderButtons { - constructor(props) { - super(props, HEADER_KIND_GROUP); - this._onMembersClicked = this._onMembersClicked.bind(this); - this._onRoomsClicked = this._onRoomsClicked.bind(this); + constructor(props: IProps) { + super(props, HeaderKind.Group); + this.onMembersClicked = this.onMembersClicked.bind(this); + this.onRoomsClicked = this.onRoomsClicked.bind(this); } - onAction(payload: ActionPayload) { + protected onAction(payload: ActionPayload) { super.onAction(payload); if (payload.action === Action.ViewUser) { - if (payload.member) { - this.setPhase(RIGHT_PANEL_PHASES.RoomMemberInfo, {member: payload.member}); + if ((payload as ViewUserPayload).member) { + this.setPhase(RightPanelPhases.RoomMemberInfo, {member: payload.member}); } else { - this.setPhase(RIGHT_PANEL_PHASES.GroupMemberList); + this.setPhase(RightPanelPhases.GroupMemberList); } } else if (payload.action === "view_group") { - this.setPhase(RIGHT_PANEL_PHASES.GroupMemberList); + this.setPhase(RightPanelPhases.GroupMemberList); } else if (payload.action === "view_group_room") { this.setPhase( - RIGHT_PANEL_PHASES.GroupRoomInfo, + RightPanelPhases.GroupRoomInfo, {groupRoomId: payload.groupRoomId, groupId: payload.groupId}, ); } else if (payload.action === "view_group_room_list") { - this.setPhase(RIGHT_PANEL_PHASES.GroupRoomList); + this.setPhase(RightPanelPhases.GroupRoomList); } else if (payload.action === "view_group_member_list") { - this.setPhase(RIGHT_PANEL_PHASES.GroupMemberList); + this.setPhase(RightPanelPhases.GroupMemberList); } else if (payload.action === "view_group_user") { - this.setPhase(RIGHT_PANEL_PHASES.GroupMemberInfo, {member: payload.member}); + this.setPhase(RightPanelPhases.GroupMemberInfo, {member: payload.member}); } } - _onMembersClicked() { - if (this.state.phase === RIGHT_PANEL_PHASES.GroupMemberInfo) { + private onMembersClicked() { + if (this.state.phase === RightPanelPhases.GroupMemberInfo) { // send the active phase to trigger a toggle - this.setPhase(RIGHT_PANEL_PHASES.GroupMemberInfo); + this.setPhase(RightPanelPhases.GroupMemberInfo); } else { // This toggles for us, if needed - this.setPhase(RIGHT_PANEL_PHASES.GroupMemberList); + this.setPhase(RightPanelPhases.GroupMemberList); } } - _onRoomsClicked() { + private onRoomsClicked() { // This toggles for us, if needed - this.setPhase(RIGHT_PANEL_PHASES.GroupRoomList); + this.setPhase(RightPanelPhases.GroupRoomList); } renderButtons() { @@ -87,13 +90,13 @@ export default class GroupHeaderButtons extends HeaderButtons { , , ]; diff --git a/src/components/views/right_panel/HeaderButton.js b/src/components/views/right_panel/HeaderButton.tsx similarity index 79% rename from src/components/views/right_panel/HeaderButton.js rename to src/components/views/right_panel/HeaderButton.tsx index 2cfc060bba..c7cd064184 100644 --- a/src/components/views/right_panel/HeaderButton.js +++ b/src/components/views/right_panel/HeaderButton.tsx @@ -19,23 +19,38 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import classNames from 'classnames'; import Analytics from '../../../Analytics'; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; -export default class HeaderButton extends React.Component { - constructor() { - super(); +interface IProps { + // Whether this button is highlighted + isHighlighted: boolean; + // click handler + onClick: () => void; + // The badge to display above the icon + badge?: React.ReactNode; + // The parameters to track the click event + analytics: string[]; + + // Button name + name: string; + // Button title + title: string; +} + +export default class HeaderButton extends React.Component { + constructor(props: IProps) { + super(props); this.onClick = this.onClick.bind(this); } - onClick(ev) { + private onClick() { Analytics.trackEvent(...this.props.analytics); this.props.onClick(); } - render() { + public render() { const classes = classNames({ mx_RightPanel_headerButton: true, mx_RightPanel_headerButton_highlight: this.props.isHighlighted, @@ -51,19 +66,3 @@ export default class HeaderButton extends React.Component { />; } } - -HeaderButton.propTypes = { - // Whether this button is highlighted - isHighlighted: PropTypes.bool.isRequired, - // click handler - onClick: PropTypes.func.isRequired, - // The badge to display above the icon - badge: PropTypes.node, - // The parameters to track the click event - analytics: PropTypes.arrayOf(PropTypes.string).isRequired, - - // Button name - name: PropTypes.string.isRequired, - // Button title - title: PropTypes.string.isRequired, -}; diff --git a/src/components/views/right_panel/HeaderButtons.js b/src/components/views/right_panel/HeaderButtons.js deleted file mode 100644 index 1c66fe5828..0000000000 --- a/src/components/views/right_panel/HeaderButtons.js +++ /dev/null @@ -1,88 +0,0 @@ -/* -Copyright 2015, 2016 OpenMarket Ltd -Copyright 2017 Vector Creations Ltd -Copyright 2017 New Vector Ltd -Copyright 2018 New Vector Ltd -Copyright 2019 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import React from 'react'; -import dis from '../../../dispatcher/dispatcher'; -import RightPanelStore from "../../../stores/RightPanelStore"; - -export const HEADER_KIND_ROOM = "room"; -export const HEADER_KIND_GROUP = "group"; - -const HEADER_KINDS = [HEADER_KIND_GROUP, HEADER_KIND_ROOM]; - -export default class HeaderButtons extends React.Component { - constructor(props, kind) { - super(props); - - if (!HEADER_KINDS.includes(kind)) throw new Error(`Invalid header kind: ${kind}`); - - const rps = RightPanelStore.getSharedInstance(); - this.state = { - headerKind: kind, - phase: kind === HEADER_KIND_ROOM ? rps.visibleRoomPanelPhase : rps.visibleGroupPanelPhase, - }; - } - - componentDidMount() { - this._storeToken = RightPanelStore.getSharedInstance().addListener(this.onRightPanelUpdate.bind(this)); - this._dispatcherRef = dis.register(this.onAction.bind(this)); // used by subclasses - } - - componentWillUnmount() { - if (this._storeToken) this._storeToken.remove(); - if (this._dispatcherRef) dis.unregister(this._dispatcherRef); - } - - onAction(payload) { - // Ignore - intended to be overridden by subclasses - } - - setPhase(phase, extras) { - dis.dispatch({ - action: 'set_right_panel_phase', - phase: phase, - refireParams: extras, - }); - } - - isPhase(phases: string | string[]) { - if (Array.isArray(phases)) { - return phases.includes(this.state.phase); - } else { - return phases === this.state.phase; - } - } - - onRightPanelUpdate() { - const rps = RightPanelStore.getSharedInstance(); - if (this.state.headerKind === HEADER_KIND_ROOM) { - this.setState({phase: rps.visibleRoomPanelPhase}); - } else if (this.state.headerKind === HEADER_KIND_GROUP) { - this.setState({phase: rps.visibleGroupPanelPhase}); - } - } - - render() { - // inline style as this will be swapped around in future commits - return
    - {this.renderButtons()} -
    ; - } -} diff --git a/src/components/views/right_panel/HeaderButtons.tsx b/src/components/views/right_panel/HeaderButtons.tsx new file mode 100644 index 0000000000..57d3075739 --- /dev/null +++ b/src/components/views/right_panel/HeaderButtons.tsx @@ -0,0 +1,110 @@ +/* +Copyright 2015, 2016 OpenMarket Ltd +Copyright 2017 Vector Creations Ltd +Copyright 2017 New Vector Ltd +Copyright 2018 New Vector Ltd +Copyright 2019 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from 'react'; +import dis from '../../../dispatcher/dispatcher'; +import RightPanelStore from "../../../stores/RightPanelStore"; +import {RightPanelPhases} from "../../../stores/RightPanelStorePhases"; +import {Action} from '../../../dispatcher/actions'; +import {SetRightPanelPhasePayload, SetRightPanelPhaseRefireParams} from '../../../dispatcher/payloads/SetRightPanelPhasePayload'; +import {EventSubscription} from "fbemitter"; + +export enum HeaderKind { + Room = "room", + Group = "group", +} + +interface IState { + headerKind: HeaderKind; + phase: RightPanelPhases; +} + +interface IProps {} + +export default class HeaderButtons extends React.Component { + private storeToken: EventSubscription; + private dispatcherRef: string; + + constructor(props: IProps, kind: HeaderKind) { + super(props); + + const rps = RightPanelStore.getSharedInstance(); + this.state = { + headerKind: kind, + phase: kind === HeaderKind.Room ? rps.visibleRoomPanelPhase : rps.visibleGroupPanelPhase, + }; + } + + public componentDidMount() { + this.storeToken = RightPanelStore.getSharedInstance().addListener(this.onRightPanelUpdate.bind(this)); + this.dispatcherRef = dis.register(this.onAction.bind(this)); // used by subclasses + } + + public componentWillUnmount() { + if (this.storeToken) this.storeToken.remove(); + if (this.dispatcherRef) dis.unregister(this.dispatcherRef); + } + + protected onAction(payload) { + // Ignore - intended to be overridden by subclasses + } + + public setPhase(phase: RightPanelPhases, extras?: Partial) { + dis.dispatch({ + action: Action.SetRightPanelPhase, + phase: phase, + refireParams: extras, + }); + } + + public isPhase(phases: string | string[]) { + if (Array.isArray(phases)) { + return phases.includes(this.state.phase); + } else { + return phases === this.state.phase; + } + } + + private onRightPanelUpdate() { + const rps = RightPanelStore.getSharedInstance(); + if (this.state.headerKind === HeaderKind.Room) { + this.setState({phase: rps.visibleRoomPanelPhase}); + } else if (this.state.headerKind === HeaderKind.Group) { + this.setState({phase: rps.visibleGroupPanelPhase}); + } + } + + // XXX: Make renderButtons a prop + public renderButtons(): JSX.Element[] { + // Ignore - intended to be overridden by subclasses + // Return empty fragment to satisfy the type + return [ + + + ]; + } + + public render() { + // inline style as this will be swapped around in future commits + return
    + {this.renderButtons()} +
    ; + } +} diff --git a/src/components/views/right_panel/RoomHeaderButtons.js b/src/components/views/right_panel/RoomHeaderButtons.tsx similarity index 59% rename from src/components/views/right_panel/RoomHeaderButtons.js rename to src/components/views/right_panel/RoomHeaderButtons.tsx index 838727981d..7ac547f499 100644 --- a/src/components/views/right_panel/RoomHeaderButtons.js +++ b/src/components/views/right_panel/RoomHeaderButtons.tsx @@ -21,82 +21,82 @@ limitations under the License. import React from 'react'; import { _t } from '../../../languageHandler'; import HeaderButton from './HeaderButton'; -import HeaderButtons, {HEADER_KIND_ROOM} from './HeaderButtons'; -import {RIGHT_PANEL_PHASES} from "../../../stores/RightPanelStorePhases"; +import HeaderButtons, {HeaderKind} from './HeaderButtons'; +import {RightPanelPhases} from "../../../stores/RightPanelStorePhases"; import {Action} from "../../../dispatcher/actions"; import {ActionPayload} from "../../../dispatcher/payloads"; const MEMBER_PHASES = [ - RIGHT_PANEL_PHASES.RoomMemberList, - RIGHT_PANEL_PHASES.RoomMemberInfo, - RIGHT_PANEL_PHASES.EncryptionPanel, - RIGHT_PANEL_PHASES.Room3pidMemberInfo, + RightPanelPhases.RoomMemberList, + RightPanelPhases.RoomMemberInfo, + RightPanelPhases.EncryptionPanel, + RightPanelPhases.Room3pidMemberInfo, ]; export default class RoomHeaderButtons extends HeaderButtons { constructor(props) { - super(props, HEADER_KIND_ROOM); - this._onMembersClicked = this._onMembersClicked.bind(this); - this._onFilesClicked = this._onFilesClicked.bind(this); - this._onNotificationsClicked = this._onNotificationsClicked.bind(this); + super(props, HeaderKind.Room); + this.onMembersClicked = this.onMembersClicked.bind(this); + this.onFilesClicked = this.onFilesClicked.bind(this); + this.onNotificationsClicked = this.onNotificationsClicked.bind(this); } - onAction(payload: ActionPayload) { + protected onAction(payload: ActionPayload) { super.onAction(payload); if (payload.action === Action.ViewUser) { if (payload.member) { - this.setPhase(RIGHT_PANEL_PHASES.RoomMemberInfo, {member: payload.member}); + this.setPhase(RightPanelPhases.RoomMemberInfo, {member: payload.member}); } else { - this.setPhase(RIGHT_PANEL_PHASES.RoomMemberList); + this.setPhase(RightPanelPhases.RoomMemberList); } } else if (payload.action === "view_3pid_invite") { if (payload.event) { - this.setPhase(RIGHT_PANEL_PHASES.Room3pidMemberInfo, {event: payload.event}); + this.setPhase(RightPanelPhases.Room3pidMemberInfo, {event: payload.event}); } else { - this.setPhase(RIGHT_PANEL_PHASES.RoomMemberList); + this.setPhase(RightPanelPhases.RoomMemberList); } } } - _onMembersClicked() { - if (this.state.phase === RIGHT_PANEL_PHASES.RoomMemberInfo) { + private onMembersClicked() { + if (this.state.phase === RightPanelPhases.RoomMemberInfo) { // send the active phase to trigger a toggle // XXX: we should pass refireParams here but then it won't collapse as we desire it to - this.setPhase(RIGHT_PANEL_PHASES.RoomMemberInfo); + this.setPhase(RightPanelPhases.RoomMemberInfo); } else { // This toggles for us, if needed - this.setPhase(RIGHT_PANEL_PHASES.RoomMemberList); + this.setPhase(RightPanelPhases.RoomMemberList); } } - _onFilesClicked() { + private onFilesClicked() { // This toggles for us, if needed - this.setPhase(RIGHT_PANEL_PHASES.FilePanel); + this.setPhase(RightPanelPhases.FilePanel); } - _onNotificationsClicked() { + private onNotificationsClicked() { // This toggles for us, if needed - this.setPhase(RIGHT_PANEL_PHASES.NotificationPanel); + this.setPhase(RightPanelPhases.NotificationPanel); } - renderButtons() { + public renderButtons() { return [ , , , ]; diff --git a/src/components/views/right_panel/UserInfo.js b/src/components/views/right_panel/UserInfo.js index 719a64063d..b52792b3d1 100644 --- a/src/components/views/right_panel/UserInfo.js +++ b/src/components/views/right_panel/UserInfo.js @@ -40,7 +40,7 @@ import E2EIcon from "../rooms/E2EIcon"; import {useEventEmitter} from "../../../hooks/useEventEmitter"; import {textualPowerLevel} from '../../../Roles'; import MatrixClientContext from "../../../contexts/MatrixClientContext"; -import {RIGHT_PANEL_PHASES} from "../../../stores/RightPanelStorePhases"; +import {RightPanelPhases} from "../../../stores/RightPanelStorePhases"; import EncryptionPanel from "./EncryptionPanel"; import { useAsyncMemo } from '../../../hooks/useAsyncMemo'; import { verifyUser, legacyVerifyUser, verifyDevice } from '../../../verification'; @@ -550,7 +550,9 @@ const RedactMessagesButton = ({member}) => { let eventsToRedact = []; while (timeline) { eventsToRedact = timeline.getEvents().reduce((events, event) => { - if (event.getSender() === userId && !event.isRedacted() && !event.isRedaction()) { + if (event.getSender() === userId && !event.isRedacted() && !event.isRedaction() && + event.getType() !== "m.room.create" + ) { return events.concat(event); } else { return events; @@ -1480,7 +1482,7 @@ const UserInfoHeader = ({onClose, member, e2eStatus}) => { ; }; -const UserInfo = ({user, groupId, roomId, onClose, phase=RIGHT_PANEL_PHASES.RoomMemberInfo, ...props}) => { +const UserInfo = ({user, groupId, roomId, onClose, phase=RightPanelPhases.RoomMemberInfo, ...props}) => { const cli = useContext(MatrixClientContext); // Load room if we are given a room id and memoize it @@ -1500,8 +1502,8 @@ const UserInfo = ({user, groupId, roomId, onClose, phase=RIGHT_PANEL_PHASES.Room let content; switch (phase) { - case RIGHT_PANEL_PHASES.RoomMemberInfo: - case RIGHT_PANEL_PHASES.GroupMemberInfo: + case RightPanelPhases.RoomMemberInfo: + case RightPanelPhases.GroupMemberInfo: content = ( ); break; - case RIGHT_PANEL_PHASES.EncryptionPanel: + case RightPanelPhases.EncryptionPanel: classes.push("mx_UserInfo_smallAvatar"); content = ( diff --git a/src/components/views/right_panel/VerificationPanel.js b/src/components/views/right_panel/VerificationPanel.tsx similarity index 79% rename from src/components/views/right_panel/VerificationPanel.js rename to src/components/views/right_panel/VerificationPanel.tsx index 0b6790eac8..9cb7f54dd8 100644 --- a/src/components/views/right_panel/VerificationPanel.js +++ b/src/components/views/right_panel/VerificationPanel.tsx @@ -15,12 +15,15 @@ limitations under the License. */ import React from "react"; -import PropTypes from "prop-types"; import {MatrixClientPeg} from "../../../MatrixClientPeg"; import * as sdk from '../../../index'; import {verificationMethods} from 'matrix-js-sdk/src/crypto'; import {SCAN_QR_CODE_METHOD} from "matrix-js-sdk/src/crypto/verification/QRCode"; +import {VerificationRequest} from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest"; +import {RoomMember} from "matrix-js-sdk/src/models/room-member"; +import {ReciprocateQRCode} from "matrix-js-sdk/src/crypto/verification/QRCode"; +import {SAS} from "matrix-js-sdk/src/crypto/verification/SAS"; import VerificationQRCode from "../elements/crypto/VerificationQRCode"; import {_t} from "../../../languageHandler"; @@ -36,37 +39,51 @@ import { } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest"; import Spinner from "../elements/Spinner"; -export default class VerificationPanel extends React.PureComponent { - static propTypes = { - layout: PropTypes.string, - request: PropTypes.object.isRequired, - member: PropTypes.object.isRequired, - phase: PropTypes.oneOf([ - PHASE_UNSENT, - PHASE_REQUESTED, - PHASE_READY, - PHASE_STARTED, - PHASE_CANCELLED, - PHASE_DONE, - ]).isRequired, - onClose: PropTypes.func.isRequired, - isRoomEncrypted: PropTypes.bool, - }; +// XXX: Should be defined in matrix-js-sdk +enum VerificationPhase { + PHASE_UNSENT, + PHASE_REQUESTED, + PHASE_READY, + PHASE_DONE, + PHASE_STARTED, + PHASE_CANCELLED, +} - constructor(props) { +interface IProps { + layout: string; + request: VerificationRequest; + member: RoomMember; + phase: VerificationPhase; + onClose: () => void; + isRoomEncrypted: boolean; + inDialog: boolean; + key: number; +} + +interface IState { + sasEvent?: SAS; + emojiButtonClicked?: boolean; + reciprocateButtonClicked?: boolean; + reciprocateQREvent?: ReciprocateQRCode; +} + +export default class VerificationPanel extends React.PureComponent { + private hasVerifier: boolean; + + constructor(props: IProps) { super(props); this.state = {}; - this._hasVerifier = false; + this.hasVerifier = false; } - renderQRPhase() { + private renderQRPhase() { const {member, request} = this.props; - const showSAS = request.otherPartySupportsMethod(verificationMethods.SAS); - const showQR = request.otherPartySupportsMethod(SCAN_QR_CODE_METHOD); + const showSAS: boolean = request.otherPartySupportsMethod(verificationMethods.SAS); + const showQR: boolean = request.otherPartySupportsMethod(SCAN_QR_CODE_METHOD); const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); const brand = SdkConfig.get().brand; - const noCommonMethodError = !showSAS && !showQR ? + const noCommonMethodError: JSX.Element = !showSAS && !showQR ?

    {_t( "The session you are trying to verify doesn't support scanning a " + "QR code or emoji verification, which is what %(brand)s supports. Try " + @@ -77,41 +94,41 @@ export default class VerificationPanel extends React.PureComponent { if (this.props.layout === 'dialog') { // HACK: This is a terrible idea. - let qrBlock; - let sasBlock; + let qrBlockDialog: JSX.Element; + let sasBlockDialog: JSX.Element; if (showQR) { - qrBlock = + qrBlockDialog =

    {_t("Scan this unique code")}

    ; } if (showSAS) { - sasBlock = + sasBlockDialog =

    {_t("Compare unique emoji")}

    {_t("Compare a unique set of emoji if you don't have a camera on either device")} - + {_t("Start")}
    ; } - const or = qrBlock && sasBlock ? + const or = qrBlockDialog && sasBlockDialog ?
    {_t("or")}
    : null; return (
    {_t("Verify this session by completing one of the following:")}
    - {qrBlock} + {qrBlockDialog} {or} - {sasBlock} + {sasBlockDialog} {noCommonMethodError}
    ); } - let qrBlock; + let qrBlock: JSX.Element; if (showQR) { qrBlock =

    {_t("Verify by scanning")}

    @@ -125,7 +142,7 @@ export default class VerificationPanel extends React.PureComponent {
    ; } - let sasBlock; + let sasBlock: JSX.Element; if (showSAS) { const disabled = this.state.emojiButtonClicked; const sasLabel = showQR ? @@ -140,7 +157,7 @@ export default class VerificationPanel extends React.PureComponent { disabled={disabled} kind="primary" className="mx_UserInfo_wideButton mx_VerificationPanel_verifyByEmojiButton" - onClick={this._startSAS} + onClick={this.startSAS} > {_t("Verify by emoji")}
    @@ -159,22 +176,22 @@ export default class VerificationPanel extends React.PureComponent { ; } - _onReciprocateYesClick = () => { + private onReciprocateYesClick = () => { this.setState({reciprocateButtonClicked: true}); this.state.reciprocateQREvent.confirm(); }; - _onReciprocateNoClick = () => { + private onReciprocateNoClick = () => { this.setState({reciprocateButtonClicked: true}); this.state.reciprocateQREvent.cancel(); }; - _getDevice() { + private getDevice() { const deviceId = this.props.request && this.props.request.channel.deviceId; return MatrixClientPeg.get().getStoredDevice(MatrixClientPeg.get().getUserId(), deviceId); } - renderQRReciprocatePhase() { + private renderQRReciprocatePhase() { const {member, request} = this.props; let Button; // a bit of a hack, but the FormButton should only be used in the right panel @@ -189,7 +206,7 @@ export default class VerificationPanel extends React.PureComponent { _t("Almost there! Is %(displayName)s showing the same shield?", { displayName: member.displayName || member.name || member.userId, }); - let body; + let body: JSX.Element; if (this.state.reciprocateQREvent) { // riot web doesn't support scanning yet, so assume here we're the client being scanned. // @@ -202,11 +219,11 @@ export default class VerificationPanel extends React.PureComponent { + onClick={this.onReciprocateNoClick}>{_t("No")} + onClick={this.onReciprocateYesClick}>{_t("Yes")} ; } else { @@ -218,10 +235,10 @@ export default class VerificationPanel extends React.PureComponent { ; } - renderVerifiedPhase() { + private renderVerifiedPhase() { const {member, request} = this.props; - let text; + let text: string; if (!request.isSelfVerification) { if (this.props.isRoomEncrypted) { text = _t("Verify all users in a room to ensure it's secure."); @@ -230,9 +247,9 @@ export default class VerificationPanel extends React.PureComponent { } } - let description; + let description: string; if (request.isSelfVerification) { - const device = this._getDevice(); + const device = this.getDevice(); if (!device) { // This can happen if the device is logged out while we're still showing verification // UI for it. @@ -264,19 +281,19 @@ export default class VerificationPanel extends React.PureComponent { ); } - renderCancelledPhase() { + private renderCancelledPhase() { const {member, request} = this.props; const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); - let startAgainInstruction; + let startAgainInstruction: string; if (request.isSelfVerification) { startAgainInstruction = _t("Start verification again from the notification."); } else { startAgainInstruction = _t("Start verification again from their profile."); } - let text; + let text: string; if (request.cancellationCode === "m.timeout") { text = _t("Verification timed out.") + ` ${startAgainInstruction}`; } else if (request.cancellingUserId === request.otherUserId) { @@ -304,7 +321,7 @@ export default class VerificationPanel extends React.PureComponent { ); } - render() { + public render() { const {member, phase, request} = this.props; const displayName = member.displayName || member.name || member.userId; @@ -321,10 +338,10 @@ export default class VerificationPanel extends React.PureComponent { const emojis = this.state.sasEvent ? : ; @@ -345,7 +362,7 @@ export default class VerificationPanel extends React.PureComponent { return null; } - _startSAS = async () => { + private startSAS = async () => { this.setState({emojiButtonClicked: true}); const verifier = this.props.request.beginKeyVerification(verificationMethods.SAS); try { @@ -355,31 +372,31 @@ export default class VerificationPanel extends React.PureComponent { } }; - _onSasMatchesClick = () => { + private onSasMatchesClick = () => { this.state.sasEvent.confirm(); }; - _onSasMismatchesClick = () => { + private onSasMismatchesClick = () => { this.state.sasEvent.mismatch(); }; - _updateVerifierState = () => { + private updateVerifierState = () => { const {request} = this.props; const {sasEvent, reciprocateQREvent} = request.verifier; - request.verifier.off('show_sas', this._updateVerifierState); - request.verifier.off('show_reciprocate_qr', this._updateVerifierState); + request.verifier.off('show_sas', this.updateVerifierState); + request.verifier.off('show_reciprocate_qr', this.updateVerifierState); this.setState({sasEvent, reciprocateQREvent}); }; - _onRequestChange = async () => { + private onRequestChange = async () => { const {request} = this.props; - const hadVerifier = this._hasVerifier; - this._hasVerifier = !!request.verifier; - if (!hadVerifier && this._hasVerifier) { - request.verifier.on('show_sas', this._updateVerifierState); - request.verifier.on('show_reciprocate_qr', this._updateVerifierState); + const hadVerifier = this.hasVerifier; + this.hasVerifier = !!request.verifier; + if (!hadVerifier && this.hasVerifier) { + request.verifier.on('show_sas', this.updateVerifierState); + request.verifier.on('show_reciprocate_qr', this.updateVerifierState); try { - // on the requester side, this is also awaited in _startSAS, + // on the requester side, this is also awaited in startSAS, // but that's ok as verify should return the same promise. await request.verifier.verify(); } catch (err) { @@ -388,23 +405,22 @@ export default class VerificationPanel extends React.PureComponent { } }; - componentDidMount() { + public componentDidMount() { const {request} = this.props; - request.on("change", this._onRequestChange); + request.on("change", this.onRequestChange); if (request.verifier) { - const {request} = this.props; const {sasEvent, reciprocateQREvent} = request.verifier; this.setState({sasEvent, reciprocateQREvent}); } - this._onRequestChange(); + this.onRequestChange(); } - componentWillUnmount() { + public componentWillUnmount() { const {request} = this.props; if (request.verifier) { - request.verifier.off('show_sas', this._updateVerifierState); - request.verifier.off('show_reciprocate_qr', this._updateVerifierState); + request.verifier.off('show_sas', this.updateVerifierState); + request.verifier.off('show_reciprocate_qr', this.updateVerifierState); } - request.off("change", this._onRequestChange); + request.off("change", this.onRequestChange); } } diff --git a/src/components/views/room_settings/ColorSettings.js b/src/components/views/room_settings/ColorSettings.js index 1d26e956ab..4e8b6ba42f 100644 --- a/src/components/views/room_settings/ColorSettings.js +++ b/src/components/views/room_settings/ColorSettings.js @@ -20,7 +20,8 @@ import createReactClass from 'create-react-class'; import Tinter from '../../../Tinter'; import dis from '../../../dispatcher/dispatcher'; -import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; +import SettingsStore from "../../../settings/SettingsStore"; +import {SettingLevel} from "../../../settings/SettingLevel"; const ROOM_COLORS = [ // magic room default values courtesy of Ribot diff --git a/src/components/views/room_settings/UrlPreviewSettings.js b/src/components/views/room_settings/UrlPreviewSettings.js index 51f6954975..fa5c1baf8f 100644 --- a/src/components/views/room_settings/UrlPreviewSettings.js +++ b/src/components/views/room_settings/UrlPreviewSettings.js @@ -22,10 +22,11 @@ import PropTypes from 'prop-types'; import createReactClass from 'create-react-class'; import * as sdk from "../../../index"; import { _t, _td } from '../../../languageHandler'; -import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; +import SettingsStore from "../../../settings/SettingsStore"; import dis from "../../../dispatcher/dispatcher"; import {MatrixClientPeg} from "../../../MatrixClientPeg"; import {Action} from "../../../dispatcher/actions"; +import {SettingLevel} from "../../../settings/SettingLevel"; export default createReactClass({ diff --git a/src/components/views/rooms/BasicMessageComposer.tsx b/src/components/views/rooms/BasicMessageComposer.tsx index 1e0a639aac..2a909bdd26 100644 --- a/src/components/views/rooms/BasicMessageComposer.tsx +++ b/src/components/views/rooms/BasicMessageComposer.tsx @@ -219,7 +219,9 @@ export default class BasicMessageEditor extends React.Component }; private showPlaceholder() { - this.editorRef.current.style.setProperty("--placeholder", `'${this.props.placeholder}'`); + // escape single quotes + const placeholder = this.props.placeholder.replace(/'/g, '\\\''); + this.editorRef.current.style.setProperty("--placeholder", `'${placeholder}'`); this.editorRef.current.classList.add("mx_BasicMessageComposer_inputEmpty"); } diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js index f6eaf5f003..13554eb3d6 100644 --- a/src/components/views/rooms/EventTile.js +++ b/src/components/views/rooms/EventTile.js @@ -685,6 +685,9 @@ export default createReactClass({ mx_EventTile_emote: msgtype === 'm.emote', }); + // If the tile is in the Sending state, don't speak the message. + const ariaLive = (this.props.eventSendStatus !== null) ? 'off' : undefined; + let permalink = "#"; if (this.props.permalinkCreator) { permalink = this.props.permalinkCreator.forEvent(this.props.mxEvent.getId()); @@ -819,7 +822,7 @@ export default createReactClass({ case 'notif': { const room = this.context.getRoom(this.props.mxEvent.getRoomId()); return ( -
    +
    { room ? room.name : '' } @@ -845,7 +848,7 @@ export default createReactClass({ } case 'file_grid': { return ( -
    +
    +
    { ircTimestamp } { avatar } { sender } @@ -911,7 +914,7 @@ export default createReactClass({ // tab-index=-1 to allow it to be focusable but do not add tab stop for it, primarily for screen readers return ( -
    +
    { ircTimestamp }
    { readAvatars } diff --git a/src/components/views/rooms/NotificationBadge.tsx b/src/components/views/rooms/NotificationBadge.tsx index d215df9126..ab6ec3fbed 100644 --- a/src/components/views/rooms/NotificationBadge.tsx +++ b/src/components/views/rooms/NotificationBadge.tsx @@ -72,6 +72,7 @@ export default class NotificationBadge extends React.PureComponent) { diff --git a/src/components/views/rooms/ReplyPreview.js b/src/components/views/rooms/ReplyPreview.js index e7cd2b4c0d..de70338245 100644 --- a/src/components/views/rooms/ReplyPreview.js +++ b/src/components/views/rooms/ReplyPreview.js @@ -73,7 +73,7 @@ export default class ReplyPreview extends React.Component { return
    - { '💬 ' + _t('Replying') } + { _t('Replying') }
    void; @@ -50,7 +51,6 @@ interface IProps { onResize: () => void; resizeNotifier: ResizeNotifier; collapsed: boolean; - searchFilter: string; isMinimized: boolean; } @@ -80,7 +80,7 @@ interface ITagAesthetics { sectionLabel: string; sectionLabelRaw?: string; addRoomLabel?: string; - onAddRoom?: (dispatcher: Dispatcher) => void; + onAddRoom?: (dispatcher?: Dispatcher) => void; isInvite: boolean; defaultHidden: boolean; } @@ -104,14 +104,18 @@ const TAG_AESTHETICS: { isInvite: false, defaultHidden: false, addRoomLabel: _td("Start chat"), - onAddRoom: (dispatcher: Dispatcher) => dispatcher.dispatch({action: 'view_create_chat'}), + onAddRoom: (dispatcher?: Dispatcher) => { + (dispatcher || defaultDispatcher).dispatch({action: 'view_create_chat'}); + }, }, [DefaultTagID.Untagged]: { sectionLabel: _td("Rooms"), isInvite: false, defaultHidden: false, addRoomLabel: _td("Create room"), - onAddRoom: (dispatcher: Dispatcher) => dispatcher.dispatch({action: 'view_create_room'}), + onAddRoom: (dispatcher?: Dispatcher) => { + (dispatcher || defaultDispatcher).dispatch({action: 'view_create_room'}) + }, }, [DefaultTagID.LowPriority]: { sectionLabel: _td("Low priority"), @@ -144,8 +148,7 @@ function customTagAesthetics(tagId: TagID): ITagAesthetics { }; } -export default class RoomList extends React.Component { - private searchFilter: NameFilterCondition = new NameFilterCondition(); +export default class RoomList extends React.PureComponent { private dispatcherRef; private customTagStoreRef; @@ -159,21 +162,6 @@ export default class RoomList extends React.Component { this.dispatcherRef = defaultDispatcher.register(this.onAction); } - public componentDidUpdate(prevProps: Readonly): void { - if (prevProps.searchFilter !== this.props.searchFilter) { - const hadSearch = !!this.searchFilter.search.trim(); - const haveSearch = !!this.props.searchFilter.trim(); - this.searchFilter.search = this.props.searchFilter; - if (!hadSearch && haveSearch) { - // started a new filter - add the condition - RoomListStore.instance.addFilter(this.searchFilter); - } else if (hadSearch && !haveSearch) { - // cleared a filter - remove the condition - RoomListStore.instance.removeFilter(this.searchFilter); - } // else the filter hasn't changed enough for us to care here - } - } - public componentDidMount(): void { RoomListStore.instance.on(LISTS_UPDATE_EVENT, this.updateLists); this.customTagStoreRef = CustomRoomTagStore.addListener(this.updateLists); @@ -210,7 +198,7 @@ export default class RoomList extends React.Component { if (unread) { // filter to only notification rooms (and our current active room so we can index properly) listRooms = listRooms.filter(r => { - const state = RoomNotificationStateStore.instance.getRoomState(r, t); + const state = RoomNotificationStateStore.instance.getRoomState(r); return state.room.roomId === roomId || state.isUnread; }); } @@ -231,17 +219,46 @@ export default class RoomList extends React.Component { console.log("new lists", newLists); } - this.setState({sublists: newLists}, () => { - this.props.onResize(); + const previousListIds = Object.keys(this.state.sublists); + const newListIds = Object.keys(newLists).filter(t => { + if (!isCustomTag(t)) return true; // always include non-custom tags + + // if the tag is custom though, only include it if it is enabled + return CustomRoomTagStore.getTags()[t]; }); + + let doUpdate = arrayHasDiff(previousListIds, newListIds); + if (!doUpdate) { + // so we didn't have the visible sublists change, but did the contents of those + // sublists change significantly enough to break the sticky headers? Probably, so + // let's check the length of each. + for (const tagId of newListIds) { + const oldRooms = this.state.sublists[tagId]; + const newRooms = newLists[tagId]; + if (oldRooms.length !== newRooms.length) { + doUpdate = true; + break; + } + } + } + + if (doUpdate) { + // We have to break our reference to the room list store if we want to be able to + // diff the object for changes, so do that. + const newSublists = objectWithOnly(newLists, newListIds); + const sublists = objectShallowClone(newSublists, (k, v) => arrayFastClone(v)); + + this.setState({sublists}, () => { + this.props.onResize(); + }); + } }; - private renderCommunityInvites(): React.ReactElement[] { + private renderCommunityInvites(): TemporaryTile[] { // TODO: Put community invites in a more sensible place (not in the room list) // See https://github.com/vector-im/riot-web/issues/14456 return MatrixClientPeg.get().getGroups().filter(g => { - if (g.myMembership !== 'invite') return false; - return !this.searchFilter || this.searchFilter.matches(g.name || ""); + return g.myMembership === 'invite'; }).map(g => { const avatar = ( { const tagOrder = TAG_ORDER.reduce((p, c) => { if (c === CUSTOM_TAGS_BEFORE_TAG) { const customTags = Object.keys(this.state.sublists) - .filter(t => isCustomTag(t)) - .filter(t => CustomRoomTagStore.getTags()[t]); // isSelected + .filter(t => isCustomTag(t)); p.push(...customTags); } p.push(c); @@ -298,21 +314,18 @@ export default class RoomList extends React.Component { : TAG_AESTHETICS[orderedTagId]; if (!aesthetics) throw new Error(`Tag ${orderedTagId} does not have aesthetics`); - const onAddRoomFn = aesthetics.onAddRoom ? () => aesthetics.onAddRoom(dis) : null; components.push( ); } diff --git a/src/components/views/rooms/RoomPreviewBar.js b/src/components/views/rooms/RoomPreviewBar.js index 5c181ec3c4..9aa78fbbfd 100644 --- a/src/components/views/rooms/RoomPreviewBar.js +++ b/src/components/views/rooms/RoomPreviewBar.js @@ -288,7 +288,6 @@ export default createReactClass({ const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); let showSpinner = false; - let darkStyle = false; let title; let subTitle; let primaryActionHandler; @@ -316,7 +315,6 @@ export default createReactClass({ break; } case MessageCase.NotLoggedIn: { - darkStyle = true; title = _t("Join the conversation with an account"); primaryActionLabel = _t("Sign Up"); primaryActionHandler = this.onRegisterClick; @@ -557,7 +555,6 @@ export default createReactClass({ const classes = classNames("mx_RoomPreviewBar", "dark-panel", `mx_RoomPreviewBar_${messageCase}`, { "mx_RoomPreviewBar_panel": this.props.canPreview, "mx_RoomPreviewBar_dialog": !this.props.canPreview, - "mx_RoomPreviewBar_dark": darkStyle, }); return ( diff --git a/src/components/views/rooms/RoomRecoveryReminder.js b/src/components/views/rooms/RoomRecoveryReminder.js index a29467b07f..859df6dd1b 100644 --- a/src/components/views/rooms/RoomRecoveryReminder.js +++ b/src/components/views/rooms/RoomRecoveryReminder.js @@ -21,7 +21,8 @@ import * as sdk from "../../../index"; import { _t } from "../../../languageHandler"; import Modal from "../../../Modal"; import {MatrixClientPeg} from "../../../MatrixClientPeg"; -import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; +import SettingsStore from "../../../settings/SettingsStore"; +import {SettingLevel} from "../../../settings/SettingLevel"; export default class RoomRecoveryReminder extends React.PureComponent { static propTypes = { diff --git a/src/components/views/rooms/RoomSublist.tsx b/src/components/views/rooms/RoomSublist.tsx index 18bf56e9ba..f6d0d1c22e 100644 --- a/src/components/views/rooms/RoomSublist.tsx +++ b/src/components/views/rooms/RoomSublist.tsx @@ -32,13 +32,12 @@ import { StyledMenuItemCheckbox, StyledMenuItemRadio, } from "../../structures/ContextMenu"; -import RoomListStore from "../../../stores/room-list/RoomListStore"; +import RoomListStore, { LISTS_UPDATE_EVENT } from "../../../stores/room-list/RoomListStore"; import { ListAlgorithm, SortAlgorithm } from "../../../stores/room-list/algorithms/models"; import { DefaultTagID, TagID } from "../../../stores/room-list/models"; import dis from "../../../dispatcher/dispatcher"; import defaultDispatcher from "../../../dispatcher/dispatcher"; import NotificationBadge from "./NotificationBadge"; -import { ListNotificationState } from "../../../stores/notifications/ListNotificationState"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; import { Key } from "../../../Keyboard"; import { ActionPayload } from "../../../dispatcher/payloads"; @@ -47,6 +46,10 @@ import { Direction } from "re-resizable/lib/resizer"; import { polyfillTouchEvent } from "../../../@types/polyfill"; import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore"; import RoomListLayoutStore from "../../../stores/room-list/RoomListLayoutStore"; +import { arrayFastClone, arrayHasOrderChange } from "../../../utils/arrays"; +import { objectExcluding, objectHasDiff } from "../../../utils/objects"; +import TemporaryTile from "./TemporaryTile"; +import { ListNotificationState } from "../../../stores/notifications/ListNotificationState"; const SHOW_N_BUTTON_HEIGHT = 28; // As defined by CSS const RESIZE_HANDLE_HEIGHT = 4; // As defined by CSS @@ -59,7 +62,6 @@ polyfillTouchEvent(); interface IProps { forRooms: boolean; - rooms?: Room[]; startAsHidden: boolean; label: string; onAddRoom?: () => void; @@ -67,11 +69,10 @@ interface IProps { isMinimized: boolean; tagId: TagID; onResize: () => void; - isFiltered: boolean; // TODO: Don't use this. It's for community invites, and community invites shouldn't be here. // You should feel bad if you use this. - extraBadTilesThatShouldntExist?: React.ReactElement[]; + extraBadTilesThatShouldntExist?: TemporaryTile[]; // TODO: Account for https://github.com/vector-im/riot-web/issues/14179 } @@ -85,11 +86,12 @@ interface ResizeDelta { type PartialDOMRect = Pick; interface IState { - notificationState: ListNotificationState; contextMenuPosition: PartialDOMRect; isResizing: boolean; isExpanded: boolean; // used for the for expand of the sublist when the room list is being filtered height: number; + rooms: Room[]; + filteredExtraTiles?: TemporaryTile[]; } export default class RoomSublist extends React.Component { @@ -98,22 +100,27 @@ export default class RoomSublist extends React.Component { private dispatcherRef: string; private layout: ListLayout; private heightAtStart: number; + private isBeingFiltered: boolean; + private notificationState: ListNotificationState; constructor(props: IProps) { super(props); this.layout = RoomListLayoutStore.instance.getLayoutFor(this.props.tagId); this.heightAtStart = 0; - const height = this.calculateInitialHeight(); + this.isBeingFiltered = !!RoomListStore.instance.getFirstNameFilterCondition(); + this.notificationState = RoomNotificationStateStore.instance.getListState(this.props.tagId); this.state = { - notificationState: RoomNotificationStateStore.instance.getListState(this.props.tagId), contextMenuPosition: null, isResizing: false, - isExpanded: this.props.isFiltered ? this.props.isFiltered : !this.layout.isCollapsed, - height, + isExpanded: this.isBeingFiltered ? this.isBeingFiltered : !this.layout.isCollapsed, + height: 0, // to be fixed in a moment, we need `rooms` to calculate this. + rooms: arrayFastClone(RoomListStore.instance.orderedLists[this.props.tagId] || []), }; - this.state.notificationState.setRooms(this.props.rooms); + // Why Object.assign() and not this.state.height? Because TypeScript says no. + this.state = Object.assign(this.state, {height: this.calculateInitialHeight()}); this.dispatcherRef = defaultDispatcher.register(this.onAction); + RoomListStore.instance.on(LISTS_UPDATE_EVENT, this.onListsUpdated); } private calculateInitialHeight() { @@ -141,12 +148,22 @@ export default class RoomSublist extends React.Component { return padding; } - private get numTiles(): number { - return RoomSublist.calcNumTiles(this.props); + private get extraTiles(): TemporaryTile[] | null { + if (this.state.filteredExtraTiles) { + return this.state.filteredExtraTiles; + } + if (this.props.extraBadTilesThatShouldntExist) { + return this.props.extraBadTilesThatShouldntExist; + } + return null; } - private static calcNumTiles(props) { - return (props.rooms || []).length + (props.extraBadTilesThatShouldntExist || []).length; + private get numTiles(): number { + return RoomSublist.calcNumTiles(this.state.rooms, this.extraTiles); + } + + private static calcNumTiles(rooms: Room[], extraTiles: any[]) { + return (rooms || []).length + (extraTiles || []).length; } private get numVisibleTiles(): number { @@ -154,33 +171,116 @@ export default class RoomSublist extends React.Component { return Math.min(nVisible, this.numTiles); } - public componentDidUpdate(prevProps: Readonly) { - this.state.notificationState.setRooms(this.props.rooms); - if (prevProps.isFiltered !== this.props.isFiltered) { - if (this.props.isFiltered) { - this.setState({isExpanded: true}); - } else { - this.setState({isExpanded: !this.layout.isCollapsed}); - } - } + public componentDidUpdate(prevProps: Readonly, prevState: Readonly) { + const prevExtraTiles = prevState.filteredExtraTiles || prevProps.extraBadTilesThatShouldntExist; // as the rooms can come in one by one we need to reevaluate // the amount of available rooms to cap the amount of requested visible rooms by the layout - if (RoomSublist.calcNumTiles(prevProps) !== this.numTiles) { + if (RoomSublist.calcNumTiles(prevState.rooms, prevExtraTiles) !== this.numTiles) { this.setState({height: this.calculateInitialHeight()}); } } - public componentWillUnmount() { - this.state.notificationState.destroy(); - defaultDispatcher.unregister(this.dispatcherRef); + public shouldComponentUpdate(nextProps: Readonly, nextState: Readonly): boolean { + if (objectHasDiff(this.props, nextProps)) { + // Something we don't care to optimize has updated, so update. + return true; + } + + // Do the same check used on props for state, without the rooms we're going to no-op + const prevStateNoRooms = objectExcluding(this.state, ['rooms']); + const nextStateNoRooms = objectExcluding(nextState, ['rooms']); + if (objectHasDiff(prevStateNoRooms, nextStateNoRooms)) { + return true; + } + + // If we're supposed to handle extra tiles, take the performance hit and re-render all the + // time so we don't have to consider them as part of the visible room optimization. + const prevExtraTiles = this.props.extraBadTilesThatShouldntExist || []; + const nextExtraTiles = (nextState.filteredExtraTiles || nextProps.extraBadTilesThatShouldntExist) || []; + if (prevExtraTiles.length > 0 || nextExtraTiles.length > 0) { + return true; + } + + // If we're about to update the height of the list, we don't really care about which rooms + // are visible or not for no-op purposes, so ensure that the height calculation runs through. + if (RoomSublist.calcNumTiles(nextState.rooms, nextExtraTiles) !== this.numTiles) { + return true; + } + + // Before we go analyzing the rooms, we can see if we're collapsed. If we're collapsed, we don't need + // to render anything. We do this after the height check though to ensure that the height gets appropriately + // calculated for when/if we become uncollapsed. + if (!nextState.isExpanded) { + return false; + } + + // Quickly double check we're not about to break something due to the number of rooms changing. + if (this.state.rooms.length !== nextState.rooms.length) { + return true; + } + + // Finally, determine if the room update (as presumably that's all that's left) is within + // our visible range. If it is, then do a render. If the update is outside our visible range + // then we can skip the update. + // + // We also optimize for order changing here: if the update did happen in our visible range + // but doesn't result in the list re-sorting itself then there's no reason for us to update + // on our own. + const prevSlicedRooms = this.state.rooms.slice(0, this.numVisibleTiles); + const nextSlicedRooms = nextState.rooms.slice(0, this.numVisibleTiles); + if (arrayHasOrderChange(prevSlicedRooms, nextSlicedRooms)) { + return true; + } + + // Finally, nothing happened so no-op the update + return false; } + public componentWillUnmount() { + defaultDispatcher.unregister(this.dispatcherRef); + RoomListStore.instance.off(LISTS_UPDATE_EVENT, this.onListsUpdated); + } + + private onListsUpdated = () => { + const stateUpdates: IState & any = {}; // &any is to avoid a cast on the initializer + + if (this.props.extraBadTilesThatShouldntExist) { + const nameCondition = RoomListStore.instance.getFirstNameFilterCondition(); + if (nameCondition) { + stateUpdates.filteredExtraTiles = this.props.extraBadTilesThatShouldntExist + .filter(t => nameCondition.matches(t.props.displayName || "")); + } else if (this.state.filteredExtraTiles) { + stateUpdates.filteredExtraTiles = null; + } + } + + const currentRooms = this.state.rooms; + const newRooms = arrayFastClone(RoomListStore.instance.orderedLists[this.props.tagId] || []); + if (arrayHasOrderChange(currentRooms, newRooms)) { + stateUpdates.rooms = newRooms; + } + + const isStillBeingFiltered = !!RoomListStore.instance.getFirstNameFilterCondition(); + if (isStillBeingFiltered !== this.isBeingFiltered) { + this.isBeingFiltered = isStillBeingFiltered; + if (isStillBeingFiltered) { + stateUpdates.isExpanded = true; + } else { + stateUpdates.isExpanded = !this.layout.isCollapsed; + } + } + + if (Object.keys(stateUpdates).length > 0) { + this.setState(stateUpdates); + } + }; + private onAction = (payload: ActionPayload) => { - if (payload.action === "view_room" && payload.show_room_tile && this.props.rooms) { + if (payload.action === "view_room" && payload.show_room_tile && this.state.rooms) { // XXX: we have to do this a tick later because we have incorrect intermediate props during a room change // where we lose the room we are changing from temporarily and then it comes back in an update right after. setImmediate(() => { - const roomIndex = this.props.rooms.findIndex((r) => r.roomId === payload.room_id); + const roomIndex = this.state.rooms.findIndex((r) => r.roomId === payload.room_id); if (!this.state.isExpanded && roomIndex > -1) { this.toggleCollapsed(); @@ -302,12 +402,12 @@ export default class RoomSublist extends React.Component { let room; if (this.props.tagId === DefaultTagID.Invite) { // switch to first room as that'll be the top of the list for the user - room = this.props.rooms && this.props.rooms[0]; + room = this.state.rooms && this.state.rooms[0]; } else { // find the first room with a count of the same colour as the badge count - room = this.props.rooms.find((r: Room) => { - const notifState = this.state.notificationState.getForRoom(r); - return notifState.count > 0 && notifState.color === this.state.notificationState.color; + room = this.state.rooms.find((r: Room) => { + const notifState = this.notificationState.getForRoom(r); + return notifState.count > 0 && notifState.color === this.notificationState.color; }); } @@ -399,8 +499,8 @@ export default class RoomSublist extends React.Component { const tiles: React.ReactElement[] = []; - if (this.props.rooms) { - const visibleRooms = this.props.rooms.slice(0, this.numVisibleTiles); + if (this.state.rooms) { + const visibleRooms = this.state.rooms.slice(0, this.numVisibleTiles); for (const room of visibleRooms) { tiles.push( { } } - if (this.props.extraBadTilesThatShouldntExist) { - tiles.push(...this.props.extraBadTilesThatShouldntExist); + if (this.extraTiles) { + // HACK: We break typing here, but this 'extra tiles' property shouldn't exist. + (tiles as any[]).push(...this.extraTiles); } // We only have to do this because of the extra tiles. We do it conditionally @@ -522,7 +623,7 @@ export default class RoomSublist extends React.Component { const badge = ( ; interface IState { - hover: boolean; - notificationState: NotificationState; selected: boolean; notificationsMenuPosition: PartialDOMRect; generalMenuPosition: PartialDOMRect; + messagePreview?: string; } const messagePreviewId = (roomId: string) => `mx_RoomTile_messagePreview_${roomId}`; @@ -111,25 +104,42 @@ const NotifOption: React.FC = ({active, onClick, iconClassNam ); }; -export default class RoomTile extends React.Component { +export default class RoomTile extends React.PureComponent { private dispatcherRef: string; private roomTileRef = createRef(); + private notificationState: NotificationState; + private roomProps: RoomEchoChamber; constructor(props: IProps) { super(props); this.state = { - hover: false, - notificationState: RoomNotificationStateStore.instance.getRoomState(this.props.room, this.props.tag), selected: ActiveRoomObserver.activeRoomId === this.props.room.roomId, notificationsMenuPosition: null, generalMenuPosition: null, + + // generatePreview() will return nothing if the user has previews disabled + messagePreview: this.generatePreview(), }; ActiveRoomObserver.addListener(this.props.room.roomId, this.onActiveRoomUpdate); this.dispatcherRef = defaultDispatcher.register(this.onAction); + MessagePreviewStore.instance.on(ROOM_PREVIEW_CHANGED, this.onRoomPreviewChanged); + this.notificationState = RoomNotificationStateStore.instance.getRoomState(this.props.room); + this.notificationState.on(NOTIFICATION_STATE_UPDATE, this.onNotificationUpdate); + this.roomProps = EchoChamber.forRoom(this.props.room); + this.roomProps.on(PROPERTY_UPDATED, this.onRoomPropertyUpdate); } + private onNotificationUpdate = () => { + this.forceUpdate(); // notification state changed - update + }; + + private onRoomPropertyUpdate = (property: CachedRoomKey) => { + if (property === CachedRoomKey.NotificationVolume) this.onNotificationUpdate(); + // else ignore - not important for this tile + }; + private get showContextMenu(): boolean { return !this.props.isMinimized && this.props.tag !== DefaultTagID.Invite; } @@ -150,6 +160,8 @@ export default class RoomTile extends React.Component { ActiveRoomObserver.removeListener(this.props.room.roomId, this.onActiveRoomUpdate); } defaultDispatcher.unregister(this.dispatcherRef); + MessagePreviewStore.instance.off(ROOM_PREVIEW_CHANGED, this.onRoomPreviewChanged); + this.notificationState.off(NOTIFICATION_STATE_UPDATE, this.onNotificationUpdate); } private onAction = (payload: ActionPayload) => { @@ -160,6 +172,21 @@ export default class RoomTile extends React.Component { } }; + private onRoomPreviewChanged = (room: Room) => { + if (this.props.room && room.roomId === this.props.room.roomId) { + // generatePreview() will return nothing if the user has previews disabled + this.setState({messagePreview: this.generatePreview()}); + } + }; + + private generatePreview(): string | null { + if (!this.showMessagePreview) { + return null; + } + + return MessagePreviewStore.instance.getPreviewForRoom(this.props.room, this.props.tag); + } + private scrollIntoView = () => { if (!this.roomTileRef.current) return; this.roomTileRef.current.scrollIntoView({ @@ -168,14 +195,6 @@ export default class RoomTile extends React.Component { }); }; - private onTileMouseEnter = () => { - this.setState({hover: true}); - }; - - private onTileMouseLeave = () => { - this.setState({hover: false}); - }; - private onTileClick = (ev: React.KeyboardEvent) => { ev.preventDefault(); ev.stopPropagation(); @@ -231,11 +250,11 @@ export default class RoomTile extends React.Component { ev.preventDefault(); ev.stopPropagation(); - if (tagId === DefaultTagID.Favourite) { - const roomTags = RoomListStore.instance.getTagsForRoom(this.props.room); - const isFavourite = roomTags.includes(DefaultTagID.Favourite); - const removeTag = isFavourite ? DefaultTagID.Favourite : DefaultTagID.LowPriority; - const addTag = isFavourite ? null : DefaultTagID.Favourite; + if (tagId === DefaultTagID.Favourite || tagId === DefaultTagID.LowPriority) { + const inverseTag = tagId === DefaultTagID.Favourite ? DefaultTagID.LowPriority : DefaultTagID.Favourite; + const isApplied = RoomListStore.instance.getTagsForRoom(this.props.room).includes(tagId); + const removeTag = isApplied ? tagId : inverseTag; + const addTag = isApplied ? null : tagId; dis.dispatch(RoomListActions.tagRoom( MatrixClientPeg.get(), this.props.room, @@ -292,17 +311,9 @@ export default class RoomTile extends React.Component { ev.stopPropagation(); if (MatrixClientPeg.get().isGuest()) return; - // get key before we go async and React discards the nativeEvent - const key = (ev as React.KeyboardEvent).key; - try { - // TODO add local echo - https://github.com/vector-im/riot-web/issues/14280 - await setRoomNotifsState(this.props.room.roomId, newState); - } catch (error) { - // TODO: some form of error notification to the user to inform them that their state change failed. - // See https://github.com/vector-im/riot-web/issues/14281 - console.error(error); - } + this.roomProps.notificationVolume = newState; + const key = (ev as React.KeyboardEvent).key; if (key === Key.ENTER) { // Implements https://www.w3.org/TR/wai-aria-practices/#keyboard-interaction-12 this.setState({notificationsMenuPosition: null}); // hide the menu @@ -320,7 +331,7 @@ export default class RoomTile extends React.Component { return null; } - const state = getRoomNotifsState(this.props.room.roomId); + const state = this.roomProps.notificationVolume; let contextMenu = null; if (this.state.notificationsMenuPosition) { @@ -387,13 +398,6 @@ export default class RoomTile extends React.Component { private renderGeneralMenu(): React.ReactElement { if (!this.showContextMenu) return null; // no menu to show - const roomTags = RoomListStore.instance.getTagsForRoom(this.props.room); - - const isFavorite = roomTags.includes(DefaultTagID.Favourite); - const favouriteIconClassName = isFavorite ? "mx_RoomTile_iconFavorite" : "mx_RoomTile_iconStar"; - const favouriteLabelClassName = isFavorite ? "mx_RoomTile_contextMenu_activeRow" : ""; - const favouriteLabel = isFavorite ? _t("Favourited") : _t("Favourite"); - let contextMenu = null; if (this.state.generalMenuPosition && this.props.tag === DefaultTagID.Archived) { contextMenu = ( @@ -409,19 +413,36 @@ export default class RoomTile extends React.Component { ); } else if (this.state.generalMenuPosition) { + const roomTags = RoomListStore.instance.getTagsForRoom(this.props.room); + + const isFavorite = roomTags.includes(DefaultTagID.Favourite); + const favouriteLabel = isFavorite ? _t("Favourited") : _t("Favourite"); + + const isLowPriority = roomTags.includes(DefaultTagID.LowPriority); + const lowPriorityLabel = _t("Low Priority"); + contextMenu = (
    this.onTagRoom(e, DefaultTagID.Favourite)} active={isFavorite} label={favouriteLabel} > - + {favouriteLabel} + this.onTagRoom(e, DefaultTagID.LowPriority)} + active={isLowPriority} + label={lowPriorityLabel} + > + + {lowPriorityLabel} + {_t("Settings")} @@ -472,7 +493,7 @@ export default class RoomTile extends React.Component { badge = ( -
    - {_t('Make this room low priority')} - -
    ); } diff --git a/src/components/views/settings/tabs/room/NotificationSettingsTab.js b/src/components/views/settings/tabs/room/NotificationSettingsTab.js index 257f4a5d23..dd88b5018f 100644 --- a/src/components/views/settings/tabs/room/NotificationSettingsTab.js +++ b/src/components/views/settings/tabs/room/NotificationSettingsTab.js @@ -21,7 +21,7 @@ import {MatrixClientPeg} from "../../../../../MatrixClientPeg"; import AccessibleButton from "../../../elements/AccessibleButton"; import Notifier from "../../../../../Notifier"; import SettingsStore from '../../../../../settings/SettingsStore'; -import { SettingLevel } from '../../../../../settings/SettingsStore'; +import {SettingLevel} from "../../../../../settings/SettingLevel"; export default class NotificationsSettingsTab extends React.Component { static propTypes = { diff --git a/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.js b/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.js index c67596a3a5..596344d7cd 100644 --- a/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.js +++ b/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.js @@ -20,9 +20,9 @@ import {_t} from "../../../../../languageHandler"; import {MatrixClientPeg} from "../../../../../MatrixClientPeg"; import * as sdk from "../../../../.."; import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch"; -import {SettingLevel} from "../../../../../settings/SettingsStore"; import Modal from "../../../../../Modal"; import QuestionDialog from "../../../dialogs/QuestionDialog"; +import {SettingLevel} from "../../../../../settings/SettingLevel"; export default class SecurityRoomSettingsTab extends React.Component { static propTypes = { diff --git a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx index 9f3b8ba46c..c646025bbe 100644 --- a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx @@ -18,7 +18,7 @@ limitations under the License. import React from 'react'; import {_t} from "../../../../../languageHandler"; import SdkConfig from "../../../../../SdkConfig"; -import SettingsStore, {SettingLevel} from "../../../../../settings/SettingsStore"; +import SettingsStore from "../../../../../settings/SettingsStore"; import { enumerateThemes } from "../../../../../theme"; import ThemeWatcher from "../../../../../settings/watchers/ThemeWatcher"; import Slider from "../../../elements/Slider"; @@ -35,6 +35,7 @@ import Field from '../../../elements/Field'; import EventTilePreview from '../../../elements/EventTilePreview'; import StyledRadioGroup from "../../../elements/StyledRadioGroup"; import classNames from 'classnames'; +import { SettingLevel } from "../../../../../settings/SettingLevel"; interface IProps { } diff --git a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js index c7e7ce7c2c..1ebefae590 100644 --- a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js @@ -20,7 +20,6 @@ import React from 'react'; import {_t} from "../../../../../languageHandler"; import ProfileSettings from "../../ProfileSettings"; import * as languageHandler from "../../../../../languageHandler"; -import {SettingLevel} from "../../../../../settings/SettingsStore"; import SettingsStore from "../../../../../settings/SettingsStore"; import LanguageDropdown from "../../../elements/LanguageDropdown"; import AccessibleButton from "../../../elements/AccessibleButton"; @@ -37,6 +36,7 @@ import IdentityAuthClient from "../../../../../IdentityAuthClient"; import {abbreviateUrl} from "../../../../../utils/UrlUtils"; import { getThreepidsWithBindStatus } from '../../../../../boundThreepids'; import Spinner from "../../../elements/Spinner"; +import {SettingLevel} from "../../../../../settings/SettingLevel"; export default class GeneralUserSettingsTab extends React.Component { static propTypes = { diff --git a/src/components/views/settings/tabs/user/LabsUserSettingsTab.js b/src/components/views/settings/tabs/user/LabsUserSettingsTab.js index 2b8d7c5d3f..25dfd9e100 100644 --- a/src/components/views/settings/tabs/user/LabsUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/LabsUserSettingsTab.js @@ -17,9 +17,10 @@ limitations under the License. import React from 'react'; import {_t} from "../../../../../languageHandler"; import PropTypes from "prop-types"; -import SettingsStore, {SettingLevel} from "../../../../../settings/SettingsStore"; +import SettingsStore from "../../../../../settings/SettingsStore"; import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch"; import * as sdk from "../../../../../index"; +import {SettingLevel} from "../../../../../settings/SettingLevel"; export class LabsSettingToggle extends React.Component { static propTypes = { diff --git a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js index fe60a4a179..a77815a68c 100644 --- a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js @@ -17,12 +17,12 @@ limitations under the License. import React from 'react'; import {_t} from "../../../../../languageHandler"; -import {SettingLevel} from "../../../../../settings/SettingsStore"; import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch"; import SettingsStore from "../../../../../settings/SettingsStore"; import Field from "../../../elements/Field"; import * as sdk from "../../../../.."; import PlatformPeg from "../../../../../PlatformPeg"; +import {SettingLevel} from "../../../../../settings/SettingLevel"; export default class PreferencesUserSettingsTab extends React.Component { static ROOM_LIST_SETTINGS = [ diff --git a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js index 591927411d..fda7ccb005 100644 --- a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js @@ -19,7 +19,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import {_t} from "../../../../../languageHandler"; import SdkConfig from "../../../../../SdkConfig"; -import {SettingLevel} from "../../../../../settings/SettingsStore"; import {MatrixClientPeg} from "../../../../../MatrixClientPeg"; import * as FormattingUtils from "../../../../../utils/FormattingUtils"; import AccessibleButton from "../../../elements/AccessibleButton"; @@ -29,6 +28,7 @@ import * as sdk from "../../../../.."; import {sleep} from "../../../../../utils/promise"; import dis from "../../../../../dispatcher/dispatcher"; import {privateShouldBeEncrypted} from "../../../../../createRoom"; +import {SettingLevel} from "../../../../../settings/SettingLevel"; export class IgnoredUser extends React.Component { static propTypes = { diff --git a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.js b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.js index efd184069e..4114f6bb22 100644 --- a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.js @@ -21,10 +21,10 @@ import SdkConfig from "../../../../../SdkConfig"; import CallMediaHandler from "../../../../../CallMediaHandler"; import Field from "../../../elements/Field"; import AccessibleButton from "../../../elements/AccessibleButton"; -import {SettingLevel} from "../../../../../settings/SettingsStore"; import {MatrixClientPeg} from "../../../../../MatrixClientPeg"; import * as sdk from "../../../../../index"; import Modal from "../../../../../Modal"; +import {SettingLevel} from "../../../../../settings/SettingLevel"; export default class VoiceUserSettingsTab extends React.Component { constructor() { diff --git a/src/components/views/toasts/NonUrgentEchoFailureToast.tsx b/src/components/views/toasts/NonUrgentEchoFailureToast.tsx new file mode 100644 index 0000000000..76d0328e8b --- /dev/null +++ b/src/components/views/toasts/NonUrgentEchoFailureToast.tsx @@ -0,0 +1,40 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from "react"; +import { _t } from "../../../languageHandler"; +import AccessibleButton from "../elements/AccessibleButton"; +import Modal from "../../../Modal"; +import ServerOfflineDialog from "../dialogs/ServerOfflineDialog"; + +export default class NonUrgentEchoFailureToast extends React.PureComponent { + private openDialog = () => { + Modal.createTrackedDialog('Local Echo Server Error', '', ServerOfflineDialog, {}); + }; + + public render() { + return ( +
    + + {_t("Your server isn't responding to some requests.", {}, { + 'a': (sub) => ( + {sub} + ), + })} +
    + ) + } +} diff --git a/src/components/views/toasts/VerificationRequestToast.tsx b/src/components/views/toasts/VerificationRequestToast.tsx index cc41e81b33..8c8a74b2be 100644 --- a/src/components/views/toasts/VerificationRequestToast.tsx +++ b/src/components/views/toasts/VerificationRequestToast.tsx @@ -19,7 +19,8 @@ import React from "react"; import * as sdk from "../../../index"; import { _t } from '../../../languageHandler'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; -import {RIGHT_PANEL_PHASES} from "../../../stores/RightPanelStorePhases"; +import {RightPanelPhases} from "../../../stores/RightPanelStorePhases"; +import {SetRightPanelPhasePayload} from "../../../dispatcher/payloads/SetRightPanelPhasePayload" import {userLabelForEventRoom} from "../../../utils/KeyVerificationStateObserver"; import dis from "../../../dispatcher/dispatcher"; import ToastStore from "../../../stores/ToastStore"; @@ -27,6 +28,7 @@ import Modal from "../../../Modal"; import GenericToast from "./GenericToast"; import {VerificationRequest} from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest"; import {DeviceInfo} from "matrix-js-sdk/src/crypto/deviceinfo"; +import {Action} from "../../../dispatcher/actions"; interface IProps { toastKey: string; @@ -104,9 +106,9 @@ export default class VerificationRequestToast extends React.PureComponent({ + action: Action.SetRightPanelPhase, + phase: RightPanelPhases.EncryptionPanel, refireParams: { verificationRequest: request, member: cli.getUser(request.otherUserId), diff --git a/src/dispatcher/actions.ts b/src/dispatcher/actions.ts index 519a799e67..6fb71df30d 100644 --- a/src/dispatcher/actions.ts +++ b/src/dispatcher/actions.ts @@ -79,4 +79,19 @@ export enum Action { * Changes room based on room list order and payload parameters. Should be used with ViewRoomDeltaPayload. */ ViewRoomDelta = "view_room_delta", + + /** + * Sets the phase for the right panel. Should be used with SetRightPanelPhasePayload. + */ + SetRightPanelPhase = "set_right_panel_phase", + + /** + * Toggles the right panel. Should be used with ToggleRightPanelPayload. + */ + ToggleRightPanel = "toggle_right_panel", + + /** + * Trigged after the phase of the right panel is set. Should be used with AfterRightPanelPhaseChangePayload. + */ + AfterRightPanelPhaseChange = "after_right_panel_phase_change", } diff --git a/src/dispatcher/payloads/AfterRightPanelPhaseChangePayload.ts b/src/dispatcher/payloads/AfterRightPanelPhaseChangePayload.ts new file mode 100644 index 0000000000..cfd4a2d3cc --- /dev/null +++ b/src/dispatcher/payloads/AfterRightPanelPhaseChangePayload.ts @@ -0,0 +1,30 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { RightPanelPhases } from "../../stores/RightPanelStorePhases"; +import { SetRightPanelPhaseRefireParams } from "./SetRightPanelPhasePayload"; +import { ActionPayload } from "../payloads"; +import { Action } from "../actions"; +import { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest"; + +interface AfterRightPanelPhaseChangeAction extends ActionPayload { + action: Action.AfterRightPanelPhaseChange; + phase: RightPanelPhases; + verificationRequestPromise?: Promise; +} + +export type AfterRightPanelPhaseChangePayload + = AfterRightPanelPhaseChangeAction & SetRightPanelPhaseRefireParams; diff --git a/src/dispatcher/payloads/SetRightPanelPhasePayload.ts b/src/dispatcher/payloads/SetRightPanelPhasePayload.ts new file mode 100644 index 0000000000..75dea9f3df --- /dev/null +++ b/src/dispatcher/payloads/SetRightPanelPhasePayload.ts @@ -0,0 +1,37 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest"; +import { RoomMember } from "matrix-js-sdk/src/models/room-member"; +import { RightPanelPhases } from "../../stores/RightPanelStorePhases"; +import { ActionPayload } from "../payloads"; +import { Action } from "../actions"; + +export interface SetRightPanelPhasePayload extends ActionPayload { + action: Action.SetRightPanelPhase; + + phase: RightPanelPhases; + refireParams?: SetRightPanelPhaseRefireParams; +} + +export interface SetRightPanelPhaseRefireParams { + member?: RoomMember; + verificationRequest?: VerificationRequest; + groupId?: string; + groupRoomId?: string; + // XXX: The type for event should 'view_3pid_invite' action's payload + event?: any; +} diff --git a/src/dispatcher/payloads/ToggleRightPanelPayload.ts b/src/dispatcher/payloads/ToggleRightPanelPayload.ts new file mode 100644 index 0000000000..0635194890 --- /dev/null +++ b/src/dispatcher/payloads/ToggleRightPanelPayload.ts @@ -0,0 +1,27 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { ActionPayload } from "../payloads"; +import { Action } from "../actions"; + +export interface ToggleRightPanelPayload extends ActionPayload { + action: Action.ToggleRightPanel; + + /** + * The type of room that the panel is toggled in. + */ + type: "group" | "room"; +} diff --git a/src/editor/deserialize.ts b/src/editor/deserialize.ts index 46eb74f818..28543137be 100644 --- a/src/editor/deserialize.ts +++ b/src/editor/deserialize.ts @@ -64,7 +64,7 @@ function parseCodeBlock(n: HTMLElement, partCreator: PartCreator) { let language = ""; if (n.firstChild && n.firstChild.nodeName === "CODE") { for (const className of (n.firstChild).classList) { - if (className.startsWith("language-")) { + if (className.startsWith("language-") && !className.startsWith("language-_")) { language = className.substr("language-".length); break; } diff --git a/src/editor/parts.ts b/src/editor/parts.ts index ed48fcbe4e..5ed0c0529f 100644 --- a/src/editor/parts.ts +++ b/src/editor/parts.ts @@ -186,7 +186,11 @@ abstract class PlainBasePart extends BasePart { } // when not pasting or dropping text, reject characters that should start a pill candidate if (inputType !== "insertFromPaste" && inputType !== "insertFromDrop") { - return chr !== "@" && chr !== "#" && chr !== ":"; + if (chr !== "@" && chr !== "#" && chr !== ":" && chr !== "+") { + return true; + } + // only split if the previous character is a space + return this._text[offset - 1] !== " "; } return true; } @@ -463,6 +467,7 @@ export class PartCreator { case "#": case "@": case ":": + case "+": return this.pillCandidate(""); case "\n": return new NewlinePart(); diff --git a/src/editor/render.ts b/src/editor/render.ts index e0f7c07975..8aa5c5dea9 100644 --- a/src/editor/render.ts +++ b/src/editor/render.ts @@ -162,10 +162,10 @@ export function renderModel(editor: HTMLDivElement, model: EditorModel) { lines.forEach((parts, i) => { // find first (and remove anything else) div without className // (as browsers insert these in contenteditable) line container - let lineContainer = editor.children[i]; - while (lineContainer && (lineContainer.tagName !== "DIV" || !!lineContainer.className)) { + let lineContainer = editor.childNodes[i]; + while (lineContainer && ((lineContainer).tagName !== "DIV" || !!(lineContainer).className)) { editor.removeChild(lineContainer); - lineContainer = editor.children[i]; + lineContainer = editor.childNodes[i]; } if (!lineContainer) { lineContainer = document.createElement("div"); diff --git a/src/emojipicker/recent.ts b/src/emojipicker/recent.ts index 1ba15d87b8..d86aad660d 100644 --- a/src/emojipicker/recent.ts +++ b/src/emojipicker/recent.ts @@ -15,8 +15,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import SettingsStore, {SettingLevel} from "../settings/SettingsStore"; +import SettingsStore from "../settings/SettingsStore"; import {orderBy} from "lodash"; +import { SettingLevel } from "../settings/SettingLevel"; interface ILegacyFormat { [emoji: string]: [number, number]; // [count, date] diff --git a/src/i18n/strings/ar.json b/src/i18n/strings/ar.json index 75ab15a778..a6a52b147d 100644 --- a/src/i18n/strings/ar.json +++ b/src/i18n/strings/ar.json @@ -60,5 +60,310 @@ "powered by Matrix": "مشغل بواسطة Matrix", "The platform you're on": "المنصة الحالية", "Your language of choice": "اللغة المختارة", - "e.g. %(exampleValue)s": "مثال %(exampleValue)s" + "e.g. %(exampleValue)s": "مثال %(exampleValue)s", + "Use Single Sign On to continue": "استخدم تسجيل الدخول الموحد للاستمرار", + "Confirm adding this email address by using Single Sign On to prove your identity.": "اكد اضافة بريدك الالكتروني عن طريق الدخول الموحد (SSO) لتثبت هويتك.", + "Single Sign On": "تسجيل الدخول الموحد", + "Confirm adding email": "تأكيد اضافة بريدك الالكتروني", + "Click the button below to confirm adding this email address.": "انقر على الزر ادناه لتأكد اضافة هذا البريد الالكتروني.", + "Confirm": "تأكيد", + "Add Email Address": "اضافة بريد الكتروني", + "Confirm adding this phone number by using Single Sign On to prove your identity.": "قم بتأكيد اضافة رقم الهاتف هذا باستخدام تقنية الدخول الموحد لتثبت هويتك.", + "Confirm adding phone number": "قم بتأكيد اضافة رقم الهاتف", + "Click the button below to confirm adding this phone number.": "انقر الزر ادناه لتأكيد اضافة رقم الهاتف.", + "Add Phone Number": "اضافة رقم هاتف", + "Which officially provided instance you are using, if any": "التي تقدم البيئة التي تستخدمها بشكل رسمي، اذا كان هناك", + "Whether you're using %(brand)s on a device where touch is the primary input mechanism": "عندما تستخدم %(brand)s على جهاز تكون شاشة اللمس هي طريقة الادخال الرئيسية", + "Whether or not you're using the 'breadcrumbs' feature (avatars above the room list)": "اذا كنت تستخدم او لا تستخدم ميزة 'breadcrumbs' (الافاتار فوق قائمة الغرف)", + "Whether you're using %(brand)s as an installed Progressive Web App": "اذا كنت تستخدم %(brand)s كتطبيق ويب", + "Your user agent": "وكيل المستخدم الخاص بك", + "Unable to load! Check your network connectivity and try again.": "غير قادر على التحميل! قم فحص اتصالك الشبكي وحاول مرة اخرى.", + "Call Timeout": "مهلة الاتصال", + "Call failed due to misconfigured server": "فشل الاتصال بسبب إعداد السيرفر بشكل خاطئ", + "Please ask the administrator of your homeserver (%(homeserverDomain)s) to configure a TURN server in order for calls to work reliably.": "يرجى مطالبة مسئول سيرفرك (%(homeserverDomain)s) بإعداد سيرفر TURN لكي تعمل المكالمات بشكل صحيح.", + "Alternatively, you can try to use the public server at turn.matrix.org, but this will not be as reliable, and it will share your IP address with that server. You can also manage this in Settings.": "بدلاً من ذلك، يمكنك محاولة استخدام السيرفر العام على turn.matrix.org، ولكن هذا لن يكون موثوقًا به، وسيشارك عنوان IP الخاص بك مع هذا السيرفر. يمكنك أيضًا تعديل ذلك في الإعدادات.", + "Try using turn.matrix.org": "جرب استخدام turn.matrix.org", + "OK": "حسنا", + "Unable to capture screen": "غير قادر على التقاط الشاشة", + "Call Failed": "فل الاتصال", + "You are already in a call.": "أنت بالفعل في مكالمة.", + "VoIP is unsupported": "تقنية VoIP غير مدعومة", + "You cannot place VoIP calls in this browser.": "لايمكنك اجراء مكالمات VoIP عبر هذا المتصفح.", + "A call is currently being placed!": "يتم حاليًا إجراء مكالمة!", + "A call is already in progress!": "المكالمة جارية بالفعل!", + "Permission Required": "مطلوب صلاحية", + "You do not have permission to start a conference call in this room": "ليس لديك صلاحية لبدء مكالمة جماعية في هذه الغرفة", + "Replying With Files": "الرد مع الملفات", + "At this time it is not possible to reply with a file. Would you like to upload this file without replying?": "في الوقت الحالي ، لا يمكن الرد مع ملف. هل تريد تحميل هذا الملف بدون رد؟", + "The file '%(fileName)s' failed to upload.": "فشل في رفع الملف '%(fileName)s'.", + "The file '%(fileName)s' exceeds this homeserver's size limit for uploads": "إن حجم الملف '%(fileName)s' يتجاوز الحد المسموح به للرفع في السيرفر", + "Upload Failed": "فشل الرفع", + "Server may be unavailable, overloaded, or you hit a bug.": "قد يكون السيرفر غير متوفر، او محملا بشكل زائد او انك طلبت ميزة بها مشكلة.", + "The server does not support the room version specified.": "السيرفر لا يدعم إصدار الغرفة المحدد.", + "Failure to create room": "فشل في انشاء الغرفة", + "Cancel entering passphrase?": "هل تريد إلغاء إدخال عبارة المرور؟", + "Are you sure you want to cancel entering passphrase?": "هل أنت متأكد من أنك تريد إلغاء إدخال عبارة المرور؟", + "Go Back": "الرجوع للخلف", + "Setting up keys": "إعداد المفاتيح", + "Sun": "احد", + "Mon": "اثنين", + "Tue": "ثلاثاء", + "Wed": "اربعاء", + "Thu": "خميس", + "Fri": "جمعة", + "Sat": "سبت", + "Jan": "يناير", + "Feb": "فبراير", + "Mar": "مارس", + "Apr": "ابريل", + "May": "مايو", + "Jun": "يونيو", + "Jul": "يوليو", + "Aug": "اغسطس", + "Sep": "سبتمبر", + "Oct": "اكتوبر", + "Nov": "نوفمبر", + "Dec": "ديسمبر", + "PM": "مساء", + "AM": "صباحا", + "%(weekDayName)s %(time)s": "%(weekDayName)s %(time)s", + "%(weekDayName)s, %(monthName)s %(day)s %(time)s": "%(weekDayName)s, %(monthName)s %(day)s %(time)s", + "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s", + "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s": "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s", + "Who would you like to add to this community?": "هل ترغب في اضافة هذا المجتمع؟", + "Warning: any person you add to a community will be publicly visible to anyone who knows the community ID": "تحذير: أي شخص تضيفه إلى مجتمع سيكون مرئيًا للعامة لأي شخص يعرف معرف المجتمع", + "Invite new community members": "دعوى اعضاء جدد للمجتمع", + "Name or Matrix ID": "الاسم او معرف Matrix", + "Invite to Community": "دعوة الى المجتمع", + "Which rooms would you like to add to this community?": "ما هي الغرف التي ترغب في إضافتها إلى هذا المجتمع؟", + "Show these rooms to non-members on the community page and room list?": "هل تريد إظهار هذه الغرف لغير الأعضاء في صفحة المجتمع وقائمة الغرف؟", + "Add rooms to the community": "اضافة غرف الى المجتمع", + "Room name or address": "اسم او عنوان الغرفة", + "Add to community": "اضافة لمجتمع", + "Failed to invite the following users to %(groupId)s:": "فشل في اضافة المستخدمين التاليين الى %(groupId)s:", + "Failed to invite users to community": "فشل دعوة المستخدمين إلى المجتمع", + "Failed to invite users to %(groupId)s": "فشل في دعوة المستخدمين الى %(groupId)s", + "Failed to add the following rooms to %(groupId)s:": "فشل في اضافة الغرف التالية الى %(groupId)s:", + "Unnamed Room": "غرفة بدون اسم", + "Identity server has no terms of service": "سيرفر الهوية ليس لديه شروط للخدمة", + "This action requires accessing the default identity server to validate an email address or phone number, but the server does not have any terms of service.": "هذا الحدث يتطلب الوصول الى السيرفر الافتراضي للهوية للتحقق من البريد الالكتروني او رقم الهاتف، ولكن هذا السيرفر ليس لديه اي شروط للخدمة.", + "Only continue if you trust the owner of the server.": "لا تستمر إلا إذا كنت تثق في مالك السيرفر.", + "Trust": "ثِق", + "%(name)s is requesting verification": "%(name)s يطلب التحقق", + "%(brand)s does not have permission to send you notifications - please check your browser settings": "%(brand)s ليس لديه الصلاحية لارسال التنبيهات - يرجى فحص اعدادات متصفحك", + "%(brand)s was not given permission to send notifications - please try again": "لم تعطى الصلاحية ل %(brand)s لارسال التنبيهات - يرجى المحاولة ثانية", + "Unable to enable Notifications": "غير قادر على تفعيل التنبيهات", + "This email address was not found": "لم يتم العثور على البريد الالكتروني هذا", + "Your email address does not appear to be associated with a Matrix ID on this Homeserver.": "يبدو ان بريدك الالكتروني غير مرتبط بمعرف Matrix على هذا السيرفر.", + "Use your account to sign in to the latest version": "استخدم حسابك للدخول الى الاصدار الاخير", + "We’re excited to announce Riot is now Element": "نحن سعيدون باعلان ان Riot اصبح الان Element", + "Riot is now Element!": "Riot اصبح الان Element!", + "Learn More": "تعلم المزيد", + "Sign In or Create Account": "قم بتسجيل الدخول او انشاء حساب جديد", + "Use your account or create a new one to continue.": "استخدم حسابك او قم بانشاء حساب اخر للاستمرار.", + "Create Account": "انشاء حساب", + "Sign In": "الدخول", + "Default": "افتراضي", + "Restricted": "مقيد", + "Moderator": "مشرف", + "Admin": "مدير", + "Custom (%(level)s)": "(%(level)s) مخصص", + "Failed to invite": "فشل في الدعوة", + "Operation failed": "فشلت العملية", + "Failed to invite users to the room:": "فشل في دعوة المستخدمين للغرفة:", + "Failed to invite the following users to the %(roomName)s room:": "فشل في دعوة المستخدمين التالية اسمائهم الى الغرفة %(roomName)s:", + "You need to be logged in.": "تحتاج إلى تسجيل الدخول.", + "You need to be able to invite users to do that.": "يجب أن تكون قادرًا على دعوة المستخدمين للقيام بذلك.", + "Unable to create widget.": "غير قادر على إنشاء Widget.", + "Missing roomId.": "معرف الغرفة مفقود.", + "Failed to send request.": "فشل في ارسال الطلب.", + "This room is not recognised.": "لم يتم التعرف على هذه الغرفة.", + "Power level must be positive integer.": "يجب أن يكون مستوى الطاقة عددًا صحيحًا موجبًا.", + "You are not in this room.": "أنت لست في هذه الغرفة.", + "You do not have permission to do that in this room.": "ليس لديك صلاحية للقيام بذلك في هذه الغرفة.", + "Missing room_id in request": "رقم الغرفة مفقود في الطلب", + "Room %(roomId)s not visible": "الغرفة %(roomId)s غير مرئية", + "Missing user_id in request": "رقم المستخدم مفقود في الطلب", + "Messages": "الرسائل", + "Actions": "الإجراءات", + "Advanced": "متقدم", + "Other": "أخرى", + "Command error": "خطأ في الأمر", + "Usage": "الاستخدام", + "Prepends ¯\\_(ツ)_/¯ to a plain-text message": "ادخل احد الرموز ¯\\_(ツ)_/¯ قبل نص الرسالة", + "Sends a message as plain text, without interpreting it as markdown": "ارسال رسالة كنص، دون تفسيرها على انها معلمات", + "Sends a message as html, without interpreting it as markdown": "ارسال رسالة بشكل HTML، دون تفسيرها على انها معلمات", + "Searches DuckDuckGo for results": "البحث في DuckDuckGo للحصول على نتائج", + "/ddg is not a command": "/ddg ليس امر", + "To use it, just wait for autocomplete results to load and tab through them.": "لاستخدامها، فقط انتظر حتى يكتمل تحميل النتائج والمرور عليها.", + "Upgrades a room to a new version": "ترقية الغرفة الى الاصدار الجديد", + "You do not have the required permissions to use this command.": "ليس لديك الأذونات المطلوبة لاستخدام هذا الأمر.", + "Error upgrading room": "خطأ في ترقية الغرفة", + "Double check that your server supports the room version chosen and try again.": "تحقق مرة أخرى من أن سيرفرك يدعم إصدار الغرفة المختار وحاول مرة أخرى.", + "Changes your display nickname": "يغير لقب العرض الخاص بك", + "Changes your display nickname in the current room only": "يغير لقب العرض الخاص بك في الغرفة الحالية فقط", + "Changes the avatar of the current room": "يغير الصورة الرمزية للغرفة الحالية", + "Changes your avatar in this current room only": "تغيير الصورة الرمزية الخاصة بك في هذه الغرفة الحالية فقط", + "Changes your avatar in all rooms": "يغير صورتك الرمزية في جميع الغرف", + "Gets or sets the room topic": "الحصول على أو تحديد موضوع الغرفة", + "Failed to set topic": "فشل في تحديد الموضوع", + "This room has no topic.": "هذه الغرفة ليس لها موضوع.", + "Sets the room name": "يضبط اسم الغرفة", + "Invites user with given id to current room": "يدعو المستخدم حسب المعرّف المعطى إلى الغرفة الحالية", + "Use an identity server": "خادوم التعريف", + "Use an identity server to invite by email. Click continue to use the default identity server (%(defaultIdentityServerName)s) or manage in Settings.": "استخدم سيرفر للهوية للدعوة عبر البريد الالكتروني. انقر على استمرار لاستخدام سيرفر الهوية الافتراضي (%(defaultIdentityServerName)s) او قم بضبط الاعدادات.", + "Use an identity server to invite by email. Manage in Settings.": "استخدم سيرفر الهوية للدعوة عبر البريد الالكتروني. ضبط الاعدادات.", + "Joins room with given address": "الانضمام الى الغرفة بحسب العنوان المعطى", + "Leave room": "اترك الغرفة", + "Unrecognised room address:": "عنوان الغرفة غير معروف:", + "Kicks user with given id": "يطرد المستخدم حسب المعرّف المعطى", + "Bans user with given id": "يحظر المستخدم حسب المعرّف المعطى", + "Unbans user with given ID": "يُلغي الحظر عن المستخدم حسب المعرّف المعطى", + "Ignores a user, hiding their messages from you": "يتجاهل المستخدم، ويخفي رسائله عنك", + "Ignored user": "مستخدم متجاهل", + "You are now ignoring %(userId)s": "انت تقوم الان بتجاهل %(userId)s", + "Stops ignoring a user, showing their messages going forward": "يوقف تجاهل المستخدم ويظهر رسائله من الان فصاعدا", + "Unignored user": "المستخدم غير متجاهل", + "You are no longer ignoring %(userId)s": "انت لم تعد متجاهلا للمستخدم %(userId)s", + "Define the power level of a user": "قم بتعريف مستوى الطاقة للمستخدم", + "Command failed": "فشل الامر", + "Could not find user in room": "لم يستطع ايجاد مستخدم في غرفة", + "Deops user with given id": "يُلغي إدارية المستخدم حسب المعرّف المعطى", + "Opens the Developer Tools dialog": "يفتح نافذة ادوات المطور", + "Adds a custom widget by URL to the room": "يضيف Widget خاص عبر URL الى الغرفة", + "Please supply a widget URL or embed code": "رجاء قم بتحديد Widget URL او قم بتضمين كود", + "Please supply a https:// or http:// widget URL": "يرجى ادخال a https:// او http:// widget URL", + "You cannot modify widgets in this room.": "لا يمكنك تعديل الحاجيات في هذه الغرفة.", + "Verifies a user, session, and pubkey tuple": "يتحقق من العناصر: المستخدم والجلسة والمفتاح العام", + "Unknown (user, session) pair:": "زوج (المستخدم، الجلسة)غير معروف:", + "Session already verified!": "تم التحقق من الجلسة بالفعل!", + "WARNING: Session already verified, but keys do NOT MATCH!": "تحذير: تم التحقق من الجلسة بالفعل ، ولكن لا تتطابق المفاتيح!", + "WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and session %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!": "تحذير: فشل التحقق من المفتاح! مفتاح التوقيع للمستخدم %(userId)s و الجلسة %(deviceId)s هو \"%(fprint)s\" والتي لا تتوافق مع المفتاح \"%(fingerprint)s\" المعطى. هذا يعني ان اتصالك اصبح مكشوف!", + "Verified key": "مفتاح مؤكد", + "The signing key you provided matches the signing key you received from %(userId)s's session %(deviceId)s. Session marked as verified.": "مفتاح التوقيع الذي اعطيته يتوافق مع مفتاح التوقيع الذي استلمته من جلسة المستخدم %(userId)s رقم %(deviceId)s. تم تحديد الجلسة على انها مؤكدة.", + "Forces the current outbound group session in an encrypted room to be discarded": "يفرض تجاهل جلسة المجموعة الصادرة الحالية في غرفة مشفرة", + "Sends the given message coloured as a rainbow": "يرسل رسالة معينة ملونة مثل قوس قزح", + "Sends the given emote coloured as a rainbow": "يرسل الرمز المعطى باللون كقوس قزح", + "Displays list of commands with usages and descriptions": "يعرض قائمة الأوامر مع الوصف وطرق الاستخدام", + "Displays information about a user": "يعرض معلومات عن المستخدم", + "Send a bug report with logs": "إرسال تقرير خطأ يحتوي على سجلات الاحداث", + "Logs sent": "تم ارسال سجل الاحداث", + "Opens chat with the given user": "يفتح دردشة من المستخدم المعطى", + "Sends a message to the given user": "يرسل رسالة الى المستخدم المعطى", + "Displays action": "يعرض إجراءً", + "Reason": "السبب", + "%(targetName)s accepted the invitation for %(displayName)s.": "%(targetName)s قبل دعوة %(displayName)s.", + "%(targetName)s accepted an invitation.": "%(targetName)s قبل الدعوة.", + "%(senderName)s requested a VoIP conference.": "%(senderName)s طلب مكالمة VoIP جماعية.", + "%(senderName)s invited %(targetName)s.": "%(senderName)s دعا %(targetName)s.", + "%(senderName)s banned %(targetName)s.": "%(senderName)s حظر %(targetName)s.", + "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s غير اسم العرض الخاص به الى %(displayName)s.", + "%(senderName)s set their display name to %(displayName)s.": "%(senderName)s حدد اسم العرض:%(displayName)s.", + "%(senderName)s removed their display name (%(oldDisplayName)s).": "%(senderName)s ازال اسم العرض (%(oldDisplayName)s).", + "%(senderName)s removed their profile picture.": "%(senderName)s ازال صورة البروفايل الخاصة به.", + "%(senderName)s changed their profile picture.": "%(senderName)s غير صورة البروفايل الخاصة به.", + "%(senderName)s set a profile picture.": "%(senderName)s غير صورة البروفايل الخاصة به.", + "%(senderName)s made no change.": "%(senderName)s لم يقم باية تعديلات.", + "VoIP conference started.": "بدأ اجتماع VoIP.", + "%(targetName)s joined the room.": "%(targetName)s انضم الى الغرفة.", + "VoIP conference finished.": "انتهى اجتماع VoIP.", + "%(targetName)s rejected the invitation.": "%(targetName)s رفض الدعوة.", + "%(targetName)s left the room.": "%(targetName)s غادر الغرفة.", + "%(senderName)s unbanned %(targetName)s.": "%(senderName)s الغى الحظر على %(targetName)s.", + "%(senderName)s withdrew %(targetName)s's invitation.": "%(senderName)s سحب دعوة %(targetName)s.", + "%(senderName)s kicked %(targetName)s.": "%(senderName)s طرد %(targetName)s.", + "%(senderDisplayName)s changed the topic to \"%(topic)s\".": "%(senderDisplayName)s غير الموضوع الى \"%(topic)s\".", + "%(senderDisplayName)s removed the room name.": "%(senderDisplayName)s ازال اسم الغرفة.", + "%(senderDisplayName)s changed the room name from %(oldRoomName)s to %(newRoomName)s.": "%(senderDisplayName)s غير اسم الغرفة من %(oldRoomName)s الى %(newRoomName)s.", + "%(senderDisplayName)s changed the room name to %(roomName)s.": "%(senderDisplayName)s غير اسم الغرفة الى %(roomName)s.", + "%(senderDisplayName)s upgraded this room.": "%(senderDisplayName)s قام بترقية هذه الغرفة.", + "%(senderDisplayName)s made the room public to whoever knows the link.": "%(senderDisplayName)s قام بجعل هذة الغرفة عامة لكل شخص يعرف الرابط.", + "%(senderDisplayName)s made the room invite only.": "%(senderDisplayName)s جعل ممكنه لكل من لديه دعوة فقط.", + "%(senderDisplayName)s changed the join rule to %(rule)s": "%(senderDisplayName)s قام بتغيير قاعدة الانضمام الى %(rule)s", + "%(senderDisplayName)s has allowed guests to join the room.": "%(senderDisplayName)s قام بالسماح للضيوف بالانضمام الى الغرفة.", + "%(senderDisplayName)s has prevented guests from joining the room.": "%(senderDisplayName)s قام بإيقاف امكانية انضمام الضيوف الى الغرفة.", + "%(senderDisplayName)s changed guest access to %(rule)s": "%(senderDisplayName)s غير طريقة دخول الضيوف الى %(rule)s", + "%(senderDisplayName)s enabled flair for %(groups)s in this room.": "%(senderDisplayName)s قام بتفعيل الذوق لمجموعة %(groups)s في هذه الغرفة.", + "%(senderDisplayName)s disabled flair for %(groups)s in this room.": "%(senderDisplayName)s قام بإيقاف الذوق لمجموعة %(groups)s في هذه الغرفة.", + "%(senderDisplayName)s enabled flair for %(newGroups)s and disabled flair for %(oldGroups)s in this room.": "%(senderDisplayName)s قام بتفعيل الذوق لمجموعة %(newGroups)s و إيقاف الذوق للمجموعة %(oldGroups)s في هذه الغرفة.", + "%(senderDisplayName)s sent an image.": "قام %(senderDisplayName)s بإرسال صورة.", + "%(senderName)s set the main address for this room to %(address)s.": "قام %(senderName)s بتعديل العنوان الرئيسي لهذه الغرفة الى %(address)s.", + "%(senderName)s removed the main address for this room.": "قام %(senderName)s بإزالة العنوان الرئيسي لهذه الغرفة.", + "%(senderName)s added the alternative addresses %(addresses)s for this room.|other": "قام %(senderName)s بإضافة العناوين البديلة %(addresses)s لهذه الغرفة.", + "%(senderName)s added the alternative addresses %(addresses)s for this room.|one": "قام %(senderName)s بإضافة العنوان البديل %(addresses)s لهذه الغرفة.", + "%(senderName)s removed the alternative addresses %(addresses)s for this room.|other": "قام %(senderName)s بإزالة العناوين البديلة %(addresses)s لهذه الغرفة.", + "%(senderName)s removed the alternative addresses %(addresses)s for this room.|one": "قام %(senderName)s بإزالة العنوان البديل %(addresses)s لهذه الغرفة.", + "%(senderName)s changed the alternative addresses for this room.": "قام %(senderName)s بتعديل العناوين البديلة لهذه الغرفة.", + "%(senderName)s changed the main and alternative addresses for this room.": "قام %(senderName)s بتعديل العناوين الرئيسية و البديلة لهذه الغرفة.", + "%(senderName)s changed the addresses for this room.": "قام %(senderName)s بتعديل عناوين هذه الغرفة.", + "Someone": "شخص ما", + "(not supported by this browser)": "(غير مدعوم في هذا المتصفح)", + "%(senderName)s answered the call.": "%(senderName)s رد على المكالمة.", + "(could not connect media)": "(غير قادر على الاتصال بالوسيط)", + "(no answer)": "(لايوجد رد)", + "(unknown failure: %(reason)s)": "(فشل غير معروف:%(reason)s)", + "%(senderName)s ended the call.": "%(senderName)s انهى المكالمة.", + "%(senderName)s placed a voice call.": "أجرى ⁨%(senderName)s⁩ مكالمة صوتية.", + "%(senderName)s placed a voice call. (not supported by this browser)": "أجرى %(senderName)s مكالمة صوتية. (غير متوافقة مع هذا المتصفح)", + "%(senderName)s placed a video call.": "أجرى %(senderName)s مكالمة فيديو.", + "%(senderName)s placed a video call. (not supported by this browser)": "أجرى %(senderName)s مكالمة فيديو. (غير متوافقة مع هذا المتصفح)", + "%(senderName)s revoked the invitation for %(targetDisplayName)s to join the room.": "قام %(senderName)s بسحب الدعوة الى %(targetDisplayName)s بالانضمام الى الغرفة.", + "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.": "أرسل %(senderName)s دعوة الى %(targetDisplayName)s للانضمام الى الغرفة.", + "%(senderName)s made future room history visible to all room members, from the point they are invited.": "قام %(senderName)s بتعديل رؤية المحادثات السابقة ممكنة لكل الاعضاء من تاريخ دعوتهم بالانضمام.", + "%(senderName)s made future room history visible to all room members, from the point they joined.": "قام %(senderName)s بتعديل رؤية المحادثات السابقة ممكنة لكل الاعضاء من لحظة انضمامهم.", + "%(senderName)s made future room history visible to all room members.": "قام %(senderName)s بتعديل رؤية المحادثات السابقة ممكنة لكل الاعضاء.", + "%(senderName)s made future room history visible to anyone.": "قام %(senderName)s بتعديل رؤية المحادثات السابقة ممكنة لأي شخص.", + "%(senderName)s made future room history visible to unknown (%(visibility)s).": "قام %(senderName)s بجعل المحادثات السابقة مرئية لمجهول (%(visibility)s).", + "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s من %(fromPowerLevel)s الى %(toPowerLevel)s", + "%(senderName)s changed the power level of %(powerLevelDiffText)s.": "غير %(senderName)s مستوى الطاقة الخاصة ب %(powerLevelDiffText)s.", + "%(senderName)s changed the pinned messages for the room.": "عدل %(senderName)s الرسائل المثبتة للغرفة.", + "%(widgetName)s widget modified by %(senderName)s": "الودجت %(widgetName)s تعدلت بواسطة %(senderName)s", + "%(widgetName)s widget added by %(senderName)s": "الودجت %(widgetName)s اضيفت بواسطة %(senderName)s", + "%(widgetName)s widget removed by %(senderName)s": "الودجت %(widgetName)s حذفت بواسطة %(senderName)s", + "Whether or not you're logged in (we don't record your username)": "سواءً كنت مسجلا دخولك أم لا (لا نحتفظ باسم المستخدم)", + "Every page you use in the app": "كل صفحة تستخدمها في التطبيق", + "e.g. ": "مثلا <رابط الصفحة الحالية>", + "Your device resolution": "دقة شاشة جهازك", + "Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": "على الرغم من كون هذه الصفحة تحوي معلومات تمكن تحديد الهوية، مثل معرف الغرفة والمستخدم والمجموعة، فهذه البيانات يتم حذفها قبل أن ترسل للسيرفر.", + "The remote side failed to pick up": "الطرف الآخر لم يتمكن من الرد", + "Existing Call": "مكالمة موجودة", + "You cannot place a call with yourself.": "لا يمكنك الاتصال بنفسك.", + "Call in Progress": "المكالمة قيد التحضير", + "Please install Chrome, Firefox, or Safari for the best experience.": "يرجى تثبيت Chrome, Firefox, or Safari for the best experience.", + "%(senderName)s removed the rule banning users matching %(glob)s": "%(اسم المرسل)S إزالة القاعدة التي تحظر المستخدمين المتطابقين %(عام)s", + "%(senderName)s removed the rule banning rooms matching %(glob)s": "%(اسم المرسل)s إزالة القاعدة التي تحظر الغرف المتطابقة %(عام)s", + "%(senderName)s removed the rule banning servers matching %(glob)s": "%(اسم المرسل)s إزالة القاعدة التي تحظر الغرف المتطابقة %(عام)s", + "%(senderName)s removed a ban rule matching %(glob)s": "%(اسم المرسل)s إزالة قاعدة الحظر المتطابقة %(عام)s", + "%(senderName)s updated an invalid ban rule": "%(اسم المرسل)s قاعدة حظر محدثة غير صالحة", + "%(senderName)s updated the rule banning users matching %(glob)s for %(reason)s": "%(senderName)s قاعدة حظر المستخدمين المتطابقين محدثة %(glob)s من أجل %(reason)s", + "%(senderName)s updated a ban rule matching %(glob)s for %(reason)s": "%(senderName)s قاعدة حظر مطابقة محدثة %(glob)s من أجل %(reason)s", + "%(senderName)s created a rule banning rooms matching %(glob)s for %(reason)s": "%(senderName)s قاعدة حظر غرف مطابقة منشأة %(glob)s من أجل %(reason)s", + "%(senderName)s created a rule banning servers matching %(glob)s for %(reason)s": "%(senderName)s قاعدة حظر سيرفرات مظابقة منشأة %(glob)s من أجل %(reason)s", + "%(senderName)s created a ban rule matching %(glob)s for %(reason)s": "%(senderName)s قاعدة حظر مطابق منشأة %(glob)s من أجل %(reason)s", + "%(senderName)s changed a rule that was banning users matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s قاعدة متغيرة التي تحظر المستخدمين المطابقين %(oldGlob)s من أجل تطابق %(newGlob)s من أجل %(reason)s", + "%(senderName)s changed a rule that was banning rooms matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s قاعدة متغيرة التي تحظر الغرف المطابقة %(oldGlob)s من أجل مطابقة %(newGlob)s من أجل %(reason)s", + "%(senderName)s changed a rule that was banning servers matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s قاعدة متغيرة التي تحظر سيرفرات مطابقة %(oldGlob)s من أجل مطابقة %(newGlob)s من أجل %(reason)s", + "%(senderName)s updated a ban rule that was matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s قاعدة حظر محدثة التي طابقت %(oldGlob)s لتطابق %(newGlob)s من أجل %(reason)s", + "Light": "ضوء", + "Dark": "مظلم", + "You signed in to a new session without verifying it:": "قمت بتسجيل الدخول لجلسة جديدة من غير التحقق منها", + "Verify your other session using one of the options below.": "تحقق من جلستك الأخرى باستخدام أحد الخيارات في الأسفل", + "%(name)s (%(userId)s) signed in to a new session without verifying it:": "%(name)s%(userId)s تم تسجيل الدخول لجلسة جديدة من غير التحقق منها", + "Ask this user to verify their session, or manually verify it below.": "اطلب من هذا المستخدم التحقق من جلسته أو تحقق منها بشكل يدوي في الأسفل", + "Not Trusted": "غير موثوقة", + "Manually Verify by Text": "التحقق بشكل يدوي عبر نص", + "Interactively verify by Emoji": "التحقق بشكل تفاعلي عبر صور إيموجي", + "Done": "تم", + "%(displayName)s is typing …": "%(displayName)s يكتب", + "%(names)s and %(count)s others are typing …|other": "%(names)s و %(count)s آخرين يكتبون", + "%(names)s and %(count)s others are typing …|one": "%(names)s و آخر يكتب", + "%(names)s and %(lastPerson)s are typing …": "%(names)s و %(lastPerson)s يكتبون", + "Cannot reach homeserver": "لا يمكن الوصول إلى السيرفر", + "Ensure you have a stable internet connection, or get in touch with the server admin": "تأكد من أنك تملك اتصال بالانترنت مستقر أو تواصل مع مدير السيرفر", + "Your %(brand)s is misconfigured": "%(brand)s لديك غير مهيأ", + "Ask your %(brand)s admin to check
    your config for incorrect or duplicate entries.": "اطلب من %(brand)s مديرك لفحص إعدادك من أجل مدخلات مكررة أو خاطئة", + "Cannot reach identity server": "لا يمكن الوصول لهوية السيرفر", + "You can register, but some features will be unavailable until the identity server is back online. If you keep seeing this warning, check your configuration or contact a server admin.": "يمكنك التسجيل , لكن بعض الميزات ستكون غير متوفرة حتى يتم التعرف على هوية السيرفر بشكل متصل . إن كنت ما تزال ترى هذا التحذير , تأكد من إعداداتك أو تواصل مع مدير السيرفر", + "You can reset your password, but some features will be unavailable until the identity server is back online. If you keep seeing this warning, check your configuration or contact a server admin.": "يمكنك إعادة ضبط كلمة السر لكن بعض الميزات ستكون غير متوفرة حتى عودة السيرفر للإنترنت . إذا كنت لا تزال ترى هذا التحذير تأكد من إعداداتك أو تواصل مع مدير السيرفر", + "I understand the risks and wish to continue": "ادرك المخاطر وارغب في الاستمرار" } diff --git a/src/i18n/strings/bg.json b/src/i18n/strings/bg.json index f914e928b5..32652669af 100644 --- a/src/i18n/strings/bg.json +++ b/src/i18n/strings/bg.json @@ -2267,5 +2267,43 @@ "Leave Room": "Напусни стаята", "Room options": "Настройки на стаята", "Use Recovery Key or Passphrase": "Използвай ключ за възстановяване или парола", - "Use Recovery Key": "Използвай ключ за възстановяване" + "Use Recovery Key": "Използвай ключ за възстановяване", + "Use your account to sign in to the latest version": "Използвайте профила си за да влезете в последната версия", + "We’re excited to announce Riot is now Element": "Развълнувани сме да обявим, че Riot вече е Element", + "Riot is now Element!": "Riot вече е Element!", + "Learn More": "Научи повече", + "You joined the call": "Присъединихте се към разговор", + "%(senderName)s joined the call": "%(senderName)s се присъедини към разговор", + "Call in progress": "Тече разговор", + "You left the call": "Напуснахте разговора", + "%(senderName)s left the call": "%(senderName)s напусна разговора", + "Call ended": "Разговора приключи", + "You started a call": "Започнахте разговор", + "%(senderName)s started a call": "%(senderName)s започна разговор", + "Waiting for answer": "Изчакване на отговор", + "%(senderName)s is calling": "%(senderName)s се обажда", + "You created the room": "Създадохте стаята", + "%(senderName)s created the room": "%(senderName)s създаде стаята", + "You made the chat encrypted": "Направихте чата шифрован", + "%(senderName)s made the chat encrypted": "%(senderName)s направи чата шифрован", + "You made history visible to new members": "Направихте историята видима за нови членове", + "%(senderName)s made history visible to new members": "%(senderName)s направи историята видима за нови членове", + "You made history visible to anyone": "Направихте историята видима за всички", + "%(senderName)s made history visible to anyone": "%(senderName)s направи историята видима за всички", + "You made history visible to future members": "Направихте историята видима за бъдещи членове", + "%(senderName)s made history visible to future members": "%(senderName)s направи историята видима за бъдещи членове", + "You were invited": "Бяхте поканени", + "%(targetName)s was invited": "%(targetName)s беше поканен", + "You left": "Напуснахте", + "%(targetName)s left": "%(targetName)s напусна", + "You were kicked (%(reason)s)": "Бяхте изгонени (%(reason)s)", + "%(targetName)s was kicked (%(reason)s)": "%(targetName)s беше изгонен(а) (%(reason)s)", + "You were kicked": "Бяхте изгонени", + "%(targetName)s was kicked": "%(targetName)s беше изгонен(а)", + "You rejected the invite": "Отхвърлихте поканата", + "%(targetName)s rejected the invite": "%(targetName)s отхвърли поканата", + "You were uninvited": "Поканата към вас беше премахната", + "%(targetName)s was uninvited": "Поканата към %(targetName)s беше премахната", + "You were banned (%(reason)s)": "Бяхте блокирани (%(reason)s)", + "%(targetName)s was banned (%(reason)s)": "%(targetName)s беше блокиран(а) (%(reason)s)" } diff --git a/src/i18n/strings/cs.json b/src/i18n/strings/cs.json index ca241f4d4e..de80c4aa74 100644 --- a/src/i18n/strings/cs.json +++ b/src/i18n/strings/cs.json @@ -544,7 +544,7 @@ "Public Chat": "Veřejná konverzace", "You must register to use this functionality": "Pro využívání této funkce se zaregistrujte", "You must join the room to see its files": "Pro zobrazení souborů musíte do místnosti vstoupit", - "

    HTML for your community's page

    \n

    \n Use the long description to introduce new members to the community, or distribute\n some important links\n

    \n

    \n You can even use 'img' tags\n

    \n": "

    HTML kód stránky vaší skupiny

    \n

    \n Pomocí dlouhého popisu nejprve představte skupinu novým členům nebo uvěďte \n nějaké důležité odkazy\n

    \n

    \n Pro vložení obrázků můžete používat i HTML značky 'img'\n

    \n", + "

    HTML for your community's page

    \n

    \n Use the long description to introduce new members to the community, or distribute\n some important links\n

    \n

    \n You can even use 'img' tags\n

    \n": "

    HTML kód stránky vaší skupiny

    \n

    \n Pomocí dlouhého popisu nejprve představte skupinu novým členům nebo uvěďte \n nějaké důležité odkazy\n

    \n

    \n Pro vložení obrázků můžete používat i HTML značky „img“\n

    \n", "Add rooms to the community summary": "Přidat místnosti do přehledu skupiny", "Which rooms would you like to add to this summary?": "Které místnosti se přejete přidat do tohoto přehledu?", "Add to summary": "Přidat do přehledu", @@ -614,7 +614,7 @@ "Old cryptography data detected": "Nalezeny starší šifrované datové zprávy", "Warning": "Varování", "Fetching third party location failed": "Nepodařilo se zjistit umístění třetí strany", - "I understand the risks and wish to continue": "Rozumím rizikům a přeji si pokračovat", + "I understand the risks and wish to continue": "Rozumím a přesto chci pokračovat", "Send Account Data": "Poslat data o účtu", "Advanced notification settings": "Rozšířená nastavení oznámení", "Uploading report": "Nahrávání hlášení", @@ -828,7 +828,7 @@ "Who can join this community?": "Kdo může vstoupit do této skupiny?", "Everyone": "Všichni", "This room is not public. You will not be able to rejoin without an invite.": "Tato místnost není veřejná. Bez pozvánky nebudete moci znovu vstoupit.", - "Can't leave Server Notices room": "Místnost \"Server Notices\" nelze opustit", + "Can't leave Server Notices room": "Místnost „Server Notices“ nelze opustit", "This room is used for important messages from the Homeserver, so you cannot leave it.": "Tato místnost je určena pro důležité zprávy od domovského serveru, a proto ji nelze opustit.", "Terms and Conditions": "Smluvní podmínky", "To continue using the %(homeserverDomain)s homeserver you must review and agree to our terms and conditions.": "Chcete-li nadále používat domovský server %(homeserverDomain)s, měli byste si přečíst a odsouhlasit naše smluvní podmínky.", @@ -975,8 +975,8 @@ "Reversed words aren't much harder to guess": "Otočená slova nejsou moc těžká na uhodnutí", "Predictable substitutions like '@' instead of 'a' don't help very much": "Časté substituce jako 'a' za '@' a 'S' za '$' moc nepomůžou", "Add another word or two. Uncommon words are better.": "Přidejte další slovo nebo dvě. Čím výjimečnější tím lepší.", - "Repeats like \"aaa\" are easy to guess": "Opakování jako \"aaa\" jsou jednoduché uhodnout", - "Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Opakování typu \"abcabcabc\" jsou jen o málo složitější uhodnout než \"abc\"", + "Repeats like \"aaa\" are easy to guess": "Opakování jako „aaa“ lze snadno uhodnout", + "Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Opakování typu „abcabcabc“ jsou jen o málo složitější k uhádnutí než „abc“", "Sequences like abc or 6543 are easy to guess": "Posloupnosti jako abc nebo 6543 je lehké uhodnout", "Recent years are easy to guess": "Nedávné roky je lehké uhodnout", "Dates are often easy to guess": "Data je většinou lehké uhodnout", @@ -1217,7 +1217,7 @@ "Create your Matrix account on %(serverName)s": "Vytvořte si účet Matrix na %(serverName)s", "Could not load user profile": "Nepovedlo se načíst profil uživatele", "Your Matrix account on %(serverName)s": "Váš účet Matrix na serveru %(serverName)s", - "Whether or not you're using the 'breadcrumbs' feature (avatars above the room list)": "Zda používáte funkci \"breadcrumb\" (ikony nad seznamem místností)", + "Whether or not you're using the 'breadcrumbs' feature (avatars above the room list)": "Zda používáte funkci „breadcrumb“ (ikony nad seznamem místností)", "Replying With Files": "Odpovídání souborem", "At this time it is not possible to reply with a file. Would you like to upload this file without replying?": "Aktuálně nelze odpovědět souborem. Chcete soubor nahrát a poslat bez odpovídání?", "The file '%(fileName)s' failed to upload.": "Soubor '%(fileName)s' se nepodařilo nahrát.", @@ -1721,7 +1721,7 @@ "Unknown (user, session) pair:": "Neznámý pár (uživatel, relace):", "Session already verified!": "Relace je už ověřená!", "WARNING: Session already verified, but keys do NOT MATCH!": "VAROVÁNÍ: Relace je už ověřená, ale klíče NEODPOVÍDAJÍ!", - "WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and session %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!": "VAROVÁNÍ: OVĚŘENÍ KLÍČŮ SELHALO! Podpisový klíč pro uživatele %(userId)s a relaci %(deviceId)s je \"%(fprint)s\", což neodpovídá klíči \"%(fingerprint)s\". Může to znamenat, že je vaše komunikace rušena!", + "WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and session %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!": "VAROVÁNÍ: OVĚŘENÍ KLÍČŮ SELHALO! Podpisový klíč pro uživatele %(userId)s a relaci %(deviceId)s je „%(fprint)s“, což neodpovídá klíči „%(fingerprint)s“. Může to znamenat, že je vaše komunikace rušena!", "The signing key you provided matches the signing key you received from %(userId)s's session %(deviceId)s. Session marked as verified.": "Zadaný podpisový klíč odpovídá klíči relace %(deviceId)s od uživatele %(userId)s. Relace byla označena za platnou.", "a few seconds ago": "před pár vteřinami", "about a minute ago": "před minutou", @@ -1903,7 +1903,7 @@ "Enter your account password to confirm the upgrade:": "Potvrďte, že chcete aktualizaci provést zadáním svého uživatelského hesla:", "You'll need to authenticate with the server to confirm the upgrade.": "Server si vás potřebuje ověřit, abychom mohli provést aktualizaci.", "Upgrade this session to allow it to verify other sessions, granting them access to encrypted messages and marking them as trusted for other users.": "Aktualizujte tuto přihlášenou relaci abyste mohli ověřovat ostatní relace. Tím jim dáte přístup k šifrovaným konverzacím a ostatní uživatelé je jim budou automaticky věřit.", - "Show typing notifications": "Zobrazovat oznámení \"... právě píše...\"", + "Show typing notifications": "Zobrazovat oznámení „... právě píše...“", "Reset cross-signing and secret storage": "Obnovit bezpečné úložiště a cross-signing", "Destroy cross-signing keys?": "Nenávratně smazat klíče pro cross-signing?", "Deleting cross-signing keys is permanent. Anyone you have verified with will see security alerts. You almost certainly don't want to do this, unless you've lost every device you can cross-sign from.": "Smazání klíčů pro cross-signing je definitivní. Každý, kdo vás ověřil, teď uvidí bezpečnostní varování. Pokud jste zrovna neztratili všechna zařízení, ze kterých se můžete ověřit, tak to asi nechcete udělat.", @@ -2103,5 +2103,66 @@ "To return to your account in future you need to set a password": "Abyste se k účtu mohli v budoucnu vrátit, je potřeba nastavit heslo", "Restart": "Restartovat", "Upgrade your %(brand)s": "Aktualizovat %(brand)s", - "A new version of %(brand)s is available!": "Je dostupná nová verze %(brand)su!" + "A new version of %(brand)s is available!": "Je dostupná nová verze %(brand)su!", + "Are you sure you want to cancel entering passphrase?": "Chcete určitě zrušit zadávání hesla?", + "Use your account to sign in to the latest version": "Přihlašte se za pomoci svého účtu do nejnovější verze", + "Riot is now Element!": "Riot je nyní Element!", + "Learn More": "Zjistit více", + "Light": "Světlý", + "Dark": "Tmavý", + "You joined the call": "Připojili jste se k hovoru", + "%(senderName)s joined the call": "%(senderName)s se připojil k hovoru", + "Call in progress": "Probíhá hovor", + "Show rooms with unread messages first": "Zobrazovat místnosti s nepřečtenými zprávami jako první", + "Show previews of messages": "Zobrazovat náhledy zpráv", + "Sort by": "Řadit dle", + "Activity": "Aktivity", + "A-Z": "A–Z", + "List options": "Možnosti seznamu", + "Show %(count)s more|other": "Zobrazit %(count)s dalších", + "Show %(count)s more|one": "Zobrazit %(count)s další", + "Use default": "Použít výchozí", + "Mentions & Keywords": "Zmínky a klíčová slova", + "Notification options": "Možnosti oznámení", + "Favourited": "Oblíbená", + "Leave Room": "Opustit místnost", + "Forget Room": "Zapomenout místnost", + "Room options": "Možnosti místnosti", + "This room is public": "Tato místnost je veřejná", + "Away": "Pryč", + "Error creating address": "Chyba při tvorbě adresy", + "There was an error creating that address. It may not be allowed by the server or a temporary failure occurred.": "Při vytváření adresy došlo k chybě. Mohl to zakázat server, nebo mohlo dojít k dočasnému selhání.", + "You don't have permission to delete the address.": "Nemáte oprávnění adresu smazat.", + "There was an error removing that address. It may no longer exist or a temporary error occurred.": "Při odstraňování adresy došlo k chybě. Adresa již nemusí ekzistovat, nebo mohlo dojít k dočasné chybě.", + "Error removing address": "Chyba při odstraňování adresy", + "Message deleted on %(date)s": "Zpráva byla odstraněna %(date)s", + "Edited at %(date)s": "Upraveno %(date)s", + "Click to view edits": "Klikněte pro zobrazení úprav", + "Categories": "Kategorie", + "QR Code": "QR kód", + "Room address": "Adresa místnosti", + "Please provide a room address": "Zadejte prosím adresu místnosti", + "This address is available to use": "Tato adresa je dostupná", + "This address is already in use": "Tato adresa je již používána", + "Reminder: Your browser is unsupported, so your experience may be unpredictable.": "Připomínka: váš prohlížeč není podporován, takže vaše zkušenost může být nepředvídatelná.", + "Set a room address to easily share your room with other people.": "Nastavte adresu místnosti, abyste ji mohli snadno sdílet s lidmi.", + "To continue, use Single Sign On to prove your identity.": "Pro pokračování prokažte svou identitu pomocí Jednotného přihlášení.", + "Confirm to continue": "Pro pokračování potvrďte", + "Click the button below to confirm your identity.": "Klikněte na tlačítko níže pro potvrzení vaší identity.", + "Invite someone using their name, username (like ), email address or share this room.": "Pozvěte někoho za použití jeho jména, uživatelského jména (např. ), e-mailové adresy, a nebo sdílejte tuto místnost.", + "a new master key signature": "nový podpis hlavního klíče", + "Please install Chrome, Firefox, or Safari for the best experience.": "Pro nejlepší zážitek si prosím nainstalujte prohlížeč Chrome, Firefox, nebo Safari.", + "We’re excited to announce Riot is now Element": "S nadšením oznamujeme, že Riot je nyní Element", + "Enable experimental, compact IRC style layout": "Povolit experimentální, kompaktní zobrazení zpráv ve stylu IRC", + "New version available. Update now.": "Je dostupná nová verze. Aktualizovat nyní.", + "Message layout": "Zobrazení zpráv", + "Compact": "Kompaktní", + "Modern": "Moderní", + "Set the name of a font installed on your system & %(brand)s will attempt to use it.": "Zadejte jméno písma, které máte naistalované v systému, a %(brand)s se jej pokusí použít.", + "Customise your appearance": "Přizpůsobte si vzhled aplikace", + "Appearance Settings only affect this %(brand)s session.": "Nastavení vzhledu působí jen v této relaci programu %(brand)s.", + "Add users and servers you want to ignore here. Use asterisks to have %(brand)s match any characters. For example, @bot:* would ignore all users that have the name 'bot' on any server.": "Sem přídejte servery a uživatele, které chcete ignorovat. Hvězdička pro %(brand)s zastupuje libovolný počet kterýchkoliv znaků. Např. @bot:* bude ignorovat všechny uživatele se jménem „bot“ na kterémkoliv serveru.", + "Signature upload success": "Podpis úspěšně nahrán", + "Signature upload failed": "Podpis se nepodařilo nahrát", + "If the other version of %(brand)s is still open in another tab, please close it as using %(brand)s on the same host with both lazy loading enabled and disabled simultaneously will cause issues.": "Je-li jiná verze programu %(brand)s stále otevřená na jiné kartě, tak ji prosím zavřete, neboť užívání programu %(brand)s stejným hostitelem se zpožděným nahráváním současně povoleným i zakázaným bude působit problémy." } diff --git a/src/i18n/strings/de_DE.json b/src/i18n/strings/de_DE.json index 0fb38fcb20..09dbcb2e18 100644 --- a/src/i18n/strings/de_DE.json +++ b/src/i18n/strings/de_DE.json @@ -1146,7 +1146,7 @@ "You'll lose access to your encrypted messages": "Du wirst den Zugang zu deinen verschlüsselten Nachrichten verlieren", "If you run into any bugs or have feedback you'd like to share, please let us know on GitHub.": "Wenn du Fehler bemerkst oder eine Rückmeldung geben möchtest, teile dies uns auf GitHub mit.", "To help avoid duplicate issues, please view existing issues first (and add a +1) or create a new issue if you can't find it.": "Um doppelte Issues zu vermeiden, schauen Sie bitte zuerst die existierenden Issues an (und fügen Sie ein \"+1\" hinzu), oder erstellen Sie ein neues Issue, wenn Sie keines finden können.", - "Report bugs & give feedback": "Melde Fehler & gebe Rückmeldungen", + "Report bugs & give feedback": "Melde Fehler & gib Rückmeldungen", "Update status": "Aktualisiere Status", "Set status": "Setze Status", "Hide": "Verberge", @@ -2326,5 +2326,40 @@ "Message deleted on %(date)s": "Nachricht am %(date)s gelöscht", "Wrong file type": "Falscher Dateityp", "Wrong Recovery Key": "Falscher Wiederherstellungsschlüssel", - "Invalid Recovery Key": "Ungültiger Wiederherstellungsschlüssel" + "Invalid Recovery Key": "Ungültiger Wiederherstellungsschlüssel", + "Riot is now Element!": "Riot ist jetzt Element!", + "Learn More": "Mehr erfahren", + "Unknown caller": "Unbekannter Anrufer", + "Incoming voice call": "Eingehender Sprachanruf", + "Incoming video call": "Eingehender Videoanruf", + "Incoming call": "Eingehender Anruf", + "There are advanced notifications which are not shown here.": "Es sind erweiterte Benachrichtigungen vorhanden, die hier nicht angezeigt werden.", + "Are you sure you want to cancel entering passphrase?": "Bist du sicher dass du die Eingabe der Passphrase abbrechen möchtest?", + "Use your account to sign in to the latest version": "Verwende dein Konto um dich bei der neusten Version anzumelden", + "* %(senderName)s %(emote)s": "* %(senderName)s %(emote)s", + "Enable advanced debugging for the room list": "Erweiterte Fehlersuche für die Raumliste aktivieren", + "Enable experimental, compact IRC style layout": "Kompaktes, experimentelles Layout im IRC-Stil aktivieren", + "User menu": "Benutzermenü", + "%(brand)s Web": "%(brand)s Web", + "%(brand)s Desktop": "%(brand)s Desktop", + "%(brand)s iOS": "%(brand)s iOS", + "%(brand)s X for Android": "%(brand)s X für Android", + "We’re excited to announce Riot is now Element": "Wir freuen uns bekanntzugeben: Riot ist jetzt Element", + "%(brand)s can't securely cache encrypted messages locally while running in a web browser. Use %(brand)s Desktop for encrypted messages to appear in search results.": "%(brand)s kann verschlüsselte Nachrichten nicht sicher zwischenspeichern während es in einem Browser läuft. Verwende %(brand)s Desktop damit verschlüsselte Nachrichten durchsuchbar werden.", + "Show rooms with unread messages first": "Zeige Räume mit ungelesenen Nachrichten zuerst", + "Show previews of messages": "Zeige Vorschau von Nachrichten", + "Use default": "Verwende den Standard", + "Mentions & Keywords": "Erwähnungen & Schlüsselwörter", + "Notification options": "Benachrichtigungsoptionen", + "Forget Room": "Vergesse Raum", + "Favourited": "Favorisiert", + "This room is public": "Dieser Raum ist öffentlich", + "Away": "Abwesend", + "The session you are trying to verify doesn't support scanning a QR code or emoji verification, which is what %(brand)s supports. Try with a different client.": "Die Sitzung, die du verifizieren möchtest, unterstützt weder das scannen eines QR Codes noch eine Emoji Verifikation, welche von %(brand)s unterstützt werden. Versuche es mit einem anderen Client.", + "Edited at %(date)s": "Geändert am %(date)s", + "Click to view edits": "Klicke um Änderungen anzuzeigen", + "%(brand)s encountered an error during upload of:": "%(brand)s hat einen Fehler festgestellt beim hochladen von:", + "Use your account to sign in to the latest version of the app at ": "Verwende dein Konto um dich an der neusten Version der App anzumelden", + "We’re excited to announce Riot is now Element!": "Wir freuen uns bekanntzugeben: Riot ist jetzt Element!", + "Learn more at element.io/previously-riot": "Erfahre mehr unter element.io/previously-riot" } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 1b508feb19..8314402849 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -426,6 +426,8 @@ "There was an error joining the room": "There was an error joining the room", "Sorry, your homeserver is too old to participate in this room.": "Sorry, your homeserver is too old to participate in this room.", "Please contact your homeserver administrator.": "Please contact your homeserver administrator.", + "The person who invited you already left the room.": "The person who invited you already left the room.", + "The person who invited you already left the room, or their server is offline.": "The person who invited you already left the room, or their server is offline.", "Failed to join room": "Failed to join room", "You joined the call": "You joined the call", "%(senderName)s joined the call": "%(senderName)s joined the call", @@ -437,50 +439,11 @@ "%(senderName)s started a call": "%(senderName)s started a call", "Waiting for answer": "Waiting for answer", "%(senderName)s is calling": "%(senderName)s is calling", - "You created the room": "You created the room", - "%(senderName)s created the room": "%(senderName)s created the room", - "You made the chat encrypted": "You made the chat encrypted", - "%(senderName)s made the chat encrypted": "%(senderName)s made the chat encrypted", - "You made history visible to new members": "You made history visible to new members", - "%(senderName)s made history visible to new members": "%(senderName)s made history visible to new members", - "You made history visible to anyone": "You made history visible to anyone", - "%(senderName)s made history visible to anyone": "%(senderName)s made history visible to anyone", - "You made history visible to future members": "You made history visible to future members", - "%(senderName)s made history visible to future members": "%(senderName)s made history visible to future members", - "You were invited": "You were invited", - "%(targetName)s was invited": "%(targetName)s was invited", - "You left": "You left", - "%(targetName)s left": "%(targetName)s left", - "You were kicked (%(reason)s)": "You were kicked (%(reason)s)", - "%(targetName)s was kicked (%(reason)s)": "%(targetName)s was kicked (%(reason)s)", - "You were kicked": "You were kicked", - "%(targetName)s was kicked": "%(targetName)s was kicked", - "You rejected the invite": "You rejected the invite", - "%(targetName)s rejected the invite": "%(targetName)s rejected the invite", - "You were uninvited": "You were uninvited", - "%(targetName)s was uninvited": "%(targetName)s was uninvited", - "You were banned (%(reason)s)": "You were banned (%(reason)s)", - "%(targetName)s was banned (%(reason)s)": "%(targetName)s was banned (%(reason)s)", - "You were banned": "You were banned", - "%(targetName)s was banned": "%(targetName)s was banned", - "You joined": "You joined", - "%(targetName)s joined": "%(targetName)s joined", - "You changed your name": "You changed your name", - "%(targetName)s changed their name": "%(targetName)s changed their name", - "You changed your avatar": "You changed your avatar", - "%(targetName)s changed their avatar": "%(targetName)s changed their avatar", - "%(senderName)s %(emote)s": "%(senderName)s %(emote)s", + "* %(senderName)s %(emote)s": "* %(senderName)s %(emote)s", "%(senderName)s: %(message)s": "%(senderName)s: %(message)s", - "You changed the room name": "You changed the room name", - "%(senderName)s changed the room name": "%(senderName)s changed the room name", "%(senderName)s: %(reaction)s": "%(senderName)s: %(reaction)s", "%(senderName)s: %(stickerName)s": "%(senderName)s: %(stickerName)s", - "You uninvited %(targetName)s": "You uninvited %(targetName)s", - "%(senderName)s uninvited %(targetName)s": "%(senderName)s uninvited %(targetName)s", - "You invited %(targetName)s": "You invited %(targetName)s", - "%(senderName)s invited %(targetName)s": "%(senderName)s invited %(targetName)s", - "You changed the room topic": "You changed the room topic", - "%(senderName)s changed the room topic": "%(senderName)s changed the room topic", + "Change notification settings": "Change notification settings", "New spinner design": "New spinner design", "Message Pinning": "Message Pinning", "Custom user status messages": "Custom user status messages", @@ -651,6 +614,7 @@ "Headphones": "Headphones", "Folder": "Folder", "Pin": "Pin", + "Your server isn't responding to some requests.": "Your server isn't responding to some requests.", "From %(deviceName)s (%(deviceId)s)": "From %(deviceName)s (%(deviceId)s)", "Decline (%(counter)s)": "Decline (%(counter)s)", "Accept to continue:": "Accept to continue:", @@ -967,8 +931,6 @@ "Room version:": "Room version:", "Developer options": "Developer options", "Open Devtools": "Open Devtools", - "Make this room low priority": "Make this room low priority", - "Low priority rooms show up at the bottom of your room list in a dedicated section at the bottom of your room list": "Low priority rooms show up at the bottom of your room list in a dedicated section at the bottom of your room list", "This room is bridging messages to the following platforms. Learn more.": "This room is bridging messages to the following platforms. Learn more.", "This room isn’t bridging messages to any platforms. Learn more.": "This room isn’t bridging messages to any platforms. Learn more.", "Bridges": "Bridges", @@ -1216,10 +1178,11 @@ "All messages": "All messages", "Mentions & Keywords": "Mentions & Keywords", "Notification options": "Notification options", - "Favourited": "Favourited", - "Favourite": "Favourite", "Leave Room": "Leave Room", "Forget Room": "Forget Room", + "Favourited": "Favourited", + "Favourite": "Favourite", + "Low Priority": "Low Priority", "Room options": "Room options", "%(count)s unread messages including mentions.|other": "%(count)s unread messages including mentions.", "%(count)s unread messages including mentions.|one": "1 unread mention.", @@ -1784,6 +1747,19 @@ "Upgrading a room is an advanced action and is usually recommended when a room is unstable due to bugs, missing features or security vulnerabilities.": "Upgrading a room is an advanced action and is usually recommended when a room is unstable due to bugs, missing features or security vulnerabilities.", "This usually only affects how the room is processed on the server. If you're having problems with your %(brand)s, please report a bug.": "This usually only affects how the room is processed on the server. If you're having problems with your %(brand)s, please report a bug.", "You'll upgrade this room from to .": "You'll upgrade this room from to .", + "Resend": "Resend", + "You're all caught up.": "You're all caught up.", + "Server isn't responding": "Server isn't responding", + "Your server isn't responding to some of your requests. Below are some of the most likely reasons.": "Your server isn't responding to some of your requests. Below are some of the most likely reasons.", + "The server (%(serverName)s) took too long to respond.": "The server (%(serverName)s) took too long to respond.", + "Your firewall or anti-virus is blocking the request.": "Your firewall or anti-virus is blocking the request.", + "A browser extension is preventing the request.": "A browser extension is preventing the request.", + "The server is offline.": "The server is offline.", + "The server has denied your request.": "The server has denied your request.", + "Your area is experiencing difficulties connecting to the internet.": "Your area is experiencing difficulties connecting to the internet.", + "A connection error occurred while trying to contact the server.": "A connection error occurred while trying to contact the server.", + "The server is not configured to indicate what the problem is (CORS).": "The server is not configured to indicate what the problem is (CORS).", + "Recent changes that have not yet been received": "Recent changes that have not yet been received", "Sign out and remove encryption keys?": "Sign out and remove encryption keys?", "Clear Storage and Sign Out": "Clear Storage and Sign Out", "Send Logs": "Send Logs", @@ -1891,7 +1867,6 @@ "Reject invitation": "Reject invitation", "Are you sure you want to reject the invitation?": "Are you sure you want to reject the invitation?", "Unable to reject invite": "Unable to reject invite", - "Resend": "Resend", "Resend edit": "Resend edit", "Resend %(unsentCount)s reaction(s)": "Resend %(unsentCount)s reaction(s)", "Resend removal": "Resend removal", @@ -1912,7 +1887,6 @@ "Mentions only": "Mentions only", "Leave": "Leave", "Forget": "Forget", - "Low Priority": "Low Priority", "Direct Chat": "Direct Chat", "Clear status": "Clear status", "Update status": "Update status", @@ -2000,7 +1974,8 @@ "Couldn't load page": "Couldn't load page", "You must register to use this functionality": "You must register to use this functionality", "You must join the room to see its files": "You must join the room to see its files", - "There are no visible files in this room": "There are no visible files in this room", + "No files visible in this room": "No files visible in this room", + "Attach files from chat or just drag and drop them anywhere in a room.": "Attach files from chat or just drag and drop them anywhere in a room.", "

    HTML for your community's page

    \n

    \n Use the long description to introduce new members to the community, or distribute\n some important links\n

    \n

    \n You can even use 'img' tags\n

    \n": "

    HTML for your community's page

    \n

    \n Use the long description to introduce new members to the community, or distribute\n some important links\n

    \n

    \n You can even use 'img' tags\n

    \n", "Add rooms to the community summary": "Add rooms to the community summary", "Which rooms would you like to add to this summary?": "Which rooms would you like to add to this summary?", @@ -2073,7 +2048,8 @@ "Communities": "Communities", "Create a new community": "Create a new community", "Create a community to group together users and rooms! Build a custom homepage to mark out your space in the Matrix universe.": "Create a community to group together users and rooms! Build a custom homepage to mark out your space in the Matrix universe.", - "You have no visible notifications": "You have no visible notifications", + "You’re all caught up": "You’re all caught up", + "You have no visible notifications in this room.": "You have no visible notifications in this room.", "%(brand)s failed to get the protocol list from the homeserver. The homeserver may be too old to support third party networks.": "%(brand)s failed to get the protocol list from the homeserver. The homeserver may be too old to support third party networks.", "%(brand)s failed to get the public room list.": "%(brand)s failed to get the public room list.", "The homeserver may be unavailable or overloaded.": "The homeserver may be unavailable or overloaded.", diff --git a/src/i18n/strings/eo.json b/src/i18n/strings/eo.json index c49e72a1f2..8d07db7eaf 100644 --- a/src/i18n/strings/eo.json +++ b/src/i18n/strings/eo.json @@ -56,7 +56,7 @@ "Unable to enable Notifications": "Ne povas ŝalti sciigojn", "This email address was not found": "Tiu ĉi retpoŝtadreso ne troviĝis", "Your email address does not appear to be associated with a Matrix ID on this Homeserver.": "Via retpoŝtareso ŝajne ne ligiĝas al Matrix-identigilo sur tiu ĉi hejmservilo.", - "Default": "Norma", + "Default": "Ordinara", "Restricted": "Limigita", "Moderator": "Ĉambrestro", "Admin": "Administranto", @@ -131,7 +131,7 @@ "Not a valid %(brand)s keyfile": "Nevalida ŝlosila dosiero de %(brand)s", "Authentication check failed: incorrect password?": "Aŭtentikiga kontrolo malsukcesis: ĉu pro malĝusta pasvorto?", "Failed to join room": "Malsukcesis aliĝi al ĉambro", - "Message Pinning": "Fikso de mesaĝoj", + "Message Pinning": "Fiksado de mesaĝoj", "Show timestamps in 12 hour format (e.g. 2:30pm)": "Montri tempindikojn en 12-hora formo (ekz. 2:30 post.)", "Always show message timestamps": "Ĉiam montri mesaĝajn tempindikojn", "Autoplay GIFs and videos": "Memfare ludi GIF-bildojn kaj filmojn", @@ -800,7 +800,7 @@ "There was an error joining the room": "Aliĝo al la ĉambro eraris", "Sorry, your homeserver is too old to participate in this room.": "Pardonon, via hejmservilo estas tro malnova por partoprenado en la ĉambro.", "Please contact your homeserver administrator.": "Bonvolu kontakti la administranton de via hejmservilo.", - "Show a reminder to enable Secure Message Recovery in encrypted rooms": "Montri memorigilon por ŝalti Sekuran Ricevon de Mesaĝoj en ĉifrataj ĉambroj", + "Show a reminder to enable Secure Message Recovery in encrypted rooms": "Montri memorigilon por ŝalti Sekuran ricevon de mesaĝoj en ĉifrataj ĉambroj", "Show developer tools": "Montri verkistajn ilojn", "Messages containing @room": "Mesaĝoj enhavantaj @room", "Encrypted messages in one-to-one chats": "Ĉifritaj mesaĝoj en duopaj babiloj", @@ -915,7 +915,7 @@ "Change permissions": "Ŝanĝi permesojn", "Change topic": "Ŝanĝi temon", "Modify widgets": "Aliigi fenestraĵojn", - "Default role": "Norma rolo", + "Default role": "Ordinara rolo", "Send messages": "Sendi mesaĝojn", "Invite users": "Inviti uzantojn", "Change settings": "Ŝanĝi agordojn", @@ -1222,9 +1222,9 @@ "Adds a custom widget by URL to the room": "Aldonas propran fenestraĵon al la ĉambro per URL", "You cannot modify widgets in this room.": "Vi ne rajtas modifi fenestraĵojn en ĉi tiu ĉambro.", "Forces the current outbound group session in an encrypted room to be discarded": "Devigas la aktualan eliran grupan salutaĵon en ĉifrita ĉambro forĵetiĝi", - "%(senderDisplayName)s enabled flair for %(groups)s in this room.": "%(senderDisplayName)s ŝaltis etikedojn por %(groups)s en ĉi tiu ĉambro.", - "%(senderDisplayName)s disabled flair for %(groups)s in this room.": "%(senderDisplayName)s malŝaltis etikedojn por %(groups)s en ĉi tiu ĉambro.", - "%(senderDisplayName)s enabled flair for %(newGroups)s and disabled flair for %(oldGroups)s in this room.": "%(senderDisplayName)s ŝaltis etikedojn por %(newGroups)s kaj malŝaltis etikedojn por %(oldGroups)s en ĉi tiu ĉambro.", + "%(senderDisplayName)s enabled flair for %(groups)s in this room.": "%(senderDisplayName)s ŝaltis insignojn por %(groups)s en ĉi tiu ĉambro.", + "%(senderDisplayName)s disabled flair for %(groups)s in this room.": "%(senderDisplayName)s malŝaltis insignojn por %(groups)s en ĉi tiu ĉambro.", + "%(senderDisplayName)s enabled flair for %(newGroups)s and disabled flair for %(oldGroups)s in this room.": "%(senderDisplayName)s ŝaltis insignojn por %(newGroups)s kaj malŝaltis insignojn por %(oldGroups)s en ĉi tiu ĉambro.", "%(senderName)s revoked the invitation for %(targetDisplayName)s to join the room.": "%(senderName)s nuligis inviton en la ĉambron por %(targetDisplayName)s.", "Cannot reach homeserver": "Ne povas atingi hejmservilon", "Ensure you have a stable internet connection, or get in touch with the server admin": "Certiĝu ke vi havas stabilan retkonekton, aŭ kontaktu la administranton de la servilo", @@ -1273,7 +1273,7 @@ "No backup found!": "Neniu savkopio troviĝis!", "Resend edit": "Resendi redakton", "Go to Settings": "Iri al agordoj", - "Flair": "Etikedo", + "Flair": "Insigno", "No Audio Outputs detected": "Neniu soneligo troviĝis", "Send %(eventType)s events": "Sendi okazojn de tipo « %(eventType)s »", "Select the roles required to change various parts of the room": "Elektu la rolojn postulatajn por ŝanĝado de diversaj partoj de la ĉambro", @@ -1282,15 +1282,15 @@ "Encryption": "Ĉifrado", "Once enabled, encryption cannot be disabled.": "Post ŝalto, ne plu eblas malŝalti ĉifradon.", "Encrypted": "Ĉifrata", - "The conversation continues here.": "La interparolo pluas ĉi tie.", + "The conversation continues here.": "La interparolo daŭras ĉi tie.", "This room has been replaced and is no longer active.": "Ĉi tiu ĉambro estas anstataŭita, kaj ne plu aktivas.", "Loading room preview": "Preparas antaŭrigardon al la ĉambro", "Only room administrators will see this warning": "Nur administrantoj de ĉambro vidos ĉi tiun averton", - "Error updating flair": "Eraris ĝisdatigo de etikedo", - "There was an error updating the flair for this room. The server may not allow it or a temporary error occurred.": "Eraris ĝisdatigo de etikedo por ĉi tiu ĉambro. Aŭ la servilo ne permesas ĝin, aŭ dumtempa eraro okazis.", - "Showing flair for these communities:": "Montras etikedojn de la jenaj komunumoj:", - "This room is not showing flair for any communities": "Ĉi tiu ĉambro montras etikedojn de neniuj komunumoj", - "Display your community flair in rooms configured to show it.": "Montri etikedon de via komunumo en ĉambroj agorditaj por montri ĝin.", + "Error updating flair": "Eraris ĝisdatigo de insigno", + "There was an error updating the flair for this room. The server may not allow it or a temporary error occurred.": "Eraris ĝisdatigo de insigno por ĉi tiu ĉambro. Aŭ la servilo ne permesas ĝin, aŭ dumtempa eraro okazis.", + "Showing flair for these communities:": "Montras insignojn de la jenaj komunumoj:", + "This room is not showing flair for any communities": "Ĉi tiu ĉambro montras insignojn de neniuj komunumoj", + "Display your community flair in rooms configured to show it.": "Montri insignon de via komunumo en ĉambroj agorditaj por montri ĝin.", "%(severalUsers)smade no changes %(count)s times|other": "%(severalUsers)snenion ŝanĝis je %(count)s fojoj", "%(severalUsers)smade no changes %(count)s times|one": "%(severalUsers)snenion ŝanĝis", "%(oneUser)smade no changes %(count)s times|other": "%(oneUser)snenion ŝanĝis je %(count)s fojoj", @@ -1357,9 +1357,9 @@ "If you don't want to set this up now, you can later in Settings.": "Se vi ne volas agordi tion nun, vi povas fari ĝin poste per agordoj.", "Don't ask again": "Ne demandi ree", "New Recovery Method": "Nova rehava metodo", - "A new recovery passphrase and key for Secure Messages have been detected.": "Novaj rehava pasfrazo kaj ŝlosilo por sekuraj mesaĝoj troviĝis.", + "A new recovery passphrase and key for Secure Messages have been detected.": "Novaj rehava pasfrazo kaj ŝlosilo por Sekuraj mesaĝoj troviĝis.", "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Se vi ne agordis la novan rehavan metodon, eble atakanto provas aliri vian konton. Vi tuj ŝanĝu la pasvorton de via konto, kaj agordu novan rehavan metodon en la agordoj.", - "Set up Secure Messages": "Agordi sekurajn mesaĝojn", + "Set up Secure Messages": "Agordi Sekurajn mesaĝojn", "Recovery Method Removed": "Rehava metodo foriĝis", "If you didn't remove the recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Se vi ne forigis la rehavan metodon, eble atakanto provas aliri vian konton. Vi tuj ŝanĝu la pasvorton de via konto, kaj agordu novan rehavan metodon en la agordoj.", "Use a longer keyboard pattern with more turns": "Uzu pli longan tekston kun plia varieco", @@ -1386,7 +1386,7 @@ "Save it on a USB key or backup drive": "Konservu ĝin en poŝmemorilo aŭ savkopia disko", "Copy it to your personal cloud storage": "Kopiu ĝin al via persona enreta konservejo", "Your keys are being backed up (the first backup could take a few minutes).": "Viaj ŝlosiloj estas savkopiataj (la unua savkopio povas daŭri kelkajn minutojn).", - "Set up Secure Message Recovery": "Agordi sekuran rehavon de mesaĝoj", + "Set up Secure Message Recovery": "Agordi Sekuran rehavon de mesaĝoj", "Starting backup...": "Komencante savkopion…", "Unable to create key backup": "Ne povas krei savkopion de ŝlosiloj", "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Sen agordo de Sekura rehavo de mesaĝoj, vi perdos vian sekuran historion de mesaĝoj per adiaŭo.", @@ -1721,8 +1721,8 @@ "To be secure, do this in person or use a trusted way to communicate.": "Por plia sekureco, faru tion persone, aŭ uzu alian fidatan komunikilon.", "Verify yourself & others to keep your chats safe": "Kontrolu vin mem kaj aliajn por sekurigi viajn babilojn", "Channel: %(channelName)s": "Kanalo: %(channelName)s", - "Show less": "Montri pli", - "Show more": "Montri malpli", + "Show less": "Montri malpli", + "Show more": "Montri pli", "Help": "Helpo", "Session verified": "Salutaĵo kontroliĝis", "Copy": "Kopii", @@ -1762,16 +1762,16 @@ "This bridge is managed by .": "Ĉi tiu ponto estas administrata de .", "Workspace: %(networkName)s": "Labortablo: %(networkName)s", "Changing password will currently reset any end-to-end encryption keys on all sessions, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "Ŝanĝo de pasvorto nuntempe restarigos ĉiujn tutvoje ĉifrajn ŝlosilojn en ĉiuj salutaĵoj, malebligante legadon de ĉifrita historio, malse vi unue elportus la ŝlosilojn de viaj ĉambroj kaj reenportus ilin poste. Ĉi tion ni plibonigos ose.", - "Your homeserver does not support cross-signing.": "Via hejmservilo ne subtenas transirajn subskribojn.", - "Cross-signing and secret storage are enabled.": "Transiraj subskriboj kaj sekreta deponejo estas ŝaltitaj.", - "Your account has a cross-signing identity in secret storage, but it is not yet trusted by this session.": "Via konto havas identecon de transiraj subskriboj en sekreta deponejo, sed ĉi tiu salutaĵo ankoraŭ ne fidas ĝin.", - "Cross-signing and secret storage are not yet set up.": "Transiraj subskriboj kaj sekreta deponejo ankoraŭ ne agordiĝis.", - "Reset cross-signing and secret storage": "Remeti transirajn subskribojn kaj sekretan deponejon", - "Bootstrap cross-signing and secret storage": "Praŝargi transirajn subskribojn kaj sekretan deponejon", - "Cross-signing public keys:": "Transiraj publikaj ŝlosiloj:", + "Your homeserver does not support cross-signing.": "Via hejmservilo ne subtenas delegajn subskribojn.", + "Cross-signing and secret storage are enabled.": "Delegaj subskriboj kaj sekreta deponejo estas ŝaltitaj.", + "Your account has a cross-signing identity in secret storage, but it is not yet trusted by this session.": "Via konto havas identecon por delegaj subskriboj en sekreta deponejo, sed ĉi tiu salutaĵo ankoraŭ ne fidas ĝin.", + "Cross-signing and secret storage are not yet set up.": "Delegaj subskriboj kaj sekreta deponejo ankoraŭ ne agordiĝis.", + "Reset cross-signing and secret storage": "Remeti delegajn subskribojn kaj sekretan deponejon", + "Bootstrap cross-signing and secret storage": "Pretigi delegajn subskribojn kaj sekretan deponejon", + "Cross-signing public keys:": "Delegaj publikaj ŝlosiloj:", "in memory": "en memoro", "not found": "ne trovita", - "Cross-signing private keys:": "Transiraj privataj ŝlosiloj:", + "Cross-signing private keys:": "Delegaj privataj ŝlosiloj:", "in secret storage": "en sekreta deponejo", "Secret storage public key:": "Publika ŝlosilo de sekreta deponejo:", "in account data": "en datumoj de konto", @@ -1837,7 +1837,7 @@ "Session ID:": "Identigilo de salutaĵo:", "Session key:": "Ŝlosilo de salutaĵo:", "Message search": "Serĉado de mesaĝoj", - "Cross-signing": "Transiraj subskriboj", + "Cross-signing": "Delegaj subskriboj", "A session's public name is visible to people you communicate with": "Publika nomo de salutaĵo estas videbla al homoj, kun kiuj vi komunikas", "This room is bridging messages to the following platforms. Learn more.": "Ĉi tiu ĉambro transpontigas mesaĝojn al la jenaj platformoj. Eksciu plion.", "This room isn’t bridging messages to any platforms. Learn more.": "Ĉi tiu ĉambro transpontigas mesaĝojn al neniu platformo. Eksciu plion.", @@ -1898,9 +1898,9 @@ "Using this widget may share data with %(widgetDomain)s & your Integration Manager.": "Uzo de tiu ĉi fenestraĵo eble havigos datumojn kun %(widgetDomain)s kaj via kunigilo.", "Using this widget may share data with %(widgetDomain)s.": "Uzo de tiu ĉi fenestraĵo eble havigos datumojn kun %(widgetDomain)s.", "Language Dropdown": "Lingva falmenuo", - "Destroy cross-signing keys?": "Ĉu detrui transire ĉifrajn ŝlosilojn?", - "Deleting cross-signing keys is permanent. Anyone you have verified with will see security alerts. You almost certainly don't want to do this, unless you've lost every device you can cross-sign from.": "Forigo de transire ĉifraj ŝlosiloj estas porĉiama. Ĉiu, kun kiu vi interkontrolis, vidos avertojn pri sekureco. Vi preskaŭ certe ne volas ĉi tion fari, malse vi perdis ĉiun aparaton, el kiu vi povus transire subskribadi.", - "Clear cross-signing keys": "Vakigi transire ĉifrajn ŝlosilojn", + "Destroy cross-signing keys?": "Ĉu detrui delege ĉifrajn ŝlosilojn?", + "Deleting cross-signing keys is permanent. Anyone you have verified with will see security alerts. You almost certainly don't want to do this, unless you've lost every device you can cross-sign from.": "Forigo de delege ĉifraj ŝlosiloj estas porĉiama. Ĉiu, kun kiu vi interkontrolis, vidos avertojn pri sekureco. Vi preskaŭ certe ne volas ĉi tion fari, malse vi perdis ĉiun aparaton, el kiu vi povus delege subskribadi.", + "Clear cross-signing keys": "Vakigi delege ĉifrajn ŝlosilojn", "Clear all data in this session?": "Ĉu vakigi ĉiujn datumojn en ĉi tiu salutaĵo?", "Clearing all data from this session is permanent. Encrypted messages will be lost unless their keys have been backed up.": "Vakigo de ĉiuj datumoj el ĉi tiu salutaĵo estas porĉiama. Ĉifritaj mesaĝoj perdiĝos, malse iliaj ŝlosiloj savkopiiĝis.", "Verify session": "Kontroli salutaĵon", @@ -2014,8 +2014,8 @@ "Keyboard Shortcuts": "Klavkombinoj", "Start a conversation with someone using their name, username (like ) or email address.": "Komencu interparolon kun iu per ĝia nomo, uzantonomo (kiel ), aŭ retpoŝtadreso.", "a new master key signature": "nova ĉefŝlosila subskribo", - "a new cross-signing key signature": "nova transire subskriba ŝlosila subskribo", - "a device cross-signing signature": "aparata transire subskriba ŝlosila subskribo", + "a new cross-signing key signature": "nova subskribo de delega ŝlosilo", + "a device cross-signing signature": "delega subskribo de aparato", "a key signature": "ŝlosila subskribo", "%(brand)s encountered an error during upload of:": "%(brand)s eraris dum alŝuto de:", "Upload completed": "Alŝuto finiĝis", @@ -2068,7 +2068,7 @@ "Whether you're using %(brand)s as an installed Progressive Web App": "Ĉu vi uzas %(brand)son kiel Progresan retan aplikaĵon", "Manually verify all remote sessions": "Permane kontroli ĉiujn forajn salutaĵojn", "Session backup key:": "Savkopia ŝlosilo de salutaĵo:", - "Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.": "Unuope kontroli ĉiun salutaĵon de uzanto por marki ĝin fidata, ne fidante transire subskribitajn aparatojn.", + "Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.": "Unuope kontroli ĉiun salutaĵon de uzanto por marki ĝin fidata, ne fidante delege subskribitajn aparatojn.", "Invalid theme schema.": "Nevalida skemo de haŭto.", "Mod": "Reguligisto", "In encrypted rooms, your messages are secured and only you and the recipient have the unique keys to unlock them.": "En ĉifritaj ĉambroj, viaj mesaĝoj estas sekurigitaj, kaj nur vi kaj la ricevanto havas la unikajn malĉifrajn ŝlosilojn.", @@ -2158,7 +2158,7 @@ "If you've joined lots of rooms, this might take a while": "Se vi aliĝis al multaj ĉambroj, tio povas daŭri longe", "Confirm your identity by verifying this login from one of your other sessions, granting it access to encrypted messages.": "Konfirmu vian identecon per kontrolo de ĉi tiu saluto el unu el viaj aliaj salutaĵoj, permesante al ĝi legadon de ĉifritaj mesaĝoj.", "This requires the latest %(brand)s on your other devices:": "Ĉi tio bezonas la plej freŝan version de %(brand)s en viaj aliaj aparatoj:", - "or another cross-signing capable Matrix client": "aŭ alian Matrix-klienton kapablan je transiraj subskriboj", + "or another cross-signing capable Matrix client": "aŭ alian Matrix-klienton kapablan je delegaj subskriboj", "Great! This recovery passphrase looks strong enough.": "Bonege! Ĉi tiu rehava pasfrazo ŝajnas sufiĉe forta.", "Enter a recovery passphrase": "Enigu rehavan pasfrazon", "Enter your recovery passphrase a second time to confirm it.": "Enigu vian rehavan pasfrazon duafoje por konfirmi ĝin.", @@ -2230,5 +2230,162 @@ "Upgrade your %(brand)s": "Gradaltigi vian %(brand)son", "A new version of %(brand)s is available!": "Nova versio de %(brand)s estas disponebla!", "New version available. Update now.": "Nova versio estas disponebla. Ĝisdatigu nun.", - "Emoji picker": "Elektilo de bildsignoj" + "Emoji picker": "Elektilo de bildsignoj", + "Use your account to sign in to the latest version": "Uzu vian konton por saluti la plej freŝan version", + "We’re excited to announce Riot is now Element": "Ni ekscite anoncas, ke Riot nun estas Elemento", + "Riot is now Element!": "Riot nun estas Elemento!", + "Learn More": "Eksciu plion", + "Light": "Hela", + "Dark": "Malhela", + "You joined the call": "Vi aliĝis al la voko", + "%(senderName)s joined the call": "%(senderName)s aliĝis al la voko", + "Call in progress": "Voko okazas", + "You left the call": "Vi foriris de la voko", + "%(senderName)s left the call": "%(senderName)s foriris de la voko", + "Call ended": "Voko finiĝis", + "You started a call": "Vi komencis vokon", + "%(senderName)s started a call": "%(senderName)s komencis vokon", + "Waiting for answer": "Atendante respondon", + "%(senderName)s is calling": "%(senderName)s vokas", + "You created the room": "Vi kreis la ĉambron", + "%(senderName)s created the room": "%(senderName)s kreis la ĉambron", + "You made the chat encrypted": "Vi ekĉifris la babilon", + "%(senderName)s made the chat encrypted": "%(senderName)s ekĉifris la babilon", + "You made history visible to new members": "Vi videbligis la historion al novaj anoj", + "%(senderName)s made history visible to new members": "%(senderName)s videbligis la historion al novaj anoj", + "You made history visible to anyone": "Vi videbligis la historion al ĉiu ajn", + "%(senderName)s made history visible to anyone": "%(senderName)s videbligis la historion al ĉiu ajn", + "You made history visible to future members": "Vi videbligis la historion al osaj anoj", + "%(senderName)s made history visible to future members": "%(senderName)s videbligis la historion al osaj anoj", + "You were invited": "Vi estis invitita", + "%(targetName)s was invited": "%(senderName)s estis invitita", + "You left": "Vi foriris", + "%(targetName)s left": "%(senderName)s foriris", + "You were kicked (%(reason)s)": "Vi estis forpelita (%(reason)s)", + "%(targetName)s was kicked (%(reason)s)": "%(targetName)s estis forpelita (%(reason)s)", + "You were kicked": "Vi estis forpelita", + "%(targetName)s was kicked": "%(targetName)s estis forpelita", + "You rejected the invite": "Vi rifuzis la inviton", + "%(targetName)s rejected the invite": "%(targetName)s rifuzis la inviton", + "You were uninvited": "Vi estis malinvitita", + "%(targetName)s was uninvited": "%(targetName)s estis malinvitita", + "You were banned (%(reason)s)": "Vi estis forbarita (%(reason)s)", + "%(targetName)s was banned (%(reason)s)": "%(targetName)s estis forbarita (%(reason)s)", + "You were banned": "Vi estis forbarita", + "%(targetName)s was banned": "%(targetName)s estis forbarita", + "You joined": "Vi aliĝis", + "%(targetName)s joined": "%(targetName)s aliĝis", + "You changed your name": "Vi ŝanĝis vian nomon", + "%(targetName)s changed their name": "%(targetName)s ŝanĝis sian nomon", + "You changed your avatar": "Vi ŝanĝis vian profilbildon", + "%(targetName)s changed their avatar": "%(targetName)s ŝanĝis sian profilbildon", + "%(senderName)s %(emote)s": "%(senderName)s %(emote)s", + "%(senderName)s: %(message)s": "%(senderName)s: %(message)s", + "You changed the room name": "Vi ŝanĝis la nomon de la ĉambro", + "%(senderName)s changed the room name": "%(senderName)s ŝanĝis la nomon de la ĉambro", + "%(senderName)s: %(reaction)s": "%(senderName)s: %(reaction)s", + "%(senderName)s: %(stickerName)s": "%(senderName)s: %(stickerName)s", + "You uninvited %(targetName)s": "Vi malinvitis uzanton %(targetName)s", + "%(senderName)s uninvited %(targetName)s": "%(senderName)s malinvitis uzanton %(targetName)s", + "You invited %(targetName)s": "Vi invitis uzanton %(targetName)s", + "%(senderName)s invited %(targetName)s": "%(senderName)s invitis uzanton %(targetName)s", + "You changed the room topic": "Vi ŝanĝis la temon de la ĉambro", + "%(senderName)s changed the room topic": "%(senderName)s ŝanĝis la temon de la ĉambro", + "Use the improved room list (will refresh to apply changes)": "Uzi la plibonigitan ĉambrobreton (aktualigos la paĝon por apliki la ŝanĝojn)", + "Use custom size": "Uzi propran grandon", + "Use a more compact ‘Modern’ layout": "Uzi pli densan »Modernan« aranĝon", + "Use a system font": "Uzi sisteman tiparon", + "System font name": "Nomo de sistema tiparo", + "Enable experimental, compact IRC style layout": "Ŝalti eksperimentan, densan IRC-ecan aranĝon", + "Unknown caller": "Nekonata vokanto", + "Incoming voice call": "Envena voĉvoko", + "Incoming video call": "Envena vidvoko", + "Incoming call": "Envena voko", + "%(brand)s can't securely cache encrypted messages locally while running in a web browser. Use %(brand)s Desktop for encrypted messages to appear in search results.": "%(brand)s ne povas sekure kaŝkopii ĉifritajn mesaĝojn loke, funkciante per foliumilo. Uzu %(brand)s Desktop por aperigi ĉifritajn mesaĝojn en serĉrezultoj.", + "There are advanced notifications which are not shown here.": "Ekzistas specialaj sciigoj, kiuj ne estas montrataj ĉi tie.", + "You might have configured them in a client other than %(brand)s. You cannot tune them in %(brand)s but they still apply.": "Vi eble agordis ilin en kliento alia ol %(brand)s. Vi ne povas agordi ilin en %(brand)s, sed ili tamen estas aplikataj.", + "Hey you. You're the best!": "He, vi. Vi bonegas!", + "Message layout": "Aranĝo de mesaĝoj", + "Compact": "Densa", + "Modern": "Moderna", + "Set the name of a font installed on your system & %(brand)s will attempt to use it.": "Agordu la nomon de tiparo instalita en via sistemo kaj %(brand)s provos ĝin uzi.", + "Customise your appearance": "Adaptu vian aspekton", + "Appearance Settings only affect this %(brand)s session.": "Agordoj de aspekto nur efikos sur ĉi tiun salutaĵon de %(brand)s.", + "Add users and servers you want to ignore here. Use asterisks to have %(brand)s match any characters. For example, @bot:* would ignore all users that have the name 'bot' on any server.": "Aldonu uzantojn kaj servilojn, kiujn vi volas malatenti, ĉi tien. Uzu steletojn por ke %(brand)s atendu iujn ajn signojn. Ekzemple, @bot:* malatentigus ĉiujn uzantojn, kiuj havas la nomon «bot» sur ĉiu ajn servilo.", + "Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.": "La administranto de via servilo malŝaltis implicitan tutvojan ĉifradon en privataj kaj rektaj ĉambroj.", + "Make this room low priority": "Doni al la ĉambro malaltan prioritaton", + "Low priority rooms show up at the bottom of your room list in a dedicated section at the bottom of your room list": "Ĉambroj kun malalta prioritato montriĝas en aparta sekcio, en la suba parto de via ĉambrobreto,", + "The authenticity of this encrypted message can't be guaranteed on this device.": "La aŭtentikeco de ĉi tiu ĉifrita mesaĝo ne povas esti garantiita sur ĉi tiu aparato.", + "No recently visited rooms": "Neniuj freŝdate vizititaj ĉambroj", + "People": "Homoj", + "Unread rooms": "Nelegitaj ĉambroj", + "Always show first": "Ĉiam montri unuaj", + "Show": "Montri", + "Message preview": "Antaŭrigardo al mesaĝo", + "Sort by": "Ordigi laŭ", + "Activity": "Aktiveco", + "A-Z": "A–Z", + "List options": "Elektebloj pri listo", + "Show %(count)s more|other": "Montri %(count)s pliajn", + "Show %(count)s more|one": "Montri %(count)s plian", + "Use default": "Uzi implicitan", + "Mentions & Keywords": "Mencioj kaj ŝlosilvortoj", + "Notification options": "Elektebloj pri sciigoj", + "Favourited": "Elstarigita", + "Leave Room": "Foriri de ĉambro", + "Forget Room": "Forgesi ĉambron", + "Room options": "Elektebloj pri ĉambro", + "Message deleted on %(date)s": "Mesaĝo forigita je %(date)s", + "Use your account to sign in to the latest version of the app at ": "Uzu vian konton por saluti la plej freŝan version de la aplikaĵo je ", + "You’re already signed in and good to go here, but you can also grab the latest versions of the app on all platforms at element.io/get-started.": "Vi jam estas salutinta kaj preta ĉi tie, sed vi povas ankaŭ ekhavi la plej freŝajn versiojn de la aplikaĵoj sur ĉiuj platformoj je element.io/get-started.", + "Go to Element": "Iri al Elemento", + "We’re excited to announce Riot is now Element!": "Ni estas ekscititaj anonci, ke Riot nun estas Elemento!", + "Learn more at element.io/previously-riot": "Eksciu plion je element.io/previously-riot", + "Wrong file type": "Neĝusta dosiertipo", + "Looks good!": "Ŝajnas bona!", + "Wrong Recovery Key": "Neĝusta rehava ŝlosilo", + "Invalid Recovery Key": "Nevalida rehava ŝlosilo", + "Security Phrase": "Sekureca frazo", + "Enter your Security Phrase or to continue.": "Enigu vian sekurecan frazon aŭ por daŭrigi.", + "Security Key": "Sekureca ŝlosilo", + "Use your Security Key to continue.": "Uzu vian sekurecan ŝlosilon por daŭrigi.", + "You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use %(brand)s with an existing Matrix account on a different homeserver.": "Vi povas uzi proprajn elekteblojn pri servilo por saluti aliajn servilojn de Matrix, per specifo de alia URL de hejmservilo. Tio ebligas al vi uzi la programon %(brand)s kun jama konto de Matrix je alia hejmservilo.", + "Search rooms": "Serĉi ĉambrojn", + "Switch to light mode": "Ŝalti helan reĝimon", + "Switch to dark mode": "Ŝalti malhelan reĝimon", + "Switch theme": "Ŝalti haŭton", + "Security & privacy": "Sekureco kaj privateco", + "All settings": "Ĉiuj agordoj", + "User menu": "Menuo de uzanto", + "Use Recovery Key or Passphrase": "Uzi rehavan ŝlosilon aŭ pasfrazon", + "Use Recovery Key": "Uzi rehavan ŝlosilon", + "%(brand)s Web": "%(brand)s por Reto", + "%(brand)s Desktop": "%(brand)s por Labortablo", + "%(brand)s iOS": "%(brand)s por iOS", + "%(brand)s X for Android": "%(brand)s X por Android", + "Safeguard against losing access to encrypted messages & data by backing up encryption keys on your server.": "Malhelpu perdon de aliro al ĉifritaj mesaĝoj kaj datumoj per savkopiado de ĉifraj ŝlosiloj al via servilo.", + "Generate a Security Key": "Generi sekurecan ŝlosilon", + "We’ll generate a Security Key for you to store somewhere safe, like a password manager or a safe.": "Ni estigos sekurecan ŝlosilon, kiun vi devus konservi en sekura loko, ekzemple administrilo de pasvortoj, aŭ sekurŝranko.", + "Enter a Security Phrase": "Enigiu sekurecan frazon", + "Use a secret phrase only you know, and optionally save a Security Key to use for backup.": "Uzu sekretan frazon kiun konas nur vi, kaj laŭplaĉe konservu sekurecan ŝlosilon, uzotan por savkopiado.", + "Enter a security phrase only you know, as it’s used to safeguard your data. To be secure, you shouldn’t re-use your account password.": "Enigu sekurecan pasfrazon kiun konas nur vi, ĉar ĝi protektos viajn datumojn. Por esti certa, vi ne reuzu la pasvorton de via konto.", + "Store your Security Key somewhere safe, like a password manager or a safe, as it’s used to safeguard your encrypted data.": "Deponu vian sekurecan ŝlosilon en sekura loko, ekzemple administrilo de pasvortoj aŭ sekurŝranko, ĉar ĝi protektos viajn ĉifritajn datumojn.", + "If you cancel now, you may lose encrypted messages & data if you lose access to your logins.": "Se vi nuligos nun, vi eble perdos ĉifritajn mesaĝojn kaj datumojn se vi perdos aliron al viaj salutoj.", + "You can also set up Secure Backup & manage your keys in Settings.": "Vi ankaŭ povas agordi Sekuran savkopiadon kaj administri viajn ŝlosilojn per Agordoj.", + "Set up Secure backup": "Agordi Sekuran savkopiadon", + "Set a Security Phrase": "Agordi Sekurecan frazon", + "Confirm Security Phrase": "Konfirmi Sekurecan frazon", + "Save your Security Key": "Konservi vian Sekurecan ŝlosilon", + "New spinner design": "Nova fasono de la turniĝilo", + "Show rooms with unread messages first": "Montri ĉambrojn kun nelegitaj mesaĝoj kiel unuajn", + "Show previews of messages": "Montri antaŭrigardojn al mesaĝoj", + "This room is public": "Ĉi tiu ĉambro estas publika", + "Away": "For", + "Edited at %(date)s": "Redaktita je %(date)s", + "Click to view edits": "Klaku por vidi redaktojn", + "Are you sure you want to cancel entering passphrase?": "Ĉu vi certe volas nuligi enigon de pasfrazo?", + "Enable advanced debugging for the room list": "Ŝalti altnivelan erarserĉadon por la ĉambrobreto", + "* %(senderName)s %(emote)s": "* %(senderName)s %(emote)s", + "Custom Tag": "Propra etikedo", + "Feedback": "Prikomenti" } diff --git a/src/i18n/strings/et.json b/src/i18n/strings/et.json index 0a6837fb48..271893b862 100644 --- a/src/i18n/strings/et.json +++ b/src/i18n/strings/et.json @@ -141,7 +141,7 @@ "Remove recent messages by %(user)s": "Eemalda %(user)s hiljutised sõnumid", "Replying With Files": "Vasta faili(de)ga", "Invite new community members": "Kutsu uusi liikmeid kogukonda", - "rooms.": "jututoad.", + "rooms.": "jututubadest.", "Notify for all other messages/rooms": "Teavita kõikidest teistest sõnumitest/jututubadest", "Members only (since the point in time of selecting this option)": "Ainult liikmetele (alates selle seadistuse kasutuselevõtmisest)", "Members only (since they were invited)": "Ainult liikmetele (alates nende kutsumise ajast)", @@ -280,8 +280,8 @@ "Some session data, including encrypted message keys, is missing. Sign out and sign in to fix this, restoring keys from backup.": "Osa sessiooniandmetest, sealhulgas sõnumi krüptovõtmed, on puudu. Vea parandamiseks logi välja ja sisse, vajadusel taasta võtmed varundusest.", "Your browser likely removed this data when running low on disk space.": "On võimalik et sinu brauser kustutas need andmed, sest kõvakettaruumist jäi puudu.", "Integration Manager": "Lõiminguhaldur", - "Find others by phone or email": "Leia teisi kasutajaid telefoninumbri või e-posti aadressi alsusel", - "Be found by phone or email": "Ole leitav telefoninumbri või e-posti aadressi alsusel", + "Find others by phone or email": "Leia teisi kasutajaid telefoninumbri või e-posti aadressi alusel", + "Be found by phone or email": "Ole leitav telefoninumbri või e-posti aadressi alusel", "Terms of Service": "Kasutustingimused", "To continue you need to accept the terms of this service.": "Jätkamaks pead nõustuma kasutustingimustega.", "Service": "Teenus", @@ -879,7 +879,7 @@ "Set up": "Võta kasutusele", "Upgrade": "Uuenda", "Verify": "Verifitseeri", - "Verify the new login accessing your account: %(name)s": "Verifitseeri uus kasutajasessioon, kes pruugib sinu kontot: %(name)s", + "Verify the new login accessing your account: %(name)s": "Verifitseeri uus kasutajasessioon, mis pruugib sinu kontot: %(name)s", "From %(deviceName)s (%(deviceId)s)": "Seadmest %(deviceName)s (%(deviceId)s)", "Decline (%(counter)s)": "Lükka tagasi (%(counter)s)", "Accept to continue:": "Jätkamiseks nõustu 'ga:", @@ -1021,7 +1021,7 @@ "Send a Direct Message": "Saada otsesõnum", "Are you sure you want to leave the room '%(roomName)s'?": "Kas oled kindel, et soovid lahkuda jututoast '%(roomName)s'?", "Unknown error": "Teadmata viga", - "To continue using the %(homeserverDomain)s homeserver you must review and agree to our terms and conditions.": "Selleka et jätkata koduserveri %(homeserverDomain)s kasutamist sa pead üle vaatama ja nõustuma meie kasutamistingimustega.", + "To continue using the %(homeserverDomain)s homeserver you must review and agree to our terms and conditions.": "Selleks et jätkata koduserveri %(homeserverDomain)s kasutamist sa pead üle vaatama ja nõustuma meie kasutustingimustega.", "Permissions": "Õigused", "Select the roles required to change various parts of the room": "Vali rollid, mis on vajalikud jututoa eri osade muutmiseks", "Enable encryption?": "Kas võtame krüptimise kasutusele?", @@ -1084,7 +1084,7 @@ "Try again later, or ask a room admin to check if you have access.": "Proovi hiljem uuesti või küsi jututoa haldurilt, kas sul on ligipääs olemas.", "%(errcode)s was returned while trying to access the room. If you think you're seeing this message in error, please submit a bug report.": "Astumisel jututuppa tekkis viga %(errcode)s. Kui sa arvad, et sellise põhjusega viga ei tohiks tekkida, siis palun koosta veateade.", "Never lose encrypted messages": "Ära kunagi kaota krüptitud sõnumeid", - "Messages in this room are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Sõnumid siis jututoas kasutavad läbivat krüptimist. Ainult sinul ja saaja(te)l on võtmed selliste sõnumite lugemiseks.", + "Messages in this room are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Sõnumid siin jututoas kasutavad läbivat krüptimist. Ainult sinul ja saaja(te)l on võtmed selliste sõnumite lugemiseks.", "Securely back up your keys to avoid losing them. Learn more.": "Vältimaks nende kaotamist, varunda turvaliselt oma võtmed. Loe lisateavet.", "Not now": "Mitte praegu", "Don't ask me again": "Ära küsi minult uuesti", @@ -1107,7 +1107,7 @@ "Unable to revoke sharing for email address": "Ei õnnestu tagasi võtta otsust e-posti aadressi jagamise kohta", "Unable to share email address": "Ei õnnestu jagada e-posti aadressi", "Your email address hasn't been verified yet": "Sinu e-posti aadress pole veel verifitseeritud", - "Click the link in the email you received to verify and then click continue again.": "Klõpsi saabunud e-kirjas olevat verifitseerimisviidet ning seejärel klõpsi siin uuesti nuppu \"Jätka\".", + "Click the link in the email you received to verify and then click continue again.": "Klõpsi saabunud e-kirjas olevat verifitseerimisviidet ning seejärel klõpsi siin uuesti nuppu „Jätka“.", "Unable to verify email address.": "E-posti aadressi verifitseerimine ei õnnestunud.", "Verify the link in your inbox": "Verifitseeri klõpsides viidet saabunud e-kirjas", "Complete": "Valmis", @@ -1115,7 +1115,7 @@ "Share": "Jaga", "Session already verified!": "Sessioon on juba verifitseeritud!", "WARNING: Session already verified, but keys do NOT MATCH!": "HOIATUS: Sessioon on juba verifitseeritud, aga võtmed ei klapi!", - "WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and session %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!": "HOIATUS: VÕTMETE VERIFITSEERIMINE EI ÕNNESTUNUD! Kasutaja %(userId)s ja sessiooni %(deviceId)s allkirjastamise võti on \"%(fprint)s\", aga see ei vasta antud sõrmejäljele \"%(fingerprint)s\". See võib tähendada, et sinu kasutatavad ühendused võivad olla kolmanda osapoole poolt vahelt lõigatud!", + "WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and session %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!": "HOIATUS: VÕTMETE VERIFITSEERIMINE EI ÕNNESTUNUD! Kasutaja %(userId)s ja sessiooni %(deviceId)s allkirjastamise võti on „%(fprint)s“, aga see ei vasta antud sõrmejäljele „%(fingerprint)s“. See võib tähendada, et sinu kasutatavad ühendused võivad olla kolmanda osapoole poolt vahelt lõigatud!", "Verified key": "Verifitseeritud võti", "The signing key you provided matches the signing key you received from %(userId)s's session %(deviceId)s. Session marked as verified.": "Sinu antud allkirjavõti vastab allkirjavõtmele, mille sa said kasutaja %(userId)s sessioonist %(deviceId)s. Sessioon on märgitud verifitseerituks.", "Sends the given message coloured as a rainbow": "Saadab selle sõnumi vikerkaarevärvilisena", @@ -1178,7 +1178,7 @@ "Invite someone using their name, username (like ), email address or share this room.": "Kutsu kedagi tema nime, kasutajanime (nagu ), e-posti aadressi alusel või jaga seda jututuba.", "Upload completed": "Üleslaadimine valmis", "%(brand)s now uses 3-5x less memory, by only loading information about other users when needed. Please wait whilst we resynchronise with the server!": "%(brand)s kasutab varasemaga võrreldes 3-5 korda vähem mälu, sest laeb teavet kasutajate kohta vaid siis, kui vaja. Palun oota hetke, kuni sünkroniseerime andmeid serveriga!", - "Updating %(brand)s": "Uuenda %(brand)s'it", + "Updating %(brand)s": "Uuendan rakendust %(brand)s", "I don't want my encrypted messages": "Ma ei soovi oma krüptitud sõnumeid", "Manually export keys": "Ekspordi võtmed käsitsi", "You'll lose access to your encrypted messages": "Sa kaotad ligipääsu oma krüptitud sõnumitele", @@ -1193,7 +1193,7 @@ "Remember my selection for this widget": "Jäta meelde minu valik selle vidina kohta", "Allow": "Luba", "Deny": "Keela", - "Unable to restore backup": "Varukoopiast taastamine ei õnenstu", + "Unable to restore backup": "Varukoopiast taastamine ei õnnestu", "No backup found!": "Varukoopiat ei leidunud!", "Keys restored": "Krüptimise võtmed on taastatud", "Failed to decrypt %(failedCount)s sessions!": "%(failedCount)s sessiooni dekrüptimine ei õnnestunud!", @@ -1310,7 +1310,7 @@ "%(oneUser)schanged their avatar %(count)s times|other": "Kasutaja %(oneUser)s muutis oma tunnuspilti %(count)s korda", "%(oneUser)schanged their avatar %(count)s times|one": "Kasutaja %(oneUser)s muutis oma tunnuspilti", "Please ask the administrator of your homeserver (%(homeserverDomain)s) to configure a TURN server in order for calls to work reliably.": "Palu oma koduserveri haldajat (%(homeserverDomain)s), et ta seadistaks kõnede kindlamaks toimimiseks TURN serveri.", - "Alternatively, you can try to use the public server at turn.matrix.org, but this will not be as reliable, and it will share your IP address with that server. You can also manage this in Settings.": "Alternatiivina võid sa kasutada avalikku serverit turn.matrix.org, kuid see ei pruugi olla piisavalt töökindel ning sa jagaad ka oma IP-aadressi selle serveriga. Täpsemalt saad seda määrata seadistustes.", + "Alternatively, you can try to use the public server at turn.matrix.org, but this will not be as reliable, and it will share your IP address with that server. You can also manage this in Settings.": "Alternatiivina võid sa kasutada avalikku serverit turn.matrix.org, kuid see ei pruugi olla piisavalt töökindel ning sa jagad ka oma IP-aadressi selle serveriga. Täpsemalt saad seda määrata seadistustes.", "Try using turn.matrix.org": "Proovi kasutada turn.matrix.org serverit", "OK": "Sobib", "Unable to capture screen": "Ekraanipildi hõive ei õnnestunud", @@ -1352,7 +1352,7 @@ "Before submitting logs, you must create a GitHub issue to describe your problem.": "Enne logide saatmist sa peaksid GitHub'is looma veateate ja kirjeldama seal tekkinud probleemi.", "GitHub issue": "Veateade GitHub'is", "Notes": "Märkused", - "%(senderDisplayName)s changed the topic to \"%(topic)s\".": "%(senderDisplayName)s muutis uueks teemaks \"%(topic)s\".", + "%(senderDisplayName)s changed the topic to \"%(topic)s\".": "%(senderDisplayName)s muutis uueks teemaks „%(topic)s“.", "%(senderDisplayName)s upgraded this room.": "%(senderDisplayName)s uuendas seda jututuba.", "%(senderDisplayName)s made the room public to whoever knows the link.": "%(senderDisplayName)s muutis selle jututoa avalikuks kõigile, kes teavad tema aadressi.", "Light": "Hele", @@ -1425,9 +1425,9 @@ "Reversed words aren't much harder to guess": "Tagurpidi kirjutatud sõnu pole eriti keeruline ära arvata", "Predictable substitutions like '@' instead of 'a' don't help very much": "Ennustatavatest asendustest nagu '@' 'a' asemel pole eriti kasu", "Add another word or two. Uncommon words are better.": "Lisa veel mõni sõna. Ebatavaliste sõnade kasutamine on hea mõte.", - "Repeats like \"aaa\" are easy to guess": "Kordusi, nagu \"aaa\" on lihtne ära arvata", - "Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Kordusi, nagu \"abcabcabc\" on vaid natuke raskem ära arvata kui \"abc\"", - "Sequences like abc or 6543 are easy to guess": "Jadasid nagu \"abc\" või \"6543\" on lihtne ära arvata", + "Repeats like \"aaa\" are easy to guess": "Kordusi, nagu „aaa“ on lihtne ära arvata", + "Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Kordusi, nagu „abcabcabc“ on vaid natuke raskem ära arvata kui „abc“", + "Sequences like abc or 6543 are easy to guess": "Jadasid nagu „abc“ või „6543“ on lihtne ära arvata", "Recent years are easy to guess": "Hiljutisi aastaid on lihtne ära arvata", "Dates are often easy to guess": "Kuupäevi on sageli lihtne ära arvata", "A word by itself is easy to guess": "Üksikut sõna on lihtne ära arvata", @@ -1524,7 +1524,7 @@ "Waiting for partner to confirm...": "Ootan teise osapoole kinnitust...", "Incoming Verification Request": "Saabuv verifitseerimispalve", "Integrations are disabled": "Lõimingud ei ole kasutusel", - "Enable 'Manage Integrations' in Settings to do this.": "Selle tegevuse jaoks määra seadetes \"Halda lõiminguid\" kasutuselevõetuks.", + "Enable 'Manage Integrations' in Settings to do this.": "Selle tegevuse kasutuselevõetuks lülita seadetes sisse „Halda lõiminguid“ valik.", "Integrations not allowed": "Lõimingute kasutamine ei ole lubatud", "Your %(brand)s doesn't allow you to use an Integration Manager to do this. Please contact an admin.": "Sinu %(brand)s ei võimalda selle tegevuse jaoks kasutada Lõimingute haldurit. Palun küsi lisateavet administraatorilt.", "Failed to invite the following users to chat: %(csvUsers)s": "Järgnevate kasutajate vestlema kutsumine ei õnnestunud: %(csvUsers)s", @@ -1683,7 +1683,7 @@ "%(senderName)s changed the room topic": "%(senderName)s muutis jututoa teemat", "Use the improved room list (will refresh to apply changes)": "Kasuta parandaatud jututubade loendit (muudatuse jõustamine eeldab andmete uuesti laadimist)", "Use custom size": "Kasuta kohandatud suurust", - "Use a more compact ‘Modern’ layout": "Kasuta veel kompaktsemat \"moodsat\" paigutust", + "Use a more compact ‘Modern’ layout": "Kasuta veel kompaktsemat „moodsat“ paigutust", "Cross-signing public keys:": "Avalikud võtmed risttunnustamise jaoks:", "in memory": "on mälus", "not found": "pole leitavad", @@ -1714,10 +1714,10 @@ "%(role)s in %(roomName)s": "%(role)s jututoas %(roomName)s", "Failed to change power level": "Õiguste muutmine ei õnnestunud", "You will not be able to undo this change as you are promoting the user to have the same power level as yourself.": "Sa ei saa seda muudatust hiljem tagasi pöörata, sest annad teisele kasutajale samad õigused, mis sinul on.", - "Deactivate user?": "Kas blokeerime kasutaja?", - "Deactivating this user will log them out and prevent them from logging back in. Additionally, they will leave all the rooms they are in. This action cannot be reversed. Are you sure you want to deactivate this user?": "Kasutaja blokeerimisel logitakse ta automaatselt välja ning ei lubata enam sisse logida. Lisaks lahkub ta kõikidest jututubadest, mille liige ta parasjagu on. Seda tegevust ei saa tagasi pöörata. Kas sa oled ikka kindel, et soovid selle kasutaja blokeerida?", - "Deactivate user": "Blokeeri kasutaja", - "Failed to deactivate user": "Kasutaja blokeerimine ei õnnestunud", + "Deactivate user?": "Kas deaktiveerime kasutajakonto?", + "Deactivating this user will log them out and prevent them from logging back in. Additionally, they will leave all the rooms they are in. This action cannot be reversed. Are you sure you want to deactivate this user?": "Kasutaja deaktiveerimisel logitakse ta automaatselt välja ning ei lubata enam sisse logida. Lisaks lahkub ta kõikidest jututubadest, mille liige ta parasjagu on. Seda tegevust ei saa tagasi pöörata. Kas sa oled ikka kindel, et soovid selle kasutaja kõijkalt eemaldada?", + "Deactivate user": "Deaktiveeri kasutaja", + "Failed to deactivate user": "Kasutaja deaktiveerimine ei õnnestunud", "This client does not support end-to-end encryption.": "See klient ei toeta läbivat krüptimist.", "Security": "Turvalisus", "Using this widget may share data with %(widgetDomain)s & your Integration Manager.": "Selle vidina kasutamisel võidakse jagada andmeid saitidega %(widgetDomain)s ning sinu vidinahalduriga.", @@ -1750,5 +1750,640 @@ "%(severalUsers)sleft and rejoined %(count)s times|other": "%(severalUsers)s lahkusid ja liitusid uuesti %(count)s korda", "%(severalUsers)sleft and rejoined %(count)s times|one": "%(severalUsers)s lahkusid ja liitusid uuesti", "%(oneUser)sleft and rejoined %(count)s times|other": "%(oneUser)s lahkus ja liitus uuesti %(count)s korda", - "%(oneUser)sleft and rejoined %(count)s times|one": "%(oneUser)s lahkus ja liitus uuesti" + "%(oneUser)sleft and rejoined %(count)s times|one": "%(oneUser)s lahkus ja liitus uuesti", + "To use it, just wait for autocomplete results to load and tab through them.": "Selle kasutamiseks oota, kuni automaatne sõnalõpetus laeb kõik valikud ja sa saad nad läbi lapata.", + "Bans user with given id": "Keela ligipääs antud tunnusega kasutajale", + "Unbans user with given ID": "Taasta ligipääs antud tunnusega kasutajale", + "Ignores a user, hiding their messages from you": "Eirab kasutajat peites kõik tema sõnumid sinu eest", + "Ignored user": "Eiratud kasutaja", + "You are now ignoring %(userId)s": "Sa praegu eirad kasutajat %(userId)s", + "%(senderName)s banned %(targetName)s.": "%(senderName)s keelas ligipääsu kasutajale %(targetName)s.", + "%(senderName)s unbanned %(targetName)s.": "%(senderName)s taastas ligipääsu kasutajale %(targetName)s.", + "%(senderName)s withdrew %(targetName)s's invitation.": "%(senderName)s võttis tagasi %(targetName)s kutse.", + "%(senderName)s kicked %(targetName)s.": "%(senderName)s müksas kasutajat %(targetName)s.", + "%(senderName)s changed the pinned messages for the room.": "%(senderName)s muutis selle jututoa klammerdatud sõnumeid.", + "%(senderName)s removed the rule banning users matching %(glob)s": "%(senderName)s eemaldas kasutajate ligipääsukeelu reegli, mis vastas tingimusele %(glob)s", + "%(senderName)s removed the rule banning rooms matching %(glob)s": "%(senderName)s eemaldas jututubade ligipääsukeelu reegli, mis vastas tingimusele %(glob)s", + "%(senderName)s removed the rule banning servers matching %(glob)s": "%(senderName)s eemaldas serverite ligipääsukeelu reegli, mis vastas tingimusele %(glob)s", + "%(senderName)s removed a ban rule matching %(glob)s": "%(senderName)s eemaldas ligipääsukeelu reegli, mis vastas tingimusele %(glob)s", + "%(senderName)s updated an invalid ban rule": "%(senderName)s uuendas vigast ligipääsukeelu reeglit", + "%(senderName)s updated the rule banning users matching %(glob)s for %(reason)s": "%(senderName)s uuendas %(reason)s põhjusel kasutajate ligipääsukeelu reeglit, mis vastas tingimusele %(glob)s", + "%(senderName)s updated the rule banning rooms matching %(glob)s for %(reason)s": "%(senderName)s uuendas %(reason)s põhjusel jututubade ligipääsukeelu reeglit, mis vastas tingimusele %(glob)s", + "%(senderName)s updated the rule banning servers matching %(glob)s for %(reason)s": "%(senderName)s uuendas %(reason)s põhjusel serverite ligipääsukeelu reeglit, mis vastas tingimusele %(glob)s", + "%(senderName)s updated a ban rule matching %(glob)s for %(reason)s": "%(senderName)s uuendas %(reason)s põhjusel ligipääsukeelu reeglit, mis vastas tingimusele %(glob)s", + "%(senderName)s created a rule banning users matching %(glob)s for %(reason)s": "%(senderName)s määras %(reason)s tõttu kasutajate ligipääsukeelu reegli, mis vastas tingimusele %(glob)s", + "%(senderName)s created a rule banning rooms matching %(glob)s for %(reason)s": "%(senderName)s määras %(reason)s tõttu jututubade ligipääsukeelu reegli, mis vastas tingimusele %(glob)s", + "%(senderName)s created a rule banning servers matching %(glob)s for %(reason)s": "%(senderName)s määras %(reason)s tõttu serverite ligipääsukeelu reegli, mis vastas tingimusele %(glob)s", + "%(senderName)s created a ban rule matching %(glob)s for %(reason)s": "%(senderName)s määras %(reason)s tõttu ligipääsukeelu reegli, mis vastas tingimusele %(glob)s", + "%(senderName)s changed a rule that was banning users matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s muutis %(reason)s tõttu kasutajate ligipääsukeelu reegli algset tingimust %(oldGlob)s uueks tingimuseks %(newGlob)s", + "%(senderName)s changed a rule that was banning rooms matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s muutis %(reason)s tõttu jututubade ligipääsukeelu reegli algset tingimust %(oldGlob)s uueks tingimuseks %(newGlob)s", + "%(senderName)s changed a rule that was banning servers matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s muutis %(reason)s tõttu serverite ligipääsukeelu reegli algset tingimust %(oldGlob)s uueks tingimuseks %(newGlob)s", + "%(senderName)s updated a ban rule that was matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s muutis %(reason)s tõttu ligipääsukeelu reegli algset tingimust %(oldGlob)s uueks tingimuseks %(newGlob)s", + "The user must be unbanned before they can be invited.": "Enne kutse saatmist peab kasutajalt olema eemaldatud ligipääsukeeld.", + "Your homeserver has exceeded its user limit.": "Sinu koduserver on ületanud kasutajate arvu ülempiiri.", + "Your homeserver has exceeded one of its resource limits.": "Sinu koduserver on ületanud ühe oma ressursipiirangutest.", + "Contact your server admin.": "Võta ühendust oma serveri haldajaga.", + "Warning": "Hoiatus", + "Ok": "Sobib", + "Set password": "Määra salasõna", + "To return to your account in future you need to set a password": "Selleks, et sa saaksid tulevikus oma konto juurde tagasi pöörduda, peaksid määrama salasõna", + "You were banned (%(reason)s)": "Sinule on seatud ligipääsukeeld %(reason)s", + "%(targetName)s was banned (%(reason)s)": "%(targetName)s seati ligipääsukeeld %(reason)s", + "You were banned": "Sinule seati ligipääsukeeld", + "%(targetName)s was banned": "%(targetName)s'le seati ligipääsukeeld", + "New spinner design": "Uus vurri-moodi paigutus", + "Message Pinning": "Sõnumite klammerdamine", + "IRC display name width": "IRC kuvatava nime laius", + "Enable experimental, compact IRC style layout": "Võta kasutusele katseline, IRC-stiilis kompaktne sõnumite paigutus", + "My Ban List": "Minu poolt seatud ligipääsukeeldude loend", + "Active call (%(roomName)s)": "Käsilolev kõne (%(roomName)s)", + "Unknown caller": "Tundmatu helistaja", + "Incoming voice call": "Saabuv häälkõne", + "Incoming video call": "Saabuv videokõne", + "Incoming call": "Saabuv kõne", + "Waiting for your other session to verify…": "Ootan, et sinu teine sessioon alustaks verifitseerimist…", + "This bridge was provisioned by .": "Selle võrgusilla võttis kasutusele .", + "This bridge is managed by .": "Seda võrgusilda haldab .", + "Workspace: %(networkName)s": "Tööruum: %(networkName)s", + "Channel: %(channelName)s": "Kanal: %(channelName)s", + "Upload new:": "Lae üles uus:", + "Export E2E room keys": "Ekspordi jututubade läbiva krüptimise võtmed", + "Your homeserver does not support cross-signing.": "Sinu koduserver ei toeta risttunnustamist.", + "Cross-signing and secret storage are enabled.": "Risttunnustamine ja turvahoidla on kasutusel.", + "Connecting to integration manager...": "Ühendan lõiminguhalduriga...", + "Cannot connect to integration manager": "Ei saa ühendust lõiminguhalduriga", + "The integration manager is offline or it cannot reach your homeserver.": "Lõiminguhaldur kas ei tööta või ei õnnestu tal teha päringuid sinu koduserveri suunas.", + "Delete Backup": "Kustuta varukoopia", + "Are you sure? You will lose your encrypted messages if your keys are not backed up properly.": "Kas sa oled kindel? Kui sul muud varundust pole, siis kaotad ligipääsu oma krüptitud sõnumitele.", + "Your keys are not being backed up from this session.": "Sinu selle sessiooni krüptovõtmeid ei varundata.", + "Back up your keys before signing out to avoid losing them.": "Vältimaks nende kaotamist, varunda krüptovõtmed enne väljalogimist.", + "Advanced notification settings": "Teavituste lisaseadistused", + "Enable desktop notifications for this session": "Võta selleks sessiooniks kasutusele töölauakeskkonnale omased teavitused", + "Show message in desktop notification": "Näita sõnumit töölauakeskkonnale omases teavituses", + "Enable audible notifications for this session": "Võta selleks sessiooniks kasutusele kuuldavad teavitused", + "Off": "Välja lülitatud", + "On": "Kasutusel", + "Noisy": "Jutukas", + "Upgrade to your own domain": "Võta kasutusele oma domeen", + "Error encountered (%(errorDetail)s).": "Tekkis viga (%(errorDetail)s).", + "Checking for an update...": "Kontrollin uuenduste olemasolu...", + "No update available.": "Uuendusi pole saadaval.", + "New version available. Update now.": "Saadaval on uus versioon. Uuenda nüüd.", + "Check for update": "Kontrolli uuendusi", + "Hey you. You're the best!": "Hei sina. Sa oled parim!", + "Size must be a number": "Suurus peab olema number", + "Custom font size can only be between %(min)s pt and %(max)s pt": "Kohandatud fondisuurus peab olema vahemikus %(min)s pt ja %(max)s pt", + "Use between %(min)s pt and %(max)s pt": "Kasuta suurust vahemikus %(min)s pt ja %(max)s pt", + "Message layout": "Sõnumite paigutus", + "Compact": "Kompaktne", + "Modern": "Moodne", + "Set the name of a font installed on your system & %(brand)s will attempt to use it.": "Vali sinu seadmes leiduv fondi nimi ning %(brand)s proovib seda kasutada.", + "Customise your appearance": "Kohenda välimust", + "Appearance Settings only affect this %(brand)s session.": "Välimuse kohendused kehtivad vaid selles %(brand)s'i sessioonis.", + "Legal": "Juriidiline teave", + "Credits": "Tänuavaldused", + "Bug reporting": "Vigadest teatamine", + "Clear cache and reload": "Tühjenda puhver ja lae uuesti", + "FAQ": "Korduma kippuvad küsimused", + "Versions": "Versioonid", + "%(brand)s version:": "%(brand)s'i versioon:", + "olm version:": "olm'i versioon:", + "Homeserver is": "Koduserver on", + "Identity Server is": "Isikutuvastusserver on", + "Access Token:": "Pääsuluba:", + "click to reveal": "kuvamiseks klõpsi siin", + "Labs": "Katsed", + "Customise your experience with experimental labs features. Learn more.": "Sa võid täiendada oma kasutuskogemust katseliste funktsionaalsusetega. Vaata lisateavet.", + "Ignored/Blocked": "Eiratud või ligipääs blokeeritud", + "Error adding ignored user/server": "Viga eiratud kasutaja või serveri lisamisel", + "Something went wrong. Please try again or view your console for hints.": "Midagi läks valesti. Proovi uuesti või otsi lisavihjeid konsoolilt.", + "Error subscribing to list": "Viga loendiga liitumisel", + "Please verify the room ID or address and try again.": "Palun kontrolli, kas jututoa tunnus või aadress on õiged ja proovi uuesti.", + "Error removing ignored user/server": "Viga eiratud kasutaja või serveri eemaldamisel", + "Error unsubscribing from list": "Viga loendist lahkumisel", + "Please try again or view your console for hints.": "Palun proovi uuesti või otsi lisavihjeid konsoolilt.", + "None": "Ei ühelgi juhul", + "Ban list rules - %(roomName)s": "Ligipääsukeelu reeglid - %(roomName)s", + "Server rules": "Serveri kasutustingimused", + "User rules": "Kasutajaga seotud tingimused", + "You have not ignored anyone.": "Sa ei ole veel kedagi eiranud.", + "You are currently ignoring:": "Hetkel eiratavate kasutajate loend:", + "You are not subscribed to any lists": "Sa ei ole liitunud ühegi loendiga", + "Unsubscribe": "Lõpeta liitumine", + "View rules": "Näita reegleid", + "You are currently subscribed to:": "Sa oled hetkel liitunud:", + "Ignored users": "Eiratud kasutajad", + "⚠ These settings are meant for advanced users.": "⚠ Need seadistused on mõeldud kogenud kasutajatele.", + "Ignoring people is done through ban lists which contain rules for who to ban. Subscribing to a ban list means the users/servers blocked by that list will be hidden from you.": "Kasutajate eiramine toimub ligipääsukeelu reeglite loendite alusel ning seal on kirjas blokeeritavad kasutajad, jututoad või serverid. Sellise loendi kasutusele võtmine tähendab et blokeeritud kasutajad või serverid ei ole sulle nähtavad.", + "Personal ban list": "Minu isiklik ligipääsukeelu reeglite loend", + "Your personal ban list holds all the users/servers you personally don't want to see messages from. After ignoring your first user/server, a new room will show up in your room list named 'My Ban List' - stay in this room to keep the ban list in effect.": "Sinu isiklikus ligipääsukeelu reeglite loendis on kasutajad ja serverid, kellelt sa ei soovi sõnumeid saada. Peale esimese kasutaja või serveri blokeerimist tekib sinu jututubade loendisse uus jututuba „Minu isiklik ligipääsukeelu reeglite loend“ ning selle jõustamiseks ära logi nimetatud jututoast välja.", + "Subscribing to a ban list will cause you to join it!": "Ligipääsukeelu reeglite loendi tellimine tähendab sellega liitumist!", + "Room ID or address of ban list": "Ligipääsukeelu reeglite loendi jututoa tunnus või aadress", + "Show tray icon and minimize window to it on close": "Näita süsteemisalve ikooni ja Element'i akna sulgemisel minimeeri ta salve", + "Read Marker off-screen lifetime (ms)": "Lugemise markeri iga, kui Element pole fookuses (ms)", + "Make this room low priority": "Muuda see jututuba vähetähtsaks", + "Low priority rooms show up at the bottom of your room list in a dedicated section at the bottom of your room list": "Vähetähtsad jututoad kuvatakse jututubade loendi lõpus omaette grupina", + "Failed to unban": "Ligipääsu taastamine ei õnnestunud", + "Unban": "Taasta ligipääs", + "Banned by %(displayName)s": "Ligipääs on keelatud %(displayName)s poolt", + "Error changing power level requirement": "Viga õiguste taseme nõuete muutmisel", + "An error occurred changing the room's power level requirements. Ensure you have sufficient permissions and try again.": "Jututoa õiguste taseme nõuete muutmisel tekkis viga. Kontrolli, et sul on selleks piisavalt õigusi ja proovi uuesti.", + "Error changing power level": "Viga õiguste muutmisel", + "An error occurred changing the user's power level. Ensure you have sufficient permissions and try again.": "Kasutaja õiguste muutmisel tekkis viga. Kontrolli, et sul on selleks piisavalt õigusi ja proovi uuesti.", + "To link to this room, please add an address.": "Sellele jututoale viitamiseks palun lisa talle aadress.", + "Discovery options will appear once you have added an email above.": "Otsinguvõimaluste loend kuvatakse, kui oled ülale sisestanud e-posti aadressi.", + "Discovery options will appear once you have added a phone number above.": "Otsinguvõimaluste loend kuvatakse, kui oled ülale sisestanud telefoninumbri.", + "Mod": "Moderaator", + "Key share requests are sent to your other sessions automatically. If you rejected or dismissed the key share request on your other sessions, click here to request the keys for this session again.": "Võtmete jagamise päringud saadetakse sinu teistele sessioonidele automaatselt. Kui sa oled mõnes muus sessioonis võtmete jagamise päringud tagasi lükanud või tühistanud, siis klõpsi siia võtmete uuesti pärimiseks selle sessiooni jaoks.", + "If your other sessions do not have the key for this message you will not be able to decrypt them.": "Kui sinu muudel sesioonidel pole selle sõnumi jaoks võtmeid, siis nad ei suuda ka sõnumit dekrüptida.", + "Key request sent.": "Võtmete jagamise päring on saadetud.", + "Re-request encryption keys from your other sessions.": "Küsi oma muudest sessioonidest krüptimisvõtmed uuesti.", + "The authenticity of this encrypted message can't be guaranteed on this device.": "Selle krüptitud sõnumi autentsus pole selles seadmes tagatud.", + "and %(count)s others...|other": "ja %(count)s muud...", + "and %(count)s others...|one": "ja üks muu...", + "Invited": "Kutsutud", + "%(userName)s (power %(powerLevelNumber)s)": "%(userName)s (õigused %(powerLevelNumber)s)", + "Emoji picker": "Emoji'de valija", + "No pinned messages.": "Klammerdatud sõnumeid ei ole.", + "Loading...": "Laen...", + "Pinned Messages": "Klammerdatud sõnumid", + "Unpin Message": "Eemalda sõnumi klammerdus", + "No recently visited rooms": "Hiljuti külastatud jututubasid ei leidu", + "Create room": "Loo jututuba", + "People": "Inimesed", + "Unread rooms": "Lugemata jututoad", + "Always show first": "Näita alati esimisena", + "Error creating address": "Viga aadressi loomisel", + "There was an error creating that address. It may not be allowed by the server or a temporary failure occurred.": "Aadressi loomisel tekkis viga. See kas on serveri poolt keelatud või tekkis ajutine tõrge.", + "You don't have permission to delete the address.": "Sinul pole õigusi selle aadressi kustutamiseks.", + "There was an error removing that address. It may no longer exist or a temporary error occurred.": "Selle aadressi kustutamisel tekkis viga. See kas juba on kustutatud või tekkis ajutine tõrge.", + "Error removing address": "Viga aadresi kustutamisel", + "This room has no local addresses": "Sellel jututoal puudub kohalik aadress", + "Local address": "Kohalik aadress", + "Published Addresses": "Avaldatud aadressid", + "Published addresses can be used by anyone on any server to join your room. To publish an address, it needs to be set as a local address first.": "Avaldatud aadresse saab mis iganes serveri kasutaja pruukida sinu jututoaga liitumiseks. Aadressi avaldamiseks peab ta alustuseks olema määratud kohaliku aadressina.", + "Other published addresses:": "Muud avaldatud aadressid:", + "No other published addresses yet, add one below": "Ühtegi muud aadressi pole veel avaldatud, lisa üks alljärgnevalt", + "Local Addresses": "Kohalikud aadressid", + "Set addresses for this room so users can find this room through your homeserver (%(localDomain)s)": "Et muud kasutajad saaks seda jututuba leida sinu koduserveri (%(localDomain)s) kaudu, lisa sellele jututoale aadresse", + "Invalid community ID": "Vigane kogukonna tunnus", + "'%(groupId)s' is not a valid community ID": "'%(groupId)s' ei ole korrektne kogukonna tunnus", + "Direct message": "Otsevestlus", + "Demote yourself?": "Kas vähendad enda õigusi?", + "You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges.": "Kuna sa vähendad enda õigusi, siis sul ei pruugi enam olla võimalik seda muutust tagasi pöörata. Kui sa juhtumisi oled viimane haldusõigustega kasutaja jututoas, siis hiljem on võimatu samu õigusi tagasi saada.", + "Demote": "Vähenda enda õigusi", + "Ban": "Keela ligipääs", + "Unban this user?": "Kas taastame selle kasutaja ligipääsu?", + "Ban this user?": "Kas keelame selle kasutaja ligipääsu?", + "Failed to ban user": "Kasutaja ligipääsu keelamine ei õnnestunud", + "Almost there! Is your other session showing the same shield?": "Peaaegu valmis! Kas sinu teises sessioonis kuvatakse sama kilpi?", + "Almost there! Is %(displayName)s showing the same shield?": "Peaaegu valmis! Kas %(displayName)s kuvab sama kilpi?", + "Yes": "Jah", + "Verify all users in a room to ensure it's secure.": "Tagamaks, et jututuba on turvaline, verifitseeri kõik selle kasutajad.", + "You've successfully verified your device!": "Sinu seadme verifitseerimine oli edukas!", + "You've successfully verified %(deviceName)s (%(deviceId)s)!": "Sa oled edukalt verifitseerinud seadme %(deviceName)s (%(deviceId)s)!", + "You've successfully verified %(displayName)s!": "Sa oled edukalt verifitseerinud kasutaja %(displayName)s!", + "Verified": "Verifitseeritud", + "Got it": "Selge lugu", + "Start verification again from the notification.": "Alusta verifitseerimist uuesti teavitusest.", + "Message deleted": "Sõnum on kustutatud", + "Message deleted by %(name)s": "%(name)s kustutas sõnumi", + "Message deleted on %(date)s": "Sõnum on kustutatud %(date)s", + "Add an Integration": "Lisa lõiming", + "You are about to be taken to a third-party site so you can authenticate your account for use with %(integrationsUrl)s. Do you wish to continue?": "Sind juhatatakse kolmanda osapoole veebisaiti, kus sa saad autentida oma kontoga %(integrationsUrl)s kasutamiseks. Kas sa soovid jätkata?", + "Categories": "Kategooriad", + "%(severalUsers)srejected their invitations %(count)s times|other": "%(severalUsers)s lükkasid tagasi oma kutse %(count)s korda", + "%(severalUsers)srejected their invitations %(count)s times|one": "%(severalUsers)s lükkasid tagasi oma kutse", + "%(oneUser)srejected their invitation %(count)s times|other": "%(oneUser)s lükkas tagasi oma kutse %(count)s korda", + "%(oneUser)srejected their invitation %(count)s times|one": "%(oneUser)s lükkas taagasi oma kutse", + "%(severalUsers)shad their invitations withdrawn %(count)s times|other": "%(severalUsers)s kutse võeti tagasi %(count)s korda", + "%(severalUsers)shad their invitations withdrawn %(count)s times|one": "Kasutajate %(severalUsers)s kutse võeti tagasi", + "%(oneUser)shad their invitation withdrawn %(count)s times|other": "%(oneUser)s kutse võeti tagasi %(count)s korda", + "%(oneUser)shad their invitation withdrawn %(count)s times|one": "Kasutaja %(oneUser)s kutse võeti tagasi", + "were banned %(count)s times|other": "said ligipääsukeelu %(count)s korda", + "were banned %(count)s times|one": "said ligipääsukeelu", + "was banned %(count)s times|other": "sai ligipääsukeelu %(count)s korda", + "was banned %(count)s times|one": "sai ligipääsukeelu", + "were unbanned %(count)s times|other": "taastati ligipääs %(count)s korda", + "were unbanned %(count)s times|one": "taastati ligipääs", + "was unbanned %(count)s times|other": "taastati ligipääs %(count)s korda", + "was unbanned %(count)s times|one": "taastati ligipääs", + "were kicked %(count)s times|other": "müksati välja %(count)s korda", + "were kicked %(count)s times|one": "müksati välja", + "was kicked %(count)s times|other": "müksati välja %(count)s korda", + "was kicked %(count)s times|one": "müksati välja", + "%(severalUsers)smade no changes %(count)s times|other": "%(severalUsers)s ei teinud muudatusi %(count)s korda", + "%(severalUsers)smade no changes %(count)s times|one": "%(severalUsers)s ei teinud muudatusi", + "%(oneUser)smade no changes %(count)s times|other": "%(oneUser)s ei teinud muutusi %(count)s korda", + "%(oneUser)smade no changes %(count)s times|one": "%(oneUser)s ei teinud muudatusi", + "Power level": "Õiguste tase", + "Custom level": "Kohandatud õigused", + "QR Code": "QR kood", + "Unable to load event that was replied to, it either does not exist or you do not have permission to view it.": "Ei ole võimalik laadida seda sündmust, millele vastus on tehtud - teda kas pole olemas või sul pole õigusi seda näha.", + "Room address": "Jututoa aadress", + "Some characters not allowed": "Mõned tähemärgid ei ole siin lubatud", + "Please provide a room address": "Palun kirjuta jututoa aadress", + "This address is available to use": "See aadress on kasutatav", + "This address is already in use": "See aadress on juba kasutusel", + "Room directory": "Jututubade loend", + "Sign in with single sign-on": "Logi sisse ühekordse sisselogimise abil", + "And %(count)s more...|other": "Ja %(count)s muud...", + "ex. @bob:example.com": "näiteks @kati:mingidomeen.com", + "If there is additional context that would help in analysing the issue, such as what you were doing at the time, room IDs, user IDs, etc., please include those things here.": "Kui sul leidub lisateavet, mis võis selle vea analüüsimisel abiks olla, siis palun lisa need ka siia - näiteks mida sa vea tekkimise hetkel tegid, jututoa tunnus, kasutajate tunnused, jne.", + "Send logs": "Saada logikirjed", + "Unable to load commit detail: %(msg)s": "Ei õnnestu laadida sõnumi lisateavet: %(msg)s", + "Unavailable": "Ei ole saadaval", + "Changelog": "Versioonimuudatuste loend", + "You cannot delete this message. (%(code)s)": "Sa ei saa seda sõnumit kustutada. (%(code)s)", + "Navigate recent messages to edit": "Muutmiseks liigu viimaste sõnumite juurde", + "Move autocomplete selection up/down": "Liiguta automaatse sõnalõpetuse valikut üles või alla", + "Cancel autocomplete": "Lülita automaatne sõnalõpetus välja", + "Removing…": "Eemaldan…", + "Destroy cross-signing keys?": "Kas hävitame risttunnustamise võtmed?", + "Deleting cross-signing keys is permanent. Anyone you have verified with will see security alerts. You almost certainly don't want to do this, unless you've lost every device you can cross-sign from.": "Risttunnustamise võtmete kustutamine on tegevus, mida ei saa tagasi pöörata. Kõik sinu verifitseeritud vestluskaaslased näevad seejärel turvateateid. Kui sa just pole kaotanud ligipääsu kõikidele oma seadmetele, kust sa risttunnustamist oled teinud, siis sa ilmselgelt ei peaks kustutamist ette võtma.", + "Clear cross-signing keys": "Eemalda risttunnustamise võtmed", + "Confirm Removal": "Kinnita eemaldamine", + "Clear all data in this session?": "Kas eemaldame kõik selle sessiooni andmed?", + "Clearing all data from this session is permanent. Encrypted messages will be lost unless their keys have been backed up.": "Sessiooni kõikide andmete kustutamine on tegevus, mida ei saa tagasi pöörata. Kui sa pole varundanud krüptovõtmeid, siis sa kaotad ligipääsu krüptitud sõnumitele.", + "Clear all data": "Eemalda kõik andmed", + "Community IDs cannot be empty.": "Kogukonna tunnus ei või olla puudu.", + "Community IDs may only contain characters a-z, 0-9, or '=_-./'": "Kogukonna tunnuses võivad olla vaid järgnevad tähemärgid: a-z, 0-9, or '=_-./'", + "Something went wrong whilst creating your community": "Kogukonna loomisel läks midagi viltu", + "Create Community": "Loo kogukond", + "Community Name": "Kogukonna nimi", + "Example": "Näiteks", + "Community ID": "Kogukonna tunnus", + "example": "näiteks", + "Create": "Loo", + "Please enter a name for the room": "Palun sisesta jututoa nimi", + "Set a room address to easily share your room with other people.": "Jagamaks jututuba teiste kasutajatega, sisesta jututoa aadress.", + "You can’t disable this later. Bridges & most bots won’t work yet.": "Seda funktsionaalsust sa ei saa hiljem kinni keerata. Sõnumisillad ja enamus roboteid veel ei oska seda kasutada.", + "Enable end-to-end encryption": "Võta läbiv krüptimine kasutusele", + "Confirm your account deactivation by using Single Sign On to prove your identity.": "Kinnitamaks seda, et soovid oma konto kasutusest eemaldada, kasuta oma isiku tuvastamiseks ühekordset sisselogimist.", + "This will make your account permanently unusable. You will not be able to log in, and no one will be able to re-register the same user ID. This will cause your account to leave all rooms it is participating in, and it will remove your account details from your identity server. This action is irreversible.": "See muudab sinu konto jäädavalt mittekasutatavaks. Sina ei saa enam sisse logida ja keegi teine ei saa seda kasutajatunnust uuesti pruukida. Samuti logitakse sind välja kõikidest jututubadest, kus sa osaled ning eemaldatakse kõik sinu andmed sinu isikutuvastusserverist. Seda tegevust ei saa tagasi pöörata.", + "Deactivating your account does not by default cause us to forget messages you have sent. If you would like us to forget your messages, please tick the box below.": "Sinu konto kustutamine vaikimisi ei tähenda, et unustatakse ka sinu saadetud sõnumid. Kui sa siiski soovid seda, siis palun tee märge alljärgnevasse kasti.", + "Message visibility in Matrix is similar to email. Our forgetting your messages means that messages you have sent will not be shared with any new or unregistered users, but registered users who already have access to these messages will still have access to their copy.": "Matrix'i sõnumite nähtavus on sarnane e-posti kirjadega. Sõnumite unustamine tegelikult tähendab seda, et sinu varemsaadetud sõnumeid ei jagata uute või veel registreerumata kasutajatega, kuid registeerunud kasutajad, kes juba on need sõnumid saanud, võivad neid ka jätkuvalt lugeda.", + "Please forget all messages I have sent when my account is deactivated (Warning: this will cause future users to see an incomplete view of conversations)": "Minu konto kustutamisel palun unusta minu saadetud sõnumid (Hoiatus: seetõttu näevad tulevased kasutajad poolikuid vestlusi)", + "To continue, use Single Sign On to prove your identity.": "Jätkamaks tuvasta oma isik kasutades ühekordset sisselogimist.", + "Confirm to continue": "Soovin jätkata", + "Click the button below to confirm your identity.": "Oma isiku tuvastamiseks klõpsi alljärgnevat nuppu.", + "Incompatible local cache": "Kohalikud andmepuhvrid ei ühildu", + "Clear cache and resync": "Tühjenda puhver ja sünkroniseeri andmed uuesti", + "Confirm by comparing the following with the User Settings in your other session:": "Kinnita seda võrreldes järgnevaid andmeid oma teise sessiooni kasutajaseadetes:", + "Confirm this user's session by comparing the following with their User Settings:": "Kinnita selle kasutaja sessioon võrreldes järgnevaid andmeid tema kasutajaseadetes:", + "Session name": "Sessiooni nimi", + "Session ID": "Sessiooni tunnus", + "Session key": "Sessiooni võti", + "If they don't match, the security of your communication may be compromised.": "Kui nad omavahel ei klapi, siis teie suhtluse turvalisus võib olla ohus.", + "Your homeserver doesn't seem to support this feature.": "Tundub, et sinu koduserver ei toeta sellist funktsionaalsust.", + "Message edits": "Sõnumite muutmised", + "Your account is not secure": "Sinu kasutajakonto ei ole turvaline", + "This session, or the other session": "See või teine sessioon", + "The internet connection either session is using": "Internetiühendus, mida emb-kumb sessioon kasutab", + "New session": "Uus sessioon", + "Use this session to verify your new one, granting it access to encrypted messages:": "Kasuta seda sessiooni uute sessioonide verifitseerimiseks, andes sellega ligipääsu krüptitud sõnumitele:", + "If you didn’t sign in to this session, your account may be compromised.": "Kui sa pole sellesse sessiooni sisse loginud, siis sinu kasutajakonto andmed võivad olla sattunud valedesse kätesse.", + "This wasn't me": "See ei olnud mina", + "If you run into any bugs or have feedback you'd like to share, please let us know on GitHub.": "Kui sa leiad vigu või soovid jagada muud tagasisidet, siis teata sellest GitHub'i vahendusel.", + "To help avoid duplicate issues, please view existing issues first (and add a +1) or create a new issue if you can't find it.": "Topelt veateadete vältimiseks palun vaata esmalt olemasolevaid (ning lisa a + 1), aga kui sa samal teemal viga ei leia, siis koosta uus veateade.", + "Reporting this message will send its unique 'event ID' to the administrator of your homeserver. If messages in this room are encrypted, your homeserver administrator will not be able to read the message text or view any files or images.": "Sellest sõnumist teatamine saadab tema unikaalse sõnumi tunnuse sinu koduserveri haldurile. Kui selle jututoa sõnumid on krüptitud, siis sinu koduserveri haldur ei saa lugeda selle sõnumi teksti ega vaadata seal leiduvaid faile ja pilte.", + "Failed to upgrade room": "Jututoa versiooni uuendamine ei õnnestunud", + "The room upgrade could not be completed": "Jututoa uuendust ei õnnestunud teha", + "Please check your email and click on the link it contains. Once this is done, click continue.": "Palun vaata oma e-kirju ning klõpsi meie saadetud kirjas leiduvat linki. Kui see on tehtud, siis vajuta Jätka-nuppu.", + "Email address": "E-posti aadress", + "This will allow you to reset your password and receive notifications.": "See võimaldab sul luua uue salasõna ning saada teavitusi.", + "Wrong file type": "Vale failitüüp", + "Wrong Recovery Key": "Vale taastevõti", + "Invalid Recovery Key": "Vigane taastevõti", + "Security Phrase": "Turvafraas", + "Unable to access secret storage. Please verify that you entered the correct recovery passphrase.": "Ei õnnestu saada ligipääsu turvahoidlale. Palun kontrolli, et sa oleksid sisestanud õige taastamiseks mõeldud paroolifraasi.", + "Enter your Security Phrase or to continue.": "Jätkamiseks sisesta oma turvafraas või kasuta .", + "Security Key": "Turvavõti", + "Use your Security Key to continue.": "Jätkamiseks kasuta turvavõtit.", + "Restoring keys from backup": "Taastan võtmed varundusest", + "Fetching keys from server...": "Laen võtmed serverist...", + "%(completed)s of %(total)s keys restored": "%(completed)s / %(total)s võtit taastatud", + "Unable to load backup status": "Varunduse oleku laadimine ei õnnestunud", + "Recovery key mismatch": "Taastevõtmed ei klapi", + "Backup could not be decrypted with this recovery key: please verify that you entered the correct recovery key.": "Selle taastevõtmega ei õnnestunud varundust dekrüptida: palun kontrolli, kas sa kasutad õiget taastevõtit.", + "Incorrect recovery passphrase": "Vigane taastamiseks mõeldud paroolifraas", + "Backup could not be decrypted with this recovery passphrase: please verify that you entered the correct recovery passphrase.": "Selle paroolifraasiga ei õnnestunud varundust dekrüptida: palun kontrolli, kas sa kasutad õiget taastamiseks mõeldud paroolifraasi.", + "Access your secure message history and set up secure messaging by entering your recovery passphrase.": "Sisestades taastamiseks mõeldud paroolifraasi, saad ligipääsu oma turvatud sõnumitele ning sätid üles krüptitud sõnumivahetuse.", + "If you've forgotten your recovery passphrase you can use your recovery key or set up new recovery options": "Kui sa oled unudtanud taastamiseks mõeldud paroolifraasi, siis sa saad kasutada oma taastevõtit või seadistada uued taastamise võimalused", + "Warning: You should only set up key backup from a trusted computer.": "Hoiatus: Sa peaksid võtmete varundust seadistama vaid arvutist, mida sa usaldad.", + "We’re excited to announce Riot is now Element": "Meil on hea meel teatada, et Riot'i uus nimi on nüüd Element", + "Riot is now Element!": "Riot'i uus nimi on Element!", + "Secret storage public key:": "Turvahoidla avalik võti:", + "Verify User": "Verifitseeri kasutaja", + "For extra security, verify this user by checking a one-time code on both of your devices.": "Lisaturvalisus mõttes verifitseeri see kasutaja võrreldes selleks üheks korraks loodud koodi mõlemas seadmes.", + "Your messages are not secure": "Sinu sõnumid ei ole turvatud", + "Use your account to sign in to the latest version of the app at ": "Kasuta oma kontot logimaks sisse rakenduse viimasesse versiooni serveris", + "You’re already signed in and good to go here, but you can also grab the latest versions of the app on all platforms at element.io/get-started.": "Sa oled juba sisse loginud ja võid rahumeeli jätkata, kuid alati on hea mõte, kui kasutad viimast rakenduse versiooni, mille erinevate süsteemide jaoks leiad element.io/get-started lehelt.", + "Go to Element": "Võta Element kasutusele", + "We’re excited to announce Riot is now Element!": "Meil on hea meel teatada, et Riot'i uus nimi on nüüd Element!", + "Learn more at element.io/previously-riot": "Lisateavet leiad element.io/previously-riot lehelt", + "Access your secure message history and set up secure messaging by entering your recovery key.": "Pääse ligi oma turvatud sõnumitele ning säti üles krüptitud sõnumivahetus.", + "If you've forgotten your recovery key you can ": "Kui sa oled unustanud oma taastevõtme, siis sa võid ", + "Custom": "Kohandatud", + "Enter the location of your Element Matrix Services homeserver. It may use your own domain name or be a subdomain of element.io.": "Sisesta Element Matrix Services kodiserveri aadress. See võib kasutada nii sinu oma domeeni, kui olla element.io alamdomeen.", + "To set up a filter, drag a community avatar over to the filter panel on the far left hand side of the screen. You can click on an avatar in the filter panel at any time to see only the rooms and people associated with that community.": "Tõhusamaks kasutuseks seadista filter sikutades kogukonna tunnuspilti filtriribale ekraani vasakus ääres. Sa saad sobival ajal klõpsata filtriribal asuvat tunnuspilti ning näha vaid kasutajaid ja jututubasid, kes on seotud selle kogukonnaga.", + "Delete the room address %(alias)s and remove %(name)s from the directory?": "Kas kustutame jututoa aadressi %(alias)s ja eemaldame %(name)s kataloogist?", + "delete the address.": "kustuta aadress.", + "The server may be unavailable or overloaded": "Server kas pole kättesaadav või on ülekoormatud", + "Unable to join network": "Võrguga liitumine ei õnnestu", + "Search rooms": "Otsi jututube", + "User menu": "Kasutajamenüü", + "You have been logged out of all sessions and will no longer receive push notifications. To re-enable notifications, sign in again on each device.": "Sa oled kõikidest sessioonidest välja logitud ning enam ei saa tõuketeavitusi. Nende taaskuvamiseks logi sisse kõikides oma seadmetes.", + "Return to login screen": "Mine tagasi sisselogimisvaatele", + "Set a new password": "Seadista uus salasõna", + "Invalid homeserver discovery response": "Vigane vastus koduserveri tuvastamise päringule", + "Failed to get autodiscovery configuration from server": "Serveri automaattuvastuse seadistuste laadimine ei õnnestunud", + "Invalid base_url for m.homeserver": "m.homeserver'i kehtetu base_url", + "Homeserver URL does not appear to be a valid Matrix homeserver": "Koduserveri URL ei tundu viitama korrektsele Matrix'i koduserverile", + "Invalid identity server discovery response": "Vigane vastus isikutuvastusserveri tuvastamise päringule", + "Invalid base_url for m.identity_server": "m.identity_server'i kehtetu base_url", + "Passphrases must match": "Paroolifraasid ei klapi omavahel", + "Passphrase must not be empty": "Paroolifraas ei tohi olla tühi", + "Export room keys": "Ekspordi jututoa võtmed", + "This process allows you to export the keys for messages you have received in encrypted rooms to a local file. You will then be able to import the file into another Matrix client in the future, so that client will also be able to decrypt these messages.": "Selle toiminguga on sul võimalik saabunud krüptitud sõnumite võtmed eksportida sinu kontrollitavasse kohalikku faili. Seetõttu on sul tulevikus võimalik importida need võtmed mõnda teise Matrix'i klienti ning seeläbi muuta saabunud krüptitud sõnumid ka seal loetavaks.", + "The exported file will allow anyone who can read it to decrypt any encrypted messages that you can see, so you should be careful to keep it secure. To help with this, you should enter a passphrase below, which will be used to encrypt the exported data. It will only be possible to import the data by using the same passphrase.": "Kes iganes saab kätte selle ekspordifaili, saab ka lugeda sinu krüptitud sõnumeid, seega ole hoolikas selle faili talletamisel. Andmaks lisakihi turvalisust, peaksid sa alljärgnevalt sisestama paroolifraasi, millega krüptitakse eksporditavad andmed. Faili hilisem importimine õnnestub vaid sama paroolifraasi sisestamisel.", + "Confirm passphrase": "Sisesta paroolifraas veel üks kord", + "Export": "Ekspordi", + "Import room keys": "Impordi jututoa võtmed", + "This process allows you to import encryption keys that you had previously exported from another Matrix client. You will then be able to decrypt any messages that the other client could decrypt.": "Selle toiminguga saad importida krüptimisvõtmed, mis sa viimati olid teisest Matrix'i kliendist eksportinud. Seejärel on võimalik dekrüptida ka siin kõik need samad sõnumid, mida see teine klient suutis dekrüptida.", + "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.": "Ekspordifail on turvatud paroolifraasiga ning alljärgnevalt peaksid dekrüptimiseks sisestama selle paroolifraasi.", + "File to import": "Imporditav fail", + "Import": "Impordi", + "Confirm encryption setup": "Krüptimise seadistuse kinnitamine", + "Click the button below to confirm setting up encryption.": "Kinnitamaks, et soovid krüptimist seadistada, klõpsi järgnevat nuppu.", + "Safeguard against losing access to encrypted messages & data by backing up encryption keys on your server.": "Tagamaks, et sa ei kaota ligipääsu krüptitud sõnumitele ja andmetele, varunda krüptimisvõtmed oma serveris.", + "Generate a Security Key": "Loo turvavõti", + "We’ll generate a Security Key for you to store somewhere safe, like a password manager or a safe.": "Me loome turvavõtme, mida sa peaksid hoidma turvalises kohas, nagu näiteks arvutis salasõnade halduris või vana kooli seifis.", + "Enter a Security Phrase": "Sisesta turvafraas", + "Use a secret phrase only you know, and optionally save a Security Key to use for backup.": "Sisesta turvafraas, mida vaid sina tead ning lisaks võid salvestada varunduse turvavõtme.", + "Enter your account password to confirm the upgrade:": "Kinnitamaks seda muudatust, sisesta oma konto salasõna:", + "Restore your key backup to upgrade your encryption": "Krüptimine uuendamiseks taasta oma varundatud võtmed", + "Restore": "Taasta", + "You'll need to authenticate with the server to confirm the upgrade.": "Uuenduse kinnitamiseks pead end autentima serveris.", + "Upgrade this session to allow it to verify other sessions, granting them access to encrypted messages and marking them as trusted for other users.": "Teiste sessioonide verifitseerimiseks pead uuendama seda sessiooni. Muud verifitseeritud sessioonid saavad sellega ligipääsu krüptitud sõnumitele ning nad märgitakse usaldusväärseteks ka teiste kasutajate jaoks.", + "Enter a security phrase only you know, as it’s used to safeguard your data. To be secure, you shouldn’t re-use your account password.": "Andmete kaitsmiseks sisesta turvafraas, mida vaid sina tead. On mõistlik ja palun ära kasuta selleks oma tavalist konto salasõna.", + "Enter a recovery passphrase": "Sisesta taastamiseks mõeldud paroolifraas", + "Great! This recovery passphrase looks strong enough.": "Suurepärane! Taastamiseks mõeldud paroolifraas on piisavalt kange.", + "That matches!": "Klapib!", + "Use a different passphrase?": "Kas kasutame muud paroolifraasi?", + "That doesn't match.": "Ei klapi mitte.", + "Go back to set it again.": "Mine tagasi ja sisesta nad uuesti.", + "Enter your recovery passphrase a second time to confirm it.": "Kinnitamaks sisesta taastamiseks mõeldud paroolifraas teist korda.", + "Confirm your recovery passphrase": "Kinnita oma taastamiseks mõeldud paroolifraas", + "Store your Security Key somewhere safe, like a password manager or a safe, as it’s used to safeguard your encrypted data.": "Kuna seda kasutatakse sinu krüptitud andmete kaitsmiseks, siis hoia oma turvavõtit kaitstud ja turvalises kohas, nagu näiteks arvutis salasõnade halduris või vana kooli seifis.", + "Unable to query secret storage status": "Ei õnnestu tuvastada turvahoidla olekut", + "If you cancel now, you may lose encrypted messages & data if you lose access to your logins.": "Kui sa tühistad nüüd, siis sa võid peale viimasest seadmest välja logimist kaotada ligipääsu oma krüptitud sõnumitele ja andmetele.", + "You can also set up Secure Backup & manage your keys in Settings.": "Samuti võid sa seadetes võtta kasutusse turvalise varunduse ning hallata oma krüptovõtmeid.", + "Set up Secure backup": "Võta kasutusele turvaline varundus", + "Set a Security Phrase": "Sisesta turvafraas", + "Confirm Security Phrase": "Kinnita turvafraas", + "Save your Security Key": "Salvesta turvavõti", + "Unable to set up secret storage": "Turvahoidla kasutuselevõtmine ei õnnestu", + "We'll store an encrypted copy of your keys on our server. Secure your backup with a recovery passphrase.": "Me salvestame krüptitud koopia sinu krüptovõtmetest oma serveris. Seades taastamiseks mõeldud paroolifraasi, saad turvata oma varundust.", + "For maximum security, this should be different from your account password.": "Parima turvalisuse jaoks peaks paroolifraas olema erinev sinu konto salasõnast.", + "Set up with a recovery key": "Võta kasutusele taastevõti", + "Please enter your recovery passphrase a second time to confirm.": "Kinnitamiseks palun sisesta taastamiseks mõeldud paroolifraas teist korda.", + "Repeat your recovery passphrase...": "Korda oma taastamiseks mõeldud paroolifraasi...", + "Your recovery key is a safety net - you can use it to restore access to your encrypted messages if you forget your recovery passphrase.": "Sinu taastevõti toimib turvavõrguna - juhul, kui sa unustad taastamiseks mõeldud paroolifraasi, siis sa saad seda kasutada taastamaks ligipääsu krüptitud sõnumitele.", + "Keep a copy of it somewhere secure, like a password manager or even a safe.": "Hoia seda turvalises kohas, nagu näiteks salasõnahalduris või vana kooli seifis.", + "Your keys are being backed up (the first backup could take a few minutes).": "Sinu krüptovõtmeid varundatakse (esimese varukoopia tegemine võib võtta paar minutit).", + "Autocomplete": "Automaatne sõnalõpetus", + "Favourited": "Märgitud lemmikuks", + "Leave Room": "Lahku jututoast", + "Forget Room": "Unusta jututuba ära", + "Which officially provided instance you are using, if any": "Mis iganes ametlikku klienti sa kasutad, kui üldse kasutad", + "Whether you're using %(brand)s on a device where touch is the primary input mechanism": "Kui kasutad %(brand)s seadmes, kus puuteekraan on põhiline sisestusviis", + "Use your account to sign in to the latest version": "Kasuta oma kontot selleks, et sisse logida rakenduse viimasesse versiooni", + "Learn More": "Lisateave", + "Upgrades a room to a new version": "Uuendab jututoa uue versioonini", + "You do not have the required permissions to use this command.": "Sul ei ole piisavalt õigusi selle käsu käivitamiseks.", + "Error upgrading room": "Viga jututoa uuendamisel", + "Double check that your server supports the room version chosen and try again.": "Kontrolli veel kord, kas sinu koduserver toetab seda jututoa versiooni ning proovi uuesti.", + "Changes your display nickname": "Muudab sinu kuvatavat nime", + "Changes your display nickname in the current room only": "Muudab sinu kuvatavat nime vaid selles jututoas", + "Changes the avatar of the current room": "Muudab selle jututoa tunnuspilti", + "Changes your avatar in this current room only": "Muudab sinu tunnuspilti vaid selles jututoas", + "Failed to set topic": "Teema määramine ei õnnestunud", + "This room has no topic.": "Sellel jututoal puudub teema.", + "Invites user with given id to current room": "Kutsub nimetatud kasutajatunnusega kasutaja sellesse jututuppa", + "Use an identity server": "Kasuta isikutuvastusserverit", + "%(targetName)s accepted the invitation for %(displayName)s.": "%(targetName)s võttis vastu kutse %(displayName)s nimel.", + "%(targetName)s accepted an invitation.": "%(targetName)s võttis kutse vastu.", + "%(senderName)s requested a VoIP conference.": "%(senderName)s soovib alustada VoIP rühmakõnet.", + "%(senderName)s made no change.": "%(senderName)s ei teinud muutusi.", + "VoIP conference started.": "VoIP rühmakõne algas.", + "VoIP conference finished.": "VoIP rühmakõne lõppes.", + "%(targetName)s rejected the invitation.": "%(targetName)s lükkas kutse tagasi.", + "%(targetName)s left the room.": "%(targetName)s lahkus jututoast.", + "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s õigused muutusid: %(fromPowerLevel)s -> %(toPowerLevel)s", + "%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s muutis %(powerLevelDiffText)s õigusi.", + "Render simple counters in room header": "Näita jututoa päises lihtsaid loendure", + "Multiple integration managers": "Mitmed lõiminguhaldurid", + "Enable advanced debugging for the room list": "Lülita jututubade loendi jaoks sisse detailne silumine", + "Show a reminder to enable Secure Message Recovery in encrypted rooms": "Näita krüptitud jututubades meeldetuletust krüptitud sõnumite taastamisvõimaluste kohta", + "Use a system font": "Kasuta süsteemset fonti", + "System font name": "Süsteemse fondi nimi", + "Allow fallback call assist server turn.matrix.org when your homeserver does not offer one (your IP address would be shared during a call)": "Kui sinu koduserveris on seadistamata kõnehõlbustusserver, siis luba alternatiivina kasutada avalikku serverit turn.matrix.org (kõne ajal jagatakse nii sinu avalikku, kui privaatvõrgu IP-aadressi)", + "Send read receipts for messages (requires compatible homeserver to disable)": "Saada sõnumite lugemiskinnitusi (selle võimaluse keelamine eeldab, et koduserver sellist funktsionaalsust toetab)", + "This is your list of users/servers you have blocked - don't leave the room!": "See on sinu serverite ja kasutajate ligipääsukeeldude loend. Palun ära lahku sellest jututoast!", + "Changing password will currently reset any end-to-end encryption keys on all sessions, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "Kui sa just enne ekspordi selle jututoa võtmed ja impordi need hiljem, siis salasõna muutmine tühistab kõik läbiva krüptimise võtmed sinu kõikides sessioonides ning seega muutub kogu sinu krüptitud vestluste ajalugu loetamatuks. Tulevaste arenduste käigus tehakse see funktsionaalsus paremaks.", + "Your account has a cross-signing identity in secret storage, but it is not yet trusted by this session.": "Sinu kontol on turvahoidlas olemas risttunnustamise identiteet, kuid seda veel ei loeta antud sessioonis usaldusväärseks.", + "Cross-signing and secret storage are not yet set up.": "Risttunnustamine ja turvahoidla pole veel seadistatud.", + "Reset cross-signing and secret storage": "Tühista risttunnustamise tulemused ja turvahoidla sisu", + "Bootstrap cross-signing and secret storage": "Võta risttunnustamine ja turvahoidla kasutusele", + "well formed": "korrektses vormingus", + "unexpected type": "tundmatut tüüpi", + "in secret storage": "turvahoidlas", + "Self signing private key:": "Sinu privaatvõtmed:", + "cached locally": "on puhverdatud kohalikus seadmes", + "not found locally": "ei leidu kohalikus seadmes", + "User signing private key:": "Kasutaja privaatvõti:", + "Session backup key:": "Sessiooni varundusvõti:", + "in account data": "kasutajakonto andmete hulgas", + "Homeserver feature support:": "Koduserver on tugi sellele funktsionaalusele:", + "exists": "olemas", + "Confirm deleting these sessions by using Single Sign On to prove your identity.|other": "Kinnitamaks seda, et soovid neid sessioone kustutada, kasuta oma isiku tuvastamiseks ühekordset sisselogimist.", + "Confirm deleting these sessions by using Single Sign On to prove your identity.|one": "Kinnitamaks seda, et soovid seda sessiooni kustutada, kasuta oma isiku tuvastamiseks ühekordset sisselogimist.", + "Confirm deleting these sessions": "Kinnita nende sessioonide kustutamine", + "Click the button below to confirm deleting these sessions.|other": "Nende sessioonide kustutamiseks klõpsi järgnevat nuppu.", + "Click the button below to confirm deleting these sessions.|one": "Selle sessiooni kustutamiseks klõpsi järgnevat nuppu.", + "Delete sessions|other": "Kustuta sessioonid", + "Delete sessions|one": "Kustuta sessioon", + "Authentication": "Autentimine", + "%(brand)s can't securely cache encrypted messages locally while running in a web browser. Use %(brand)s Desktop for encrypted messages to appear in search results.": "%(brand)s ei võimalda veebibrauseris töötades krüptitud sõnumeid turvaliselt puhverdada. Selleks, et krüptitud sõnumeid saaks otsida, kasuta %(brand)s Desktop rakendust Matrix'i kliendina.", + "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Krüptitud sõnumid kasutavad läbivat krüptimist. Ainult sinul ja saaja(te)l on võtmed selliste sõnumite lugemiseks.", + "Unable to load key backup status": "Võtmete varunduse oleku laadimine ei õnnestunud", + "Restore from Backup": "Taasta varundusest", + "This session is backing up your keys. ": "See sessioon varundab sinu krüptovõtmeid. ", + "This session is not backing up your keys, but you do have an existing backup you can restore from and add to going forward.": "See sessioon ei varunda sinu krüptovõtmeid, aga sul on olemas varundus, millest saad taastada ning millele saad võtmeid lisada.", + "Success": "Õnnestus", + "Your password was successfully changed. You will not receive push notifications on other sessions until you log back in to them": "Sinu salasõna sai edukalt muudetud. Sa ei saa oma teistes sessioonides tõuketeateid seni, kuni sa pole neist välja ja tagasi loginud", + "Agree to the identity server (%(serverName)s) Terms of Service to allow yourself to be discoverable by email address or phone number.": "Selleks, et sind võiks leida e-posti aadressi või telefoninumbri alusel, nõustu isikutuvastusserveri (%(serverName)s) kasutustingimustega.", + "Account management": "Kontohaldus", + "Deactivating your account is a permanent action - be careful!": "Kuna kasutajakonto dektiveerimist ei saa tagasi pöörata, siis palun ole ettevaatlik!", + "Deactivate Account": "Deaktiveeri konto", + "Discovery": "Leia kasutajaid", + "Deactivate account": "Deaktiveeri kasutajakonto", + "For help with using %(brand)s, click here.": "Kui otsid lisateavet %(brand)s kasutamise kohta, palun vaata siia.", + "Add users and servers you want to ignore here. Use asterisks to have %(brand)s match any characters. For example, @bot:* would ignore all users that have the name 'bot' on any server.": "Lisa siia kasutajad ja serverid, mida sa soovid eirata. Kui soovid, et %(brand)s kasutaks üldist asendamist, siis kasuta tärni. Näiteks @bot:* eirab kõikide serverite kasutajat 'bot'.", + "Use default": "Kasuta vaikimisi väärtusi", + "Mentions & Keywords": "Mainimised ja võtmesõnad", + "Notification options": "Teavituste eelistused", + "Room options": "Jututoa eelistused", + "This room is public": "See jututuba on avalik", + "Away": "Eemal", + "Room avatar": "Jututoa tunnuspilt ehk avatar", + "Publish this room to the public in %(domain)s's room directory?": "Kas avaldame selle jututoa %(domain)s jututubade loendis?", + "When someone puts a URL in their message, a URL preview can be shown to give more information about that link such as the title, description, and an image from the website.": "Kui keegi lisab oma sõnumisse URL'i, siis võidakse näidata selle URL'i eelvaadet, mis annab lisateavet tema kohta, nagu näiteks pealkiri, kirjeldus ja kuidas ta välja näeb.", + "Waiting for you to accept on your other session…": "Ootan, et sa nõustuksid teises sessioonis…", + "Waiting for %(displayName)s to accept…": "Ootan, et %(displayName)s nõustuks…", + "Accepting…": "Nõustun …", + "Start Verification": "Alusta verifitseerimist", + "Messages in this room are end-to-end encrypted.": "See jututuba on läbivalt krüptitud.", + "Your messages are secured and only you and the recipient have the unique keys to unlock them.": "Sinu sõnumid on turvatud ning ainult sinul ja saaja(te)l on unikaalsed võtmed selliste sõnumite lugemiseks.", + "Messages in this room are not end-to-end encrypted.": "See jututuba ei ole läbivalt krüptitud.", + "One of the following may be compromised:": "Üks järgnevatest võib olla sattunud valedesse kätesse:", + "Your homeserver": "Sinu koduserver", + "The homeserver the user you’re verifying is connected to": "Sinu poolt verifitseeritava kasutaja koduserver", + "Yours, or the other users’ internet connection": "Sinu või teise kasutaja internetiühendus", + "Yours, or the other users’ session": "Sinu või teise kasutaja sessioon", + "Trusted": "Usaldusväärsed", + "Not trusted": "Ei ole usaldusväärsed", + "%(count)s verified sessions|other": "%(count)s verifitseeritud sessiooni", + "%(count)s verified sessions|one": "1 verifitseeritud sessioon", + "Hide verified sessions": "Peida verifitseeritud sessioonid", + "%(count)s sessions|other": "%(count)s sessiooni", + "%(count)s sessions|one": "%(count)s sessioon", + "Hide sessions": "Peida sessioonid", + "The session you are trying to verify doesn't support scanning a QR code or emoji verification, which is what %(brand)s supports. Try with a different client.": "See sessioon, mida sa tahad verifitseerida ei toeta QR koodi ega emoji-põhist verifitseerimist, aga just neid %(brand)s oskab kasutada. Proovi mõne muu Matrix'i kliendiga.", + "Verify by scanning": "Verifitseeri skaneerides", + "Ask %(displayName)s to scan your code:": "Palu, et %(displayName)s skaneeriks sinu koodi:", + "If you can't scan the code above, verify by comparing unique emoji.": "Kui sa ei saa skaneerida eespool kuvatud koodi, siis verifitseeri unikaalsete emoji'de võrdlemise teel.", + "Verify by comparing unique emoji.": "Verifitseeri unikaalsete emoji'de võrdlemise teel.", + "Verify by emoji": "Verifitseeri emoji'de abil", + "Edited at %(date)s": "Muutmise kuupäev %(date)s", + "Click to view edits": "Muudatuste nägemiseks klõpsi", + "In reply to ": "Vastuseks kasutajale ", + "There are advanced notifications which are not shown here.": "On olemad detailseid teavitusi, mida siin ei kuvata.", + "You might have configured them in a client other than %(brand)s. You cannot tune them in %(brand)s but they still apply.": "Sa võib-olla oled seadistanud nad %(brand)s'ist erinevas kliendis. Sa küll ei saa neid %(brand)s'is muuta, kuid nad kehtivad siiski.", + "You are currently using to discover and be discoverable by existing contacts you know. You can change your identity server below.": "Sa hetkel kasutad serverit, et olla leitav ja ise leida sinule teadaolevaid inimesi. Alljärgnevalt saad sa muuta oma isikutuvastusserverit.", + "If you don't want to use to discover and be discoverable by existing contacts you know, enter another identity server below.": "Kui sa ei soovi kasutada serverit, et olla leitav ja ise leida sinule teadaolevaid inimesi, siis sisesta alljärgnevalt mõni teine isikutuvastusserver.", + "Identity Server": "Isikutuvastusserver", + "Do not use an identity server": "Ära kasuta isikutuvastusserverit", + "Enter a new identity server": "Sisesta uue isikutuvastusserveri nimi", + "Change": "Muuda", + "Use an Integration Manager (%(serverName)s) to manage bots, widgets, and sticker packs.": "Robotite, vidinate ja kleepsupakkide jaoks kasuta lõiminguhaldurit (%(serverName)s).", + "Use an Integration Manager to manage bots, widgets, and sticker packs.": "Robotite, vidinate ja kleepsupakkide seadistamiseks kasuta lõiminguhaldurit.", + "Manage integrations": "Halda lõiminguid", + "Integration Managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Lõiminguhalduritel on laiad volitused - nad võivad sinu nimel lugeda seadistusi, kohandada vidinaid, saata jututubade kutseid ning määrata õigusi.", + "Define the power level of a user": "Määra kasutaja õigused", + "Command failed": "Käsk ei toiminud", + "Opens the Developer Tools dialog": "Avab arendusvahendite akna", + "Adds a custom widget by URL to the room": "Lisab jututuppa URL-ist valitud kohandatud vidina", + "Backing up %(sessionsRemaining)s keys...": "Varundan %(sessionsRemaining)s krüptovõtmeid...", + "All keys backed up": "Kõik krüptovõtmed on varundatud", + "Backup has a valid signature from this user": "Varukoopial on selle kasutaja kehtiv allkiri", + "Backup has a invalid signature from this user": "Varukoopial on selle kasutaja vigane allkiri", + "Backup has a signature from unknown user with ID %(deviceId)s": "Varukoopial tundmatu kasutaja allkiri seadme tunnusega %(deviceId)s", + "Backup has a signature from unknown session with ID %(deviceId)s": "Varukoopial tundmatu sessiooni allkiri seadme tunnusega %(deviceId)s", + "Backup has a valid signature from this session": "Varukoopial on selle sessiooni kehtiv allkiri", + "Backup has an invalid signature from this session": "Varukoopial on selle sessiooni vigane allkiri", + "Backup is not signed by any of your sessions": "Varunduse andmetel pole mitte ühegi sinu sessiooni allkirja", + "This backup is trusted because it has been restored on this session": "See varukoopia on usaldusväärne, sest ta on taastatud sellest sessioonist", + "Backup version: ": "Varukoopia versioon: ", + "Algorithm: ": "Algoritm: ", + "Backup key stored: ": "Varukoopia võti on salvestatud: ", + "Start using Key Backup": "Võta kasutusele krüptovõtmete varundamine", + "You are not currently using an identity server. To discover and be discoverable by existing contacts you know, add one below.": "Sa hetkel ei kasuta isikutuvastusserverit. Et olla leitav ja ise leida sinule teadaolevaid inimesi seadista ta alljärgnevalt.", + "Show rooms with unread messages first": "Näita lugemata sõnumitega jututubasid esimesena", + "Show previews of messages": "Näita sõnumite eelvaateid", + "Sort by": "Järjestamisviis", + "Activity": "Aktiivsuse alusel", + "A-Z": "Tähestiku järjekorras", + "Jump to first unread room.": "Siirdu esimesse lugemata jututuppa.", + "Jump to first invite.": "Siirdu esimese kutse juurde.", + "Recovery Method Removed": "Taastemeetod on eemaldatud", + "This session has detected that your recovery passphrase and key for Secure Messages have been removed.": "Oleme tuvastanud, et selles sessioonis ei leidu taastamiseks mõeldud paroolifraas ega krüptitud sõnumite taastevõtit.", + "If you did this accidentally, you can setup Secure Messages on this session which will re-encrypt this session's message history with a new recovery method.": "Kui sa tegid seda juhuslikult, siis sa võid selles sessioonis uuesti seadistada sõnumite krüptimise, mille tulemusel krüptime uuesti kõik sõnumid ja loome uue taastamise meetodi.", + "If you didn't remove the recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Kui sa ei ole ise taastamise meetodeid eemaldanud, siis võib olla tegemist ründega sinu konto vastu. Palun vaheta koheselt oma kasutajakonto salasõna ning määra seadistustes uus taastemeetod.", + "Are you sure you want to cancel entering passphrase?": "Kas oled kindel et sa soovid katkestada paroolifraasi sisestamise?", + "Use an identity server to invite by email. Click continue to use the default identity server (%(defaultIdentityServerName)s) or manage in Settings.": "E-posti teel kutse saatmiseks kasuta isikutuvastusserverit. Võid kasutada vaikimisi serverit (%(defaultIdentityServerName)s) või määrata muu serveri seadistustes.", + "Use an identity server to invite by email. Manage in Settings.": "Kasutajatele e-posti teel kutse saatmiseks pruugi isikutuvastusserverit. Täpsemalt saad seda hallata seadistustes.", + "Joins room with given address": "Liitu antud aadressiga jututoaga", + "Leave room": "Lahku jututoast", + "Unrecognised room address:": "Tundmatu jututoa aadress:", + "Kicks user with given id": "Müksa selle tunnusega kasutaja jututoast välja", + "Stops ignoring a user, showing their messages going forward": "Lõpeta kasutaja eiramine ja näita edaspidi tema sõnumeid", + "Unignored user": "Kasutaja, kelle eiramine on lõppenud", + "You are no longer ignoring %(userId)s": "Sa edaspidi ei eira kasutajat %(userId)s", + "Deops user with given id": "Eemalda antud tunnusega kasutajalt haldusõigused selles jututoas", + "Please supply a widget URL or embed code": "Palun lisa antud vidina aadress või lisatav kood", + "Please supply a https:// or http:// widget URL": "Vidina aadressi alguses peab olema kas https:// või http://", + "You cannot modify widgets in this room.": "Sul pole õigusi vidinate muutmiseks selles jututoas.", + "Verifies a user, session, and pubkey tuple": "Verifitseerib kasutaja, sessiooni ja avalikud võtmed", + "Unknown (user, session) pair:": "Tundmatu kasutaja-sessioon paar:", + "Displays action": "Näitab tegevusi", + "Reason": "Põhjus", + "Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.": "Ära usalda risttunnustamist ning verifitseeri kasutaja iga sessioon eraldi.", + "Connect this session to Key Backup": "Seo see sessioon krüptovõtmete varundusega", + "not stored": "ei ole salvestatud", + "Backup has a valid signature from verified session ": "Varukoopial on kehtiv allkiri verifitseeritud sessioonist ", + "Backup has a valid signature from unverified session ": "Varukoopial on kehtiv allkiri verifitseerimata sessioonist ", + "Backup has an invalid signature from verified session ": "Varukoopial on vigane allkiri verifitseeritud sessioonist ", + "Backup has an invalid signature from unverified session ": "Varukoopial on vigane allkiri verifitseerimata sessioonist ", + "Using an identity server is optional. If you choose not to use an identity server, you won't be discoverable by other users and you won't be able to invite others by email or phone.": "Isikutuvastusserveri kasutamine ei ole kohustuslik. Kui sa seda ei tee, siis sa ei ole leitav teiste kasutajate poolt ega sulle ei saa telefoninumbri või e-posti aadressi alusel kutset saata. Küll aga saab kutset saata Matrix'i kasutajatunnuse alusel.", + "Help & About": "Abiteave ning info meie kohta", + "Submit debug logs": "Saada silumise logid", + "Custom Tag": "Kohandatud silt", + "%(brand)s does not know how to join a room on this network": "%(brand)s ei tea kuidas selles võrgus jututoaga liituda", + "%(brand)s Web": "%(brand)s Web", + "%(brand)s Desktop": "%(brand)s Desktop", + "%(brand)s iOS": "%(brand)s iOS", + "%(brand)s X for Android": "%(brand)s X Androidi jaoks", + "Starting backup...": "Alusta varundamist...", + "Success!": "Õnnestus!", + "Create key backup": "Tee võtmetest varukoopia", + "Unable to create key backup": "Ei õnnestu teha võtmetest varukoopiat", + "Don't ask again": "Ära küsi uuesti", + "New Recovery Method": "Uus taastamise meetod", + "A new recovery passphrase and key for Secure Messages have been detected.": "Tuvastasin krüptitud sõnumite taastamiseks mõeldud uue paroolifraasi ja võtmed.", + "This session is encrypting history using the new recovery method.": "See sessioon krüptib ajalugu kasutades uut taastamise meetodit.", + "Whether or not you're using the Richtext mode of the Rich Text Editor": "Kas sa kasutad või mitte tekstitoimetis kujundatud teksti režiimi", + "Whether or not you're using the 'breadcrumbs' feature (avatars above the room list)": "Kas sa kasutad või mitte leivapuru-funktsionaalsust (tunnuspildid jututubade loendi kohal)", + "Whether you're using %(brand)s as an installed Progressive Web App": "Kas sa kasutad %(brand)s'i PWA-na (Progressive Web App)", + "Every page you use in the app": "Iga lehekülg, mida sa rakenduses kasutad", + "Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": "Kui antud lehel leidub isikustatavaid andmeid, nagu jututoa, kasutaja või kogukonna tunnus, siis need andmed eemaldatakse enne serveri poole saatmist.", + "* %(senderName)s %(emote)s": "* %(senderName)s %(emote)s", + " to store messages from ": " salvestamaks sõnumeid ", + "Unable to fetch notification target list": "Ei õnnestu laadida teavituste eesmärkide loendit", + "Notification targets": "Teavituste eesmärgid", + "Disconnecting from your identity server will mean you won't be discoverable by other users and you won't be able to invite others by email or phone.": "Isikutuvastusserveri kasutamise lõpetamine tähendab, et sa ei ole leitav teiste kasutajate poolt ega sulle ei saa telefoninumbri või e-posti aadressi alusel kutset saata. Küll aga saab kutset saata Matrix'i kasutajatunnuse alusel.", + "If you've submitted a bug via GitHub, debug logs can help us track down the problem. Debug logs contain application usage data including your username, the IDs or aliases of the rooms or groups you have visited and the usernames of other users. They do not contain messages.": "Kui sa oled teatanud meile GitHub'i vahendusel veast, siis silumislogid aitavad meil seda viga kergemini parandada. Vigadega seotud logid sisaldavad rakenduse teavet, sealhulgas sinu kasutajanime, külastatud jututubade kasutajatunnuseid või aliasi ning teiste kasutajate kasutajanimesid. Logides ei ole saadetud sõnumite sisu.", + "To avoid losing your chat history, you must export your room keys before logging out. You will need to go back to the newer version of %(brand)s to do this": "Selleks, et sa ei kaotaks oma vestluste ajalugu, pead sa eksportima jututoa krüptovõtmed enne välja logimist. Küll, aga pead sa selleks kasutama %(brand)s uuemat versiooni", + "You've previously used a newer version of %(brand)s with this session. To use this version again with end to end encryption, you will need to sign out and back in again.": "Sa oled selle sessiooni jaoks varem kasutanud %(brand)s'i uuemat versiooni. Selle versiooni kasutamiseks läbiva krüptimisega, pead sa esmalt logima välja ja siis uuesti logima tagasi sisse.", + "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Kui sa pole seadistanud krüptitud sõnumite taastamise meetodeid, siis väljalogimisel sa kaotad võimaluse neid krüptitud sõnumeid lugeda.", + "If you don't want to set this up now, you can later in Settings.": "Kui sa ei soovi seda teha kohe, siis vastava võimaluse leiad hiljem rakenduse seadistustest.", + "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Kui sa ei ole ise uusi taastamise meetodeid lisanud, siis võib olla tegemist ründega sinu konto vastu. Palun vaheta koheselt oma kasutajakonto salasõna ning määra seadistustes uus taastemeetod.", + "%(senderDisplayName)s enabled flair for %(groups)s in this room.": "%(senderDisplayName)s võttis selles jututoas kasutusele %(groups)s kogukonna rinnamärgi.", + "%(senderDisplayName)s disabled flair for %(groups)s in this room.": "%(senderDisplayName)s eemaldas selles jututoas kasutuselt %(groups)s kogukonna rinnamärgi.", + "%(senderDisplayName)s enabled flair for %(newGroups)s and disabled flair for %(oldGroups)s in this room.": "%(senderDisplayName)s võttis selles jututoas kasutusele %(newGroups)s kogukonna rinnamärgi ning eemaldas rinnamärgi %(oldGroups)s kogukonnalt.", + "Connect this session to key backup before signing out to avoid losing any keys that may only be on this session.": "Enne väljalogimist seo see sessioon krüptovõtmete varundusega. Kui sa seda ei tee, siis võid kaotada võtmed, mida kasutatakse vaid siin sessioonis.", + "Flair": "Kogukonna rinnasilt", + "Error updating flair": "Viga kogukonna rinnasildi uuendamisel", + "There was an error updating the flair for this room. The server may not allow it or a temporary error occurred.": "Kogukonna rinnasildi uuendamisel tekkis viga. See kas on serveri poolt keelatud või tekkis mingi ajutine viga.", + "Showing flair for these communities:": "Näidatakse nende kogukondade rinnasilte:", + "This room is not showing flair for any communities": "Sellele jututoale ei ole jagatud ühtegi kogukonna rinnasilti", + "Display your community flair in rooms configured to show it.": "Näita oma kogukonna rinnasilti nendes jututubades, kus selle kuvamine on seadistatud.", + "You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use %(brand)s with an existing Matrix account on a different homeserver.": "Kohandatud serveriseadistusi saad kasutada selleks, et logida sisse sinu valitud koduserverisse. See võimaldab sinul kasutada %(brand)s'i mõnes teises koduserveri hallatava kasutajakontoga.", + "Did you know: you can use communities to filter your %(brand)s experience!": "Kas sa teadsid, et sa võid %(brand)s'i parema kasutuskogemuse nimel pruukida kogukondi!", + "Without setting up Secure Message Recovery, you won't be able to restore your encrypted message history if you log out or use another session.": "Kui sa pole seadistanud krüptitud sõnumite taastamise meetodeid, siis väljalogimisel või muu sessiooni kasutamisel sa kaotad võimaluse oma krüptitud sõnumeid lugeda.", + "Set up Secure Message Recovery": "Võta kasutusele turvaline sõnumivõtmete varundus", + "Secure your backup with a recovery passphrase": "Krüpti oma varukoopia taastamiseks mõeldud paroolifraasiga", + "The person who invited you already left the room.": "See, kes sind jututoa liikmeks kutsus, on juba jututoast lahkunud.", + "The person who invited you already left the room, or their server is offline.": "See, kes sind jututoa liikmeks kutsus, kas juba on jututoast lahkunud või tema koduserver on võrgust väljas." } diff --git a/src/i18n/strings/eu.json b/src/i18n/strings/eu.json index 7d6cfcbad0..01afa51836 100644 --- a/src/i18n/strings/eu.json +++ b/src/i18n/strings/eu.json @@ -20,7 +20,7 @@ "Start chat": "Hasi txata", "Custom Server Options": "Zerbitzari pertsonalizatuaren aukerak", "Dismiss": "Baztertu", - "powered by Matrix": "Matrix mamian", + "powered by Matrix": "Matrix-ekin egina", "Room": "Gela", "Historical": "Historiala", "Save": "Gorde", @@ -326,7 +326,7 @@ "Upload an avatar:": "Igo abatarra:", "This server does not support authentication with a phone number.": "Zerbitzari honek ez du telefono zenbakia erabiliz autentifikatzea onartzen.", "An error occurred: %(error_string)s": "Errore bat gertatu da: %(error_string)s", - "There are no visible files in this room": "Ez dago fitxategi ikusgairik gela honetan", + "There are no visible files in this room": "Ez dago fitxategirik ikusgai gela honetan", "Sent messages will be stored until your connection has returned.": "Bidalitako mezuak zure konexioa berreskuratu arte gordeko dira.", "(~%(count)s results)|one": "(~%(count)s emaitza)", "(~%(count)s results)|other": "(~%(count)s emaitza)", @@ -734,7 +734,7 @@ "All Rooms": "Gela guztiak", "Wednesday": "Asteazkena", "You cannot delete this message. (%(code)s)": "Ezin duzu mezu hau ezabatu. (%(code)s)", - "Quote": "Aipua", + "Quote": "Aipatu", "Send logs": "Bidali egunkariak", "All messages": "Mezu guztiak", "Call invitation": "Dei gonbidapena", @@ -1539,7 +1539,7 @@ "View": "Ikusi", "Find a room…": "Bilatu gela bat…", "Find a room… (e.g. %(exampleRoom)s)": "Bilatu gela bat… (adib. %(exampleRoom)s)", - "If you can't find the room you're looking for, ask for an invite or Create a new room.": "Ezin baduzu bila ari zaren gela aurkitu, eskatu gonbidapen bat edo Sortu gela berri bat.", + "If you can't find the room you're looking for, ask for an invite or Create a new room.": "Ez baduzu bilatzen duzuna aurkitzen, eskatu gonbidapen bat edo Sortu gela berri bat.", "Explore rooms": "Arakatu gelak", "Community Autocomplete": "Komunitate osatze automatikoa", "Emoji Autocomplete": "Emoji osatze automatikoa", @@ -1641,7 +1641,7 @@ "Not trusted": "Ez konfiantzazkoa", "Direct message": "Mezu zuzena", "%(role)s in %(roomName)s": "%(role)s %(roomName)s gelan", - "Messages in this room are end-to-end encrypted.": "Gela honetako mezuak ez daude muturretik muturrera zifratuta.", + "Messages in this room are end-to-end encrypted.": "Gela honetako mezuak muturretik muturrera zifratuta daude.", "Security": "Segurtasuna", "Verify": "Egiaztatu", "You have ignored this user, so their message is hidden. Show anyways.": "Erabiltzaile hau ezikusi duzu, beraz bere mezua ezkutatuta dago. Erakutsi hala ere.", @@ -1897,7 +1897,7 @@ "If your other sessions do not have the key for this message you will not be able to decrypt them.": "Zure beste saioek ez badute mezu honen gakoa ezin izango duzu deszifratu.", "Re-request encryption keys from your other sessions.": "Eskatu berriro zifratze gakoak zure beste saioei.", "Waiting for %(displayName)s to accept…": "%(displayName)s(e)k onartu bitartean zain…", - "Your messages are secured and only you and the recipient have the unique keys to unlock them.": "Zuon mezuak babestuta daude eta soilik zuk eta hartzaileak dituzue hauek irekitzeko giltza.", + "Your messages are secured and only you and the recipient have the unique keys to unlock them.": "Zuen mezuak babestuta daude eta soilik zuk eta hartzaileak dituzue hauek desblokeatzeko gakoak.", "One of the following may be compromised:": "Hauetakoren bat konprometituta egon daiteke:", "Verify this device to mark it as trusted. Trusting this device gives you and other users extra peace of mind when using end-to-end encrypted messages.": "Egiztatu gailu hau fidagarri gisa markatzeko. Gailu hau fidagarritzat jotzeak lasaitasuna ematen du muturretik-muturrera zifratutako mezuak erabiltzean.", "Verifying this device will mark it as trusted, and users who have verified with you will trust this device.": "Gailu hau egiaztatzean fidagarri gisa markatuko da, eta egiaztatu zaituzten erabiltzaileek fidagarri gisa ikusiko dute.", @@ -2248,5 +2248,23 @@ "Security & privacy": "Segurtasuna eta pribatutasuna", "All settings": "Ezarpen guztiak", "Feedback": "Iruzkinak", - "Use a different passphrase?": "Erabili pasa-esaldi desberdin bat?" + "Use a different passphrase?": "Erabili pasa-esaldi desberdin bat?", + "We’re excited to announce Riot is now Element": "Pozik jakinarazten dizugu: Riot orain Element deitzen da", + "Riot is now Element!": "Riot orain Element da!", + "Learn More": "Ikasi gehiago", + "Light": "Argia", + "The person who invited you already left the room.": "Gonbidatu zaituen pertsonak dagoeneko gela utzi du.", + "The person who invited you already left the room, or their server is offline.": "Gonbidatu zaituen pertsonak dagoeneko gela utzi du edo bere zerbitzaria lineaz kanpo dago.", + "You joined the call": "Deira batu zara", + "%(senderName)s joined the call": "%(senderName)s deira batu da", + "You left the call": "Deitik atera zara", + "%(senderName)s left the call": "%(senderName)s(e) deitik atera da", + "Call ended": "Deia amaitu da", + "You started a call": "Dei bat hasi duzu", + "%(senderName)s started a call": "%(senderName)s(e)k dei bat hasi du", + "%(senderName)s is calling": "%(senderName)s deitzen ari da", + "%(brand)s Web": "%(brand)s web", + "%(brand)s Desktop": "%(brand)s Desktop", + "%(brand)s iOS": "%(brand)s iOS", + "%(brand)s X for Android": "%(brand)s X for Android" } diff --git a/src/i18n/strings/fa.json b/src/i18n/strings/fa.json index 9dd5950cf3..6dd523cec6 100644 --- a/src/i18n/strings/fa.json +++ b/src/i18n/strings/fa.json @@ -10,11 +10,11 @@ "Failed to set direct chat tag": "تنظیم تگ برای چت مستقیم موفقیت‌آمیز نبود", "Today": "امروز", "Files": "فایل‌ها", - "You are not receiving desktop notifications": "شما آگاه‌سازی‌های دسکتاپ را دریافت نمی‌کنید", + "You are not receiving desktop notifications": "آگاهی‌های میزکار را دریافت نمی‌کنید", "Friday": "آدینه", - "Update": "به‌روزرسانی", - "Notifications": "آگاه‌سازی‌ها", - "What's New": "تازه‌ها", + "Update": "به‌روز رسانی", + "Notifications": "آگاهی‌ها", + "What's New": "چه خبر", "On": "روشن", "Changelog": "تغییراتِ به‌وجودآمده", "Waiting for response from server": "در انتظار پاسخی از سمت سرور", @@ -67,7 +67,7 @@ "Failed to set Direct Message status of room": "تنظیم حالت پیام مستقیم برای گپ موفقیت‌آمیز نبود", "Monday": "دوشنبه", "All messages (noisy)": "همه‌ی پیام‌ها(بلند)", - "Enable them now": "همین حالا فعالشان کن", + "Enable them now": "اکنون به کار بیفتند", "Collecting logs": "درحال جمع‌آوری گزارش‌ها", "Search": "جستجو", "(HTTP status %(httpStatus)s)": "(HTTP وضعیت %(httpStatus)s)", @@ -82,7 +82,7 @@ "Call invitation": "دعوت به تماس", "Messages containing my display name": "پیام‌های حاوی نمای‌نامِ من", "You have successfully set a password and an email address!": "تخصیص ایمیل و پسوردتان با موفقیت انجام شد!", - "What's new?": "تازه‌ها", + "What's new?": "چه خبر؟", "Notify me for anything else": "مرا برای هرچیز دیگری باخبر کن", "When I'm invited to a room": "وقتی من به گپی دعوت میشوم", "Close": "بستن", @@ -102,7 +102,7 @@ "Keywords": "کلیدواژه‌ها", "Low Priority": "کم اهمیت", "Unable to fetch notification target list": "ناتوانی در تطبیق لیست آگاه‌سازی‌های هدف", - "Set Password": "پسوردتان را انتخاب کنید", + "Set Password": "تنظیم گذرواژه", "An error occurred whilst saving your email notification preferences.": "خطایی در حین ذخیره‌ی ترجیجات شما درباره‌ی رایانامه رخ داد.", "Off": "خاموش", "Mentions only": "فقط نام‌بردن‌ها", @@ -120,5 +120,34 @@ "With your current browser, the look and feel of the application may be completely incorrect, and some or all features may not function. If you want to try it anyway you can continue, but you are on your own in terms of any issues you may encounter!": "با مرورگر کنونی شما، ظاهر و حس استفاده از برنامه ممکن است کاملا اشتباه باشد و برخی یا همه‌ی ویژگی‌ها ممکن است کار نکنند. می‌توانید به استفاده ادامه دهید اما مسئولیت هر مشکلی که به آن بربخورید بر عهده‌ی خودتان است!", "Checking for an update...": "درحال بررسی به‌روزرسانی‌ها...", "This email address is already in use": "این آدرس ایمیل در حال حاضر در حال استفاده است", - "This phone number is already in use": "این شماره تلفن در حال استفاده است" + "This phone number is already in use": "این شماره تلفن در حال استفاده است", + "Please install Chrome, Firefox, or Safari for the best experience.": "لطفا برای تجربه بهتر کروم، فایرفاکس، یا سافاری را نصب کنید.", + "Use Single Sign On to continue": "برای ادامه، از ورود یکپارچه استفاده کنید", + "Single Sign On": "ورود یکپارچه", + "Confirm adding email": "تأیید افزودن رایانامه", + "Confirm": "تأیید", + "Add Email Address": "افزودن نشانی رایانامه", + "Confirm adding phone number": "تأیید افزودن شماره تلفن", + "Add Phone Number": "افزودن شماره تلفن", + "The platform you're on": "بن‌سازه‌ای که رویش هستید", + "The version of %(brand)s": "نگارش %(brand)s", + "Your language of choice": "زبان انتخابیتان", + "I want to help": "می‌خواهم کمک کنم", + "No": "خیر", + "Review": "بازبینی", + "Later": "بعداً", + "Contact your server admin.": "تماس با مدیر کارسازتان.", + "Ok": "تأیید", + "Set password": "تنظیم گذرواژه", + "To return to your account in future you need to set a password": "برای بازگشت به حسابتان در آینده، نیاز به تنظیم یک گذرواژه دارید", + "Set up encryption": "برپایی رمزنگاری", + "Encryption upgrade available": "ارتقای رمزنگاری ممکن است", + "Verify this session": "تأیید این نشست", + "Set up": "برپایی", + "Upgrade": "ارتقا", + "Verify": "تأیید", + "Restart": "شروع دوباره", + "Upgrade your %(brand)s": "ارتقای %(brand)s تان", + "A new version of %(brand)s is available!": "نگارشی جدید از %(brand)s موجود است!", + "Guest": "مهمان" } diff --git a/src/i18n/strings/fi.json b/src/i18n/strings/fi.json index ddac22a9a8..8d620828e6 100644 --- a/src/i18n/strings/fi.json +++ b/src/i18n/strings/fi.json @@ -2209,5 +2209,18 @@ "System font name": "Järjestelmän fontin nimi", "Message layout": "Viestiasettelu", "Compact": "Tiivis", - "Modern": "Moderni" + "Modern": "Moderni", + "We’re excited to announce Riot is now Element": "Meillä on ilo ilmoittaa, että Riot on nyt Element", + "Riot is now Element!": "Riot on nyt Element!", + "Learn More": "Lue lisää", + "Use default": "Käytä oletusta", + "Mentions & Keywords": "Maininnat ja avainsanat", + "Notification options": "Ilmoitusasetukset", + "Room options": "Huoneen asetukset", + "This room is public": "Tämä huone on julkinen", + "You’re already signed in and good to go here, but you can also grab the latest versions of the app on all platforms at element.io/get-started.": "Olet jo kirjautuneena eikä sinun tarvitse tehdä mitään, mutta voit myös hakea sovelluksen uusimman version kaikille alustoille osoitteesta element.io/get-started.", + "We’re excited to announce Riot is now Element!": "Meillä on ilo ilmoittaa, että Riot on nyt Element!", + "Learn more at element.io/previously-riot": "Lue lisää osoitteessa element.io/previously-riot", + "Security & privacy": "Tietoturva ja -suoja", + "User menu": "Käyttäjän valikko" } diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json index eb09eacd14..42f9d74502 100644 --- a/src/i18n/strings/fr.json +++ b/src/i18n/strings/fr.json @@ -754,7 +754,7 @@ "Show message in desktop notification": "Afficher le message dans les notifications de bureau", "Unhide Preview": "Dévoiler l'aperçu", "Unable to join network": "Impossible de rejoindre le réseau", - "Sorry, your browser is not able to run %(brand)s.": "Désolé, %(brand)s n'est pas supporté par votre navigateur.", + "Sorry, your browser is not able to run %(brand)s.": "Désolé, %(brand)s n'est pas supporté par votre navigateur.", "Uploaded on %(date)s by %(user)s": "Téléchargé le %(date)s par %(user)s", "Messages in group chats": "Messages dans les discussions de groupe", "Yesterday": "Hier", @@ -2347,5 +2347,35 @@ "Set up Secure backup": "Configurer la sauvegarde sécurisée", "Set a Security Phrase": "Définir une phrase de sécurité", "Confirm Security Phrase": "Confirmer la phrase de sécurité", - "Save your Security Key": "Sauvegarder votre clé de sécurité" + "Save your Security Key": "Sauvegarder votre clé de sécurité", + "Use your account to sign in to the latest version": "Connectez-vous à la nouvelle version", + "We’re excited to announce Riot is now Element": "Nous sommes heureux de vous annoncer que Riot est désormais Element", + "Riot is now Element!": "Riot est maintenant Element !", + "Learn More": "Plus d'infos", + "Enable experimental, compact IRC style layout": "Disposition expérimentale compacte style IRC", + "Incoming voice call": "Appel vocal entrant", + "Incoming video call": "Appel vidéo entrant", + "Incoming call": "Appel entrant", + "Make this room low priority": "Définir ce salon en priorité basse", + "Low priority rooms show up at the bottom of your room list in a dedicated section at the bottom of your room list": "Les salons de priorité basse s'affichent en bas de votre liste de salons, dans une section dédiée", + "Show rooms with unread messages first": "Afficher les salons non lus en premier", + "Show previews of messages": "Afficher un aperçu des messages", + "Use default": "Utiliser la valeur par défaut", + "Mentions & Keywords": "Mentions et mots-clés", + "Notification options": "Paramètres de notifications", + "Unknown caller": "Appelant inconnu", + "Favourited": "Favori", + "Forget Room": "Oublier le salon", + "This room is public": "Ce salon est public", + "Edited at %(date)s": "Édité le %(date)s", + "Click to view edits": "Cliquez pour éditer", + "Go to Element": "Aller à Element", + "We’re excited to announce Riot is now Element!": "Nous sommes heureux d'annoncer que Riot est désormais Element !", + "Learn more at element.io/previously-riot": "Plus d'infos sur element.io/previously-riot", + "Search rooms": "Chercher des salons", + "User menu": "Menu d'utilisateur", + "%(brand)s Web": "%(brand)s Web", + "%(brand)s Desktop": "%(brand)s Desktop", + "%(brand)s iOS": "%(brand)s iOS", + "%(brand)s X for Android": "%(brand)s X pour Android" } diff --git a/src/i18n/strings/gl.json b/src/i18n/strings/gl.json index 386b78a61f..f06b1e22d9 100644 --- a/src/i18n/strings/gl.json +++ b/src/i18n/strings/gl.json @@ -273,7 +273,7 @@ "Leave room": "Deixar a sala", "Favourite": "Favorita", "Guests cannot join this room even if explicitly invited.": "As convidadas non se poden unir a esta sala ainda que fosen convidadas explicitamente.", - "Click here to fix": "Pulse aquí para solución", + "Click here to fix": "Preme aquí para solucionar", "Who can access this room?": "Quen pode acceder a esta sala?", "Only people who have been invited": "Só persoas que foron convidadas", "Anyone who knows the room's link, apart from guests": "Calquera que coñeza o enderezo da sala, aparte das convidadas", @@ -494,7 +494,7 @@ "%(inviter)s has invited you to join this community": "%(inviter)s convidoute a entrar nesta comunidade", "You are an administrator of this community": "Administras esta comunidade", "You are a member of this community": "É membro desta comunidade", - "Your community hasn't got a Long Description, a HTML page to show to community members.
    Click here to open settings and give it one!": "A súa comunidade non ten unha descrición longa, ou unha páxina HTML que lle mostrar aos seus participantes.
    Pulse aquí para abrir os axustes e publicar unha!", + "Your community hasn't got a Long Description, a HTML page to show to community members.
    Click here to open settings and give it one!": "A túa comunidade non ten unha descrición longa, ou unha páxina HTML que lle mostrar ás participantes.
    Preme aquí para abrir os axustes e publicar unha!", "Long Description (HTML)": "Descrición longa (HTML)", "Description": "Descrición", "Community %(groupId)s not found": "Non se atopou a comunidade %(groupId)s", @@ -530,11 +530,11 @@ "Room": "Sala", "Failed to reject invite": "Fallo ao rexeitar o convite", "Fill screen": "Encher pantalla", - "Click to unmute video": "Pulse para escoitar vídeo", - "Click to mute video": "Pulse para acalar video", - "Click to unmute audio": "Pulse para escoitar audio", - "Click to mute audio": "Pulse para acalar audio", - "Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.": "Intentouse cargar un punto concreto do historial desta sala, pero non ten permiso para ver a mensaxe en cuestión.", + "Click to unmute video": "Preme para escoitar vídeo", + "Click to mute video": "Preme para acalar video", + "Click to unmute audio": "Preme para escoitar audio", + "Click to mute audio": "Preme para acalar audio", + "Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.": "Intentouse cargar un punto concreto do historial desta sala, pero non tes permiso para ver a mensaxe en cuestión.", "Tried to load a specific point in this room's timeline, but was unable to find it.": "Intentouse cargar un punto específico do historial desta sala, pero non se puido atopar.", "Failed to load timeline position": "Fallo ao cargar posición da liña temporal", "Uploading %(filename)s and %(count)s others|other": "Subindo %(filename)s e %(count)s máis", @@ -567,7 +567,7 @@ "Profile": "Perfil", "Account": "Conta", "Access Token:": "Testemuño de acceso:", - "click to reveal": "pulse para revelar", + "click to reveal": "Preme para mostrar", "Homeserver is": "O servidor de inicio é", "Identity Server is": "O servidor de identidade é", "%(brand)s version:": "versión %(brand)s:", @@ -1254,7 +1254,7 @@ "Butterfly": "Bolboreta", "Flower": "Flor", "Tree": "Árbore", - "Cactus": "Cactus", + "Cactus": "Cacto", "Mushroom": "Cogomelo", "Globe": "Globo", "Moon": "Lúa", @@ -1507,7 +1507,7 @@ "Room version": "Versión da sala", "Room version:": "Versión da sala:", "Developer options": "Opcións desenvolvemento", - "Open Devtools": "Open Devtools", + "Open Devtools": "Abrir Devtools", "This room is bridging messages to the following platforms. Learn more.": "Esta sala está enviando mensaxes ás seguintes plataformas. Coñece máis.", "This room isn’t bridging messages to any platforms. Learn more.": "Esta sala non está enviando mensaxes a outras plataformas. Saber máis.", "Bridges": "Pontes", @@ -2232,7 +2232,7 @@ "Autocomplete": "Autocompletado", "Alt": "Alt", "Alt Gr": "Alt Gr", - "Shift": "Maiús.", + "Shift": "Maiús", "Super": "Super", "Ctrl": "Ctrl", "Toggle Bold": "Activa Resaltar", @@ -2344,5 +2344,51 @@ "Set up Secure backup": "Configurar Copia de apoio Segura", "Set a Security Phrase": "Establece a Frase de Seguridade", "Confirm Security Phrase": "Confirma a Frase de Seguridade", - "Save your Security Key": "Garda a Chave de Seguridade" + "Save your Security Key": "Garda a Chave de Seguridade", + "Use your account to sign in to the latest version": "Usa a túa conta para conectarte á última versión", + "We’re excited to announce Riot is now Element": "Emociónanos anunciar que Riot agora chámase Element", + "Riot is now Element!": "Riot agora é Element!", + "Learn More": "Saber máis", + "Enable experimental, compact IRC style layout": "Activar o estilo experimental IRC compacto", + "Unknown caller": "Descoñecido", + "Incoming voice call": "Chamada de voz entrante", + "Incoming video call": "Chamada de vídeo entrante", + "Incoming call": "Chamada entrante", + "%(brand)s can't securely cache encrypted messages locally while running in a web browser. Use %(brand)s Desktop for encrypted messages to appear in search results.": "%(brand)s non pode por na caché local de xeito as mensaxes cifradas cando usa un navegador web. Usa %(brand)s Desktop para que as mensaxes cifradas aparezan nos resultados.", + "There are advanced notifications which are not shown here.": "Existen notificacións avanzadas que non aparecen aquí.", + "You might have configured them in a client other than %(brand)s. You cannot tune them in %(brand)s but they still apply.": "Deberialas ter configurado nun cliente diferente de %(brand)s. Non podes modificalas en %(brand)s pero aplícanse igualmente.", + "Set the name of a font installed on your system & %(brand)s will attempt to use it.": "Escolle unha das tipografías instaladas no teu sistema e %(brand)s intentará utilizalas.", + "Make this room low priority": "Marcar a sala como de baixa prioridade", + "Low priority rooms show up at the bottom of your room list in a dedicated section at the bottom of your room list": "As salas de baixa prioridade aparecen abaixo na lista de salas, nunha sección dedicada no final da lista", + "Use default": "Usar por omisión", + "Mentions & Keywords": "Mencións e Palabras chave", + "Notification options": "Opcións de notificación", + "Favourited": "Con marca de Favorita", + "Forget Room": "Esquecer sala", + "If the other version of %(brand)s is still open in another tab, please close it as using %(brand)s on the same host with both lazy loading enabled and disabled simultaneously will cause issues.": "Se a outra versión de %(brand)s aínda está aberta noutra lapela, péchaa xa que usar %(brand)s no mesmo servidor con carga preguiceira activada e desactivada ao mesmo tempo causará problemas.", + "Use your account to sign in to the latest version of the app at ": "Usa a túa conta para conectarte á última versión da app en ", + "You’re already signed in and good to go here, but you can also grab the latest versions of the app on all platforms at element.io/get-started.": "Xa estás conectada e podes ir alá, pero tamén podes ir á última versión da app en tódalas plataformas en element.io/get-started.", + "Go to Element": "Ir a Element", + "We’re excited to announce Riot is now Element!": "Emociónanos comunicar que Riot agora é Element!", + "Learn more at element.io/previously-riot": "Coñece máis en element.io/previously-riot", + "You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use %(brand)s with an existing Matrix account on a different homeserver.": "Podes usar as opcións de servidor personalizado para conectar con outros servidores Matrix indicando un URL diferente para o servidor. Poderás usar %(brand)s cunha conta Matrix existente noutro servidor de inicio.", + "Enter the location of your Element Matrix Services homeserver. It may use your own domain name or be a subdomain of element.io.": "Escribe a localización do teu servidor Element Matrix Services. Podería ser o teu propio dominio ou un subdominio de element.io.", + "Search rooms": "Buscar salas", + "User menu": "Menú de usuaria", + "%(brand)s Web": "Web %(brand)s", + "%(brand)s Desktop": "%(brand)s Desktop", + "%(brand)s iOS": "%(brand)s iOS", + "%(brand)s X for Android": "%(brand)s X para Android", + "This room is public": "Esta é unha sala pública", + "Away": "Fóra", + "Enable advanced debugging for the room list": "Activar depuración avanzada para a lista da sala", + "Show rooms with unread messages first": "Mostrar primeiro as salas con mensaxes sen ler", + "Show previews of messages": "Mostrar vista previa das mensaxes", + "Edited at %(date)s": "Editado o %(date)s", + "Click to view edits": "Preme para ver as edicións", + "Are you sure you want to cancel entering passphrase?": "¿Estás seguro de que non queres escribir a frase de paso?", + "Custom Tag": "Etiqueta personal", + "* %(senderName)s %(emote)s": "* %(senderName)s %(emote)s", + "The person who invited you already left the room.": "A persoa que te convidou xa deixou a sala.", + "The person who invited you already left the room, or their server is offline.": "A persoa que te convidou xa deixou a sala, ou o seu servidor non está a funcionar." } diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json index b983926d3d..209c237c0c 100644 --- a/src/i18n/strings/hu.json +++ b/src/i18n/strings/hu.json @@ -145,7 +145,7 @@ "Invites": "Meghívók", "Invites user with given id to current room": "A megadott azonosítójú felhasználó meghívása a jelenlegi szobába", "Sign in with": "Belépés ezzel:", - "Join as voice or video.": "Csatlakozás hanggal vagy videóval.", + "Join as voice or video.": "Csatlakozás hanggal vagy videóval.", "Join Room": "Belépés a szobába", "%(targetName)s joined the room.": "%(targetName)s belépett a szobába.", "Jump to first unread message.": "Ugrás az első olvasatlan üzenetre.", @@ -266,7 +266,7 @@ "Users": "Felhasználók", "Verification Pending": "Ellenőrzés függőben", "Verified key": "Ellenőrzött kulcs", - "Video call": "Videó hívás", + "Video call": "Videóhívás", "Voice call": "Hang hívás", "VoIP conference finished.": "VoIP konferencia befejeződött.", "VoIP conference started.": "VoIP konferencia elkezdődött.", @@ -1021,7 +1021,7 @@ "Deactivating your account is a permanent action - be careful!": "A fiók felfüggesztése végleges - légy óvatos!", "For help with using %(brand)s, click here.": "A %(brand)s használatában való segítséghez kattints ide.", "For help with using %(brand)s, click here or start a chat with our bot using the button below.": "A %(brand)s használatában való segítségér kattints ide vagy kezdj beszélgetni a botunkkal az alábbi gombra kattintva.", - "Help & About": "Segítség & Névjegy", + "Help & About": "Súgó és névjegy", "Bug reporting": "Hiba bejelentése", "FAQ": "GYIK", "Versions": "Verziók", @@ -1032,7 +1032,7 @@ "Autocomplete delay (ms)": "Automatikus kiegészítés késleltetése (ms)", "Roles & Permissions": "Szerepek & Jogosultságok", "Changes to who can read history will only apply to future messages in this room. The visibility of existing history will be unchanged.": "A üzenetek olvashatóságának változtatása csak az új üzenetekre lesz érvényes. A régi üzenetek láthatósága nem fog változni.", - "Security & Privacy": "Biztonság & Adatvédelem", + "Security & Privacy": "Biztonság és adatvédelem", "Encryption": "Titkosítás", "Once enabled, encryption cannot be disabled.": "Ha egyszer bekapcsolod, már nem lehet kikapcsolni.", "Encrypted": "Titkosítva", @@ -1041,7 +1041,7 @@ "Key backup": "Kulcsok biztonsági mentése", "Missing media permissions, click the button below to request.": "Hiányzó média jogosultságok, kattints a gombra alul a jogok megadásához.", "Request media permissions": "Média jogosultságok megkérése", - "Voice & Video": "Hang & Videó", + "Voice & Video": "Hang és videó", "Main address": "Fő cím", "Room avatar": "Szoba képe", "Room Name": "Szoba neve", @@ -1445,7 +1445,7 @@ "Remove %(email)s?": "%(email)s törlése?", "Remove %(phone)s?": "%(phone)s törlése?", "A text message has been sent to +%(msisdn)s. Please enter the verification code it contains.": "A szöveges üzenetet elküldtük a +%(msisdn)s számra. Kérlek add meg az ellenőrző kódot amit tartalmazott.", - "Command Help": "Parancs Segítség", + "Command Help": "Parancsok súgója", "No identity server is configured: add one in server settings to reset your password.": "Nincs azonosítási szerver beállítva: adj meg egyet a szerver beállításoknál, hogy a jelszavadat vissza tudd állítani.", "This account has been deactivated.": "Ez a fiók zárolva van.", "You do not have the required permissions to use this command.": "A parancs használatához nincs meg a megfelelő jogosultságod.", @@ -1732,7 +1732,7 @@ "Language Dropdown": "Nyelvválasztó lenyíló menü", "Country Dropdown": "Ország lenyíló menü", "The message you are trying to send is too large.": "Túl nagy képet próbálsz elküldeni.", - "Help": "Segítség", + "Help": "Súgó", "Show more": "Mutass többet", "Recent Conversations": "Legújabb Beszélgetések", "Direct Messages": "Közvetlen Beszélgetések", @@ -2045,15 +2045,15 @@ "Shift": "Shift", "Super": "Super", "Ctrl": "Ctrl", - "Toggle Bold": "Félkövér váltása", - "Toggle Italics": "Dőlt váltása", - "Toggle Quote": "Idézet váltása", + "Toggle Bold": "Félkövér be/ki", + "Toggle Italics": "Dőlt be/ki", + "Toggle Quote": "Idézet be/ki", "New line": "Új sor", "Navigate recent messages to edit": "Friss üzenetekben navigálás a szerkesztéshez", "Jump to start/end of the composer": "Az üzenet elejére/végére ugrás a szerkesztőben", "Navigate composer history": "A szerkesztő korábbi üzeneteiben navigálás", - "Toggle microphone mute": "Mikrofon némítás váltása", - "Toggle video on/off": "Videó ki-/bekapcsolás váltása", + "Toggle microphone mute": "Mikrofon némítás be/ki", + "Toggle video on/off": "Videó be/ki", "Jump to room search": "A szoba keresésre ugrás", "Navigate up/down in the room list": "A szoba listában fel/le navigál", "Select room from the room list": "Szoba kiválasztása a szoba listából", @@ -2063,11 +2063,11 @@ "Scroll up/down in the timeline": "Az idővonalon görgetés fel/le", "Previous/next unread room or DM": "Előző/következő olvasatlan szoba vagy közvetlen üzenet", "Previous/next room or DM": "Előző/következő szoba vagy közvetlen üzenet", - "Toggle the top left menu": "Bal felső menü ki-/bekapcsolása", + "Toggle the top left menu": "Bal felső menü be/ki", "Close dialog or context menu": "Párbeszédablak vagy menü bezárása", "Activate selected button": "Kiválasztott gomb aktiválása", - "Toggle right panel": "Jobb oldali panel váltása", - "Toggle this dialog": "Ennek a párbeszédablaknak a váltása", + "Toggle right panel": "Jobb oldali panel be/ki", + "Toggle this dialog": "E párbeszédablak be/ki", "Move autocomplete selection up/down": "Automatikus kiegészítés kijelölésének mozgatása fel/le", "Cancel autocomplete": "Automatikus kiegészítés megszakítása", "Page Up": "Page Up", @@ -2343,5 +2343,66 @@ "Set up Secure backup": "Biztonsági mentés beállítása", "Set a Security Phrase": "Biztonsági Jelmondat beállítása", "Confirm Security Phrase": "Biztonsági Jelmondat megerősítése", - "Save your Security Key": "Ments el a Biztonsági Kulcsodat" + "Save your Security Key": "Ments el a Biztonsági Kulcsodat", + "Use your account to sign in to the latest version": "A legutolsó verzióba való bejelentkezéshez használd a fiókodat", + "We’re excited to announce Riot is now Element": "Izgatottan jelentjük, hogy a Riot mostantól Element", + "Riot is now Element!": "Riot mostantól Element!", + "Learn More": "Tudj meg többet", + "Enable experimental, compact IRC style layout": "Egyszerű (kísérleti) IRC stílusú kinézet engedélyezése", + "Unknown caller": "Ismeretlen hívó", + "Incoming voice call": "Bejövő hanghívás", + "Incoming video call": "Bejövő videó hívás", + "Incoming call": "Bejövő hívás", + "There are advanced notifications which are not shown here.": "Vannak haladó értesítési beállítások amik itt nem jelennek meg.", + "Appearance Settings only affect this %(brand)s session.": "A megjelenítési beállítások csak erre az %(brand)s munkamenetre lesznek érvényesek.", + "Make this room low priority": "Ez a szoba legyen alacsony prioritású", + "Use default": "Alapértelmezett használata", + "Mentions & Keywords": "Megemlítések és kulcsszavak", + "Notification options": "Értesítési beállítások", + "Favourited": "Kedvencek", + "Forget Room": "Szoba elfelejtése", + "Use your account to sign in to the latest version of the app at ": "Az alkalmazás legutolsó verzióba való bejelentkezéshez itt használd a fiókodat", + "Go to Element": "Irány az Element", + "We’re excited to announce Riot is now Element!": "Izgatottan jelentjük, hogy a Riot mostantól Element!", + "Learn more at element.io/previously-riot": "Tudj meg többet: element.io/previously-riot", + "Search rooms": "Szobák keresése", + "User menu": "Felhasználói menü", + "%(brand)s Web": "%(brand)s Web", + "%(brand)s Desktop": "Asztali %(brand)s", + "%(brand)s iOS": "%(brand)s iOS", + "%(brand)s X for Android": "%(brand)s X Android", + "This room is public": "Ez egy nyilvános szoba", + "Away": "Távol", + "Are you sure you want to cancel entering passphrase?": "Biztos vagy benne, hogy megszakítod a jelmondat bevitelét?", + "Enable advanced debugging for the room list": "Kibővített hibakeresés bekapcsolása a szoba listához", + "%(brand)s can't securely cache encrypted messages locally while running in a web browser. Use %(brand)s Desktop for encrypted messages to appear in search results.": "%(brand)s nem képes a web böngészőben futva biztonságosan elmenteni a titkosított üzeneteket helyben. Használd az Asztali %(brand)s ahhoz, hogy az üzenetekben való keresésekkor a titkosított üzenetek is megjelenhessenek.", + "You might have configured them in a client other than %(brand)s. You cannot tune them in %(brand)s but they still apply.": "Valószínűleg egy %(brand)s klienstől eltérő programmal konfiguráltad. %(brand)s kliensben nem tudod módosítani de attól még érvényesek.", + "Set the name of a font installed on your system & %(brand)s will attempt to use it.": "Add meg a rendszer által használt font nevét és %(brand)s megpróbálja majd azt használni.", + "Add users and servers you want to ignore here. Use asterisks to have %(brand)s match any characters. For example, @bot:* would ignore all users that have the name 'bot' on any server.": "A figyelmen kívül hagyandó felhasználókat és szervereket itt add meg. %(brand)s kliensben használj csillagot hogy a helyén minden karakterre illeszkedjen a kifejezés. Például: @bot:* figyelmen kívül fog hagyni minden „bot” nevű felhasználót bármely szerverről.", + "Low priority rooms show up at the bottom of your room list in a dedicated section at the bottom of your room list": "Az alacsony prioritású szobák egy külön helyen a szobalista alján fognak megjelenni", + "Custom Tag": "Egyedi címke", + "Show rooms with unread messages first": "Olvasatlan üzeneteket tartalmazó szobák megjelenítése elől", + "Show previews of messages": "Üzenet előnézet megjelenítése", + "Edited at %(date)s": "Szerkesztve ekkor: %(date)s", + "Click to view edits": "A szerkesztések megtekintéséhez kattints", + "You’re already signed in and good to go here, but you can also grab the latest versions of the app on all platforms at element.io/get-started.": "Már be vagy jelentkezve és ez rendben van, de minden platformon az alkalmazás legfrissebb verziójának beszerzéséhez látogass el ide: element.io/get-started.", + "You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use %(brand)s with an existing Matrix account on a different homeserver.": "Használhatod a más szerver opciót, hogy egy másik matrix szerverre jelentkezz be amihez megadod a szerver url címét. Ezzel használhatod %(brand)s klienst egy már létező Matrix fiókkal egy másik matrix szerveren.", + "Enter the location of your Element Matrix Services homeserver. It may use your own domain name or be a subdomain of element.io.": "Add meg az Element Matrix Services matrix szerveredet. Használhatod a saját domain-edet vagy az element.io al-domain-jét.", + "* %(senderName)s %(emote)s": "* %(senderName)s %(emote)s", + "The person who invited you already left the room.": "Aki meghívott a szobába már távozott.", + "The person who invited you already left the room, or their server is offline.": "Aki meghívott a szobába már távozott, vagy a szervere elérhetetlen.", + "Change notification settings": "Értesítési beállítások megváltoztatása", + "Your server isn't responding to some requests.": "A szervered nem válaszol néhány kérésre.", + "You're all caught up.": "Mindent elolvastál.", + "Server isn't responding": "A szerver nem válaszol", + "Your server isn't responding to some of your requests. Below are some of the most likely reasons.": "A szervered néhány kérésre nem válaszol. Alább felsorolunk pár lehetséges okot.", + "The server (%(serverName)s) took too long to respond.": "A szervernek (%(serverName)s) túl hosszú időbe telt válaszolni.", + "Your firewall or anti-virus is blocking the request.": "A tűzfalad vagy víruskeresőd blokkolja a kérést.", + "A browser extension is preventing the request.": "Egy böngésző kiterjesztés megakadályozza a kérést.", + "The server is offline.": "A szerver nem működik.", + "The server has denied your request.": "A szerver elutasította a kérést.", + "Your area is experiencing difficulties connecting to the internet.": "Probléma az Internet elérésben.", + "A connection error occurred while trying to contact the server.": "Kapcsolati hiba lépett fel miközben a szervert próbáltad elérni.", + "The server is not configured to indicate what the problem is (CORS).": "A szerver nincs beállítva, hogy megmutassa mi okozhatta a hibát (CORS).", + "Recent changes that have not yet been received": "Legutóbbi változások amik még nem érkeztek meg" } diff --git a/src/i18n/strings/is.json b/src/i18n/strings/is.json index 43b286aa2a..6f561331f6 100644 --- a/src/i18n/strings/is.json +++ b/src/i18n/strings/is.json @@ -298,7 +298,7 @@ "Low Priority": "Lítill forgangur", "Direct Chat": "Beint spjall", "View Community": "Skoða samfélag", - "I understand the risks and wish to continue": "Ég skil áhættuna og vil halda áfram", + "I understand the risks and wish to continue": "Ég skil áhættuna og óska að halda áfram", "Name": "Nafn", "Failed to upload image": "Gat ekki sent inn mynd", "Add rooms to this community": "Bæta spjallrásum í þetta samfélag", @@ -456,5 +456,7 @@ "Notify the whole room": "Tilkynna öllum á spjallrásinni", "Room Notification": "Tilkynning á spjallrás", "Passphrases must match": "Lykilfrasar verða að stemma", - "Passphrase must not be empty": "Lykilfrasi má ekki vera auður" + "Passphrase must not be empty": "Lykilfrasi má ekki vera auður", + "Create Account": "Stofna Reikning", + "Please install Chrome, Firefox, or Safari for the best experience.": "vinsamlegast setja upp Chrome, Firefox, eða Safari fyrir besta reynsluna." } diff --git a/src/i18n/strings/it.json b/src/i18n/strings/it.json index 4d6fff078d..3ed851fd95 100644 --- a/src/i18n/strings/it.json +++ b/src/i18n/strings/it.json @@ -193,8 +193,8 @@ "Room Colour": "Colore della stanza", "Active call (%(roomName)s)": "Chiamata attiva (%(roomName)s)", "unknown caller": "Chiamante sconosciuto", - "Incoming voice call from %(name)s": "Chiamata vocale in arrivo da %(name)s", - "Incoming video call from %(name)s": "Chiamata video in arrivo da %(name)s", + "Incoming voice call from %(name)s": "Telefonata in arrivo da %(name)s", + "Incoming video call from %(name)s": "Videochiamata in arrivo da %(name)s", "Incoming call from %(name)s": "Chiamata in arrivo da %(name)s", "Decline": "Rifiuta", "Accept": "Accetta", @@ -254,8 +254,8 @@ "%(userName)s (power %(powerLevelNumber)s)": "%(userName)s (poteri %(powerLevelNumber)s)", "Attachment": "Allegato", "Hangup": "Riaggancia", - "Voice call": "Chiamata vocale", - "Video call": "Chiamata video", + "Voice call": "Telefonata", + "Video call": "Videochiamata", "Upload file": "Invia file", "Send an encrypted reply…": "Invia una risposta criptata…", "Send an encrypted message…": "Invia un messaggio criptato…", @@ -532,7 +532,7 @@ "Failed to leave room": "Uscita dalla stanza fallita", "Signed Out": "Disconnesso", "For security, this session has been signed out. Please sign in again.": "Per sicurezza questa sessione è stata disconnessa. Accedi di nuovo.", - "Old cryptography data detected": "Rilevati dati di cifratura obsoleti", + "Old cryptography data detected": "Rilevati dati di crittografia obsoleti", "Data from an older version of %(brand)s has been detected. This will have caused end-to-end cryptography to malfunction in the older version. End-to-end encrypted messages exchanged recently whilst using the older version may not be decryptable in this version. This may also cause messages exchanged with this version to fail. If you experience problems, log out and back in again. To retain message history, export and re-import your keys.": "Sono stati rilevati dati da una vecchia versione di %(brand)s. Ciò avrà causato malfunzionamenti della crittografia end-to-end nella vecchia versione. I messaggi cifrati end-to-end scambiati di recente usando la vecchia versione potrebbero essere indecifrabili in questa versione. Anche i messaggi scambiati con questa versione possono fallire. Se riscontri problemi, disconnettiti e riaccedi. Per conservare la cronologia, esporta e re-importa le tue chiavi.", "Logout": "Disconnetti", "Your Communities": "Le tue comunità", @@ -639,7 +639,7 @@ "Confirm passphrase": "Conferma password", "Export": "Esporta", "Import room keys": "Importa chiavi della stanza", - "This process allows you to import encryption keys that you had previously exported from another Matrix client. You will then be able to decrypt any messages that the other client could decrypt.": "Questa procedura ti permette di importare le chiavi di cifratura precedentemente esportate da un altro client Matrix. Potrai poi decifrare tutti i messaggi che quel client poteva decifrare.", + "This process allows you to import encryption keys that you had previously exported from another Matrix client. You will then be able to decrypt any messages that the other client could decrypt.": "Questa procedura ti permette di importare le chiavi di crittografia precedentemente esportate da un altro client Matrix. Potrai poi decifrare tutti i messaggi che quel client poteva decifrare.", "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.": "Il file esportato sarà protetto da una password. Dovresti inserire la password qui, per decifrarlo.", "File to import": "File da importare", "Import": "Importa", @@ -783,7 +783,7 @@ "e.g. ": "es. ", "Your device resolution": "La risoluzione del dispositivo", "Missing roomId.": "ID stanza mancante.", - "Always show encryption icons": "Mostra sempre icone di cifratura", + "Always show encryption icons": "Mostra sempre icone di crittografia", "Enable widget screenshots on supported widgets": "Attiva le schermate dei widget sui widget supportati", "Unable to load event that was replied to, it either does not exist or you do not have permission to view it.": "Impossibile caricare l'evento a cui si è risposto, o non esiste o non hai il permesso di visualizzarlo.", "Refresh": "Aggiorna", @@ -914,7 +914,7 @@ "Please review and accept all of the homeserver's policies": "Si prega di rivedere e accettare tutte le politiche dell'homeserver", "To avoid losing your chat history, you must export your room keys before logging out. You will need to go back to the newer version of %(brand)s to do this": "Per evitare di perdere la cronologia della chat, devi esportare le tue chiavi della stanza prima di uscire. Dovrai tornare alla versione più recente di %(brand)s per farlo", "Incompatible Database": "Database non compatibile", - "Continue With Encryption Disabled": "Continua con la cifratura disattivata", + "Continue With Encryption Disabled": "Continua con la crittografia disattivata", "Unable to load backup status": "Impossibile caricare lo stato del backup", "Unable to restore backup": "Impossibile ripristinare il backup", "No backup found!": "Nessun backup trovato!", @@ -1082,7 +1082,7 @@ "We've sent you an email to verify your address. Please follow the instructions there and then click the button below.": "Ti abbiamo inviato un'email per verificare il tuo indirizzo. Segui le istruzioni contenute e poi clicca il pulsante sotto.", "Email Address": "Indirizzo email", "Are you sure? You will lose your encrypted messages if your keys are not backed up properly.": "Sei sicuro? Perderai i tuoi messaggi cifrati se non hai salvato adeguatamente le tue chiavi.", - "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "I messaggi criptati sono resi sicuri con una cifratura end-to-end. Solo tu e il/i destinatario/i avete le chiavi per leggere questi messaggi.", + "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "I messaggi cifrati sono resi sicuri con una crittografia end-to-end. Solo tu e il/i destinatario/i avete le chiavi per leggere questi messaggi.", "Restore from Backup": "Ripristina da un backup", "Back up your keys before signing out to avoid losing them.": "Fai una copia delle tue chiavi prima di disconnetterti per evitare di perderle.", "Backing up %(sessionsRemaining)s keys...": "Copia di %(sessionsRemaining)s chiavi...", @@ -1148,11 +1148,11 @@ "Send %(eventType)s events": "Invia eventi %(eventType)s", "Roles & Permissions": "Ruoli e permessi", "Select the roles required to change various parts of the room": "Seleziona i ruoli necessari per cambiare varie parti della stanza", - "Enable encryption?": "Attivare la cifratura?", - "Once enabled, encryption for a room cannot be disabled. Messages sent in an encrypted room cannot be seen by the server, only by the participants of the room. Enabling encryption may prevent many bots and bridges from working correctly. Learn more about encryption.": "Una volta attivata, la cifratura di una stanza non può essere disattivata. I messaggi inviati in una stanza cifrata non possono essere letti dal server, solo dai partecipanti della stanza. L'attivazione della cifratura può impedire il corretto funzionamento di bot e bridge. Maggiori informazioni sulla cifratura.", + "Enable encryption?": "Attivare la crittografia?", + "Once enabled, encryption for a room cannot be disabled. Messages sent in an encrypted room cannot be seen by the server, only by the participants of the room. Enabling encryption may prevent many bots and bridges from working correctly. Learn more about encryption.": "Una volta attivata, la crittografia di una stanza non può essere disattivata. I messaggi inviati in una stanza cifrata non possono essere letti dal server, solo dai partecipanti della stanza. L'attivazione della crittografia può impedire il corretto funzionamento di bot e bridge. Maggiori informazioni sulla crittografia.", "Changes to who can read history will only apply to future messages in this room. The visibility of existing history will be unchanged.": "Le modifiche a chi può leggere la cronologia si applicheranno solo ai messaggi futuri in questa stanza. La visibilità della cronologia esistente rimarrà invariata.", - "Encryption": "Cifratura", - "Once enabled, encryption cannot be disabled.": "Una volta attivata, la cifratura non può essere disattivata.", + "Encryption": "Crittografia", + "Once enabled, encryption cannot be disabled.": "Una volta attivata, la crittografia non può essere disattivata.", "Encrypted": "Cifrato", "Never lose encrypted messages": "Non perdere mai i messaggi cifrati", "Messages in this room are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "I messaggi in questa stanza sono protetti con crittografia end-to-end. Solo tu e i destinatari avete le chiavi per leggere questi messaggi.", @@ -1306,7 +1306,7 @@ "Notes": "Note", "If there is additional context that would help in analysing the issue, such as what you were doing at the time, room IDs, user IDs, etc., please include those things here.": "Se ci sono ulteriori dettagli che possono aiutare ad analizzare il problema, ad esempio cosa stavi facendo in quel momento, ID stanze, ID utenti, ecc., puoi includerli qui.", "View Servers in Room": "Vedi i server nella stanza", - "Sign out and remove encryption keys?": "Disconnettere e rimuovere le chiavi di cifratura?", + "Sign out and remove encryption keys?": "Disconnettere e rimuovere le chiavi di crittografia?", "To help us prevent this in future, please send us logs.": "Per aiutarci a prevenire questa cosa in futuro, inviaci i log.", "Missing session data": "Dati di sessione mancanti", "Some session data, including encrypted message keys, is missing. Sign out and sign in to fix this, restoring keys from backup.": "Alcuni dati di sessione, incluse le chiavi dei messaggi cifrati, sono mancanti. Esci e riaccedi per risolvere, ripristinando le chiavi da un backup.", @@ -1457,7 +1457,7 @@ "Use an identity server to invite by email. Click continue to use the default identity server (%(defaultIdentityServerName)s) or manage in Settings.": "Usa un server di identità per invitare via email. Clicca \"Continua\" per usare quello predefinito (%(defaultIdentityServerName)s) o gestiscilo nelle impostazioni.", "Use an identity server to invite by email. Manage in Settings.": "Usa un server di identità per invitare via email. Gestisci nelle impostazioni.", "Upgrade the room": "Aggiorna la stanza", - "Enable room encryption": "Attiva la cifratura della stanza", + "Enable room encryption": "Attiva la crittografia della stanza", "Deactivate user?": "Disattivare l'utente?", "Deactivating this user will log them out and prevent them from logging back in. Additionally, they will leave all the rooms they are in. This action cannot be reversed. Are you sure you want to deactivate this user?": "Disattivare questo utente lo disconnetterà e ne impedirà nuovi accessi. In aggiunta, abbandonerà tutte le stanze in cui è presente. Questa azione non può essere annullata. Sei sicuro di volere disattivare questo utente?", "Deactivate user": "Disattiva utente", @@ -1554,7 +1554,7 @@ "contact the administrators of identity server ": "contattare l'amministratore del server di identità ", "wait and try again later": "attendere e riprovare più tardi", "Failed to deactivate user": "Disattivazione utente fallita", - "This client does not support end-to-end encryption.": "Questo client non supporta la cifratura end-to-end.", + "This client does not support end-to-end encryption.": "Questo client non supporta la crittografia end-to-end.", "Messages in this room are not end-to-end encrypted.": "I messaggi in questa stanza non sono cifrati end-to-end.", "React": "Reagisci", "Frequently Used": "Usati di frequente", @@ -1649,7 +1649,7 @@ "Use an Integration Manager to manage bots, widgets, and sticker packs.": "Usa un gestore di integrazioni per gestire bot, widget e pacchetti di adesivi.", "Integration Managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "I gestori di integrazione ricevono dati di configurazione e possono modificare widget, inviare inviti alla stanza, assegnare permessi a tuo nome.", "Failed to connect to integration manager": "Connessione al gestore di integrazioni fallita", - "Widgets do not use message encryption.": "I widget non usano la cifratura dei messaggi.", + "Widgets do not use message encryption.": "I widget non usano la crittografia dei messaggi.", "More options": "Altre opzioni", "Integrations are disabled": "Le integrazioni sono disattivate", "Enable 'Manage Integrations' in Settings to do this.": "Attiva 'Gestisci integrazioni' nelle impostazioni per continuare.", @@ -1665,10 +1665,10 @@ "Ignored/Blocked": "Ignorati/Bloccati", "Verification Request": "Richiesta verifica", "Match system theme": "Usa il tema di sistema", - "%(senderName)s placed a voice call.": "%(senderName)s ha effettuato una chiamata vocale.", - "%(senderName)s placed a voice call. (not supported by this browser)": "%(senderName)s ha effettuato una chiamata vocale. (non supportata da questo browser)", - "%(senderName)s placed a video call.": "%(senderName)s ha effettuato una videochiamata.", - "%(senderName)s placed a video call. (not supported by this browser)": "%(senderName)s ha effettuato una videochiamata. (non supportata da questo browser)", + "%(senderName)s placed a voice call.": "%(senderName)s ha iniziato una telefonata.", + "%(senderName)s placed a voice call. (not supported by this browser)": "%(senderName)s ha iniziato una telefonata. (non supportata da questo browser)", + "%(senderName)s placed a video call.": "%(senderName)s ha iniziato una videochiamata.", + "%(senderName)s placed a video call. (not supported by this browser)": "%(senderName)s ha iniziato una videochiamata. (non supportata da questo browser)", "Clear notifications": "Cancella le notifiche", "Customise your experience with experimental labs features. Learn more.": "Personalizza la tua esperienza con funzionalità sperimentali. Maggiori informazioni.", "Error upgrading room": "Errore di aggiornamento stanza", @@ -1787,10 +1787,10 @@ "Send as message": "Invia come messaggio", "Enter your account password to confirm the upgrade:": "Inserisci la password del tuo account per confermare l'aggiornamento:", "You'll need to authenticate with the server to confirm the upgrade.": "Dovrai autenticarti con il server per confermare l'aggiornamento.", - "Upgrade your encryption": "Aggiorna la tua cifratura", - "Set up encryption": "Imposta la cifratura", + "Upgrade your encryption": "Aggiorna la tua crittografia", + "Set up encryption": "Imposta la crittografia", "Verify this session": "Verifica questa sessione", - "Encryption upgrade available": "Aggiornamento cifratura disponibile", + "Encryption upgrade available": "Aggiornamento crittografia disponibile", "Enable message search in encrypted rooms": "Attiva la ricerca messaggi nelle stanze cifrate", "Waiting for %(displayName)s to verify…": "In attesa della verifica da %(displayName)s …", "They match": "Corrispondono", @@ -1816,7 +1816,7 @@ "Never send encrypted messages to unverified sessions from this session": "Non inviare mai messaggi cifrati a sessioni non verificate da questa sessione", "Never send encrypted messages to unverified sessions in this room from this session": "Non inviare mai messaggi cifrati a sessioni non verificate in questa stanza da questa sessione", "To be secure, do this in person or use a trusted way to communicate.": "Per sicurezza, fatelo di persona o usate un metodo fidato per comunicare.", - "Changing password will currently reset any end-to-end encryption keys on all sessions, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "Il cambio della password reimposterà qualsiasi chiave di cifratura end-to-end in tutte le sessioni, rendendo illeggibile la cronologia di chat, a meno che prima non esporti le chiavi della stanza e le reimporti dopo. In futuro questa cosa verrà migliorata.", + "Changing password will currently reset any end-to-end encryption keys on all sessions, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "Il cambio della password reimposterà qualsiasi chiave di crittografia end-to-end in tutte le sessioni, rendendo illeggibile la cronologia di chat, a meno che prima non esporti le chiavi della stanza e le reimporti dopo. In futuro questa cosa verrà migliorata.", "Your account has a cross-signing identity in secret storage, but it is not yet trusted by this session.": "Il tuo account ha un'identità a firma incrociata nell'archivio segreto, ma non è ancora fidata da questa sessione.", "in memory": "in memoria", "Your homeserver does not support session management.": "Il tuo homeserver non supporta la gestione della sessione.", @@ -1859,7 +1859,7 @@ "Your key share request has been sent - please check your other sessions for key share requests.": "La tua richiesta di condivisione chiavi è stata inviata - controlla le tue altre sessioni per le richieste.", "Key share requests are sent to your other sessions automatically. If you rejected or dismissed the key share request on your other sessions, click here to request the keys for this session again.": "Le richieste di condivisione chiavi vengono inviate alle tue altre sessioni automaticamente. Se sulle altre sessioni l'hai rifiutata o annullata, clicca qui per chiedere di nuovo le chiavi per questa sessione.", "If your other sessions do not have the key for this message you will not be able to decrypt them.": "Se le altre sessioni non hanno la chiave per questo messaggio non sarai in grado di decifrarlo.", - "Re-request encryption keys from your other sessions.": "Chiedi di nuovo le chiavi di cifratura dalle altre sessioni.", + "Re-request encryption keys from your other sessions.": "Chiedi di nuovo le chiavi di crittografia dalle altre sessioni.", "Encrypted by an unverified session": "Cifrato da una sessione non verificata", "Encrypted by a deleted session": "Cifrato da una sessione eliminata", "Waiting for %(displayName)s to accept…": "In attesa che %(displayName)s accetti…", @@ -1879,10 +1879,10 @@ "If you can't scan the code above, verify by comparing unique emoji.": "Se non riesci a scansionare il codice sopra, verifica confrontando emoji specifiche.", "You've successfully verified %(displayName)s!": "Hai verificato correttamente %(displayName)s!", "Got it": "Capito", - "Encryption enabled": "Cifratura attivata", + "Encryption enabled": "Crittografia attivata", "Messages in this room are end-to-end encrypted. Learn more & verify this user in their user profile.": "I messaggi in questa stanza sono cifrati end-to-end. Maggiori info e verifica di questo utente nel suo profilo.", - "Encryption not enabled": "Cifratura non attivata", - "The encryption used by this room isn't supported.": "La cifratura usata da questa stanza non è supportata.", + "Encryption not enabled": "Crittografia non attivata", + "The encryption used by this room isn't supported.": "La crittografia usata da questa stanza non è supportata.", "Clear all data in this session?": "Svuotare tutti i dati in questa sessione?", "Clearing all data from this session is permanent. Encrypted messages will be lost unless their keys have been backed up.": "Lo svuotamento dei dati di questa sessione è permanente. I messaggi cifrati andranno persi a meno non si abbia un backup delle loro chiavi.", "Verify session": "Verifica sessione", @@ -1903,11 +1903,11 @@ "Confirm your identity by entering your account password below.": "Conferma la tua identità inserendo la password dell'account sotto.", "Your new session is now verified. Other users will see it as trusted.": "La tua nuova sessione è ora verificata. Gli altri utenti la vedranno come fidata.", "Without completing security on this session, it won’t have access to encrypted messages.": "Senza completare la sicurezza di questa sessione, essa non avrà accesso ai messaggi cifrati.", - "Changing your password will reset any end-to-end encryption keys on all of your sessions, making encrypted chat history unreadable. Set up Key Backup or export your room keys from another session before resetting your password.": "La modifica della password reimposterà qualsiasi chiave di cifratura end-to-end su tutte le sessioni, rendendo illeggibile la cronologia delle chat cifrate. Configura il Backup Chiavi o esporta le tue chiavi della stanza da un'altra sessione prima di reimpostare la password.", + "Changing your password will reset any end-to-end encryption keys on all of your sessions, making encrypted chat history unreadable. Set up Key Backup or export your room keys from another session before resetting your password.": "La modifica della password reimposterà qualsiasi chiave di crittografia end-to-end su tutte le sessioni, rendendo illeggibile la cronologia delle chat cifrate. Configura il Backup Chiavi o esporta le tue chiavi della stanza da un'altra sessione prima di reimpostare la password.", "You have been logged out of all sessions and will no longer receive push notifications. To re-enable notifications, sign in again on each device.": "Sei stato disconnesso da tutte le sessioni e non riceverai più notifiche push. Per riattivare le notifiche, riaccedi su ogni dispositivo.", - "Regain access to your account and recover encryption keys stored in this session. Without them, you won’t be able to read all of your secure messages in any session.": "Riprendi l'accesso al tuo account e recupera le chiavi di cifratura memorizzate in questa sessione. Senza di esse, non sarai in grado di leggere tutti i tuoi messaggi sicuri in qualsiasi sessione.", - "Warning: Your personal data (including encryption keys) is still stored in this session. Clear it if you're finished using this session, or want to sign in to another account.": "Attenzione: i tuoi dati personali (incluse le chiavi di cifratura) sono ancora memorizzati in questa sessione. Cancellali se hai finito di usare questa sessione o se vuoi accedere ad un altro account.", - "Restore your key backup to upgrade your encryption": "Ripristina il tuo backup chiavi per aggiornare la cifratura", + "Regain access to your account and recover encryption keys stored in this session. Without them, you won’t be able to read all of your secure messages in any session.": "Riprendi l'accesso al tuo account e recupera le chiavi di crittografia memorizzate in questa sessione. Senza di esse, non sarai in grado di leggere tutti i tuoi messaggi sicuri in qualsiasi sessione.", + "Warning: Your personal data (including encryption keys) is still stored in this session. Clear it if you're finished using this session, or want to sign in to another account.": "Attenzione: i tuoi dati personali (incluse le chiavi di crittografia) sono ancora memorizzati in questa sessione. Cancellali se hai finito di usare questa sessione o se vuoi accedere ad un altro account.", + "Restore your key backup to upgrade your encryption": "Ripristina il tuo backup chiavi per aggiornare la crittografia", "Upgrade this session to allow it to verify other sessions, granting them access to encrypted messages and marking them as trusted for other users.": "Aggiorna questa sessione per consentirle di verificare altre sessioni, garantendo loro l'accesso ai messaggi cifrati e contrassegnandole come fidate per gli altri utenti.", "Keep a copy of it somewhere secure, like a password manager or even a safe.": "Conservane una copia in un luogo sicuro, come un gestore di password o una cassaforte.", "Your recovery key": "La tua chiave di recupero", @@ -2117,7 +2117,7 @@ "Click the button below to confirm deleting these sessions.|one": "Clicca il pulsante sottostante per confermare l'eliminazione di questa sessione.", "Delete sessions|other": "Elimina sessioni", "Delete sessions|one": "Elimina sessione", - "Enable end-to-end encryption": "Attiva cifratura end-to-end", + "Enable end-to-end encryption": "Attiva crittografia end-to-end", "You can’t disable this later. Bridges & most bots won’t work yet.": "Non potrai più disattivarla. I bridge e molti bot non funzioneranno.", "Confirm your account deactivation by using Single Sign On to prove your identity.": "Conferma la disattivazione del tuo account usando Single Sign On per dare prova della tua identità.", "Are you sure you want to deactivate your account? This is irreversible.": "Sei sicuro di volere disattivare il tuo account? È irreversibile.", @@ -2185,8 +2185,8 @@ "To continue, use Single Sign On to prove your identity.": "Per continuare, usa Single Sign On per provare la tua identità.", "Confirm to continue": "Conferma per continuare", "Click the button below to confirm your identity.": "Clicca il pulsante sotto per confermare la tua identità.", - "Confirm encryption setup": "Conferma impostazione cifratura", - "Click the button below to confirm setting up encryption.": "Clicca il pulsante sotto per confermare l'impostazione della cifratura.", + "Confirm encryption setup": "Conferma impostazione crittografia", + "Click the button below to confirm setting up encryption.": "Clicca il pulsante sotto per confermare l'impostazione della crittografia.", "QR Code": "Codice QR", "Dismiss read marker and jump to bottom": "Scarta il segno di lettura e salta alla fine", "Jump to oldest unread message": "Salta al messaggio non letto più vecchio", @@ -2216,7 +2216,7 @@ "This address is available to use": "Questo indirizzo è disponibile per l'uso", "This address is already in use": "Questo indirizzo è già in uso", "Set a room address to easily share your room with other people.": "Imposta un indirizzo della stanza per condividerla facilmente con le altre persone.", - "You've previously used a newer version of %(brand)s with this session. To use this version again with end to end encryption, you will need to sign out and back in again.": "Hai precedentemente usato una versione più recente di %(brand)s con questa sessione. Per usare ancora questa versione con la cifratura end to end, dovrai disconnetterti e riaccedere.", + "You've previously used a newer version of %(brand)s with this session. To use this version again with end to end encryption, you will need to sign out and back in again.": "Hai precedentemente usato una versione più recente di %(brand)s con questa sessione. Per usare ancora questa versione con la crittografia end to end, dovrai disconnetterti e riaccedere.", "Address (optional)": "Indirizzo (facoltativo)", "Delete the room address %(alias)s and remove %(name)s from the directory?": "Eliminare l'indirizzo della stanza %(alias)s e rimuovere %(name)s dalla cartella?", "delete the address.": "elimina l'indirizzo.", @@ -2328,5 +2328,68 @@ "New spinner design": "Nuovo design dello spinner", "Use a more compact ‘Modern’ layout": "Usa un layout più compatto e moderno", "Always show first": "Mostra sempre per prime", - "Message deleted on %(date)s": "Messaggio eliminato il %(date)s" + "Message deleted on %(date)s": "Messaggio eliminato il %(date)s", + "Use your account to sign in to the latest version": "Usa il tuo account per accedere alla versione più recente", + "We’re excited to announce Riot is now Element": "Siamo entusiasti di annunciare che Riot ora si chiama Element", + "Riot is now Element!": "Riot ora si chiama Element!", + "Learn More": "Maggiori info", + "Enable experimental, compact IRC style layout": "Attiva il layout in stile IRC, sperimentale e compatto", + "Unknown caller": "Chiamante sconosciuto", + "Incoming voice call": "Telefonata in arrivo", + "Incoming video call": "Videochiamata in arrivo", + "Incoming call": "Chiamata in arrivo", + "%(brand)s can't securely cache encrypted messages locally while running in a web browser. Use %(brand)s Desktop for encrypted messages to appear in search results.": "%(brand)s non può tenere in cache i messaggi cifrati quando usato in un browser web. Usa %(brand)s Desktop affinché i messaggi cifrati appaiano nei risultati di ricerca.", + "There are advanced notifications which are not shown here.": "Ci sono notifiche avanzate che non vengono mostrate qui.", + "You might have configured them in a client other than %(brand)s. You cannot tune them in %(brand)s but they still apply.": "Potresti averle configurate in un client diverso da %(brand)s. Non puoi regolarle in %(brand)s ma sono comunque applicate.", + "Set the name of a font installed on your system & %(brand)s will attempt to use it.": "Imposta il nome di un font installato nel tuo sistema e %(brand)s proverà ad usarlo.", + "Make this room low priority": "Rendi questa stanza a bassa priorità", + "Low priority rooms show up at the bottom of your room list in a dedicated section at the bottom of your room list": "Le stanze a bassa priorità vengono mostrate in fondo all'elenco stanze in una sezione dedicata", + "Use default": "Usa predefinito", + "Mentions & Keywords": "Citazioni e parole chiave", + "Notification options": "Opzioni di notifica", + "Favourited": "Preferito", + "Forget Room": "Dimentica stanza", + "Use your account to sign in to the latest version of the app at ": "Usa il tuo account per accedere alla versione più recente dell'app in ", + "You’re already signed in and good to go here, but you can also grab the latest versions of the app on all platforms at element.io/get-started.": "Hai già fatto l'accesso e sei pronto ad iniziare, ma puoi anche ottenere le versioni più recenti dell'app su tutte le piattaforme in element.io/get-started.", + "Go to Element": "Vai su Element", + "We’re excited to announce Riot is now Element!": "Siamo entusiasti di annunciare che Riot ora si chiama Element!", + "Learn more at element.io/previously-riot": "Maggiori informazioni su element.io/previously-riot", + "Wrong file type": "Tipo di file errato", + "Wrong Recovery Key": "Chiave di ripristino errata", + "Invalid Recovery Key": "Chiave di ripristino non valida", + "Security Phrase": "Frase di sicurezza", + "Enter your Security Phrase or to continue.": "Inserisci una frase di sicurezza o per continuare.", + "Security Key": "Chiave di sicurezza", + "Use your Security Key to continue.": "Usa la tua chiave di sicurezza per continuare.", + "You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use %(brand)s with an existing Matrix account on a different homeserver.": "Puoi usare le opzioni di server personalizzato per accedere ad altri server Matrix, specificando un URL diverso di homeserver. Ciò ti consente di usare %(brand)s con un account Matrix esistente su un homeserver diverso.", + "Enter the location of your Element Matrix Services homeserver. It may use your own domain name or be a subdomain of element.io.": "Inserisci la posizione del tuo homeserver di Element Matrix Services. Potrebbe usare il tuo nome di dominio o essere un sottodominio di element.io.", + "Search rooms": "Cerca stanze", + "User menu": "Menu utente", + "%(brand)s Web": "%(brand)s Web", + "%(brand)s Desktop": "%(brand)s Desktop", + "%(brand)s iOS": "%(brand)s iOS", + "%(brand)s X for Android": "%(brand)s X per Android", + "Safeguard against losing access to encrypted messages & data by backing up encryption keys on your server.": "Proteggiti contro la perdita dell'accesso ai messaggi e dati cifrati facendo un backup delle chiavi crittografiche sul tuo server.", + "Generate a Security Key": "Genera una chiave di sicurezza", + "We’ll generate a Security Key for you to store somewhere safe, like a password manager or a safe.": "Genereremo per te una chiave di sicurezza da conservare in un posto sicuro, come un gestore di password o una cassaforte.", + "Enter a Security Phrase": "Inserisci una frase di sicurezza", + "Use a secret phrase only you know, and optionally save a Security Key to use for backup.": "Usa una frase segreta che conosci solo tu e salva facoltativamente una chiave di sicurezza da usare come backup.", + "Enter a security phrase only you know, as it’s used to safeguard your data. To be secure, you shouldn’t re-use your account password.": "Inserisci una frase di sicurezza che conosci solo tu, dato che è usata per proteggere i tuoi dati. Per sicurezza, non dovresti riutilizzare la password dell'account.", + "Store your Security Key somewhere safe, like a password manager or a safe, as it’s used to safeguard your encrypted data.": "Conserva la chiave di sicurezza in un posto sicuro, come un gestore di password o una cassaforte, dato che è usata per proteggere i tuoi dati cifrati.", + "If you cancel now, you may lose encrypted messages & data if you lose access to your logins.": "Se annulli ora, potresti perdere i messaggi e dati cifrati in caso tu perda l'accesso ai tuoi login.", + "You can also set up Secure Backup & manage your keys in Settings.": "Puoi anche impostare il Backup Sicuro e gestire le tue chiavi nelle impostazioni.", + "Set up Secure backup": "Imposta il Backup Sicuro", + "Set a Security Phrase": "Imposta una frase di sicurezza", + "Confirm Security Phrase": "Conferma frase di sicurezza", + "Save your Security Key": "Salva la tua chiave di sicurezza", + "This room is public": "Questa stanza è pubblica", + "Away": "Assente", + "Enable advanced debugging for the room list": "Attiva il debug avanzato per l'elenco di stanze", + "Show rooms with unread messages first": "Mostra prima le stanze con messaggi non letti", + "Show previews of messages": "Mostra anteprime dei messaggi", + "Edited at %(date)s": "Modificato il %(date)s", + "Click to view edits": "Clicca per vedere le modifiche", + "Are you sure you want to cancel entering passphrase?": "Sei sicuro di volere annullare l'inserimento della frase?", + "* %(senderName)s %(emote)s": "* %(senderName)s %(emote)s", + "Custom Tag": "Etichetta personalizzata" } diff --git a/src/i18n/strings/ja.json b/src/i18n/strings/ja.json index 3c786fcfd2..ee3871fc0f 100644 --- a/src/i18n/strings/ja.json +++ b/src/i18n/strings/ja.json @@ -106,7 +106,7 @@ "Download this file": "この添付ファイルをダウンロード", "Call invitation": "通話への招待", "Forget": "忘れる", - "Messages containing keywords": "keywordsを含むメッセージ", + "Messages containing keywords": "キーワード を含むメッセージ", "Error saving email notification preferences": "電子メール通知設定の保存エラー", "Tuesday": "火曜日", "Enter keywords separated by a comma:": "キーワードをコンマで区切って入力:", @@ -198,7 +198,7 @@ "Unable to capture screen": "画面をキャプチャできません", "Existing Call": "既存の通話", "You are already in a call.": "すでに通話中です。", - "VoIP is unsupported": "VoIPはサポートされていません", + "VoIP is unsupported": "VoIPは対応していません", "You cannot place VoIP calls in this browser.": "このブラウザにはVoIP通話はできません。", "You cannot place a call with yourself.": "自分自身に電話をかけることはできません。", "Call in Progress": "発信中", @@ -712,7 +712,7 @@ "Name": "名前", "You must register to use this functionality": "この機能を使用するには登録する必要があります", "You must join the room to see its files": "そのファイルを見るために部屋に参加する必要があります", - "There are no visible files in this room": "この部屋には目に見えるファイルはありません", + "There are no visible files in this room": "この部屋に表示可能なファイルは存在しません", "

    HTML for your community's page

    \n

    \n Use the long description to introduce new members to the community, or distribute\n some important links\n

    \n

    \n You can even use 'img' tags\n

    \n": "

    コミュニティのページのHTML

    \n

    \n 詳細な説明を使用して、新しいメンバーをコミュニティに紹介する、または配布する\n 重要なリンク\n

    \n

    \n あなたは 'img'タグを使うことさえできます\n

    \n", "Add rooms to the community summary": "コミュニティサマリーに部屋を追加する", "Which rooms would you like to add to this summary?": "このサマリーにどの部屋を追加したいですか?", @@ -754,8 +754,8 @@ "Failed to load %(groupId)s": "%(groupId)s をロードできませんでした", "Failed to reject invitation": "招待を拒否できませんでした", "This room is not public. You will not be able to rejoin without an invite.": "この部屋は公開されていません。 あなたは招待なしで再び参加することはできません。", - "Are you sure you want to leave the room '%(roomName)s'?": "本当にその部屋 '%(roomName)s' を離れますか?", - "Failed to leave room": "部屋を離れることができなかった", + "Are you sure you want to leave the room '%(roomName)s'?": "本当にこの部屋「%(roomName)s」から退出してよろしいですか?", + "Failed to leave room": "部屋からの退出に失敗しました", "Can't leave Server Notices room": "サーバー通知部屋を離れることはできません", "This room is used for important messages from the Homeserver, so you cannot leave it.": "この部屋はホームサーバーからの重要なメッセージに使用されるため、そこを離れることはできません。", "Signed Out": "サインアウト", @@ -772,7 +772,7 @@ "Error whilst fetching joined communities": "参加したコミュニティを取得中にエラーが発生しました", "Create a new community": "新しいコミュニティを作成する", "Create a community to group together users and rooms! Build a custom homepage to mark out your space in the Matrix universe.": "ユーザーと部屋をグループ化するコミュニティを作成してください! Matrixユニバースにあなたの空間を目立たせるためにカスタムホームページを作成してください。", - "You have no visible notifications": "表示される通知はありません", + "You have no visible notifications": "通知はありません", "You can't send any messages until you review and agree to our terms and conditions.": "利用規約 を確認して同意するまでは、いかなるメッセージも送信できません。", "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. Please contact your service administrator to continue using the service.": "このホームサーバーが月間アクティブユーザー制限を超えたため、メッセージは送信されませんでした。 サービスを引き続き使用するには、サービス管理者にお問い合わせください。", "Your message wasn't sent because this homeserver has exceeded a resource limit. Please contact your service administrator to continue using the service.": "このホームサーバーがリソース制限を超えたため、メッセージは送信されませんでした。 サービスを引き続き使用するには、サービス管理者にお問い合わせください。", @@ -906,7 +906,7 @@ "Call failed due to misconfigured server": "サーバの誤設定により呼び出し失敗", "Try using turn.matrix.org": "turn.matrix.orgで試してみる", "Replying With Files": "ファイルを添付して返信", - "The file '%(fileName)s' failed to upload.": "ファイル '%(fileName)s' のアップロードに失敗しました。", + "The file '%(fileName)s' failed to upload.": "ファイル '%(fileName)s' のアップロードに失敗しました.", "The file '%(fileName)s' exceeds this homeserver's size limit for uploads": "ファイル '%(fileName)s' はこのホームサーバのアップロードのサイズ上限を超えています", "The server does not support the room version specified.": "このサーバは指定された部屋バージョンに対応していません。", "Name or Matrix ID": "名前またはMatrix ID", @@ -1116,7 +1116,7 @@ "This room is end-to-end encrypted": "この部屋はエンドツーエンド暗号化されています", "Encrypted by an unverified session": "未検証のセッションによる暗号化", "Close preview": "プレビューを閉じる", - "Direct Messages": "ダイレクトメッセージ", + "Direct Messages": "対話", "Loading …": "読み込み中 …", "Direct message": "ダイレクトメッセージ", "Your display name": "あなたの表示名", @@ -1324,5 +1324,51 @@ "Confirm your identity by verifying this login from one of your other sessions, granting it access to encrypted messages.": "このログインを他のセッションで承認し、あなたの認証情報を確認すれば、暗号化されたメッセージへアクセスできるようになります。", "This requires the latest %(brand)s on your other devices:": "最新版の %(brand)s が他のあなたのデバイスで実行されている必要があります:", "or another cross-signing capable Matrix client": "もしくはクロス署名に対応した他の Matrix クライアント", - "Without completing security on this session, it won’t have access to encrypted messages.": "このセッションでのセキュリティを完了させない限り、暗号化されたメッセージにはアクセスできません。" + "Without completing security on this session, it won’t have access to encrypted messages.": "このセッションでのセキュリティを完了させない限り、暗号化されたメッセージにはアクセスできません。", + "Single Sign On": "シングルサインオン", + "Light": "ライト", + "Dark": "ダーク", + "Font size": "フォントサイズ", + "Use custom size": "独自のサイズを使用", + "Use a more compact ‘Modern’ layout": "よりコンパクトで現代的なレイアウトを使用", + "Use a system font": "システムフォントを使用", + "System font name": "システムフォントの名前", + "Enable experimental, compact IRC style layout": "コンパクトな IRC スタイルレイアウトを使用 (実験的機能)", + "Messages containing my username": "自身のユーザー名を含むメッセージ", + "Messages containing @room": "@room を含むメッセージ", + "When rooms are upgraded": "部屋がアップグレードされた時", + "Hey you. You're the best!": "こんにちは、よろしくね!", + "Customise your appearance": "外観のカスタマイズ", + "Appearance Settings only affect this %(brand)s session.": "外観の設定はこの %(brand)s セッションにのみ適用されます。", + "People": "連絡先", + "Notification options": "通知設定", + "Verify User": "ユーザーの検証", + "Your homeserver": "あなたのホームサーバー", + "%(displayName)s cancelled verification.": "%(displayName)s が検証をキャンセルしました。", + "You cancelled verification.": "あなたが検証をキャンセルしました。", + "Verification cancelled": "検証のキャンセル", + "Notification settings": "通知設定", + "Switch to light mode": "ライトテーマに切り替え", + "Switch to dark mode": "ダークテーマに切り替え", + "Switch theme": "テーマを切り替え", + "Security & privacy": "セキュリティとプライバシー", + "All settings": "全ての設定", + "Feedback": "フィードバック", + "User menu": "ユーザーメニュー", + "Connecting to integration manager...": "インテグレーションマネージャに接続中...", + "Cannot connect to integration manager": "インテグレーションマネージャに接続できません", + "Leave Room": "部屋を退出", + "Failed to connect to integration manager": "インテグレーションマネージャへの接続に失敗しました", + "Start verification again from their profile.": "プロフィールから再度検証を開始してください。", + "Integration Manager": "インテグレーションマネージャ", + "Do not use an identity server": "ID サーバーを使用しない", + "Composer": "入力欄", + "Sort by": "並び替え", + "List options": "一覧の設定", + "Use Single Sign On to continue": "シングルサインオンを使用して続行", + "Accept to continue:": " に同意して続行:", + "Always show the window menu bar": "常にウィンドウメニューバーを表示する", + "Create room": "部屋を作成", + "Show %(count)s more|other": "さらに %(count)s 件を表示", + "Show %(count)s more|one": "さらに %(count)s 件を表示" } diff --git a/src/i18n/strings/jbo.json b/src/i18n/strings/jbo.json index 1b5f6b4853..9ac42af1de 100644 --- a/src/i18n/strings/jbo.json +++ b/src/i18n/strings/jbo.json @@ -1,158 +1,158 @@ { - "This email address is already in use": ".i ca'o pilno le ve samymri", - "This phone number is already in use": ".i ca'o pilno le fonjudri", - "Failed to verify email address: make sure you clicked the link in the email": ".i na pu facki lo du'u xu kau do ponse le skami te mrilu .i ko birti lo du'u do pu skami cuxna le urli pe le se samymri", - "The platform you're on": "le ciste poi do pilno", - "Your language of choice": "le se cuxna be fi lo'i bangu", - "Which officially provided instance you are using, if any": "le klesi poi ca'irselzau se sabji poi do pilno", - "Whether or not you're using the Richtext mode of the Rich Text Editor": "lo du'u xu kau do pilno la .markdaun. lo nu ciski", - "Your homeserver's URL": "le urli be le do samtcise'u", - "e.g. %(exampleValue)s": "mu'a zoi gy. %(exampleValue)s .gy.", - "Every page you use in the app": "ro lo pagbu poi do pilno pe le samtci", - "e.g. ": "mu'a zoi urli. .urli", - "Your device resolution": "le ni vidnysle", - "Analytics": "lo se lanli datni", - "Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": ".i pu lo nu benji fi lo samtcise'u cu vimcu lo datni poi termi'u no'u mu'a lo termi'u be lo kumfa pe'a .o nai lo pilno .o nai lo girzu", - "Call Failed": ".i pu fliba lo nu fonjo'e", - "You are already in a call.": ".i do ca'o pu zvati lo nu fonjo'e", - "VoIP is unsupported": ".i na kakne tu'a la .voip.", - "You cannot place VoIP calls in this browser.": ".i le kibyca'o na kakne tu'a la .voip.", - "You cannot place a call with yourself.": ".i lo nu do fonjo'e do na cumki", - "Call in Progress": ".i ca'o nu fonjo'e", - "A call is currently being placed!": ".i pu'o nu fonjo'e", - "A call is already in progress!": ".i ca'o drata nu fonjo'e", - "Permission Required": ".i do notci lo nu curmi", - "You do not have permission to start a conference call in this room": ".i na curmi lo nu do co'a nunjmaji fonjo'e ne'i le kumfa pe'a", - "Upload Failed": ".i pu fliba lo nu kibdu'a", - "Failure to create room": ".i fliba lo nu zbasu lo kumfa pe'a", - "Call Timeout": ".i mutce temci lo nu co'a fonjo'e", - "The remote side failed to pick up": ".i lo se fonjo'e na pu spuda", - "Unable to capture screen": ".i na kakne lo nu benji lo vidvi be lo vidni", - "Existing Call": ".i ca'o pu fonjo'e", - "Server may be unavailable, overloaded, or you hit a bug.": ".i la'a cu'i lo samtcise'u cu spofu gi'a mutce gunka .i ja samcfi", - "Send": "benji", - "Sun": "nondei", - "Mon": "pavdei", - "Tue": "reldei", - "Wed": "cibdei", - "Thu": "vondei", - "Fri": "mumdei", - "Sat": "xavdei", - "Jan": "pa", - "Feb": "re", - "Mar": "ci", - "Apr": "vo", - "May": "mu", - "Jun": "xa", - "Jul": "ze", - "Aug": "bi", - "Sep": "so", - "Oct": "pa no", - "Nov": "pa pa", - "Dec": "pa re", - "PM": "su'i pa re", - "AM": "su'i no", - "%(weekDayName)s %(time)s": "de'i lo %(weekDayName)s ti'u li %(time)s", - "%(weekDayName)s, %(monthName)s %(day)s %(time)s": "de'i li %(day)s pi'e %(monthName)s noi %(weekDayName)s ge'u ti'u li %(time)s", - "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": "de'i li %(day)s pi'e %(monthName)s pi'e %(fullYear)s noi %(weekDayName)s", - "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s": "de'i li %(day)s pi'e %(monthName)s pi'e %(fullYear)s noi %(weekDayName)s ge'u ti'u li %(time)s", - "Who would you like to add to this community?": ".i do djica lo nu jmina ma le girzu", - "Warning: any person you add to a community will be publicly visible to anyone who knows the community ID": ".i ju'i lo djuno be lo judri be lo girzu cu kakne lo nu viska lo liste be ro lo prenu poi se jmina do gy.", - "Invite new community members": "vi'ecpe lo prenu poi cnino le girzu", - "Invite to Community": "vi'ecpe fi le girzu", - "Which rooms would you like to add to this community?": ".i do djica lo nu jmina ma poi kumfa pe'a po'u le girzu", - "Show these rooms to non-members on the community page and room list?": ".i .au pei le kumfa cu gubni zvati le girzu pagbu .e le liste be lo'i kumfa pe'a", - "Add rooms to the community": "jmina lo kumfa pe'a le girzu", - "Add to community": "jmina fi le girzu", - "Failed to invite the following users to %(groupId)s:": "lo pilno poi fliba lo nu vi'ecpe ke'a la'o ny. %(groupId)s .ny.", - "Failed to invite users to community": ".i pu fliba lo nu vi'ecpe lo pilno le girzu", - "Failed to invite users to %(groupId)s": ".i pu fliba lo nu vi'ecpe lo pilno la'o ny. %(groupId)s .ny.", - "Failed to add the following rooms to %(groupId)s:": "lo kumfa pe'a poi fliba lo nu jmina ke'a la'o ny. %(groupId)s .ny.", - "Unnamed Room": "lo kumfa pe'a noi no da cmene", + "This email address is already in use": ".i xa'o pilno fa da le samymri judri", + "This phone number is already in use": ".i xa'o pilno fa da le fonxa judri", + "Failed to verify email address: make sure you clicked the link in the email": ".i da nabmi fi lo nu facki le du'u do ponse le te samymri .i ko birti le du'u do samcu'a le judrysni pe le se samymri", + "The platform you're on": "jicmu vau je se pilno do", + "Your language of choice": "se cuxna fo le ka bangu", + "Which officially provided instance you are using, if any": "samtcise'u vau je catni jai te selfu vau je se pilno do", + "Whether or not you're using the Richtext mode of the Rich Text Editor": "jei do pilno le se jadni ciska tadji pe le notci ciska tutci", + "Your homeserver's URL": "judri le samtcise'u", + "e.g. %(exampleValue)s": ".i zoi zoi. %(exampleValue)s .zoi mupli", + "Every page you use in the app": "liste lu'i ro pagbu be le samtci be'o poi se pilno do", + "e.g. ": ".i zoi zoi. .zoi mupli", + "Your device resolution": "vidnysle relca'u le vidni", + "Analytics": "lanli datni", + "Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": ".i zilbe'i le samtcise'u fa le te zilvi'u be le datni bei lu'o ro datni be le du'u mu'a pa ve zilbe'i ja pa pilno ja pa girzu ja pa drata cu jai steci do", + "Call Failed": ".i da nabmi fi lo nu co'a fonjo'e", + "You are already in a call.": ".i do xa'o ca'o fonjo'e da", + "VoIP is unsupported": ".i na ka'e pilno la .voip.", + "You cannot place VoIP calls in this browser.": ".i le kibrbrauzero na ka'e pilno la .voip. lo nu fonjo'e", + "You cannot place a call with yourself.": ".i do na ka'e fonjo'e do", + "Call in Progress": ".i ca'o fonjo'e", + "A call is currently being placed!": ".i ca'o co'a fonjo'e", + "A call is already in progress!": ".i xa'o ca'o fonjo'e da", + "Permission Required": ".i lo nu curmi cu sarcu", + "You do not have permission to start a conference call in this room": ".i na curmi lo nu le du'u co'a girzu fonjo'e cu zilbe'i do fo le ca se cuxna", + "Upload Failed": ".i da nabmi fi lo nu kibdu'a", + "Failure to create room": ".i da nabmi fi lo nu cupra le ve zilbe'i", + "Call Timeout": ".i dukse le ka ca'o ce'u co'a fonjo'e", + "The remote side failed to pick up": ".i da poi do co'a fonjo'e ke'a na spuda", + "Unable to capture screen": ".i na ka'e facki le du'u vidvi fi le vidni", + "Existing Call": ".i xa'o ca'o fonjo'e", + "Server may be unavailable, overloaded, or you hit a bug.": ".i la'a cu'i gi ja le samtcise'u cu spofu vau ja mutce le ka gunka gi da samcfi", + "Send": "nu zilbe'i", + "Sun": "jy. dy. ze", + "Mon": "jy. dy. pa", + "Tue": "jy. dy. re", + "Wed": "jy. dy. ci", + "Thu": "dy. jy. vo", + "Fri": "dy. jy. mu", + "Sat": "dy. jy. xa", + "Jan": "ly. pa", + "Feb": "ly. re", + "Mar": "ly. ci", + "Apr": "ly. vo", + "May": "ly. mu", + "Jun": "ly. xa", + "Jul": "ly. ze", + "Aug": "ly. bi", + "Sep": "ly. so", + "Oct": "ly. pa no", + "Nov": "ly. pa pa", + "Dec": "ly. pa re", + "PM": "ly. cy.", + "AM": "cy. cy.", + "%(weekDayName)s %(time)s": ".i li %(weekDayName)s %(time)s detri", + "%(weekDayName)s, %(monthName)s %(day)s %(time)s": ".i li %(monthName)s %(day)s %(weekDayName)s %(time)s detri", + "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": ".i li %(fullYear)s %(monthName)s %(day)s %(weekDayName)s detri", + "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s": ".i li %(fullYear)s %(monthName)s %(day)s %(weekDayName)s %(time)s detri", + "Who would you like to add to this community?": ".i do djica lo nu ma ziljmina le girzu", + "Warning: any person you add to a community will be publicly visible to anyone who knows the community ID": ".i ju'i zo'e ro djuno be le du'u judri le girzu cu ka'e zgana le du'u ro da poi pagbu le girzu zo'u da go'i", + "Invite new community members": "nu friti le ka ziljmina le girzu", + "Invite to Community": "nu friti le ka ziljmina le girzu", + "Which rooms would you like to add to this community?": ".i do djica lo nu ma poi ve zilbe'i cu ziljmina le girzu", + "Show these rooms to non-members on the community page and room list?": ".i xu do djica lo nu ro na cmima cu ka'e zgana le du'u le ve zilbe'i cu pagbu le girzu je le ve zilbe'i liste", + "Add rooms to the community": "nu jmina pa ve zilbe'i le girzu", + "Add to community": "nu ziljmina le girzu", + "Failed to invite the following users to %(groupId)s:": ".i da nabmi fi lo nu friti le ka ziljmina la'o zoi. %(groupId)s .zoi kei le di'e pilno", + "Failed to invite users to community": ".i da nabmi fi lo nu friti le ka ziljmina le girzu", + "Failed to invite users to %(groupId)s": ".i da nabmi fi lo nu friti le ka ziljmina la'o zoi. %(groupId)s .zoi", + "Failed to add the following rooms to %(groupId)s:": ".i da nabmi fi lo nu le di'e ve zilbe'i cu ziljmina la'o zoi. %(groupId)s .zoi", + "Unnamed Room": "na da cmene", "Unable to enable Notifications": ".i na kakne lo nu co'a kakne lo nu benji lo sajgau", - "This email address was not found": ".i na pu facki fi le ve samymri", - "Your email address does not appear to be associated with a Matrix ID on this Homeserver.": ".i za'a le ve samymri be fo do cu ckini no lo judri be fi la nacmeimei be'o pe le samtcise'u", - "Register": "cmeveigau", - "Default": "lo zmiselcu'a", - "Restricted": "li so'u", - "Moderator": "li so'i", - "Admin": "li ro", - "Power level must be positive integer.": ".i .ei lo ni vlipa cu kacna'u", + "This email address was not found": ".i na da zo'u facki le du'u samymri judri da", + "Your email address does not appear to be associated with a Matrix ID on this Homeserver.": ".i za'a le samymri judri na ckini pa judri be fi la .meitriks. be'o pe le samtcise'u", + "Register": "nu co'a na'o jaspu", + "Default": "zmiselcu'a", + "Restricted": "vlipa so'u da", + "Moderator": "vlipa so'o da", + "Admin": "vlipa so'i da", + "Power level must be positive integer.": ".i lo nu le ni vlipa cu kacna'u cu sarcu", "%(senderName)s changed the power level of %(powerLevelDiffText)s.": ".i la'o ly. %(senderName)s .ly. gafygau %(powerLevelDiffText)s", "Failed to change power level": ".i pu fliba lo nu gafygau lo ni vlipa", "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "lo ni la'o ny. %(userId)s .ny. vlipa noi pu du %(fromPowerLevel)s ku %(toPowerLevel)s", - "Operation failed": ".i pu fliba", - "Failed to invite": ".i pu fliba lo nu vi'ecpe", - "Failed to invite the following users to the %(roomName)s room:": "lo pilno poi fliba lo nu vi'ecpe ke'a la'o ly. %(roomName)s .ly. noi kumfa pe'a", - "You need to be logged in.": ".i .ei do cmisau", - "You need to be able to invite users to do that.": ".i lo nu do kakne lo nu vi'ecpe lo pilno cu sarcu ta", + "Operation failed": ".i da nabmi", + "Failed to invite": ".i da nabmi fi lo nu friti le ka ziljmina", + "Failed to invite the following users to the %(roomName)s room:": ".i da nabmi fi lo nu friti le ka ziljmina le se zilbe'i be fo la'o zoi. %(roomName)s .zoi kei le di'e pilno", + "You need to be logged in.": ".i lo nu da jaspu do sarcu", + "You need to be able to invite users to do that.": ".i lo nu do vlipa le ka friti le ka ziljmina cu sarcu", "Unable to create widget.": ".i na kakne lo nu zbasu lo uidje", "Missing roomId.": ".i claxu lo judri be lo kumfa pe'a", - "Failed to send request.": ".i pu fliba lo nu benji lo ve cpedu", + "Failed to send request.": ".i da nabmi fi lo nu benji le ve cpedu", "This room is not recognised.": ".i na sanji le kumfa pe'a", - "You are not in this room.": ".i do na zvati le kumfa pe'a", - "You do not have permission to do that in this room.": ".i ne'i le kumfa pe'a na curmi ta poi do troci", - "Missing room_id in request": ".i lo ve cpedu cu claxu lo judri be lo kumfa pe'a", + "You are not in this room.": ".i do na pagbu le se zilbe'i", + "You do not have permission to do that in this room.": ".i do na vlipa le ka zo'e zilbe'i do fo zo'e", + "Missing room_id in request": ".i na pa judri be pa ve zilbe'i cu pagbu le ve cpedu", "Room %(roomId)s not visible": ".i na kakne lo nu viska la'o ly. %(roomId)s .ly. noi kumfa pe'a", - "Missing user_id in request": ".i lo ve cpedu cu claxu lo judri be lo pilno", - "Usage": "lo tadji be lo nu pilno", + "Missing user_id in request": ".i na pa judri be pa pilno cu pagbu le ve cpedu", + "Usage": "tadji lo nu pilno", "Searches DuckDuckGo for results": ".i sisku se pi'o la datkysisku", "/ddg is not a command": "zoi ny. /ddg .ny. na nu minde", - "Changes your display nickname": ".i galfi le do cmene", + "Changes your display nickname": "", "Invites user with given id to current room": ".i vi'ecpe lo pilno poi se judri ti ku le kumfa pe'a", - "Leave room": "cliva le kumfa pe'a", + "Leave room": "nu do zilvi'u le se zilbe'i", "Kicks user with given id": ".i rinka lo nu lo pilno poi se judri ti cu cliva", "Bans user with given id": ".i rinka lo nu lo pilno poi se judri ti cu vitno cliva", "Ignores a user, hiding their messages from you": ".i rinka lo nu no'e jundi lo pilno gi'e mipri lo notci be fi py. do", - "Ignored user": ".i do no'e jundi le pilno", - "You are now ignoring %(userId)s": ".i do ca no'e jundi la'o ny. %(userId)s .ny.", + "Ignored user": ".i mo'u co'a na jundi tu'a le pilno", + "You are now ignoring %(userId)s": ".i ca na jundi tu'a la'o zoi. %(userId)s .zoi", "Stops ignoring a user, showing their messages going forward": ".i sisti lo nu no'e jundi lo pilno gi'e mipri lo notci be fi py. do", - "Unignored user": ".i do sisti lo nu no'e jundi le pilno", - "You are no longer ignoring %(userId)s": ".i do ca sisti lo nu no'e jundi la'o ny. %(userId)s .ny.", + "Unignored user": ".i mo'u co'a jundi tu'a le pilno", + "You are no longer ignoring %(userId)s": ".i ca jundi tu'a la'o zoi. %(userId)s .zoi", "Define the power level of a user": ".i ninga'igau lo ni lo pilno cu vlipa", "Deops user with given id": ".i xruti lo ni lo pilno poi se judri ti cu vlipa", "Opens the Developer Tools dialog": ".i samymo'i lo favgau se pilno uidje", - "Verified key": "lo termifckiku poi se lacri", + "Verified key": "ckiku vau je se lacri", "Displays action": ".i mrilu lo nu do gasnu", "Forces the current outbound group session in an encrypted room to be discarded": ".i macnu vimcu lo ca barkla termifckiku gunma lo kumfa pe'a poi mifra", - "Reason": "lo krinu", - "%(targetName)s accepted the invitation for %(displayName)s.": ".i la'o ly. %(targetName)s .ly. fitytu'i lo ve vi'ecpe be fi la'o ly. %(displayName)s .ly.", - "%(targetName)s accepted an invitation.": ".i la'o ly. %(targetName)s .ly. fitytu'i lo ve vi'ecpe", - "%(senderName)s requested a VoIP conference.": ".i la'o ly. %(senderName)s .ly. cpedu lo .voip. zei nunjmaji", - "%(senderName)s invited %(targetName)s.": ".i la'o ly. %(senderName)s .ly. vi'ecpe la'o ly. %(targetName)s .ly.", + "Reason": "krinu", + "%(targetName)s accepted the invitation for %(displayName)s.": "", + "%(targetName)s accepted an invitation.": ".i la'o zoi. %(targetName)s .zoi zukte pa se friti", + "%(senderName)s requested a VoIP conference.": "", + "%(senderName)s invited %(targetName)s.": ".i la'o zoi. %(senderName)s .zoi friti le ka ziljmina kei la'o zoi. %(targetName)s .zoi", "%(senderName)s banned %(targetName)s.": ".i la'o ly. %(senderName)s .ly. gasnu lo nu la'o ly. %(targetName)s .ly. vitno cliva", - "%(oldDisplayName)s changed their display name to %(displayName)s.": ".i la'o ly. %(oldDisplayName)s .ly. gafygau lo cmene be ri zoi ly. %(displayName)s .ly.", - "%(senderName)s set their display name to %(displayName)s.": ".i la'o ny. %(senderName)s .ny. jmina lo cmene be ri be'o no'u zoi ly. %(displayName)s .ly.", - "%(senderName)s removed their display name (%(oldDisplayName)s).": ".i la'o ny. %(senderName)s .ny. vimcu lo cmene be ri be'o no'u zoi ly. %(oldDisplayName)s .ly.", - "%(senderName)s removed their profile picture.": ".i la'o ly. %(senderName)s .ly. vimcu lo predatni pixra pe ri", - "%(senderName)s changed their profile picture.": ".i la'o ly. %(senderName)s .ly. gafygau lo predatni pixra pe ri", - "%(senderName)s set a profile picture.": ".i la'o ly. %(senderName)s .ly. jmina lo predatni pixra pe ri", + "%(oldDisplayName)s changed their display name to %(displayName)s.": ".i zoi zoi. %(displayName)s .zoi basti zoi zoi. %(oldDisplayName)s .zoi le ka cmene", + "%(senderName)s set their display name to %(displayName)s.": ".i zoi zoi. %(displayName)s .zoi co'a cmene la'o zoi. %(senderName)s .zoi", + "%(senderName)s removed their display name (%(oldDisplayName)s).": ".i zoi zoi. %(oldDisplayName)s .zoi co'u cmene la'o zoi. %(senderName)s .zoi", + "%(senderName)s removed their profile picture.": ".i da co'u pixra sinxa la'o zoi. %(senderName)s .zoi", + "%(senderName)s changed their profile picture.": ".i da basti de le ka pixra sinxa la'o zoi. %(senderName)s .zoi", + "%(senderName)s set a profile picture.": ".i da co'a pixra sinxa la'o zoi. %(senderName)s .zoi", "VoIP conference started.": ".i co'a .voip. zei nunjmaji", - "%(targetName)s joined the room.": ".i la'o ly. %(targetName)s .ly. binxo lo cmima be le kumfa pe'a", + "%(targetName)s joined the room.": ".i la'o zoi. %(targetName)s .zoi ziljmina le se zilbe'i", "VoIP conference finished.": ".i mo'u .voip. zei nunjmaji", - "%(targetName)s rejected the invitation.": ".i la'o ly. %(targetName)s .ly. fitytoltu'i lo ve vi'ecpe", - "%(targetName)s left the room.": ".i la'o ly. %(targetName)s .ly. cliva le kumfa pe'a", + "%(targetName)s rejected the invitation.": ".i la'o zoi. %(targetName)s .zoi zukte le ka na ckaji le se friti", + "%(targetName)s left the room.": ".i la'o zoi. %(targetName)s .zoi zilvi'u le se zilbe'i", "%(senderName)s unbanned %(targetName)s.": ".i la'o ly. %(senderName)s .ly. xruti fo lo nu la'o ly. %(targetName)s .ly. vitno cliva", - "%(senderName)s kicked %(targetName)s.": ".i la'o ly. %(senderName)s .ly. gasnu lo nu la'o ly. %(targetName)s .ly. cliva", - "%(senderName)s withdrew %(targetName)s's invitation.": ".i la'o ly. %(senderName)s .ly. lebna lo ve vi'ecpe be la'o ly. %(targetName)s .ly.", - "%(senderDisplayName)s changed the topic to \"%(topic)s\".": ".i la'o ly. %(senderDisplayName)s .ly. gafygau lo se casnu pe le kumfa pe'a zoi ly. %(topic)s .ly.", - "%(senderDisplayName)s removed the room name.": ".i la'o ly. %(senderDisplayName)s .ly. vimcu lo cmene be le kumfa pe'a", - "%(senderDisplayName)s changed the room name to %(roomName)s.": ".i la'o ly. %(senderDisplayName)s .ly. gafygau lo cmene be le kumfa zoi ly. %(roomName)s .ly.", - "%(senderDisplayName)s sent an image.": ".i la'o ly. %(senderDisplayName)s .ly. mrilu lo pixra", - "%(senderName)s set the main address for this room to %(address)s.": ".i la'o ly. %(senderName)s .ly. gafygau lo ralju cmene be le kumfa pe'a zoi ny. %(address)s .ny.", - "%(senderName)s removed the main address for this room.": ".i la'o ly. %(senderName)s .ly. vimcu lo ralju cmene be le kumfa pe'a", - "Someone": "da poi prenu", - "(not supported by this browser)": "to le do kibyca'o na kakne toi", - "%(senderName)s answered the call.": ".i la'o ly. %(senderName)s .ly. spuda lo nu fonjo'e", + "%(senderName)s kicked %(targetName)s.": ".i gau la'o zoi. %(senderName)s .zoi la'o zoi. %(targetName)s .zoi zilvi'u le se zilbe'i", + "%(senderName)s withdrew %(targetName)s's invitation.": ".i la'o zoi. %(senderName)s .zoi co'u friti le ka ziljmina kei la'o zoi. %(targetName)s .zoi", + "%(senderDisplayName)s changed the topic to \"%(topic)s\".": ".i gau la'o zoi. %(senderDisplayName)s .zoi zoi zoi. %(topic)s .zoi basti da le ka skicu lerpoi", + "%(senderDisplayName)s removed the room name.": ".i gau la'o zoi. %(senderDisplayName)s .zoi da co'u cmene le se zilbe'i", + "%(senderDisplayName)s changed the room name to %(roomName)s.": ".i gau la'o zoi. %(senderDisplayName)s .zoi zoi zoi. %(roomName)s .zoi basti da le ka cmene le se zilbe'i", + "%(senderDisplayName)s sent an image.": ".i pa pixra cu zilbe'i fi la'o zoi. %(senderDisplayName)s .zoi", + "%(senderName)s set the main address for this room to %(address)s.": ".i gau la'o zoi. %(senderName)s .zoi zoi zoi. %(address)s .zoi co'a ralju le'i judri be le ve zilbe'i", + "%(senderName)s removed the main address for this room.": ".i gau la'o zoi. %(senderName)s .zoi da co'u ralju le'i judri be le ve zilbe'i", + "Someone": "da", + "(not supported by this browser)": ".i le kibrbrauzero na kakne", + "%(senderName)s answered the call.": ".i mo'u co'a fonjo'e la'o zoi. %(senderName)s .zoi", "(could not connect media)": "to na kakne lo nu ganvi samjongau toi", - "(no answer)": "to na spuda toi", + "(no answer)": ".i na spuda", "(unknown failure: %(reason)s)": "to na'e te djuno nu fliba fi'o ve skicu zoi gy. %(reason)s .gy. toi", - "%(senderName)s ended the call.": ".i la'o ly. %(senderName)s .ly. sisti lo nu fonjo'e", - "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.": ".i la'o ly. %(senderName)s .ly. vi'ecpe la'o ly. %(targetDisplayName)s .ly. le kumfa pe'a", - "%(senderName)s made future room history visible to all room members, from the point they are invited.": ".i la'o ly. %(senderName)s .ly. gasnu lo nu ro lo cmima ka'e viska ro lo notci be ba lo mu'e cy. se vi'ecpe", - "%(senderName)s made future room history visible to all room members, from the point they joined.": ".i la'o ly. %(senderName)s .ly. gasnu lo nu ro lo cmima ka'e viska ro lo notci be ba lo mu'e cy. cmibi'o", - "%(senderName)s made future room history visible to all room members.": ".i la'o ly. %(senderName)s .ly. gasnu lo nu ro lo cmima ka'e viska ro lo ba notci", - "%(senderName)s made future room history visible to anyone.": ".i la'o ly. %(senderName)s .ly. gasnu lo nu ro lo prenu ka'e viska ro lo ba notci", + "%(senderName)s ended the call.": ".i gau la'o zoi. %(senderName)s .zoi co'u fonjo'e ri", + "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.": ".i la'o zoi. %(senderName)s .zoi friti le ka ziljmina le se zilbe'i kei la'o zoi. %(targetDisplayName)s .zoi", + "%(senderName)s made future room history visible to all room members, from the point they are invited.": ".i ro da poi pagbu le se zilbe'i zo'u gau la'o zoi. %(senderName)s .zoi da ka'e tcidu ro notci poi ba lo nu da te friti ba zilbe'i", + "%(senderName)s made future room history visible to all room members, from the point they joined.": ".i ro da poi pagbu le se zilbe'i zo'u gau la'o zoi. %(senderName)s .zoi da ka'e tcidu ro notci poi ba lo nu da ziljmina ba zilbe'i", + "%(senderName)s made future room history visible to all room members.": ".i gau la'o zoi. %(senderName)s .zoi ro pagbu be le se zilbe'i cu ka'e tcidu ro notci poi ba zilbe'i", + "%(senderName)s made future room history visible to anyone.": ".i gau la'o zoi. %(senderName)s .zoi ro da ka'e tcidu ro notci poi ba zilbe'i", "%(senderName)s made future room history visible to unknown (%(visibility)s).": ".i la'o ly. %(senderName)s .ly. gasnu lo nu zo'e ka'e viska lo notci to cuxna zoi ny. %(visibility)s .ny. toi", "%(senderName)s changed the pinned messages for the room.": ".i la'o ly. %(senderName)s .ly. gafygau lo vitno notci pe le kumfa pe'a", "%(widgetName)s widget modified by %(senderName)s": ".i la'o ly. %(senderName)s .ly. gafygau la'o ny. %(widgetName)s .ny. noi uidje", @@ -160,13 +160,13 @@ "%(widgetName)s widget removed by %(senderName)s": ".i la'o ly. %(senderName)s .ly. vimcu la'o ny. %(widgetName)s .ny. noi uidje", "This homeserver has hit its Monthly Active User limit.": ".i le samtcise'u cu bancu lo masti jimte be ri bei lo ni ca'o pilno", "This homeserver has exceeded one of its resource limits.": ".i le samtcise'u cu bancu pa lo jimte be ri", - "Please contact your service administrator to continue using the service.": ".i .e'o ko tavla lo do te selfu admine .i ja nai do djica lo nu ca'o pilno le te selfu", - "Unable to connect to Homeserver. Retrying...": ".i pu fliba lo nu samjo'e le samtcise'u .i za'u re'u ca'o troci", - "Your browser does not support the required cryptography extensions": ".i le do kibyca'o na kakne tu'a le te mifra ciste noi se nitcu", + "Please contact your service administrator to continue using the service.": ".i lo nu do tavla pa jitro be le samtcise'u cu sarcu lo nu za'o selfu do", + "Unable to connect to Homeserver. Retrying...": ".i da nabmi fi lo nu samjo'e le samtcise'u .i ca'o za'u re'u troci", + "Your browser does not support the required cryptography extensions": ".i le kibrbrauzero na ka'e pilno le mifra ciste poi jai sarcu", "Authentication check failed: incorrect password?": ".i pu fliba lo nu birti lo du'u curmi lo nu do jonse .i na'e drani xu japyvla", "Sorry, your homeserver is too old to participate in this room.": ".i .uu le do samtcise'u cu dukse lo ka laldo ku ja'e lo du'u sy. na kakne lo nu pagbu le kumfa pe'a", "Please contact your homeserver administrator.": ".i .e'o ko tavla lo admine be le samtcise'u", - "Failed to join room": ".i pu fliba lo nu cmibi'o le kumfa pe'a", + "Failed to join room": ".i da nabmi lo nu ziljmina le se zilbe'i", "Message Pinning": "lo du'u xu kau kakne lo nu mrilu lo vitno notci", "Show timestamps in 12 hour format (e.g. 2:30pm)": "lo du'u xu kau lo tcika cu se tarmi mu'a lu ti'u li re pi'e ci no su'i pa re li'u", "Always show message timestamps": "lo du'u xu kau do ro roi viska ka'e lo tcika be tu'a lo notci", @@ -179,43 +179,43 @@ "Enable inline URL previews by default": "lo zmiselcu'a pe lo du'u xu kau zmiku purzga lo se urli", "Enable URL previews for this room (only affects you)": "lo du'u xu kau do zmiku purzga lo se urli ne'i le kumfa pe'a", "Enable URL previews by default for participants in this room": "lo zmiselcu'a pe lo du'u xu kau lo cmima be le kumfa pe'a cu zmiku purzga lo se urli", - "Room Colour": "lo se skari be le kumfa pe'a", + "Room Colour": "se skari le ve zilbe'i", "Enable widget screenshots on supported widgets": "lo du'u xu kau kakne lo nu co'a pixra lo uidje kei lo nu kakne tu'a .ubu", - "Collecting app version information": ".i ca'o crepu lo datni be lo favytcinymupli", - "Collecting logs": ".i ca'o crepu lo vreji", - "Uploading report": ".i ca'o kibdu'a lo datnynoi", + "Collecting app version information": ".i ca'o facki le du'u favytcinymupli", + "Collecting logs": ".i ca'o facki le du'u citri", + "Uploading report": ".i ca'o kibdu'a le vreji", "Waiting for response from server": ".i ca'o denpa lo nu le samtcise'u cu spuda", - "Messages containing my display name": "lo notci poi vasru lo cmene be mi", - "Messages in one-to-one chats": "lo notci be fi pa lo prenu bei pa lo prenu", - "Messages in group chats": "lo notci pe lo girzu tavla", - "When I'm invited to a room": "lo nu vi'ecpe mi lo kumfa pe'a", - "Call invitation": "lo nu vi'ecpe mi lo nu fonjo'e", - "Messages sent by bot": "lo notci be fi lo sampre", + "Messages containing my display name": "nu pa se pagbu be le cmene be mi cu zilbe'i", + "Messages in one-to-one chats": "nu da zilbe'i pa prenu", + "Messages in group chats": "nu da zilbe'i lu'o pa prenu", + "When I'm invited to a room": "nu da friti le ka ziljmina lo se zilbe'i kei do", + "Call invitation": "nu da co'a fonjo'e do", + "Messages sent by bot": "nu da zilbe'i fi pa sampre", "Active call (%(roomName)s)": "le ca fonjo'e ne la'o ly. %(roomName)s .ly.", "unknown caller": "lo fonjo'e noi na'e te djuno", "Incoming voice call from %(name)s": ".i la'o ly. %(name)s .ly. ca'o snavi fonjo'e", "Incoming video call from %(name)s": ".i la'o ly. %(name)s .ly. ca'o vidvi fonjo'e", "Incoming call from %(name)s": ".i la'o ly. %(name)s .ly. ca'o fonjo'e", - "Decline": "fitytoltu'i", - "Accept": "fitytu'i", - "Error": "lo se srera", + "Decline": "nu na fonjo'e", + "Accept": "nu fonjo'e", + "Error": "nabmi", "Incorrect verification code": ".i na'e drani ke lacri lerpoi", - "Submit": "benji", - "Phone": "lo fonxa", + "Submit": "nu zilbe'i", + "Phone": "fonxa", "Add": "jmina", - "Failed to upload profile picture!": ".i pu fliba lo nu kibdu'a lo predatni pixra", - "No display name": ".i no da cmene", - "New passwords don't match": ".i le'i japyvla poi cnino na simxu lo nu mintu", + "Failed to upload profile picture!": ".i da nabmi lo nu kibdu'a le pixra sinxa", + "No display name": ".i na da cmene", + "New passwords don't match": ".i le'i lerpoijaspu poi cnino na simxu le ka du", "Passwords can't be empty": ".i lu li'u .e'a nai japyvla", "Warning!": ".i ju'i", "Export E2E room keys": "barbei lo kumfa pe'a termifckiku", "Continue": "", "Do you want to set an email address?": ".i .au pei do jmina lo te samymri", "Current password": "lo ca japyvla", - "Password": "lo japyvla", - "New Password": "lo japyvla poi cnino", + "Password": "lerpoijaspu", + "New Password": "lerpoijaspu vau je cnino", "Confirm password": "lo za'u re'u japyvla poi cnino", - "Change Password": "galfi lo japyvla", + "Change Password": "nu basti fi le ka lerpoijaspu", "Authentication": "lo nu facki lo du'u do du ma kau", "Last seen": "lo ro re'u nu viska", "Failed to set display name": ".i pu fliba lo nu galfi lo cmene", @@ -227,5 +227,358 @@ "Failed to change settings": ".i pu fliba lo nu galfi lo se cuxna", "Can't update user notification settings": ".i pu fliba lo nu galfi lo se cuxna pe lo nu sajgau", "Failed to update keywords": ".i pu fliba lo nu galfi lo midvla", - "Messages containing keywords": "lo notci poi vasru lo midvla" + "Messages containing keywords": "lo notci poi vasru lo midvla", + "Try using turn.matrix.org": ".i ko troci le ka pilno le se judri be zoi zoi. turn.matrix.org .zoi", + "Room name or address": "fe pa ve zilbe'i cu cmene vau ja judri", + "Custom (%(level)s)": "drata (%(level)s)", + "Failed to invite users to the room:": ".i la'e di'e nabmi fi lo nu friti le ka ziljmina le se zilbe'i kei le pilno", + "Messages": "notci", + "Actions": "ka'e se zukte", + "Advanced": "macnu", + "Other": "drata", + "Command error": ".i da nabmi fi lo nu minde", + "Failed to set topic": ".i da nabmi lo nu co'a skicu lerpoi", + "This room has no topic.": ".i na da skicu lerpoi le ve zilbe'i", + "Command failed": ".i da nabmi lo nu minde", + "Could not find user in room": ".i le pilno na pagbu le se zilbe'i", + "Session already verified!": ".i xa'o lacri le se samtcise'u", + "WARNING: Session already verified, but keys do NOT MATCH!": ".i ju'i zo'e xa'o lacri le se samtcise'u .i ku'i le'i ckiku ba'e na simxu le ka mapti", + "%(senderName)s made no change.": ".i la'o zoi. %(senderName)s .zoi na binxo da de", + "%(senderDisplayName)s changed the room name from %(oldRoomName)s to %(newRoomName)s.": ".i gau la'o zoi. %(senderDisplayName)s .zoi zoi zoi. %(newRoomName)s .zoi basti zoi zoi. %(oldRoomName)s .zoi le ka cmene le se zilbe'i", + "%(senderDisplayName)s made the room public to whoever knows the link.": ".i gau la'o zoi. %(senderDisplayName)s .zoi ro djuno be le du'u judri cu ka'e ziljmina le se zilbe'i", + "%(senderDisplayName)s made the room invite only.": ".i ro da zo'u gau la'o zoi. %(senderDisplayName)s .zoi lo nu de friti le ka ziljmina le se zilbe'i kei da sarcu", + "%(senderDisplayName)s has allowed guests to join the room.": ".i la'o zoi. %(senderDisplayName)s .zoi curmi lo nu ro na te friti cu ka'e ziljmina le se zilbe'i", + "%(senderDisplayName)s has prevented guests from joining the room.": ".i la'o zoi. %(senderDisplayName)s .zoi na curmi lo nu ro na te friti cu ka'e ziljmina le se zilbe'i", + "%(senderName)s added the alternative addresses %(addresses)s for this room.|other": ".i gau la'o zoi. %(senderName)s .zoi zoi zoi. %(addresses)s .zoi poi na ralju co'a judri le se zilbe'i", + "%(senderName)s added the alternative addresses %(addresses)s for this room.|one": ".i gau la'o zoi. %(senderName)s .zoi zoi zoi. %(addresses)s .zoi poi na ralju co'a judri le se zilbe'i", + "%(senderName)s removed the alternative addresses %(addresses)s for this room.|other": ".i gau la'o zoi. %(senderName)s .zoi zoi zoi. %(addresses)s .zoi poi na ralju co'u judri le se zilbe'i", + "%(senderName)s removed the alternative addresses %(addresses)s for this room.|one": ".i gau la'o zoi. %(senderName)s .zoi zoi zoi. %(addresses)s .zoi poi na ralju co'u judri le se zilbe'i", + "%(senderName)s changed the alternative addresses for this room.": ".i gau la'o zoi. %(senderName)s .zoi pa na ralju cu basti da le ka judri le se zilbe'i", + "%(senderName)s changed the main and alternative addresses for this room.": ".i gau la'o zoi. %(senderName)s .zoi pa ralju je pa na ralju cu basti da le ka judri le se zilbe'i", + "%(senderName)s changed the addresses for this room.": ".i gau la'o zoi. %(senderName)s .zoi da basti de le ka judri le se zilbe'i", + "%(senderName)s placed a voice call.": ".i la'o zoi. %(senderName)s .zoi co'a fonjo'e", + "%(senderName)s placed a voice call. (not supported by this browser)": ".i la'o zoi. %(senderName)s .zoi co'a fonjo'e .i le do kibrbrauzero na kakne", + "%(senderName)s placed a video call.": ".i la'o zoi. %(senderName)s .zoi co'a vidvi fonjo'e", + "%(senderName)s placed a video call. (not supported by this browser)": ".i la'o zoi. %(senderName)s .zoi co'a vidvi fonjo'e .i le do kibrbrauzero na kakne", + "%(senderName)s revoked the invitation for %(targetDisplayName)s to join the room.": ".i la'o zoi. %(senderName)s .zoi co'u friti le ka ziljmina le se zilbe'i kei la'o zoi. %(targetDisplayName)s .zoi", + "Light": "carmi", + "Dark": "manku", + "You signed in to a new session without verifying it:": ".i fe le di'e se samtcise'u pu co'a jaspu vau je za'o na lacri", + "They match": "du", + "They don't match": "na du", + "Dog": "gerku", + "Cat": "mlatu", + "Lion": "cinfo", + "Horse": "xirma", + "Unicorn": "pavyseljirna", + "Pig": "xarju", + "Elephant": "xanto", + "Rabbit": "ractu", + "Panda": "ribrmelanole'usa", + "Rooster": "jipci", + "Penguin": "zipcpi", + "Turtle": "cakyrespa", + "Fish": "finpe", + "Octopus": "dalroktopoda", + "Butterfly": "toldi", + "Flower": "xrula", + "Tree": "tricu", + "Cactus": "jesyspa", + "Mushroom": "mledi", + "Globe": "bolcartu", + "Moon": "lunra", + "Cloud": "dilnu", + "Fire": "fagri", + "Banana": "badna", + "Apple": "plise", + "Strawberry": "grutrananasa", + "Corn": "zumri", + "Pizza": "cidjrpitsa", + "Cake": "titnanba", + "Heart": "risna", + "Smiley": "cisma", + "Robot": "sampre", + "Hat": "mapku", + "Glasses": "vistci", + "Santa": "la santa", + "Umbrella": "santa", + "Hourglass": "canjunla", + "Clock": "junla", + "Light bulb": "te gusni", + "Book": "cukta", + "Pencil": "pinsi", + "Scissors": "jinci", + "Lock": "stela", + "Key": "ckiku", + "Hammer": "mruli", + "Telephone": "fonxa", + "Flag": "lanci", + "Train": "trene", + "Bicycle": "carvrama'e", + "Aeroplane": "vinji", + "Rocket": "jakne", + "Ball": "bolci", + "Guitar": "jgita", + "Trumpet": "tabra", + "Bell": "janbe", + "Headphones": "selsnapra", + "Pin": "pijne", + "Upload": "nu kibdu'a", + "Send an encrypted reply…": "nu pa mifra be pa jai te spuda cu zilbe'i", + "Send a reply…": "nu pa jai te spuda cu zilbe'i", + "Send an encrypted message…": "nu pa mifra be pa notci cu zilbe'i", + "Send a message…": "nu pa notci cu zilbe'i", + "Search": "nu sisku", + "People": "prenu", + "Rooms": "ve zilbe'i", + "Show %(count)s more|other": "nu viska %(count)s na du", + "Show %(count)s more|one": "nu viska %(count)s na du", + "Search…": "nu sisku", + "Sunday": "li jy. dy. ze detri", + "Monday": "li jy. dy. pa detri", + "Tuesday": "li jy. dy. re detri", + "Wednesday": "li jy. dy. ci detri", + "Thursday": "li jy. dy. vo detri", + "Friday": "li jy. dy. mu detri", + "Saturday": "li jy. dy. xa detri", + "Today": "cabdei", + "Yesterday": "prulamdei", + "Cancel search": "nu co'u sisku", + "Search rooms": "sisku fi le'i ve zilbe'i", + "Search failed": ".i da nabmi lo nu sisku", + "Switch to light mode": "nu le jvinu cu binxo le ka carmi", + "Switch to dark mode": "nu le jvinu cu binxo le ka manku", + "Switch theme": "nu basti fi le ka jvinu", + "Syncing...": ".i ca'o samymo'i", + "Signing In...": ".i ca'o co'a jaspu", + "If you've joined lots of rooms, this might take a while": ".i gi na ja do pagbu so'i se zilbe'i gi la'a ze'u gunka", + "Set a display name:": ".i ko cuxna fo le ka cmene", + "Upload an avatar:": ".i ko cuxna fo le ka pixra sinxa", + "Incorrect password": ".i le lerpoijaspu na drani", + "Emoji": "cinmo sinxa", + "Users": "pilno", + "That matches!": ".i du", + "Download": "nu kibycpa", + "Retry": "nu za'u re'u troci", + "Success!": ".i snada", + "Room List": "liste le'i ve zilbe'i", + "Upload a file": "nu kibdu'a pa vreji", + "Verify your other session using one of the options below.": ".i ko cuxna da le di'e gai'o le ka tadji lo nu do co'a lacri", + "Ask this user to verify their session, or manually verify it below.": ".i ko cpedu le ka co'a lacri le se samtcise'u kei le pilno vau ja pilno le di'e gai'o le ka co'a lacri", + "Not Trusted": "na se lacri", + "Manually Verify by Text": "nu pilno pa lerpoi lo nu co'a lacri", + "Interactively verify by Emoji": "nu pilno vu'i pa cinmo sinxa lo nu co'a lacri", + "Done": "nu mo'u co'e", + "%(displayName)s is typing …": ".i la'o zoi. %(displayName)s .zoi ca'o ciska", + "%(names)s and %(count)s others are typing …|other": ".i la'o zoi. %(names)s .zoi je %(count)s na du ca'o ciska", + "%(names)s and %(count)s others are typing …|one": ".i la'o zoi. %(names)s .zoi je pa na du ca'o ciska", + "%(names)s and %(lastPerson)s are typing …": ".i la'o zoi. %(names)s .zoi je la'o zoi. %(lastPerson)s .zoi ca'o ciska", + "Cannot reach homeserver": ".i ca ku na da ka'e zilbe'i le samtcise'u", + "Match system theme": "nu mapti le jvinu be le vanbi", + "Never send encrypted messages to unverified sessions in this room from this session": "nu na pa mifra be pa notci cu zilbe'i pa se samtcise'u poi na se lanli ku'o le se samtcise'u le gai'o", + "Order rooms by name": "nu porsi tu'a lo cmene", + "Messages containing my username": "nu pa se pagbu be le judri be mi cu zilbe'i", + "Messages containing @room": "nu pa se pagbu be zoi zoi. @room .zoi cu zilbe'i", + "Encrypted messages in one-to-one chats": "nu pa mifra cu zilbe'i pa prenu", + "Encrypted messages in group chats": "nu pa mifra cu zilbe'i lu'o pa prenu", + "Active call": ".i ca'o fonjo'e", + "Incoming voice call": ".i da co'a snavi fonjo'e do", + "Incoming video call": ".i da co'a vidvi fonjo'e do", + "Incoming call": ".i da co'a fonjo'e do", + "The other party cancelled the verification.": ".i le na du be do co'u troci le ka co'a lacri", + "Verified!": ".i mo'u co'a lacri", + "You've successfully verified this user.": ".i mo'u co'a lacri le pilno", + "Got It": "je'e", + "Start": "nu co'a co'e", + "Waiting for your other session, %(deviceName)s (%(deviceId)s), to verify…": ".i ca'o denpa lo nu le se samtcise'u poi na du vau je du la'o zoi. %(deviceName)s .zoi poi se judri zoi zoi. %(deviceId)s .zoi mo'u co'a lacri", + "Waiting for your other session to verify…": ".i ca'o denpa lo nu le se samtcise'u poi na du mo'u co'a lacri", + "Waiting for %(displayName)s to verify…": ".i ca'o denpa lo nu la'o zoi. %(displayName)s .zoi mo'u co'a lacri", + "Cancelling…": ".i ca'o co'u co'e", + "To be secure, do this in person or use a trusted way to communicate.": ".i lo nu marji penmi vau ja pilno pa se lacri lo nu tavla cu sarcu lo nu snura", + "Matrix ID": "judri fi la .meitriks.", + "Matrix Room ID": "judri pa ve zilbe'i la .meitriks.", + "email address": "samymri judri", + "User %(userId)s is already in the room": ".i la'o zoi. %(userId)s .zoi xa'o pagbu le se zilbe'i", + "User %(user_id)s does not exist": ".i zoi zoi. %(user_id)s .zoi na judri pa pilno", + "User %(user_id)s may or may not exist": ".i la'a cu'i zoi zoi. %(user_id)s .zoi na judri pa pilno", + "Help us improve %(brand)s": ".i ko sidju fi le ka xagzengau la'o zoi. %(brand)s .zoi", + "I want to help": ".i mi kaidji le ka sidju", + "No": ".i na co'e", + "Close": "nu zilmipri", + "Ok": "je'e", + "Verify this session": "nu co'a lacri le se samtcise'u", + "Verify": "nu co'a lacri", + "What's New": "notci le du'u cnino", + "A new version of %(brand)s is available!": ".i da favytcinymupli pa cnino la'o zoi. %(brand)s .zoi", + "You joined the call": ".i do mo'u co'a fonjo'e", + "%(senderName)s joined the call": ".i la'o zoi. %(senderName)s .zoi mo'u co'a fonjo'e", + "Call in progress": ".i ca'o fonjo'e", + "You left the call": ".i do co'u fonjo'e", + "%(senderName)s left the call": ".i la'o zoi. %(senderName)s .zoi co'u fonjo'e", + "Call ended": ".i co'u fonjo'e", + "You started a call": ".i do co'a fonjo'e", + "%(senderName)s started a call": ".i la'o zoi. %(senderName)s .zoi co'a fonjo'e", + "Waiting for answer": ".i ca'o denpa lo nu spuda", + "%(senderName)s is calling": ".i la'o zoi. %(senderName)s .zoi co'a fonjo'e", + "You created the room": ".i do cupra le ve zilbe'i", + "%(senderName)s created the room": ".i la'o zoi. %(senderName)s .zoi cupra le ve zilbe'i", + "You made the chat encrypted": ".i gau do ro ba zilbe'i be fo le gai'o cu mifra", + "%(senderName)s made the chat encrypted": ".i gau la'o zoi. %(senderName)s .zoi ro ba zilbe'i be fo le gai'o cu mifra", + "You were invited": ".i da friti le ka ziljmina kei do", + "%(targetName)s was invited": ".i da friti le ka ziljmina kei la'o zoi. %(targetName)s .zoi", + "You left": ".i do zilvi'u", + "%(targetName)s left": ".i la'o zoi. %(targetName)s .zoi zilvi'u", + "You were kicked (%(reason)s)": ".i gau da do zilvi'u fi'o krinu lerpoi zoi zoi. %(reason)s .zoi", + "%(targetName)s was kicked (%(reason)s)": ".i gau da la'o zoi. %(targetName)s .zoi zilvi'u fi'o krinu lerpoi zoi zoi. %(reason)s .zoi", + "You were kicked": ".i gau da do zilvi'u", + "%(targetName)s was kicked": ".i gau da la'o zoi. %(targetName)s .zoi zilvi'u", + "You rejected the invite": ".i do zukte le ka na ckaji le se friti", + "%(targetName)s rejected the invite": ".i la'o zoi. %(targetName)s .zoi zukte le ka na ckaji le se friti", + "You were uninvited": ".i da co'u friti le ka ziljmina kei do", + "%(targetName)s was uninvited": ".i da co'u friti le ka ziljmina kei la'o zoi. %(targetName)s .zoi", + "You changed your name": ".i gau do da basti de le ka cmene do", + "%(targetName)s changed their name": ".i gau da zoi zoi. %(targetName)s .zoi basti de le ka cmene da", + "You changed your avatar": ".i gau do da basti de le ka pixra sinxa do", + "%(targetName)s changed their avatar": ".i gau la'o zoi. %(targetName)s .zoi da basti de le ka pixra sinxa ri", + "%(senderName)s %(emote)s": ".i la'o zoi. %(senderName)s .zoi ckaji le smuni be zoi zoi. %(emote)s .zoi", + "%(senderName)s: %(message)s": "%(senderName)s: %(message)s", + "You changed the room name": ".i gau do da basti de le ka cmene le ve zilbe'i", + "%(senderName)s changed the room name": ".i gau la'o zoi. %(senderName)s .zoi da basti de le ka cmene le ve zilbe'i", + "%(senderName)s: %(reaction)s": "%(senderName)s: %(reaction)s", + "%(senderName)s: %(stickerName)s": "%(senderName)s: %(stickerName)s", + "You uninvited %(targetName)s": ".i do co'u friti le ka ziljmina kei la'o zoi. %(targetName)s .zoi", + "%(senderName)s uninvited %(targetName)s": ".i la'o zoi. %(senderName)s .zoi co'u friti le ka ziljmina kei la'o zoi. %(targetName)s .zoi", + "You invited %(targetName)s": ".i do friti le ka ziljmina kei la'o zoi. %(targetName)s .zoi", + "%(senderName)s invited %(targetName)s": ".i la'o zoi. %(senderName)s .zoi friti le ka ziljmina kei la'o zoi. %(targetName)s .zoi", + "You changed the room topic": ".i gau do da basti de le ka skicu be le ve zilbe'i be'o lerpoi", + "%(senderName)s changed the room topic": ".i gau la'o zoi. %(senderName)s .zoi da basti de le ka skicu be le ve zilbe'i be'o lerpoi", + "Use a system font": "nu da pe le vanbi cu ci'artai", + "System font name": "cmene le ci'artai pe le vanbi", + "Never send encrypted messages to unverified sessions from this session": "nu na pa mifra be pa notci cu zilbe'i pa se samtcise'u poi na se lanli ku'o le se samtcise'u", + "Sign In": "nu co'a jaspu", + "Later": "nu ca na co'e", + "Other users may not trust it": ".i la'a na pa na du be do cu lacri", + "Change": "nu basti", + "Change room avatar": "nu basti fi le ka pixra sinxa le ve zilbe'i", + "Change room name": "nu basti fi le ka cmene le ve zilbe'i", + "Change main address for the room": "nu basti fi le ka ralju lu'i ro judri be le ve zilbe'i", + "Change topic": "nu basti fi le ka skicu lerpoi", + "Sign Up": "nu co'a na'o jaspu", + " wants to chat": ".i la'o zoi. .zoi kaidji le ka tavla do", + " invited you": ".i la'o zoi. .zoi friti le ka ziljmina kei do", + "Username": "judri cmene", + "Enter username": ".i ko cuxna fo le ka judri cmene", + "We’re excited to announce Riot is now Element": ".i fizbu lo nu zo .elyment. basti zo .raiyt. le ka cmene", + "Riot is now Element!": ".i zo .elyment. basti zo .raiyt. le ka cmene", + "Learn More": "nu facki", + "We’re excited to announce Riot is now Element!": ".i fizbu lo nu gubni xusra le du'u zo .elyment. basti zo .raiyt. le ka cmene", + "Messages in this room are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": ".i ro zilbe'i be fo le gai'o cu mifra .i le ka ka'e tcidu lo notci cu steci fi lu'i do je ro pagbu be le se zilbe'i", + "Messages in this room are end-to-end encrypted.": ".i ro zilbe'i be fo le gai'o cu mifra", + "Messages in this room are not end-to-end encrypted.": ".i na pa zilbe'i be fo le gai'o cu mifra", + "Members": "pagbu le se zilbe'i", + "Files": "vreji", + "Trusted": "se lacri", + "Not trusted": "na se lacri", + "%(count)s verified sessions|other": ".i lacri %(count)s se samtcise'u", + "%(count)s verified sessions|one": ".i lacri pa se samtcise'u", + "Hide verified sessions": "nu ro se samtcise'u poi se lacri cu zilmipri", + "%(count)s sessions|other": ".i samtcise'u %(count)s da", + "%(count)s sessions|one": ".i samtcise'u %(count)s da", + "Hide sessions": "nu ro se samtcise'u cu zilmipri", + "Invite": "nu friti le ka ziljmina", + "Logout": "nu co'u jaspu", + "For help with using %(brand)s, click here or start a chat with our bot using the button below.": ".i gi je lo nu samcu'a le dei gai'o gi lo nu co'a tavla le sampre cu tadji lo nu facki le du'u tadji lo nu pilno la'o zoi. %(brand)s .zoi", + "This room is end-to-end encrypted": ".i ro zilbe'i be fo le gai'o cu mifra", + "Everyone in this room is verified": ".i do lacri ro pagbu be le se zilbe'i", + "Start chat": "nu co'a tavla", + "Create room": "nu cupra pa ve zilbe'i", + "The file '%(fileName)s' failed to upload.": ".i da nabmi fi lo nu kibdu'a la'o zoi. %(fileName)s .zoi", + "Invite users": "nu friti le ka ziljmina kei pa pilno", + "Invite to this room": "nu friti le ka ziljmina le se zilbe'i", + "Voice call": "nu snavi fonjo'e", + "Video call": "nu vidvi fonjo'e", + "Upload file": "nu kibdu'a pa vreji", + "Rejecting invite …": ".i ca'o zukte le ka na ckaji le se friti", + "Leave Room": "nu co'u pagbu le se zilbe'i", + "Revoke invite": "nu zukte le ka na ckaji le se friti", + "Invalid community ID": ".i na drani le ka judri pa girzu", + "'%(groupId)s' is not a valid community ID": ".i zoi zoi. %(groupId)s .zoi na drani le ka judri pa girzu", + "Showing flair for these communities:": ".i sinxa jarco le ka pagbu le di'e girzu", + "This room is not showing flair for any communities": ".i na da poi girzu zo'u le ve zilbe'i cu sinxa jarco le ka pagbu da", + "New community ID (e.g. +foo:%(localDomain)s)": "judri le girzu to zoi zoi. +foo:%(localDomain)s .zoi mupli toi", + "Remove from community": "nu zilvi'u le girzu", + "Disinvite this user from community?": ".i xu do djica lo nu co'u friti le ka ziljmina le girzu", + "Remove this user from community?": ".i xu do djica lo nu le pilno co'u pagbu le girzu", + "Failed to remove user from community": ".i da nabmi fi lo nu le pilno co'u pagbu le girzu", + "Invite to this community": "nu friti le ka ziljmina le girzu", + "Failed to remove room from community": ".i da nabmi fi lo nu le ve zilbe'i co'u pagbu le girzu", + "Add rooms to this community": "nu pa ve zilbe'i cu ziljmina le girzu", + "Filter community rooms": "nu sisku fi lu'i ro ve zilbe'i poi pagbu le girzu", + "Something went wrong when trying to get your communities.": ".i da nabmi fi lo nu facki le du'u do pagbu lo girzu", + "You're not currently a member of any communities.": ".i do ca na pagbu pa girzu", + "collapse": "nu tcila be na ku viska", + "expand": "nu tcila viska", + "Create Community": "nu cupra pa girzu", + "Community Name": "cmene le girzu", + "Community ID": "judri le girzu", + "Create a public room": "nu cupra pa ve zilbe'i poi gubni", + "Create a private room": "nu cupra pa ve zilbe'i poi na gubni", + "Create Room": "nu cupra pa ve zilbe'i", + "Sign out": "nu co'u jaspu", + "Are you sure you want to sign out?": ".i xu do birti le du'u do kaidji le ka co'u se jaspu", + "Sign out and remove encryption keys?": ".i xu do djica lo nu co'u jaspu do je lo nu tolmo'i le du'u mifra ckiku", + "Upload %(count)s other files|one": "nu kibdu'a %(count)s vreji poi na du", + "View Community": "nu viska le girzu", + "Hide": "nu zilmipri", + "Leave Community": "nu do zilvi'u le girzu", + "Unable to leave community": ".i da nabmi fi lo nu do zilvi'u le girzu", + "Join this community": "nu do ziljmina le girzu", + "Leave this community": "nu do zilvi'u le girzu", + "Your community hasn't got a Long Description, a HTML page to show to community members.
    Click here to open settings and give it one!": ".i na da tcila skicu be le girzu bei ro girzu pagbu be'o lerpoi bau la'au xy. bu ty. my. ly. li'u
    .i lo nu samcu'a le dei gai'o cu tadji lo nu da go'i", + "Long Description (HTML)": "tcila skicu lerpoi bau la'au xy. bu ty. my. ly. li'u", + "Community %(groupId)s not found": ".i na da poi girzu zo'u facki le du'u zoi zoi. %(groupId)s .zoi judri da", + "This homeserver does not support communities": ".i le samtcise'u na kakne tu'a lo girzu", + "Are you sure you want to leave the room '%(roomName)s'?": ".i xu do birti le du'u do kaidji le ka co'u pagbu le se zilbe'i be fo la'o zoi. %(roomName)s .zoi", + "Failed to leave room": ".i da nabmi fi lo nu do co'u pagbu le se zilbe'i", + "For security, this session has been signed out. Please sign in again.": ".i ki'u lo nu snura co'u jaspu le se samtcise'u .i ko za'u re'u co'a se jaspu", + "Your Communities": "girzu vau je se pagbu do", + "Error whilst fetching joined communities": ".i da nabmi fi lo nu kibycpa ro girzu poi se pagbu do", + "Communities": "girzu", + "Create a new community": "nu cupra pa girzu", + "React": "nu cinmo spuda", + "Reply": "nu spuda", + "In reply to ": ".i nu spuda tu'a la'o zoi. .zoi", + "%(senderName)s made history visible to anyone": ".i gau la'o zoi. %(senderName)s .zoi ro da ka'e tcidu ro pu zilbe'i", + "You joined": ".i do ziljmina", + "%(targetName)s joined": ".i la'o zoi. %(targetName)s .zoi ziljmina", + "Show less": "nu viska so'u da", + "Save": "nu co'a vreji", + "Unable to share email address": ".i da nabmi fi lo nu jungau le du'u samymri judri", + "Share": "nu jungau", + "Unable to share phone number": ".i da nabmi fi lo nu jungau le du'u fonjudri", + "Edit message": "nu basti fi le ka notci", + "Share room": "nu jungau fi le du'u ve zilbe'i", + "Share Link to User": "nu jungau pa pilno le du'u judri", + "Edit": "nu basti", + "Share Room": "nu jungau fi le du'u ve zilbe'i", + "Share User": "nu jungau fi le du'u pilno", + "Share Community": "nu jungau fi le du'u girzu", + "Share Room Message": "nu jungau fi le du'u notci", + "Resend edit": "nu le basti cu za'u re'u zilbe'i", + "Share Permalink": "nu jungau fi le du'u vitno judri", + "Share Message": "nu jungau fi le du'u notci", + "%(senderName)s made history visible to new members": ".i gau la'o zoi. %(senderName)s .zoi ro cnino be fi le ka pagbu le se zilbe'i cu ka'e tcidu ro pu zilbe'i", + "%(senderName)s made history visible to future members": ".i gau la'o zoi. %(senderName)s .zoi ro ba pagbu be le se zilbe'i cu ka'e tcidu ro pu zilbe'i", + "%(senderName)s sent an image": ".i pa pixra cu zilbe'i fi la'o zoi. %(senderName)s .zoi", + "%(senderName)s sent a video": ".i pa se vidvi cu zilbe'i fi la'o zoi. %(senderName)s .zoi", + "%(senderName)s uploaded a file": ".i pa vreji cu zilbe'i fi la'o zoi. %(senderName)s .zoi", + "Seen by %(displayName)s (%(userName)s) at %(dateTime)s": ".i la'o zoi. %(displayName)s .zoi poi se judri zoi zoi. %(userName)s .zoi zgana de'i li %(dateTime)s", + "Waiting for %(displayName)s to accept…": ".i ca'o denpa lo nu la'o zoi. %(displayName)s .zoi zanru", + "Ask %(displayName)s to scan your code:": ".i ko cpedu le ka gau ce'u kacma samymo'i le sinxa kei la'o zoi. %(displayName)s .zoi", + "Almost there! Is %(displayName)s showing the same shield?": ".uo ru'e .i xu la'o zoi. %(displayName)s .zoi jarco ta'i tu'a pa sinxa poi mapti", + "You've successfully verified %(displayName)s!": ".i do mo'u co'a lacri la'o zoi. %(displayName)s .zoi", + "%(displayName)s cancelled verification.": ".i la'o zoi. %(displayName)s .zoi co'u co'a lacri", + "Decrypt %(text)s": "nu facki le du'u mifra la'o zoi. %(text)s .zoi", + "Download %(text)s": "nu kibycpa la'o zoi. %(text)s .zoi", + "Download this file": "nu kibycpa le vreji" } diff --git a/src/i18n/strings/kab.json b/src/i18n/strings/kab.json index a0b05ceee6..343238e626 100644 --- a/src/i18n/strings/kab.json +++ b/src/i18n/strings/kab.json @@ -279,10 +279,10 @@ "Download": "Sader", "Retry": "Ɛreḍ tikkelt-nniḍen", "Starting backup...": "Asenker n uḥraz...", - "Success!": "Akka d rrbeḥ !", + "Success!": "Tammug akken iwata!", "Disable": "Sens", "Navigation": "Tunigin", - "Calls": "isawalen", + "Calls": "Isawalen", "Alt": "Alt", "Shift": "Shift", "New line": "Izirig amaynut", @@ -459,5 +459,305 @@ "Failure to create room": "Timerna n texxamt ur teddi ara", "If you cancel now, you won't complete verifying your other session.": "Ma yella teffɣeḍ tura, ur tessawaḍeḍ ara ad tesneqdeḍ akk tiɣimiyin-inek.inem.", "If you cancel now, you won't complete your operation.": "Ma yella teffɣeḍ tura, tamhelt-ik.im ur tettemmed ara.", - "Show these rooms to non-members on the community page and room list?": "Sken tixxamin-a i wid ur nettekka ara deg usebter n temɣiwent d tebdert n texxamt?" + "Show these rooms to non-members on the community page and room list?": "Sken tixxamin-a i wid ur nettekka ara deg usebter n temɣiwent d tebdert n texxamt?", + "The remote side failed to pick up": "Amazan ur yessaweḍ ara ad d-yerr", + "Call failed due to misconfigured server": "Ur yeddi ara usiwel ssebba n uqeddac ur nettuswel ara akken iwata", + "Please ask the administrator of your homeserver (%(homeserverDomain)s) to configure a TURN server in order for calls to work reliably.": "Ttxil-k·m suter deg anedbal n uqeddac-ik·im agejdan (%(homeserverDomain)s) ad yeswel aqeddac TURN akken isawalen ad ddun akken ilaq.", + "Alternatively, you can try to use the public server at turn.matrix.org, but this will not be as reliable, and it will share your IP address with that server. You can also manage this in Settings.": "Neɣ, tzemreḍ ad tεerḍed aseqdec n uqeddac azayez deg turn.matrix.org, maca ayagi ur yelhi ara, yezmer ad yebḍu tansa-inek·inem IP d uqeddac-a. Tzemreḍ ad tesferkeḍ daɣen ayagi deg yiɣewwaren.", + "You do not have permission to start a conference call in this room": "Ur tesεiḍ ara tisirag ad tebduḍ asireg s usiwel deg texxamt-a", + "At this time it is not possible to reply with a file. Would you like to upload this file without replying?": "Akka tura, d awezɣi ad tili tririt s ufaylu. Tebɣiḍ ad tessaliḍ afaylu-a s war tiririt?", + "The file '%(fileName)s' exceeds this homeserver's size limit for uploads": "Teɣzi n ufaylu-a '%(fileName)s' tεedda teɣzi yettusirgen sɣur aqeddac-a i usali", + "Server may be unavailable, overloaded, or you hit a bug.": "Yezmer ulac aqeddac, yeččur ugar neɣ temlaleḍ-d d wabug.", + "Are you sure you want to cancel entering passphrase?": "S tidet tebɣiḍ ad tesfesxeḍ asekcem n tefyirt tuffirt?", + "This action requires accessing the default identity server to validate an email address or phone number, but the server does not have any terms of service.": "Tigawt-a tesra anekcum ɣer uqeddac n tmagit tamezwert i usentem n tansa n yimayl neɣ uṭṭun n tiliɣri, maca aqeddac ur yesεi ula d yiwet n twali n umeẓlu.", + "Only continue if you trust the owner of the server.": "Ala ma tettekleḍ ɣef bab n uqeddac ara tkemmleḍ.", + "Use your account to sign in to the latest version": "Seqdec amiḍan-ik·im akken ad tkecmeḍ ɣer lqem aneggaru", + "Riot is now Element!": "Tura, Riot d aferdis!", + "Learn More": "Issin ugar", + "Restricted": "Yesεa tilas", + "Set up": "Sbadu", + "Pencil": "Akeryun", + "Compact": "Akussem", + "Modern": "Atrar", + "Online": "Srid", + "Mention": "Abder", + "Verify session": "Asenqed n tɣimit", + "Message edits": "Tiẓrigin n yizen", + "Your account is not secure": "Amiḍan-ik·im d araɣelsan", + "Your password": "Awal-ik·im uffir", + "New session": "Tiɣimit tamaynut", + "This wasn't me": "Wagi/tagi mačči d nekk", + "Security Key": "Tasarut n tɣellist", + "Resend": "Ɛawed azen", + "Premium": "Premium", + "Everyone": "Yal yiwen", + "New Recovery Method": "Tarrayt tamaynut n ujebber", + "Go to Settings": "Ddu ɣer yiɣewwaren", + "Set up Secure Messages": "Sbadu iznan iɣelsanen", + "Not currently indexing messages for any room.": "Ulac asmiter amiran n yiznan i yal taxxamt.", + "Currently indexing: %(currentRoom)s": "Asmiter amiran: %(currentRoom)s", + "Space used:": "Tallunt yettwasqedcen:", + "Indexed messages:": "Iznan s umatar:", + "Indexed rooms:": "Tixxamin s umatar:", + "%(doneRooms)s out of %(totalRooms)s": "%(doneRooms)s beṛṛa n %(totalRooms)s", + "Room List": "Tabdert n texxamt", + "Autocomplete": "Asmad awurman", + "Alt Gr": "Alt Gr", + "Super": "Ayuz", + "Ctrl": "Ctrl", + "We’re excited to announce Riot is now Element": "S tumert meqqren ara d-nselɣu belli Riot tura d aferdis", + "Operation failed": "Tamhelt ur teddi ara", + "Failed to invite users to the room:": "Yegguma ad yeddu usnubget n yiseqdacen ɣer texxamt:", + "Failed to invite the following users to the %(roomName)s room:": "Asnubget n yiseqdacen i d-iteddun ɣer taxxamt %(roomName)s ur yeddi ara:", + "Unable to create widget.": "Timerna n uwiǧit ulamek.", + "Missing roomId.": "Ixuṣ usulay n texxamt.", + "Prepends ¯\\_(ツ)_/¯ to a plain-text message": "Yerna ¯\\_(ツ)_/¯ ɣer yizen n uḍris arewway", + "Searches DuckDuckGo for results": "Yettnadi DuckDuckGo ɣef yigmaḍ", + "To use it, just wait for autocomplete results to load and tab through them.": "I useqdec-ines, ṛǧu kan i yigmaḍ iwurmanen iččuranen i usali syen nadi deg-sen.", + "Changes the avatar of the current room": "Ibeddel avatar n texxamt tamirant", + "Gets or sets the room topic": "Yufa-d neɣ yesbadu asentel n texxamt", + "Failed to set topic": "Asbadu n usentel ur yeddi ara", + "This room has no topic.": "Taxxamt-a ulac ɣur-s asentel.", + "Sets the room name": "Yesbadu isem n texxamt", + "Invites user with given id to current room": "Inced iseqdacen s tikci n usulay i texxamt tamirant", + "Use an identity server to invite by email. Manage in Settings.": "Seqdec aqeddac n timagit i uncad s yimayl. Asefrek deg yiɣewwaren.", + "Unrecognised room address:": "Tansa n texxamt ur tettwassen ara:", + "Bans user with given id": "Agi aseqdac s usulay i d-yettunefken", + "Unbans user with given ID": "Kkes aseqdac s usulay i d-yettunefkan", + "Stops ignoring a user, showing their messages going forward": "Ḥbes tiǧǧtin n useqdac, sken iznan-ines sya d afella", + "Define the power level of a user": "Sbadu aswir iǧehden n useqdac", + "Please supply a https:// or http:// widget URL": "Ttxil-k·m mudd URL n uwigit https:// neɣ http://", + "You cannot modify widgets in this room.": "Ur tezmireḍ ara ad tbeddleḍ iwiǧiten n texxamt-a.", + "Unknown (user, session) pair:": "Tayuga tarussint (aseqdac, tiɣimit):", + "Session already verified!": "Tiɣimit tettwasenqed yakan!", + "Verified key": "Tasarut tettwasenqed", + "Displays information about a user": "Yeskan talɣut ɣef useqdac", + "Send a bug report with logs": "Azen aneqqis n wabug s yiɣƔisen", + "Logs sent": "Iɣmisen ttewaznen", + "Opens chat with the given user": "Yeldi adiwenni d useqdac i d-yettunefken", + "Sends a message to the given user": "Yuzen iznan i useqdac i d-yettunefken", + "Displays action": "Yeskan tigawt", + "%(targetName)s accepted an invitation.": "%(targetName)s yeqbel tinnubga.", + "%(senderName)s invited %(targetName)s.": "%(senderName)s inced-d %(targetName)s.", + "%(senderName)s banned %(targetName)s.": "%(senderName)s yugi %(targetName)s.", + "%(senderName)s removed their display name (%(oldDisplayName)s).": "%(senderName)s kksen isem ara d-ibanen (%(oldDisplayName)s).", + "%(senderName)s removed their profile picture.": "%(senderName)s yekkes tawlaft n umaqnu-ines.", + "%(senderName)s changed their profile picture.": "%(senderName)s ibeddel tawlaft n umaɣnu-ines.", + "%(senderName)s set a profile picture.": "%(senderName)s yesbadu tawlaft n umaɣnu.", + "%(senderName)s made no change.": "%(senderName)s ur yegi ara ula d yiwen n ubeddel.", + "VoIP conference started.": "Asarag VoIP yebda.", + "%(targetName)s joined the room.": "%(targetName)s yerna-d ɣer texxamt.", + "VoIP conference finished.": "Asarag VoIP yekfa.", + "%(targetName)s rejected the invitation.": "%(targetName)s yeugi tinnubga.", + "%(targetName)s left the room.": "%(targetName)s yeǧǧa texxamt.", + "%(senderName)s unbanned %(targetName)s.": "%(senderName)s yeqbel %(targetName)s.", + "%(senderName)s withdrew %(targetName)s's invitation.": "%(senderName)s yekkes-d tinnubga n %(targetName)s.", + "%(senderDisplayName)s changed the topic to \"%(topic)s\".": "%(senderDisplayName)s ibeddel asentel ɣer \"%(topic)s\".", + "%(senderDisplayName)s removed the room name.": "%(senderDisplayName)s yekkes isem n texxamt.", + "%(senderDisplayName)s upgraded this room.": "%(senderDisplayName)s ileqqem taxxamt-a.", + "%(senderDisplayName)s made the room invite only.": "%(senderDisplayName)s yerra taxxamt s tinnubga kan.", + "%(senderDisplayName)s has allowed guests to join the room.": "%(senderDisplayName)s yefka tisirag i uttekki deg texxamt.", + "%(senderDisplayName)s sent an image.": "%(senderDisplayName)s yuzen-d tugna.", + "%(senderName)s removed the main address for this room.": "%(senderName)s yekkes tansa tagejdant n texxamt-a.", + "%(senderName)s added the alternative addresses %(addresses)s for this room.|other": "%(senderName)s yerna tansiwin-nniḍen %(addresses)s ɣer texxamt-a.", + "(unknown failure: %(reason)s)": "(abrir tarussint: %(reason)s)", + "%(senderName)s ended the call.": "%(senderName)s yekfa asiwel.", + "%(widgetName)s widget added by %(senderName)s": "%(widgetName)s awiǧit yettwarna sɣur %(senderName)s", + "%(widgetName)s widget removed by %(senderName)s": "%(widgetName)s awiǧit yettwakkes sɣur %(senderName)s", + "Not Trusted": "Ur yettwattkal ara", + "%(displayName)s is typing …": "%(displayName)s yettaru-d …", + "%(names)s and %(count)s others are typing …|other": "%(names)s d %(count)s wiyaḍ ttarun-d …", + "%(names)s and %(count)s others are typing …|one": "%(names)s d wayeḍ-nniḍen yettaru-d …", + "%(names)s and %(lastPerson)s are typing …": "%(names)s d %(count)s ttarun-d …", + "%(items)s and %(count)s others|other": "%(names)s d %(count)s wiyaḍ", + "%(items)s and %(count)s others|one": "%(names)s d wayeḍ-nniḍen", + "%(items)s and %(lastItem)s": "%(items)s d %(lastItem)s", + "a few seconds ago": "kra n tesinin seg yimir-nni", + "about a minute ago": "tasdidt seg yimir-nni", + "%(num)s minutes ago": "%(num)s tesdat seg yimir-nni", + "about an hour ago": "azal n usrag seg yimir-nni", + "Set Password": "Sbadu awal uffir", + "Set up encryption": "Swel awgelhen", + "Encryption upgrade available": "Yella uleqqem n uwgelhen", + "Verify this session": "Asenqed n tɣimit", + "Other users may not trust it": "Iseqdacen-nniḍen yezmer ur tettamnen ara", + "You joined the call": "Terniḍ ɣer usiwel", + "%(senderName)s joined the call": "%(senderName)s yerna ɣer usiwel", + "Call in progress": "Asiwel la iteddu", + "You left the call": "Teǧǧiḍ asiwel", + "%(senderName)s left the call": "%(senderName)s yeǧǧa asiwel", + "Call ended": "Asiwel yekfa", + "You started a call": "Tebdiḍ asiwel", + "%(senderName)s started a call": "%(senderName)s yebda asiwel", + "Waiting for answer": "Yettṛaǧu tiririt", + "%(senderName)s is calling": "%(senderName)s yessawal", + "You created the room": "Terniḍ taxxamt", + "%(senderName)s created the room": "%(senderName)s yerna taxxamt", + "You made the chat encrypted": "Terriḍ adiwenni yettuwgelhen", + "%(senderName)s made the chat encrypted": "%(senderName)s yerra adiwenni yettuwgelhen", + "You made history visible to new members": "Terriḍ amazray yettban i yimttekkiyen imaynuten", + "%(senderName)s made history visible to new members": "%(senderName)s yerra amazray yettban i yimttekkiyen imaynuten", + "You made history visible to anyone": "Terriḍ amazray yettban i yal amdan", + "%(senderName)s made history visible to anyone": "%(senderName)s yerra amazray yettban i yal amdan", + "You made history visible to future members": "Terriḍ amazray yettban i yimttekkiyen ara d-yernun", + "%(senderName)s made history visible to future members": "%(senderName)s yerra amazray yettban i yimttekkiyen ara d-yernun", + "You were invited": "Tettusnubegteḍ", + "%(targetName)s was invited": "%(senderName)s yettusnubget", + "You left": "Truḥeḍ", + "%(targetName)s left": "%(targetName)s iṛuḥ", + "You rejected the invite": "Tugiḍ tinnubga", + "%(targetName)s rejected the invite": "%(targetName)s yugi tinnubga", + "You were uninvited": "Ur tettusnubegteḍ ara", + "%(targetName)s was uninvited": "%(senderName)s ur yettusnubget ara", + "You joined": "Terniḍ", + "%(targetName)s joined": "%(targetName)s yerna", + "You changed your name": "Tbeddleḍ isem-ik·im", + "%(targetName)s changed their name": "%(targetName)s ibeddel isem-is", + "You changed your avatar": "Tbeddleḍ avatar-inek·inem", + "%(targetName)s changed their avatar": "%(targetName)s ibeddel avatar-ines", + "%(senderName)s %(emote)s": "%(senderName)s %(emote)s", + "%(senderName)s: %(message)s": "%(senderName)s: %(message)s", + "You changed the room name": "Tbeddleḍ isem n texxamt", + "%(senderName)s changed the room name": "%(senderName)s kksen isem n texxamt", + "%(senderName)s: %(reaction)s": "%(senderName)s: %(reaction)s", + "%(senderName)s: %(stickerName)s": "%(senderName)s: %(stickerName)s", + "You uninvited %(targetName)s": "Ur tettusnubegteḍ ara sɣur %(targetName)s", + "%(senderName)s uninvited %(targetName)s": "%(senderName)s ur yettusnubget ara sɣur %(targetName)s", + "You invited %(targetName)s": "Tettusnubegteḍ sɣur %(targetName)s", + "%(senderName)s invited %(targetName)s": "%(senderName)s yettusnubget %(targetName)s", + "You changed the room topic": "Tbeddleḍ asentel n texxamt", + "%(senderName)s changed the room topic": "%(senderName)s ibeddel asentel n texxamt", + "Message Pinning": "Arezzi n yizen", + "Group & filter rooms by custom tags (refresh to apply changes)": "Sdukkel tixxamin, tsizedgeḍ-tent s tebzimin tudmawanin (smiren akken ad alin yisnifal)", + "Order rooms by name": "Semyizwer tixxamin s yisem", + "Show rooms with unread notifications first": "Sken tixxamin yesεan ilɣa ur nettwaɣra ara d timezwura", + "Collecting logs": "Alqaḍ n yiɣmisen", + "Uploading report": "Asali n uneqqis", + "Waiting for response from server": "Aṛaǧu n tririt sɣur aqeddac", + "Messages containing my display name": "Iznan ideg yella yisem-iw yettwaskanen", + "Messages containing my username": "Iznan ideg yella yisem-iw n useqdac", + "Messages containing @room": "Iznan ideg yella @taxxamt", + "Delete sessions|other": "Kkes tiɣimiyin", + "Delete sessions|one": "Kkes tiɣimit", + "Delete %(count)s sessions|other": "Kkes tiɣimiyin n %(count)s", + "Delete %(count)s sessions|one": "Kkes tiɣimit n %(count)s", + "Public Name": "Isem azayez", + "Last seen": "Timeẓri taneggarut", + "Failed to set display name": "Asbadu n yisem yettwaskanen ur yeddi ara", + " to store messages from ": " i usekles n yiznan sɣur ", + "rooms.": "tixxamin.", + "Connecting to integration manager...": "Tuqqna ɣer umsefrak n useddu...", + "Cannot connect to integration manager": "Ur nessaweḍ ara ad neqqen ɣer umsefrak n useddu...", + "Delete Backup": "Kkes aḥraz", + "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Iznan yettwawgelhen ttuḥerzen s uwgelhen n yixef ɣer yixef. Ala kečč d unermas (inermasen) i yesεan tisura akken ad ɣren iznan-a.", + "This session is backing up your keys. ": "Tiɣimit tḥerrez tisura-inek·inem. ", + "Connect this session to Key Backup": "Qqen tiɣimit-a ɣer uḥraz n tsarut", + "Server Name": "Isem n uqeddac", + "Enter password": "Sekcem awal n uffir", + "Nice, strong password!": "Igerrez, d awal uffir iǧhed aṭas!", + "Password is allowed, but unsafe": "Awal uffir yettusireg, maca d araɣelsan", + "Keep going...": "Kemmel ddu...", + "The email field must not be blank.": "Urti n yimayl ur ilaq ara ad yili d ilem.", + "The username field must not be blank.": "Urti n yisem n useqdac ur ilaq ara ad yili d ilem.", + "The phone number field must not be blank.": "Urti n wuṭṭun n tiliɣri ur ilaq ara ad yili d ilem.", + "The password field must not be blank.": "Urti n wawal uffir ilaq ara ad yili d ilem.", + "Not sure of your password? Set a new one": "Tcukkteḍ deg wawal-ik·im uffir? Sbadu yiwen-nniḍen d amaynut", + "Sign in with": "Kcem s", + "Use an email address to recover your account": "Seqdec tansa n yimayl akken ad t-terreḍ amiḍan-ik:im", + "Enter email address (required on this homeserver)": "Sekcem tansa n yimayl (yettusra deg uqeddac-a agejdan)", + "Doesn't look like a valid email address": "Ur tettban ara d tansa n yimayl tameɣtut", + "Other users can invite you to rooms using your contact details": "Iseqdacen wiyaḍ zemren ad ak·akem-snubegten ɣer texxamin s useqdec n tlqayt n unermas", + "Enter phone number (required on this homeserver)": "Sekcem uṭṭun n tiliɣri (yettusra deg uqeddac-a agejdan)", + "Doesn't look like a valid phone number": "Ur tettban ara d uṭṭun n tiliɣri ameɣtu", + "Enter username": "Sekcem isem n useqdac", + "Phone (optional)": "Tiliɣri (d afrayan)", + "Create your Matrix account on %(serverName)s": "Rnu amiḍan-ik·im Matrix deg %(serverName)s", + "Create your Matrix account on ": "Rnu amiḍan-ik·im Matrix deg ", + "Enter your custom homeserver URL What does this mean?": "Sekcem URL n uqeddac agejdan udmawan D acu-t unamek n waya?", + "Homeserver URL": "URL n uqeddac agejdan", + "Enter your custom identity server URL What does this mean?": "Sekcem URL n uqeddac n timagit udmawan D acu-t unamek n waya?", + "Forgotten your password?": "Tettuḍ awal-ik·im uffir?", + "Sign in and regain access to your account.": "Qqen syen εreḍ anekcum ɣer umiḍan-inek·inem tikkelt-nniḍen.", + "You cannot sign in to your account. Please contact your homeserver admin for more information.": "Ur tessawḍeḍ ara ad teqqneḍ ɣer umiḍan-inek:inem. Ttxil-k·m nermes anedbal n uqeddac-ik·im agejdan i wugar n talɣut.", + "You're signed out": "Teffɣeḍ-d seg tuqqna", + "Clear personal data": "Sfeḍ isefka udmawanen", + "Community Autocomplete": "Asmad awurman n temɣiwent", + "Results from DuckDuckGo": "Igmaḍ seg DuckDuchGo", + "DuckDuckGo Results": "Igmaḍ n DuckDuckGo", + "Notify the whole room": "Selɣu akk taxxamt", + "Room Notification": "Ilɣa n texxamt", + "Notification Autocomplete": "Asmad awurman n yilɣa", + "Room Autocomplete": "Asmad awurman n texxamt", + "User Autocomplete": "Asmad awurman n useqdac", + "Passphrases must match": "Tifyar tuffirin ilaq ad mṣadant", + "Passphrase must not be empty": "Tafyirt tuffirt ur ilaq ara ad ilint d tilmawin", + "Export room keys": "Sifeḍ tisura n texxamt", + "Confirm passphrase": "Sentem tafyirt tuffirt", + "Import room keys": "Kter tisura n texxamt", + "File to import": "Afaylu i uktar", + "Confirm encryption setup": "Sentem asebded n uwgelhen", + "Click the button below to confirm setting up encryption.": "Sit ɣef tqeffalt ddaw akken ad tesnetmeḍ asebded n uwgelhen.", + "Generate a Security Key": "Sirew tasarut n tɣellist", + "Enter a Security Phrase": "Sekcem tafyirt tuffirt", + "Enter your account password to confirm the upgrade:": "Sekcem awal uffir n umiḍan-ik·im akken ad tesnetmeḍ aleqqem:", + "Great! This recovery passphrase looks strong enough.": "Ayuz! Tafyirt-agi tuffirt n ujebber tettban teǧhed nezzeh.", + "That matches!": "Yemṣada!", + "Use a different passphrase?": "Seqdec tafyirt tuffirt yemgaraden?", + "That doesn't match.": "Ur yemṣada ara.", + "Go back to set it again.": "Uɣal ɣer deffir akken ad t-tesbaduḍ i tikkelt-nniḍen.", + "Enter your recovery passphrase a second time to confirm it.": "Sekcem tafyirt-ik·im tuffirt n ujebber i tikkelt-nniḍen akken ad tt-tesnetmeḍ.", + "Confirm your recovery passphrase": "Sentem tafyirt-ik·im tuffirt n ujebber", + "Set up Secure backup": "Sebded aḥraz aɣelsan", + "Upgrade your encryption": "Leqqem awgelhen-inek·inem", + "Set a Security Phrase": "Sbadu tafyirt taɣelsant", + "Confirm Security Phrase": "Sentem tafyirt tuffirt", + "Don't ask again": "Ur d-sutur ara tikelt-nniḍen", + "Recovery Method Removed": "Tarrayt n ujebber tettwakkes", + "Failed to set direct chat tag": "Asbadu n tebzimt n udiwenni usrid ur yeddi ara", + "Failed to remove tag %(tagName)s from room": "Tukksa n tebzimt %(tagName)s seg texxamt ur yeddi ara", + "Failed to add tag %(tagName)s to room": "Timerna n tebzimt %(tagName)s ɣer texxamt ur yeddi ara", + "%(num)s hours ago": "%(num)s usrag seg yimir-nni", + "about a day ago": "azal n wass seg yimir-nni", + "%(num)s days ago": "%(num)s wussan seg yimir-nni", + "a few seconds from now": "Kra n tesinin seg yimir-a", + "%(name)s (%(userId)s)": "%(name)s (%(userId)s)", + "Not a valid %(brand)s keyfile": "Afaylu n tsarut %(brand)s d arameɣtu", + "User %(user_id)s does not exist": "Aseqdac %(user_id)s ulac-it", + "Unknown server error": "Tuccḍa n uqeddac d tarussint", + "Avoid repeated words and characters": "Zgel i wawalen i d-yettasen d yisekkilen", + "Avoid sequences": "Zgel igzumen", + "Avoid recent years": "Zgel iseggasen ineggura", + "Avoid years that are associated with you": "Zgel iseggasen i icudden ɣur-k", + "Avoid dates and years that are associated with you": "Zgel izmaz akked iseggasen i icudden ɣur-k", + "System font name": "Isem n tsefsit n unagraw", + "Send analytics data": "Azen isefka n tesleḍt", + "Cancelling…": "Asefsex...", + "They match": "Mṣadan", + "They don't match": "Ur mṣadan ara", + "Dog": "Aqjun", + "Horse": "Aεewdiw", + "Pig": "Ilef", + "Elephant": "Ilu", + "Panda": "Apunda", + "Rooster": "Ayaziḍ", + "Fish": "Lḥut", + "Butterfly": "Aferteṭṭu", + "Flower": "Ajeǧǧig", + "Mushroom": "Agersal", + "Moon": "Ayyur", + "Cloud": "Agu", + "Fire": "Times", + "Banana": "Tabanant", + "Apple": "Tatteffaḥt", + "Strawberry": "Tazwelt", + "Corn": "Akbal", + "Cake": "Angul", + "Heart": "Ul", + "Smiley": "Acmumeḥ", + "Robot": "Aṛubut", + "Hat": "Acapun", + "Glasses": "Tisekkadin", + "Umbrella": "Tasiwant", + "Gift": "Asefk", + "Light bulb": "Taftilt" } diff --git a/src/i18n/strings/lt.json b/src/i18n/strings/lt.json index fc3d26b51f..9bdbb7a6f7 100644 --- a/src/i18n/strings/lt.json +++ b/src/i18n/strings/lt.json @@ -388,7 +388,7 @@ "New passwords must match each other.": "Nauji slaptažodžiai privalo sutapti.", "I have verified my email address": "Aš patvirtinau savo el. pašto adresą", "Return to login screen": "Grįžti į prisijungimą", - "Send Reset Email": "Siųsti nustatymo iš naujo el. laišką", + "Send Reset Email": "Siųsti naujo slaptažodžio nustatymo el. laišką", "Incorrect username and/or password.": "Neteisingas vartotojo vardas ir/arba slaptažodis.", "Please note you are logging into the %(hs)s server, not matrix.org.": "Atkreipkite dėmesį, kad jūs jungiatės prie %(hs)s serverio, o ne matrix.org.", "Failed to fetch avatar URL": "Nepavyko gauti pseudoportreto URL", @@ -840,10 +840,10 @@ "Confirm": "Patvirtinti", "Create your Matrix account on %(serverName)s": "Sukurkite savo Matrix paskyrą %(serverName)s serveryje", "Create your Matrix account on ": "Sukurkite savo Matrix paskyrą serveryje", - "Set an email for account recovery. Use email or phone to optionally be discoverable by existing contacts.": "Nustatykite el. paštą paskyros atgavimui. Naudokite el. paštą ar tel. nr. norėdami pasirinktinai būti aptinkami esamų kontaktų.", - "Set an email for account recovery. Use email to optionally be discoverable by existing contacts.": "Nustatykite el. paštą paskyros atgavimui. Naudokite el. paštą norėdami pasirinktinai būti aptinkami esamų kontaktų.", + "Set an email for account recovery. Use email or phone to optionally be discoverable by existing contacts.": "Nustatykite el. paštą paskyros susigrąžinimui. Naudokite el. paštą ar telefoną, jei norite, kad esami kontaktai galėtų jus rasti.", + "Set an email for account recovery. Use email to optionally be discoverable by existing contacts.": "Nustatykite el. paštą paskyros susigrąžinimui. Naudokite el. paštą, jei norite, kad esami kontaktai galėtų jus rasti.", "Sign in instead": "Prisijungti", - "A verification email will be sent to your inbox to confirm setting your new password.": "Patvirtinimo laiškas bus išsiųstas į jūsų pašto dėžutę tam, kad patvirtintumėte naujo slaptažodžio nustatymą.", + "A verification email will be sent to your inbox to confirm setting your new password.": "Tam, kad patvirtinti jūsų naujo slaptažodžio nustatymą, į jūsų pašto dėžutę bus išsiųstas patvirtinimo laiškas.", "Set a new password": "Nustatykite naują slaptažodį", "Create account": "Sukurti paskyrą", "Create your account": "Sukurkite savo paskyrą", @@ -1331,7 +1331,7 @@ "You have not verified this user.": "Jūs nepatvirtinote šio vartotojo.", "You have verified this user. This user has verified all of their sessions.": "Jūs patvirtinote šį vartotoją. Šis vartotojas patvirtino visus savo seansus.", "Everyone in this room is verified": "Visi šiame kambaryje yra patvirtinti", - "Encrypted by a deleted session": "Užšifruota ištrintos sesijos", + "Encrypted by a deleted session": "Užšifruota ištrinto seanso", "Use an identity server in Settings to receive invites directly in %(brand)s.": "Nustatymuose naudokite tapatybės serverį, kad gautumėte pakvietimus tiesiai į %(brand)s.", "%(count)s verified sessions|one": "1 patvirtintas seansas", "If you can't scan the code above, verify by comparing unique emoji.": "Jei nuskaityti aukščiau esančio kodo negalite, patvirtinkite palygindami unikalius jaustukus.", @@ -1436,7 +1436,7 @@ "%(name)s is requesting verification": "%(name)s prašo patvirtinimo", "Sign In or Create Account": "Prisijungti arba Sukurti Paskyrą", "Use your account or create a new one to continue.": "Norėdami tęsti naudokite savo paskyrą arba sukurkite naują.", - "Create Account": "Sukurti Paskyrą", + "Create Account": "Sukurti paskyrą", "Custom (%(level)s)": "Pasirinktinis (%(level)s)", "Ask this user to verify their session, or manually verify it below.": "Paprašykite šio vartotojo patvirtinti savo seansą arba patvirtinkite jį rankiniu būdu žemiau.", "Encryption upgrade available": "Galimas šifravimo atnaujinimas", @@ -1625,5 +1625,7 @@ "Toggle right panel": "Perjungti dešinį skydelį", "Toggle this dialog": "Perjungti šį dialogą", "Move autocomplete selection up/down": "Perkelti automatinio užbaigimo pasirinkimą aukštyn/žemyn", - "Cancel autocomplete": "Atšaukti automatinį užbaigimą" + "Cancel autocomplete": "Atšaukti automatinį užbaigimą", + "Please install Chrome, Firefox, or Safari for the best experience.": "Geriausiam veikimui suinstaliuokite Chrome, Firefox, arba Safari.", + "Use Recovery Key or Passphrase": "Naudoti atgavimo raktą arba slaptafrazę" } diff --git a/src/i18n/strings/nb_NO.json b/src/i18n/strings/nb_NO.json index 97a5e75b04..f0c9827c06 100644 --- a/src/i18n/strings/nb_NO.json +++ b/src/i18n/strings/nb_NO.json @@ -16,7 +16,7 @@ "Failed to set direct chat tag": "Kunne ikke angi direkte chat-tagg", "Today": "I dag", "Files": "Filer", - "You are not receiving desktop notifications": "Du mottar ikke skrivebords varsler", + "You are not receiving desktop notifications": "Du mottar ikke skrivebordsvarsler", "Friday": "Fredag", "Notifications": "Varsler", "Unable to fetch notification target list": "Kunne ikke hente varsel-mål liste", @@ -1401,5 +1401,11 @@ "Toggle Bold": "Veksle fet", "Toggle Italics": "Veksle kursiv", "Toggle Quote": "Veksle siteringsformat", - "Upload a file": "Last opp en fil" + "Upload a file": "Last opp en fil", + "Confirm the emoji below are displayed on both sessions, in the same order:": "Bekreft at emotene nedenfor vises på begge økter, i samme rekkefølge:", + "Not sure of your password? Set a new one": "Er du usikker på passordet ditt? Velg et nytt et", + "Sign in to your Matrix account on %(serverName)s": "Logg inn på Matrix-kontoen din på %(serverName)s", + "Sign in to your Matrix account on ": "Logg inn på Matrix-kontoen din på ", + "If you've joined lots of rooms, this might take a while": "Hvis du har blitt med i mange rom, kan dette ta en stund", + "Your new session is now verified. It has access to your encrypted messages, and other users will see it as trusted.": "Den nye økten din er nå verifisert. Den har tilgang til dine krypterte meldinger, og andre brukere vil se at den blir stolt på." } diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index a8cefd00f9..bb0fb5def6 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -1846,7 +1846,7 @@ "Reactions": "Reacties", " reacted with %(content)s": " heeft gereageerd met %(content)s", "Frequently Used": "Vaak gebruikt", - "Smileys & People": "Smileys en personen", + "Smileys & People": "Emoticons en personen", "Animals & Nature": "Dieren en natuur", "Food & Drink": "Eten en drinken", "Activities": "Activiteiten", @@ -2024,5 +2024,7 @@ "Dark": "Donker", "Set password": "Stel wachtwoord in", "To return to your account in future you need to set a password": "Zonder wachtwoord kunt u later niet tot uw account terugkeren", - "Restart": "Herstarten" + "Restart": "Herstarten", + "People": "Tweegesprekken", + "Set a room address to easily share your room with other people.": "Geef het gesprek een adres om het gemakkelijk met anderen te kunnen delen." } diff --git a/src/i18n/strings/nn.json b/src/i18n/strings/nn.json index cf84960b14..52cbfc75e1 100644 --- a/src/i18n/strings/nn.json +++ b/src/i18n/strings/nn.json @@ -204,9 +204,9 @@ "Do you want to set an email address?": "Vil du setja ei epostadresse?", "Current password": "Gjeldande passord", "Password": "Passord", - "New Password": "Nytt Passord", + "New Password": "Nytt passord", "Confirm password": "Stadfest passord", - "Change Password": "Endra Passord", + "Change Password": "Endra passord", "Authentication": "Authentisering", "Last seen": "Sist sedd", "Failed to set display name": "Fekk ikkje til å setja visningsnamn", @@ -311,7 +311,7 @@ "No rooms to show": "Ingen rom å visa", "Unnamed room": "Rom utan namn", "Guests can join": "Gjester kan bli med", - "Save": "Lagre", + "Save": "Lagra", "(~%(count)s results)|other": "(~%(count)s resultat)", "(~%(count)s results)|one": "(~%(count)s resultat)", "Join Room": "Bli med i rom", @@ -345,7 +345,7 @@ "Only people who have been invited": "Berre dei som har vorte inviterte", "Anyone who knows the room's link, apart from guests": "Dei som kjenner lenkja til rommet, sett vekk frå gjester", "Anyone who knows the room's link, including guests": "Dei som kjenner lenkja til rommet, gjester òg", - "Publish this room to the public in %(domain)s's room directory?": "Gjer dette rommet offentleg i %(domain)s sitt romkatalog?", + "Publish this room to the public in %(domain)s's room directory?": "Gjer dette rommet offentleg i %(domain)s sin romkatalog?", "Who can read history?": "Kven kan lesa historia?", "Anyone": "Kven som helst", "Members only (since the point in time of selecting this option)": "Berre medlemmar (frå då denne innstillinga vart skrudd på)", @@ -872,7 +872,7 @@ "Identity server URL does not appear to be a valid identity server": "URL-adressa virkar ikkje til å vere ein gyldig identitetstenar", "General failure": "Generell feil", "This homeserver does not support login using email address.": "Denne heimetenaren støttar ikkje innloggingar med e-postadresser.", - "Please contact your service administrator to continue using this service.": "Kontakt din systemadministrator for å vidare å bruke tenesta.", + "Please contact your service administrator to continue using this service.": "Kontakt din systemadministrator for å vidare bruka tenesta.", "This account has been deactivated.": "Denne kontoen har blitt deaktivert.", "Failed to perform homeserver discovery": "Fekk ikkje til å utforska heimetenaren", "Sign in with single sign-on": "Logg på med Single-Sign-On", @@ -899,7 +899,7 @@ "Go back to set it again.": "Gå tilbake for å sette den på nytt.", "Download": "Last ned", "Print it and store it somewhere safe": "Skriv ut og ta vare på den på ein trygg stad", - "Save it on a USB key or backup drive": "Lagre til ein USB-pinne eller sikkerheitskopidisk", + "Save it on a USB key or backup drive": "Lagra til ein USB-pinne eller sikkerheitskopidisk", "Copy it to your personal cloud storage": "Kopier den til personleg skylagring", "Your keys are being backed up (the first backup could take a few minutes).": "Nøklane dine blir sikkerheitskopiert (den første kopieringa kan ta nokre minutt).", "Set up Secure Message Recovery": "Sett opp sikker gjenoppretting for meldingar", @@ -1007,14 +1007,14 @@ "Show join/leave messages (invites/kicks/bans unaffected)": "Vis bli-med/forlat meldingar (ekskluderer invitasjonar/utkasting/blokkeringar)", "Prompt before sending invites to potentially invalid matrix IDs": "Spør før utsending av invitasjonar til potensielle ugyldige Matrix-IDar", "Disconnecting from your identity server will mean you won't be discoverable by other users and you won't be able to invite others by email or phone.": "Ved å fjerne koplinga mot din identitetstenar, vil ikkje brukaren din bli oppdaga av andre brukarar, og du kan heller ikkje invitera andre med e-post eller telefonnummer.", - "Using an identity server is optional. If you choose not to use an identity server, you won't be discoverable by other users and you won't be able to invite others by email or phone.": "Å bruke ein identitetstenar er frivillig. Om du vel å ikkje bruke dette, vil ikkje brukaren din bli oppdaga av andre brukarar, og du kan ikkje invitera andre med e-post eller telefonnummer.", + "Using an identity server is optional. If you choose not to use an identity server, you won't be discoverable by other users and you won't be able to invite others by email or phone.": "Å bruka ein identitetstenar er frivillig. Om du vel å ikkje bruka dette, vil ikkje brukaren din bli oppdaga av andre brukarar, og du kan ikkje invitera andre med e-post eller telefonnummer.", "Your password was successfully changed. You will not receive push notifications on other sessions until you log back in to them": "Passordet ditt vart endra. Du vil ikkje motta push-varslingar på andre økter, før etter til at du har logga inn på nytt der", "Error downloading theme information.": "Feil under nedlasting av temainformasjon.", "Theme added!": "Tema lagt til!", "Email addresses": "E-postadresser", "Phone numbers": "Telefonnummer", "Set a new account password...": "Lag nytt kontopassord...", - "Help & About": "Hjelp & Om", + "Help & About": "Hjelp og om", "Bug reporting": "Feilrapportering", "Accept all %(invitedRooms)s invites": "Aksepter alle invitasjonar frå %(invitedRooms)s", "Security & Privacy": "Sikkerheit og personvern", @@ -1047,7 +1047,7 @@ "Code block": "Kodeblokk", "Room %(name)s": "Rom %(name)s", "Recent rooms": "Siste rom", - "Direct Messages": "Direktemeldingar", + "Direct Messages": "Folk", "Joining room …": "Blir med i rommet…", "Loading …": "Lastar…", "Rejecting invite …": "Avviser invitasjon…", @@ -1089,7 +1089,7 @@ "%(count)s unread messages.|one": "1 ulesen melding.", "Unread messages.": "Uleste meldingar.", "Unknown Command": "Ukjend kommando", - "You can use /help to list available commands. Did you mean to send this as a message?": "Du kan bruke /help for å liste kommandoar. Meinte du å sende dette som ein melding ?", + "You can use /help to list available commands. Did you mean to send this as a message?": "Du kan bruka /help for å lista tilgjengelege kommandoar. Meinte du å senda dette som ein melding ?", "Hint: Begin your message with // to start it with a slash.": "Hint: Start meldinga med // for å starte den med skråstrek.", "Send as message": "Send som melding", "Failed to revoke invite": "Fekk ikkje til å trekke invitasjonen", @@ -1115,7 +1115,7 @@ "Room Topic": "Romemne", "Room avatar": "Rom-avatar", "Power level": "Tilgangsnivå", - "Voice & Video": "Tale & Video", + "Voice & Video": "Tale og video", "Show info about bridges in room settings": "Vis info om bruer under rominnstillingar", "Show display name changes": "Vis endringar for visningsnamn", "Match system theme": "Følg systemtema", @@ -1200,8 +1200,8 @@ "Add theme": "Legg til tema", "Theme": "Tema", "Credits": "Bidragsytarar", - "For help with using %(brand)s, click here.": "For hjelp med å bruke %(brand)s, klikk her.", - "For help with using %(brand)s, click here or start a chat with our bot using the button below.": "For hjelp med å bruke %(brand)s, klikk her, eller start ein samtale med vår bot ved å bruke knappen under.", + "For help with using %(brand)s, click here.": "For hjelp med å bruka %(brand)s, klikk her.", + "For help with using %(brand)s, click here or start a chat with our bot using the button below.": "For hjelp med å bruka %(brand)s, klikk her, eller start ein samtale med vår bot ved å bruke knappen under.", "Clear cache and reload": "Tøm buffer og last inn på nytt", "Composer": "Teksteditor", "Upgrade this room to the recommended room version": "Oppgrader dette rommet til anbefalt romversjon", @@ -1210,7 +1210,7 @@ "Jump to start/end of the composer": "Hopp til start/slutt av teksteditoren", "Navigate composer history": "Naviger historikk for teksteditor", "Use Single Sign On to continue": "Bruk Single-sign-on for å fortsette", - "Confirm adding this email address by using Single Sign On to prove your identity.": "Stadfest at du legger til denne e-postadressa, ved å bruke Single-sign-on for å stadfeste identiteten din.", + "Confirm adding this email address by using Single Sign On to prove your identity.": "Stadfest at du legger til denne e-postadressa, ved å bruka Single-sign-on for å stadfeste identiteten din.", "Single Sign On": "Single-sign-on", "Capitalization doesn't help very much": "Store bokstavar hjelp dessverre lite", "Predictable substitutions like '@' instead of 'a' don't help very much": "Forutsigbare teiknbytte som '@' istaden for 'a' hjelp dessverre lite", @@ -1236,7 +1236,7 @@ "Incorrect recovery passphrase": "Feil gjenopprettingspassfrase", "Enter recovery passphrase": "Skriv inn gjennopprettingspassfrase", "Access your secure message history and set up secure messaging by entering your recovery passphrase.": "Få tilgang til sikker meldingshistorikk og sett opp sikker meldingsutveksling, ved å skrive inn gjennopprettingspassfrasen.", - "If you've forgotten your recovery passphrase you can use your recovery key or set up new recovery options": "Har du gløymt gjennopprettingspassfrasen kan du bruke gjennopprettingsnøkkel eller sette opp nye gjennopprettingsval", + "If you've forgotten your recovery passphrase you can use your recovery key or set up new recovery options": "Har du gløymt gjennopprettingspassfrasen kan du bruka ein gjennopprettingsnøkkel eller setta opp nye gjennopprettingsval", "Help": "Hjelp", "Explore": "Utforsk", "%(creator)s created and configured the room.": "%(creator)s oppretta og konfiguerte dette rommet.", @@ -1285,7 +1285,7 @@ "Allow Peer-to-Peer for 1:1 calls": "Tillat peer-to-peer (P2P) for ein-til-ein samtalar", "Never send encrypted messages to unverified sessions from this session": "Aldri send krypterte meldingar til ikkje-verifiserte sesjonar frå denne sesjonen", "Never send encrypted messages to unverified sessions in this room from this session": "Aldri send krypterte meldingar i dette rommet til ikkje-verifiserte sesjonar frå denne sesjonen", - "Allow fallback call assist server turn.matrix.org when your homeserver does not offer one (your IP address would be shared during a call)": "Tillat å bruke assistansetenaren turn.matrix.org for talesamtalar viss heimetenaren din ikkje tilbyr dette (IP-adressa di vil bli delt under talesamtalen)", + "Allow fallback call assist server turn.matrix.org when your homeserver does not offer one (your IP address would be shared during a call)": "Tillat å bruka assistansetenaren turn.matrix.org for talesamtalar viss heimetenaren din ikkje tilbyr dette (IP-adressa di vil bli delt under talesamtalen)", "Enable message search in encrypted rooms": "Aktiver søk etter meldingar i krypterte rom", "Secure messages with this user are end-to-end encrypted and not able to be read by third parties.": "Sikre meldingar med denne brukaren er ende-til-ende krypterte og kan ikkje lesast av tredjepart.", "Public Name": "Offentleg namn", @@ -1328,5 +1328,8 @@ "I don't want my encrypted messages": "Eg treng ikkje mine krypterte meldingar", "You'll lose access to your encrypted messages": "Du vil miste tilgangen til dine krypterte meldingar", "No identity server is configured so you cannot add an email address in order to reset your password in the future.": "Ingen identitetstenar er konfiguert, så i framtida kan ikkje legge til ei e-postadresse for å nullstille passordet.", - "Join millions for free on the largest public server": "Kom ihop med millionar av andre på den største offentlege tenaren" + "Join millions for free on the largest public server": "Kom ihop med millionar av andre på den største offentlege tenaren", + "Order rooms by name": "Sorter rom etter namn", + "Show rooms with unread notifications first": "Vis rom med ulesne varsel fyrst", + "Show rooms with unread messages first": "Vis rom med ulesne meldingar fyrst" } diff --git a/src/i18n/strings/pl.json b/src/i18n/strings/pl.json index 3d9fdfad79..1343405781 100644 --- a/src/i18n/strings/pl.json +++ b/src/i18n/strings/pl.json @@ -757,7 +757,7 @@ "Demote yourself?": "Zdegradować siebie?", "Demote": "Zdegraduj", "Hide Stickers": "Ukryj Naklejki", - "Show Stickers": "Pokaż Naklejki", + "Show Stickers": "Pokaż naklejki", "The email field must not be blank.": "Pole e-mail nie może być puste.", "The phone number field must not be blank.": "Pole numeru telefonu nie może być puste.", "The password field must not be blank.": "Pole hasła nie może być puste.", @@ -1322,7 +1322,7 @@ "Use your account or create a new one to continue.": "Użyj konta lub utwórz nowe, aby kontynuować.", "No": "Nie", "Yes": "Tak", - "React": "Zareaguj", + "React": "Dodaj reakcję", "Edited at %(date)s. Click to view edits.": "Edytowano w %(date)s. Kliknij, aby zobaczyć zmiany.", "Frequently Used": "Często używane", "Smileys & People": "Buźki i osoby", @@ -1505,5 +1505,31 @@ "Use Single Sign On to continue": "Użyj pojedynczego logowania, aby kontynuować", "Confirm adding this email address by using Single Sign On to prove your identity.": "Potwierdź dodanie tego adresu e-mail przez użycie pojedynczego logowania, aby potwierdzić swoją tożsamość.", "Single Sign On": "Pojedyncze logowanie", - "Confirm adding this phone number by using Single Sign On to prove your identity.": "Potwierdź dodanie tego numeru telefonu przez użycie pojedynczego logowania, aby potwierdzić swoją tożsamość." + "Confirm adding this phone number by using Single Sign On to prove your identity.": "Potwierdź dodanie tego numeru telefonu przez użycie pojedynczego logowania, aby potwierdzić swoją tożsamość.", + "Learn More": "Dowiedz się więcej", + "Light": "Jasny", + "Dark": "Ciemny", + "Font size": "Rozmiar czcionki", + "People": "Ludzie", + "Appearance": "Wygląd", + "Show rooms with unread messages first": "Pokazuj najpierw pokoje z nieprzeczytanymi wiadomościami", + "Show previews of messages": "Pokazuj podglądy wiadomości", + "Sort by": "Sortuj według", + "Activity": "Aktywności", + "A-Z": "A-Z", + "Notification options": "Opcje powiadomień", + "Leave Room": "Opuść pokój", + "Favourited": "Ulubiony", + "This room is public": "Ten pokój jest publiczny", + "Unknown Command": "Nieznane polecenie", + "Unrecognised command: %(commandText)s": "Nieznane polecenie: %(commandText)s", + "You can use /help to list available commands. Did you mean to send this as a message?": "Możesz użyć /help aby wyświetlić listę dostępnych poleceń. Czy chciałeś(-aś) wysłać to jako wiadomość?", + "Hint: Begin your message with // to start it with a slash.": "Wskazówka: Rozpocznij swoją wiadomość od //, aby rozpocząć ją ukośnikiem.", + "Send as message": "Wyślij jako wiadomość", + "Remove %(count)s messages|other": "Usuń %(count)s wiadomości", + "Remove %(count)s messages|one": "Usuń 1 wiadomość", + "Switch to light mode": "Przełącz na tryb jasny", + "Switch to dark mode": "Przełącz na tryb ciemny", + "Switch theme": "Przełącz motyw", + "All settings": "Wszystkie ustawienia" } diff --git a/src/i18n/strings/pt_BR.json b/src/i18n/strings/pt_BR.json index 8e8b181f10..60beb2b726 100644 --- a/src/i18n/strings/pt_BR.json +++ b/src/i18n/strings/pt_BR.json @@ -9,7 +9,7 @@ "Are you sure you want to reject the invitation?": "Você tem certeza que deseja rejeitar este convite?", "Banned users": "Usuárias/os banidas/os", "Bans user with given id": "Banir usuários com o identificador informado", - "%(senderDisplayName)s changed the topic to \"%(topic)s\".": "%(senderDisplayName)s mudou o tópico para \"%(topic)s\".", + "%(senderDisplayName)s changed the topic to \"%(topic)s\".": "%(senderDisplayName)s mudou a descrição para \"%(topic)s\".", "Changes your display nickname": "Troca o seu apelido", "Click here to fix": "Clique aqui para resolver isso", "Commands": "Comandos", @@ -29,7 +29,7 @@ "Failed to leave room": "Falha ao tentar deixar a sala", "Failed to reject invitation": "Falha ao tentar rejeitar convite", "Failed to unban": "Não foi possível desfazer o banimento", - "Favourite": "Favorito", + "Favourite": "Favoritar", "Favourites": "Favoritos", "Filter room members": "Filtrar integrantes da sala", "Forget room": "Esquecer sala", @@ -66,7 +66,7 @@ "Privileged Users": "Usuárias/os privilegiadas/os", "Profile": "Perfil", "Reject invitation": "Rejeitar convite", - "Remove": "Remover", + "Remove": "Apagar", "Return to login screen": "Retornar à tela de login", "Room Colour": "Cores da sala", "Rooms": "Salas", @@ -262,7 +262,7 @@ "Options": "Opções", "%(brand)s collects anonymous analytics to allow us to improve the application.": "%(brand)s coleta informações anônimas de uso para nos permitir melhorar o sistema.", "Passphrases must match": "As senhas têm que ser iguais", - "Passphrase must not be empty": "A senha não pode estar vazia", + "Passphrase must not be empty": "A frase não pode estar em branco", "Export room keys": "Exportar chaves de sala", "Enter passphrase": "Entre com a senha", "Confirm passphrase": "Confirme a senha", @@ -275,7 +275,7 @@ "Failed to invite": "Falha ao enviar o convite", "Failed to invite the following users to the %(roomName)s room:": "Falha ao convidar as(os) seguintes usuárias(os) para a sala %(roomName)s:", "Confirm Removal": "Confirmar a remoção", - "Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.": "Você tem certeza que quer apagar este evento? Note que se você apaga o nome de uma sala ou uma mudança de tópico, esta ação não poderá ser desfeita.", + "Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.": "Tem certeza de que deseja apagar este evento? Observe que, se você apagar o nome ou alterar a descrição de uma sala, pode desfazer a alteração.", "Unknown error": "Erro desconhecido", "Incorrect password": "Senha incorreta", "Unable to restore session": "Não foi possível restaurar a sessão", @@ -311,17 +311,17 @@ "Invited": "Convidada(o)", "Results from DuckDuckGo": "Resultados de DuckDuckGo", "Verified key": "Chave verificada", - "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s removeu a imagem da sala.", + "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s removeu a foto da sala.", "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s alterou a imagem da sala %(roomName)s", - "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s alterou a imagem da sala para ", + "%(senderDisplayName)s changed the room avatar to ": "%(senderDisplayName)s alterou a foto da sala para ", "No Microphones detected": "Não foi detectado nenhum microfone", "No Webcams detected": "Não foi detectada nenhuma Webcam", "No media permissions": "Não há permissões de uso de vídeo/áudio no seu navegador", "You may need to manually permit %(brand)s to access your microphone/webcam": "Você talvez precise autorizar manualmente que o %(brand)s acesse seu microfone e webcam", - "Default Device": "Dispositivo padrão", + "Default Device": "Aparelho padrão", "Microphone": "Microfone", "Camera": "Câmera de vídeo", - "Add a topic": "Adicionar um tópico", + "Add a topic": "Adicionar uma descrição", "Anyone": "Qualquer pessoa", "Are you sure you want to leave the room '%(roomName)s'?": "Você tem certeza que deseja sair da sala '%(roomName)s'?", "Custom level": "Nível personalizado", @@ -400,7 +400,7 @@ "Edit": "Editar", "Unpin Message": "Desafixar Mensagem", "Add rooms to this community": "Adicionar salas na comunidade", - "The version of %(brand)s": "A Versão do %(brand)s", + "The version of %(brand)s": "A versão do %(brand)s", "The platform you're on": "A plataforma que você está usando", "Your language of choice": "O idioma que você selecionou", "Which officially provided instance you are using, if any": "Qual instância oficial você está usando, se for o caso", @@ -746,7 +746,7 @@ "Off": "Desativado", "Mentions only": "Apenas menções", "Wednesday": "Quarta", - "You can now return to your account after signing out, and sign in on other devices.": "Você pode retornar agora para a sua conta depois de fazer logout, e então fazer login em outros dispositivos.", + "You can now return to your account after signing out, and sign in on other devices.": "Agora você pode retornar à sua conta depois de sair, e fazer login em outros aparelhos.", "Enable email notifications": "Ativar notificações por email", "Event Type": "Tipo do Evento", "Download this file": "Baixar este arquivo", @@ -762,7 +762,7 @@ "Checking for an update...": "Verificando se há atualizações...", "Every page you use in the app": "Toda a página que você usa no aplicativo", "e.g. ": "ex. ", - "Your device resolution": "Sua resolução de dispositivo", + "Your device resolution": "A resolução do seu aparelho", "Call in Progress": "Chamada em andamento", "A call is currently being placed!": "Uma chamada está sendo feita atualmente!", "A call is already in progress!": "Uma chamada já está em andamento!", @@ -825,7 +825,7 @@ "Unable to load key backup status": "Não é possível carregar o status da chave de backup", "Backup version: ": "Versão do Backup: ", "Algorithm: ": "Algoritmo: ", - "This event could not be displayed": "O evento não pôde ser exibido", + "This event could not be displayed": "Este evento não pôde ser exibido", "Use a longer keyboard pattern with more turns": "Use um padrão de teclas em diferentes direções e sentido", "Share Link to User": "Compartilhar Link com Usuário", "This room has been replaced and is no longer active.": "Esta sala foi substituída e não está mais ativa.", @@ -865,9 +865,9 @@ "Failed to send logs: ": "Falha ao enviar registros: ", "Submit debug logs": "Submeter registros de depuração", "Debug logs contain application usage data including your username, the IDs or aliases of the rooms or groups you have visited and the usernames of other users. They do not contain messages.": "Os registros de depuração contêm dados de uso do aplicativo, incluindo seu nome de usuário, os IDs ou aliases das salas ou grupos que você visitou e os nomes de usuários de outros usuários. Eles não contêm mensagens.", - "Before submitting logs, you must create a GitHub issue to describe your problem.": "Antes de enviar os registros, você deve criar uma questão no GitHub para descrever seu problema.", + "Before submitting logs, you must create a GitHub issue to describe your problem.": "Antes de enviar os registros, você deve criar um bilhete de erro no GitHub para descrever seu problema.", "Unable to load commit detail: %(msg)s": "Não é possível carregar os detalhes do commit: %(msg)s", - "To avoid losing your chat history, you must export your room keys before logging out. You will need to go back to the newer version of %(brand)s to do this": "Para evitar perder seu histórico de bate-papo, você deve exportar as chaves do seu quarto antes de fazer logout. Você precisará voltar para a versão mais recente do %(brand)s para fazer isso", + "To avoid losing your chat history, you must export your room keys before logging out. You will need to go back to the newer version of %(brand)s to do this": "Para evitar perder seu histórico de bate-papo, você deve exportar as chaves da sua sala antes de se desconectar. Para fazer isso, você precisará retornar na versão mais atual do %(brand)s", "Incompatible Database": "Banco de dados incompatível", "Continue With Encryption Disabled": "Continuar com criptografia desativada", "This will make your account permanently unusable. You will not be able to log in, and no one will be able to re-register the same user ID. This will cause your account to leave all rooms it is participating in, and it will remove your account details from your identity server. This action is irreversible.": "Isso tornará sua conta permanentemente inutilizável. Você não poderá efetuar login e ninguém poderá registrar novamente o mesmo ID de usuário. Isso fará com que sua conta deixe todas as salas nas quais está participando e removerá os detalhes da sua conta do seu servidor de identidade. Esta ação é irreversível.", @@ -933,7 +933,7 @@ "You can't send any messages until you review and agree to our terms and conditions.": "Você não pode enviar nenhuma mensagem até revisar e concordar com nossos termos e condições.", "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. Please contact your service administrator to continue using the service.": "Sua mensagem não foi enviada porque este homeserver atingiu seu Limite de usuário ativo mensal. Por favor, entre em contato com o seu administrador de serviços para continuar usando o serviço.", "Your message wasn't sent because this homeserver has exceeded a resource limit. Please contact your service administrator to continue using the service.": "Sua mensagem não foi enviada porque este homeserver excedeu o limite de recursos. Por favor, entre em contato com o seu administrador de serviços para continuar usando o serviço.", - "If you've submitted a bug via GitHub, debug logs can help us track down the problem. Debug logs contain application usage data including your username, the IDs or aliases of the rooms or groups you have visited and the usernames of other users. They do not contain messages.": "Se você enviou um bug por meio do GitHub, os logs de depuração podem nos ajudar a rastrear o problema. Os logs de depuração contêm dados de uso do aplicativo, incluindo seu nome de usuário, os IDs ou aliases das salas ou grupos que você visitou e os nomes de usuários de outros usuários. Eles não contêm mensagens.", + "If you've submitted a bug via GitHub, debug logs can help us track down the problem. Debug logs contain application usage data including your username, the IDs or aliases of the rooms or groups you have visited and the usernames of other users. They do not contain messages.": "Se você enviou um bug por meio do GitHub, os logs de depuração podem nos ajudar a rastrear o problema. Os logs de depuração contêm dados de uso do aplicativo, incluindo seu nome de usuário, os IDs ou apelidos das salas ou grupos que você visitou e os nomes de usuários de outros usuários. Eles não contêm mensagens.", "Legal": "Legal", "No Audio Outputs detected": "Nenhuma saída de áudio detectada", "Audio Output": "Saída de áudio", @@ -945,7 +945,7 @@ "Sign in with single sign-on": "Entre com o logon único", "That matches!": "Isto corresponde!", "That doesn't match.": "Isto não corresponde.", - "Go back to set it again.": "Volte e configure novamente.", + "Go back to set it again.": "Voltar para configurar novamente.", "Download": "Baixar", "Print it and store it somewhere safe": "Imprima-o e armazene-o em algum lugar seguro", "Save it on a USB key or backup drive": "Salve isto em uma chave USB ou unidade de backup", @@ -968,8 +968,8 @@ "Invite anyway": "Convide mesmo assim", "Whether or not you're logged in (we don't record your username)": "Se você está logado ou não (não gravamos seu nome de usuário)", "Upgrades a room to a new version": "Atualiza uma sala para uma nova versão", - "Gets or sets the room topic": "Obtém ou define o tópico da sala", - "This room has no topic.": "Esta sala não tem assunto.", + "Gets or sets the room topic": "Consultar ou definir a descrição da sala", + "This room has no topic.": "Esta sala não tem descrição.", "Sets the room name": "Define o nome da sala", "Group & filter rooms by custom tags (refresh to apply changes)": "Agrupar e filtrar salas por tags personalizadas (atualize para aplicar as alterações)", "Render simple counters in room header": "Renderizar contadores simples no cabeçalho da sala", @@ -1127,14 +1127,1027 @@ "Room version:": "Versão da sala:", "Developer options": "Opções de desenvolvedor", "Room Addresses": "Endereços da sala", - "Change room avatar": "Alterar avatar da sala", + "Change room avatar": "Alterar a foto da sala", "Change room name": "Alterar nome da sala", "Change main address for the room": "Alterar o endereço principal da sala", "Change history visibility": "Alterar a visibilidade do histórico", "Change permissions": "Alterar permissões", - "Change topic": "Alterar o tópico", + "Change topic": "Alterar a descrição", "Modify widgets": "Modificar widgets", "Default role": "Papel padrão", "Send messages": "Enviar mensagens", - "Invite users": "Convidar usuários" + "Invite users": "Convidar usuários", + "Use Single Sign On to continue": "Use \"Single Sign On\" para continuar", + "Confirm adding this email address by using Single Sign On to prove your identity.": "Confirme a inclusão deste endereço de correio eletrônico usando o Single Sign On para comprovar sua identidade.", + "Single Sign On": "Autenticação Única", + "Confirm adding email": "Confirmar a inclusão de email", + "Click the button below to confirm adding this email address.": "Clique no botão abaixo para confirmar a adição deste endereço de email.", + "Confirm": "Confirmar", + "Add Email Address": "Adicionar endereço de email", + "Confirm adding phone number": "Confirmar adição de número de telefone", + "Add Phone Number": "Adicionar número de telefone", + "Whether you're using %(brand)s on a device where touch is the primary input mechanism": "Se estiver usando %(brand)s em um aparelho onde touch é o mecanismo primário de entrada de dados", + "Whether or not you're using the 'breadcrumbs' feature (avatars above the room list)": "Se você está usando ou não a funcionalidade 'breadcrumbs' (fotos acima da lista de salas)", + "Whether you're using %(brand)s as an installed Progressive Web App": "Se estiver usando %(brand)s como uma Progressive Web App (PWA)", + "Your user agent": "Seu agente de usuária(o)", + "Call failed due to misconfigured server": "A chamada caiu por conta de má configuração no servidor", + "Please ask the administrator of your homeserver (%(homeserverDomain)s) to configure a TURN server in order for calls to work reliably.": "Por favor, peça ao administrador do seu servidor (%(homeserverDomain)s) para configurar um servidor TURN, de modo que as chamadas funcionem de maneira estável.", + "Alternatively, you can try to use the public server at turn.matrix.org, but this will not be as reliable, and it will share your IP address with that server. You can also manage this in Settings.": "Alternativamente, você pode tentar usar o servidor público em turn.matrix.org. No entanto, ele não é tão confiável e compartilhará o seu IP com esse servidor. Você também pode configurar isso nas Configurações.", + "Try using turn.matrix.org": "Tente utilizar turn.matrix.org", + "Replying With Files": "Responder com arquivos", + "At this time it is not possible to reply with a file. Would you like to upload this file without replying?": "Momentaneamente, não é possível responder com um arquivo. Você quer fazer o envio deste arquivo sem responder a mensagem?", + "The file '%(fileName)s' failed to upload.": "O envio do arquivo '%(fileName)s' falhou.", + "The server does not support the room version specified.": "O servidor não suporta a versão da sala especificada.", + "Cancel entering passphrase?": "Cancelar a introdução da frase de senha?", + "Are you sure you want to cancel entering passphrase?": "Tem certeza que quer cancelar a introdução da frase de senha?", + "Go Back": "Voltar", + "Setting up keys": "Configurar chaves", + "Name or Matrix ID": "Nome ou ID Matrix", + "Room name or address": "Nome ou endereço da sala", + "Identity server has no terms of service": "O servidor de identidade não tem termos de serviço", + "This action requires accessing the default identity server to validate an email address or phone number, but the server does not have any terms of service.": "Esta ação requer acesso ao servidor de identidade padrão para poder validar um endereço de email ou número de telefone, mas este servidor não tem nenhum termo de uso.", + "Only continue if you trust the owner of the server.": "Continue apenas se você confia em quem possui este servidor.", + "Trust": "Confiança", + "%(name)s is requesting verification": "%(name)s está solicitando verificação", + "Use your account to sign in to the latest version": "Use sua conta para logar na última versão", + "We’re excited to announce Riot is now Element": "Estamos muito felizes em anunciar que Riot agora é Element", + "Riot is now Element!": "Riot agora é Element!", + "Learn More": "Saiba mais", + "Sign In or Create Account": "Faça login ou crie uma conta", + "Use your account or create a new one to continue.": "Use sua conta ou crie uma nova para continuar.", + "Create Account": "Criar conta", + "Sign In": "Entrar", + "Custom (%(level)s)": "Personalizado (%(level)s)", + "Messages": "Mensagens", + "Actions": "Ações", + "Other": "Outros", + "Sends a message as plain text, without interpreting it as markdown": "Envia uma mensagem como texto puro, sem interpretá-la como markdown", + "Sends a message as html, without interpreting it as markdown": "Envia uma mensagem como HTML, sem interpretá-la como markdown", + "You do not have the required permissions to use this command.": "Você não tem as permissões necessárias para usar este comando.", + "Error upgrading room": "Erro atualizando a sala", + "Double check that your server supports the room version chosen and try again.": "Verifique mais uma ver se seu servidor suporta a versão de sala escolhida e tente novamente.", + "Changes the avatar of the current room": "Altera a imagem da sala atual", + "Changes your avatar in this current room only": "Muda sua imagem de perfil apenas nesta sala", + "Changes your avatar in all rooms": "Muda sua imagem de perfil em todas as salas", + "Failed to set topic": "Não foi possível definir a descrição", + "Use an identity server": "Usar um servidor de identidade", + "Use an identity server to invite by email. Manage in Settings.": "Use um servidor de identidade para convidar pessoas por email. Gerencie nas Configurações.", + "Joins room with given address": "Entra em uma sala com o endereço fornecido", + "Unrecognised room address:": "Endereço de sala não reconhecido:", + "Unbans user with given ID": "Desfaz o banimento de usuária(o) com ID definido", + "Command failed": "O comando falhou", + "Could not find user in room": "Não encontrei este(a) usuário(a) na sala", + "Adds a custom widget by URL to the room": "Adiciona um widget personalizado por URL na sala", + "Please supply a widget URL or embed code": "Por favor, forneça uma URL de widget ou código de integração", + "Please supply a https:// or http:// widget URL": "Por favor, forneça uma URL de widget com https:// ou http://", + "You cannot modify widgets in this room.": "Você não pode modificar widgets nesta sala.", + "Verifies a user, session, and pubkey tuple": "Verifica um(a) usuário(a), e a tupla de chave pública", + "Unknown (user, session) pair:": "Par (usuária(o), sessão) desconhecido:", + "Session already verified!": "Sessão já verificada!", + "WARNING: Session already verified, but keys do NOT MATCH!": "ATENÇÃO: Sessão já verificada, mas as chaves NÃO SE CORRESPONDEM!", + "WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and session %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!": "ATENÇÃO: A VERIFICAÇÃO DA CHAVE FALHOU! A chave de assinatura para %(userId)s e sessão %(deviceId)s é \"%(fprint)s\", o que não corresponde à chave fornecida \"%(fingerprint)s\". Isso pode significar que suas comunicações estejam sendo interceptadas por terceiros!", + "The signing key you provided matches the signing key you received from %(userId)s's session %(deviceId)s. Session marked as verified.": "A chave de assinatura que você forneceu corresponde à chave de assinatura que você recebeu da sessão %(deviceId)s da(do) usuária(o) %(userId)s. Esta sessão foi marcada como verificada.", + "Sends the given message coloured as a rainbow": "Envia a mensagem colorida como arco-íris", + "Sends the given emote coloured as a rainbow": "Envia o emoji colorido como um arco-íris", + "Displays list of commands with usages and descriptions": "Exibe a lista de comandos com usos e descrições", + "Displays information about a user": "Exibe informação sobre um(a) usuário(a)", + "Send a bug report with logs": "Envia um relatório de erros com os logs", + "Opens chat with the given user": "Abre um chat com determinada pessoa", + "Sends a message to the given user": "Envia uma mensagem com determinada pessoa", + "%(senderName)s made no change.": "%(senderName)s não fez nenhuma alteração.", + "%(senderDisplayName)s changed the room name from %(oldRoomName)s to %(newRoomName)s.": "%(senderDisplayName)s alterou o nome da sala de %(oldRoomName)s para %(newRoomName)s.", + "%(senderName)s added the alternative addresses %(addresses)s for this room.|other": "%(senderName)s adicionou os endereços alternativos %(addresses)s para esta sala.", + "%(senderName)s added the alternative addresses %(addresses)s for this room.|one": "%(senderName)s adicionou o endereço alternativo %(addresses)s para esta sala.", + "%(senderName)s removed the alternative addresses %(addresses)s for this room.|other": "%(senderName)s removeu os endereços alternativos %(addresses)s para esta sala.", + "%(senderName)s removed the alternative addresses %(addresses)s for this room.|one": "%(senderName)s removeu o endereço alternativo %(addresses)s para esta sala.", + "%(senderName)s changed the alternative addresses for this room.": "%(senderName)s alterou os endereços alternativos desta sala.", + "%(senderName)s changed the main and alternative addresses for this room.": "%(senderName)s alterou os endereços principal e alternativos para esta sala.", + "%(senderName)s changed the addresses for this room.": "%(senderName)s alterou os endereços desta sala.", + "%(senderName)s placed a voice call.": "%(senderName)s iniciou uma chamada de voz.", + "%(senderName)s placed a voice call. (not supported by this browser)": "%(senderName)s iniciou uma chamada de voz. (não suportada por este navegador)", + "%(senderName)s placed a video call.": "%(senderName)s iniciou uma chamada de vídeo.", + "%(senderName)s placed a video call. (not supported by this browser)": "%(senderName)s iniciou uma chamada de vídeo. (não suportada por este navegador)", + "%(senderName)s revoked the invitation for %(targetDisplayName)s to join the room.": "%(senderName)s cancelou o convite a %(targetDisplayName)s para entrar na sala.", + "%(senderName)s removed the rule banning users matching %(glob)s": "%(senderName)s removeu a regra que bane usuárias(os) que correspondem a %(glob)s", + "%(senderName)s removed the rule banning rooms matching %(glob)s": "%(senderName)s removeu a regra que bane salas que correspondem a %(glob)s", + "%(senderName)s removed the rule banning servers matching %(glob)s": "%(senderName)s removeu a regra que bane servidores que correspondem a %(glob)s", + "%(senderName)s removed a ban rule matching %(glob)s": "%(senderName)s removeu uma regra de banimento correspondendo a %(glob)s", + "%(senderName)s updated an invalid ban rule": "%(senderName)s atualizou uma regra de banimento inválida", + "%(senderName)s updated the rule banning users matching %(glob)s for %(reason)s": "%(senderName)s atualizou a regra de banimento de usuárias(os) correspondendo a %(glob)s por %(reason)s", + "%(senderName)s updated the rule banning rooms matching %(glob)s for %(reason)s": "%(senderName)s atualizou a regra banindo salas correspondendo a %(glob)s por %(reason)s", + "%(senderName)s updated the rule banning servers matching %(glob)s for %(reason)s": "%(senderName)s atualizou a regra banindo servidores correspondendo a %(glob)s por %(reason)s", + "%(senderName)s updated a ban rule matching %(glob)s for %(reason)s": "%(senderName)s atualizou uma regra de banimento correspondendo a %(glob)s por %(reason)s", + "%(senderName)s created a rule banning users matching %(glob)s for %(reason)s": "%(senderName)s criou uma regra banindo usuárias(os) correspondentes a %(glob)s por %(reason)s", + "%(senderName)s created a rule banning rooms matching %(glob)s for %(reason)s": "%(senderName)s criou uma regra banindo salas correspondendo a %(glob)s por %(reason)s", + "%(senderName)s created a rule banning servers matching %(glob)s for %(reason)s": "%(senderName)s criou uma regra banindo servidores correspondendo a %(glob)s por %(reason)s", + "%(senderName)s created a ban rule matching %(glob)s for %(reason)s": "%(senderName)s criou uma regra de banimento correspondendo a %(glob)s por %(reason)s", + "%(senderName)s changed a rule that was banning users matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s alterou uma regra que estava banindo usuárias(os) correspondendo a %(oldGlob)s para corresponder a %(newGlob)s por %(reason)s", + "%(senderName)s changed a rule that was banning rooms matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s alterou uma regra que estava banindo salas correspondendo a %(oldGlob)s para corresponder a %(newGlob)s por %(reason)s", + "%(senderName)s changed a rule that was banning servers matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s alterou uma regra que estava banindo servidores correspondendo a %(oldGlob)s para corresponder a %(newGlob)s por %(reason)s", + "%(senderName)s updated a ban rule that was matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s alterou uma regra de banimento correspondendo a %(oldGlob)s para corresponder a %(newGlob)s por %(reason)s", + "Light": "Claro", + "Dark": "Escuro", + "You signed in to a new session without verifying it:": "Você entrou em uma nova sessão sem verificá-la:", + "Verify your other session using one of the options below.": "Verifique suas outras sessões usando uma das opções abaixo.", + "%(name)s (%(userId)s) signed in to a new session without verifying it:": "%(name)s (%(userId)s) entrou em uma nova sessão sem verificá-la:", + "Ask this user to verify their session, or manually verify it below.": "Peça a esta(e) usuária(o) para verificar sua sessão, ou verifiquem manualmente abaixo.", + "Not Trusted": "Não confiável", + "Manually Verify by Text": "Verificada manualmente por texto", + "Interactively verify by Emoji": "Verificar interativamente por emojis", + "Done": "Feito", + "Cannot reach homeserver": "Não consigo acessar o servidor", + "Ensure you have a stable internet connection, or get in touch with the server admin": "Verifique se está com uma conexão de internet estável, ou entre em contato com os administradores do servidor", + "Your %(brand)s is misconfigured": "O %(brand)s está mal configurado", + "Ask your %(brand)s admin to check your config for incorrect or duplicate entries.": "Peça aos administradores do %(brand)s que verifique suas configurações por entradas incorretas ou duplicadas.", + "Cannot reach identity server": "Não consigo acessar o servidor de identidade", + "You can register, but some features will be unavailable until the identity server is back online. If you keep seeing this warning, check your configuration or contact a server admin.": "Você pode se registrar, mas algumas funcionalidades não estarão disponíveis até que o servidor de identidade esteja de volta online. Se você continuar vendo este alerta, verifique sua configuração ou entre em contato com um dos administradores do servidor.", + "You can reset your password, but some features will be unavailable until the identity server is back online. If you keep seeing this warning, check your configuration or contact a server admin.": "Você pode trocar sua senha, mas algumas das funcionalidades não estarão mais disponíveis até que o servidor de identidade esteja de volta ao ar. Se você seguir vendo este alerta, verifique suas configurações ou entre em contato com um dos administradores do servidor.", + "You can log in, but some features will be unavailable until the identity server is back online. If you keep seeing this warning, check your configuration or contact a server admin.": "Você pode fazer login, mas algumas funcionalidades estarão indisponíveis até que o servidor de identidade estiver de volta. Se você continuar vendo esta mensagem, verifique suas configurações ou entre em contato com os administradores do servidor.", + "No homeserver URL provided": "Nenhuma URL de provedor fornecida", + "Unexpected error resolving homeserver configuration": "Erro inesperado buscando a configuração do servidor", + "Unexpected error resolving identity server configuration": "Erro inesperado buscando a configuração do servidor de identidade", + "The message you are trying to send is too large.": "A mensagem que você está tentando enviar é muito grande.", + "a few seconds ago": "há alguns segundos", + "about a minute ago": "há aproximadamente um minuto", + "%(num)s minutes ago": "há %(num)s minutos", + "about an hour ago": "há aproximadamente uma hora", + "%(num)s hours ago": "há %(num)s horas", + "about a day ago": "há aproximadamente um dia", + "%(num)s days ago": "há %(num)s dias", + "a few seconds from now": "dentro de alguns segundos", + "about a minute from now": "dentro de aproximadamente um minuto", + "%(num)s minutes from now": "dentro de %(num)s minutos", + "about an hour from now": "dentro de aproximadamente uma hora", + "%(num)s hours from now": "dentro de %(num)s horas", + "about a day from now": "dentro de aproximadamente um dia", + "%(num)s days from now": "dentro de %(num)s dias", + "%(name)s (%(userId)s)": "%(name)s (%(userId)s)", + "The user's homeserver does not support the version of the room.": "O servidor desta(e) usuária(o) não suporta a versão desta sala.", + "Help us improve %(brand)s": "Ajude-nos a melhorar %(brand)s", + "Send anonymous usage data which helps us improve %(brand)s. This will use a cookie.": "Envie dados anônimos de uso que nos ajudam a melhorar o %(brand)s. Isso necessitará do uso de um cookie.", + "I want to help": "Quero ajudar", + "Review where you’re logged in": "Revisar onde você está logada(o)", + "Verify all your sessions to ensure your account & messages are safe": "Verifique todas as suas sessões para garantir que sua conta e mensagens estão seguras", + "Review": "Revisar", + "Later": "Mais tarde", + "Your homeserver has exceeded its user limit.": "Seu servidor ultrapassou seu limite de usuárias(os).", + "Your homeserver has exceeded one of its resource limits.": "Seu servidor excedeu um de seus limites de recursos.", + "Contact your server admin.": "Entre em contato com sua(seu) administrador(a) do servidor.", + "Ok": "Ok", + "Set password": "Definir senha", + "To return to your account in future you need to set a password": "Para retornar à sua conta no futuro, você precisa definir uma senha", + "Set up encryption": "Configurar a criptografia", + "Encryption upgrade available": "Atualização de criptografia disponível", + "Verify this session": "Verificar esta sessão", + "Upgrade": "Atualizar", + "Verify": "Verificar", + "Verify yourself & others to keep your chats safe": "Verifique a sua conta e as dos seus contatos, para manter suas conversas seguras", + "Other users may not trust it": "Outras(os) usuárias(os) podem não confiar nela", + "New login. Was this you?": "Novo login. Foi você?", + "Verify the new login accessing your account: %(name)s": "Verifique o novo login acessando sua conta: %(name)s", + "Restart": "Reiniciar", + "Upgrade your %(brand)s": "Atualize o seu %(brand)s", + "A new version of %(brand)s is available!": "Uma nova versão do %(brand)s está disponível!", + "Guest": "Convidada(o)", + "You joined the call": "Você entrou na chamada", + "%(senderName)s joined the call": "%(senderName)s entrou na chamada", + "Call in progress": "Chamada em andamento", + "You left the call": "Você abandonou a chamada", + "%(senderName)s left the call": "%(senderName)s saiu da chamada", + "Call ended": "Chamada encerrada", + "You started a call": "Você iniciou uma chamada", + "%(senderName)s started a call": "%(senderName)s iniciou uma chamada", + "Waiting for answer": "Esperando por uma resposta", + "%(senderName)s is calling": "%(senderName)s está chamando", + "* %(senderName)s %(emote)s": "* %(senderName)s %(emote)s", + "%(senderName)s: %(message)s": "%(senderName)s: %(message)s", + "%(senderName)s: %(reaction)s": "%(senderName)s: %(reaction)s", + "%(senderName)s: %(stickerName)s": "%(senderName)s: %(stickerName)s", + "New spinner design": "Novo design do spinner", + "Multiple integration managers": "Múltiplos gestores de integrações", + "Try out new ways to ignore people (experimental)": "Tente novas maneiras de ignorar pessoas (experimental)", + "Support adding custom themes": "Permite adicionar temas personalizados", + "Enable advanced debugging for the room list": "Habilitar análise (debugging) avançada para a lista de salas", + "Show info about bridges in room settings": "Exibir informações sobre bridges nas configurações das salas", + "Font size": "Tamanho da fonte", + "Use custom size": "Usar tamanho personalizado", + "Use a more compact ‘Modern’ layout": "Usar um layout mais compacto 'Moderno'", + "Show typing notifications": "Mostrar notificações de digitação", + "Match system theme": "Se adaptar ao tema do sistema", + "Use a system font": "Usar uma fonte do sistema", + "System font name": "Nome da fonte do sistema", + "Never send encrypted messages to unverified sessions from this session": "Nunca envie mensagens criptografadas para sessões não verificadas desta sessão", + "Never send encrypted messages to unverified sessions in this room from this session": "Nunca envie mensagens criptografadas para sessões não verificadas nesta sala, desta sessão", + "Order rooms by name": "Ordenar salas por nome", + "Show rooms with unread notifications first": "Mostrar primeiro as salas com notificações não lidas", + "Show shortcuts to recently viewed rooms above the room list": "Mostrar atalhos para salas recentemente visualizadas acima da lista de salas", + "Show hidden events in timeline": "Mostrar eventos ocultos na timeline", + "Low bandwidth mode": "Modo de baixo uso de internet", + "Allow fallback call assist server turn.matrix.org when your homeserver does not offer one (your IP address would be shared during a call)": "Permitir a assistência do servidor de chamadas reserva turn.matrix.org quando seu servidor não oferecer este serviço (seu endereço IP será transmitido quando você ligar)", + "Send read receipts for messages (requires compatible homeserver to disable)": "Enviar confirmação de leitura para mensagens (necessita um servidor compatível para desativar)", + "Show previews/thumbnails for images": "Mostrar miniaturas e resumos para imagens", + "Enable message search in encrypted rooms": "Ativar busca de mensagens em salas criptografadas", + "How fast should messages be downloaded.": "Com qual rapidez as mensagens devem ser baixadas.", + "Manually verify all remote sessions": "Verificar manualmente todas as sessões remotas", + "IRC display name width": "Largura do nome IRC", + "Enable experimental, compact IRC style layout": "Ativar o layout compacto IRC experimental", + "When rooms are upgraded": "Quando salas são atualizadas", + "My Ban List": "Minha lista de banimentos", + "This is your list of users/servers you have blocked - don't leave the room!": "Esta é a sua lista de usuárias(os)/servidores que você bloqueou - não saia da sala!", + "Unknown caller": "Pessoa desconhecida chamando", + "Incoming voice call": "Recebendo chamada de voz", + "Incoming video call": "Recebendo chamada de vídeo", + "Incoming call": "Recebendo chamada", + "Verify this session by completing one of the following:": "Verifique esta sessão completando um dos seguintes:", + "Scan this unique code": "Escaneie este código único", + "or": "ou", + "Compare unique emoji": "Compare um emoji único", + "Compare a unique set of emoji if you don't have a camera on either device": "Compare um conjunto único de emojis se você não tem uma câmera em nenhum dos dois aparelhos", + "Start": "Iniciar", + "Confirm the emoji below are displayed on both sessions, in the same order:": "Confirme que o emoji abaixo está sendo exibido nas duas sessões, na mesma ordem:", + "Verify this session by confirming the following number appears on its screen.": "Verifique esta sessão confirmando que o seguinte número aparece na sua tela.", + "Waiting for your other session, %(deviceName)s (%(deviceId)s), to verify…": "Esperando pela outra sessão, %(deviceName)s (%(deviceId)s), verificar…", + "Waiting for your other session to verify…": "Esperando sua outra sessão verificar…", + "Waiting for %(displayName)s to verify…": "Esperando por %(displayName)s verificar…", + "Cancelling…": "Cancelando…", + "They match": "São coincidentes", + "They don't match": "Elas não são correspondentes", + "To be secure, do this in person or use a trusted way to communicate.": "Para sua segurança, faça isso pessoalmente ou use uma forma confiável de comunicação.", + "Lock": "Cadeado", + "From %(deviceName)s (%(deviceId)s)": "De %(deviceName)s (%(deviceId)s)", + "Decline (%(counter)s)": "Recusar (%(counter)s)", + "Accept to continue:": "Aceitar para continuar:", + "Upload": "Enviar", + "This bridge was provisioned by .": "Esta ponte foi disponibilizada por .", + "This bridge is managed by .": "Esta ponte é gerida por .", + "Workspace: %(networkName)s": "Espaço de trabalho: %(networkName)s", + "Channel: %(channelName)s": "Canal: %(channelName)s", + "Show less": "Mostrar menos", + "Show more": "Mostrar mais", + "Changing password will currently reset any end-to-end encryption keys on all sessions, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "Ao mudar a senha, você apagará quaisquer chaves de criptografia ponta-a-ponta existentes em todas as sessões, fazendo com que o histórico de conversas criptografadas fique ilegível, a não ser que você exporte as salas das chaves criptografadas antes de mudar a senha e então as importe novamente depois. No futuro, isso será melhorado.", + "Your homeserver does not support cross-signing.": "Seu servidor não suporta assinatura cruzada.", + "Cross-signing and secret storage are enabled.": "Assinaturas cruzadas e armazenamento secreto estão habilitadas.", + "Your account has a cross-signing identity in secret storage, but it is not yet trusted by this session.": "Sua conta tem uma identidade de assinatura cruzada em um armazenamento secreto, mas ainda não é considerada confiável por esta sessão.", + "Cross-signing and secret storage are not yet set up.": "A assinatura cruzada e o armazenamento seguro ainda não foram configurados.", + "Reset cross-signing and secret storage": "Reinicializar a assinatura cruzada e o armazenamento secreto", + "Bootstrap cross-signing and secret storage": "Inicializar a assinatura cruzada e o armazenamento secreto", + "well formed": "bem formado", + "unexpected type": "tipo inesperado", + "Cross-signing public keys:": "Chaves públicas de assinatura cruzada:", + "in memory": "na memória", + "not found": "não encontradas", + "Cross-signing private keys:": "Chaves privadas de assinatura cruzada:", + "in secret storage": "em armazenamento secreto", + "Self signing private key:": "Chave privada auto-assinada:", + "cached locally": "armazenado localmente", + "not found locally": "não encontrado localmente", + "User signing private key:": "Chave privada de assinatura da(do) usuária(o):", + "Session backup key:": "Chave de cópia (backup) da sessão:", + "Secret storage public key:": "Chave pública do armazenamento secreto:", + "in account data": "nos dados de conta", + "Homeserver feature support:": "Funcionalidades suportadas pelo servidor:", + "exists": "existe", + "Your homeserver does not support session management.": "Seu servidor não suporta gerenciamento de sessões.", + "Unable to load session list": "Não foi possível carregar a lista de sessões", + "Confirm deleting these sessions by using Single Sign On to prove your identity.|other": "Confirme o apagamento destas sessões usando Single Sign On para comprovar sua identidade.", + "Confirm deleting these sessions by using Single Sign On to prove your identity.|one": "Confirme o apagamento desta sessão usando Single Sign On para comprovar sua identidade.", + "Confirm deleting these sessions": "Confirme o apagamento destas sessões", + "Click the button below to confirm deleting these sessions.|other": "Clique no botão abaixo para confirmar o apagamento destas sessões.", + "Click the button below to confirm deleting these sessions.|one": "Clique no botão abaixo para confirmar o apagamento desta sessão.", + "Delete sessions|other": "Apagar sessões", + "Delete sessions|one": "Apagar sessão", + "Delete %(count)s sessions|other": "Apagar %(count)s sessões", + "Delete %(count)s sessions|one": "Apagar %(count)s sessão", + "ID": "ID", + "Public Name": "Nome Público", + "Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.": "Verificar individualmente cada sessão usada por um(a) usuário(a) para marcá-la como confiável, sem confiar em aparelhos assinados com assinatura cruzada.", + "Securely cache encrypted messages locally for them to appear in search results, using ": "Armazene mensagens criptografadas localmente para que elas apareçam nas buscas, usando ", + " to store messages from ": " para armazenar mensagens de ", + "rooms.": "salas.", + "Manage": "Gerenciar", + "Securely cache encrypted messages locally for them to appear in search results.": "Armazene mensagens criptografadas de forma segura localmente para que possam aparecer nos resultados das buscas.", + "Enable": "Ativar", + "%(brand)s is missing some components required for securely caching encrypted messages locally. If you'd like to experiment with this feature, build a custom %(brand)s Desktop with search components added.": "%(brand)s não está com alguns dos componentes necessários para armazenar com segurança mensagens criptografadas localmente. Se você quer fazer testes com esta funcionalidade, construa uma versão Desktop do %(brand)s com componentes de busca ativos.", + "%(brand)s can't securely cache encrypted messages locally while running in a web browser. Use %(brand)s Desktop for encrypted messages to appear in search results.": "%(brand)s não consegue armazenar de forma segura as mensagens criptografadas localmente enquando funciona em um navegador web. Use %(brand)s Desktop para que mensagens criptografadas sejam exibidas nos resultados de buscas.", + "Connecting to integration manager...": "Conectando ao gestor de integrações...", + "Cannot connect to integration manager": "Não foi possível conectar ao gerenciador de integrações", + "The integration manager is offline or it cannot reach your homeserver.": "O gerenciador de integrações está offline ou não consegue acesso ao seu servidor.", + "This session is backing up your keys. ": "Esta sessão está fazendo a cópia (backup) das suas chaves. ", + "This session is not backing up your keys, but you do have an existing backup you can restore from and add to going forward.": "Esta sessão não está fazendo cópia (backup) de suas chaves, mas você tem uma cópia existente que pode restaurar e adicionar para continuar.", + "Connect this session to key backup before signing out to avoid losing any keys that may only be on this session.": "Conecte esta sessão à cópia de segurança (backup) das chaves antes de fazer logout para evitar perder quaisquer chaves que possam estar apenas nesta sessão.", + "Connect this session to Key Backup": "Conecte esta sessão à Cópia de Segurança (Backup) da Chave", + "not stored": "não armazenado", + "Backup has a valid signature from this user": "A cópia de segurança (backup) tem uma assinatura válida deste(a) usuário(a)", + "Backup has a invalid signature from this user": "A cópia de segurança (backup) tem uma assinatura inválida deste(a) usuário(a)", + "Backup has a signature from unknown user with ID %(deviceId)s": "A cópia de segurança tem uma assinatura de um(a) usuário desconhecido com ID %(deviceId)s", + "Backup has a signature from unknown session with ID %(deviceId)s": "A cópia de segurança tem uma assinatura de uma sessão desconhecida com ID %(deviceId)s", + "Backup has a valid signature from this session": "A cópia de segurança (backup) tem uma assinatura válida desta sessão", + "Backup has an invalid signature from this session": "A cópia de segurança (backup) tem uma assinatura inválida desta sessão", + "Backup has a valid signature from verified session ": "A cópia de segurança (backup) tem uma assinatura válida da sessão verificada ", + "Backup has a valid signature from unverified session ": "A cópia de segurança tem uma assinatura válida de uma sessão não verificada ", + "Backup has an invalid signature from verified session ": "A cópia de segurança tem uma assinatura inválida de uma sessão verificada ", + "Backup has an invalid signature from unverified session ": "A cópia de segurança (backup) tem uma assinatura inválida de uma sessão não verificada ", + "Backup is not signed by any of your sessions": "A cópia de segurança (backup) não foi assinada por nenhuma de suas sessões", + "This backup is trusted because it has been restored on this session": "Esta cópia de segurança (backup) é confiável, pois foi restaurada nesta sessão", + "Backup key stored: ": "Chave de segurança (backup) armazenada: ", + "Your keys are not being backed up from this session.": "Suas chaves não estão sendo copiadas desta sessão.", + "wait and try again later": "espere e tente novamente mais tarde", + "Please verify the room ID or address and try again.": "Por favor, verifique o ID ou endereço da sala e tente novamente.", + "Ignoring people is done through ban lists which contain rules for who to ban. Subscribing to a ban list means the users/servers blocked by that list will be hidden from you.": "É possível ignorar pessoas através de listas de banimento que contém regras sobre quem banir. Colocar alguém na lista de banimento significa que as pessoas ou servidores bloqueadas pela lista não serão visíveis por você.", + "Session key:": "Chave da sessão:", + "Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.": "O/a administrador/a desativou criptografia ponta-a-ponta por padrão em salas privadas e conversas diretas.", + "Manage the names of and sign out of your sessions below or verify them in your User Profile.": "Gerencie os nomes de suas sessões e saia das mesmas abaixo ou verifique-as no seu Perfil de Usuária(o).", + "A session's public name is visible to people you communicate with": "Um nome público de uma sessão é visível a pessoas com as quais você já se comunica", + "Enable room encryption": "Ativar criptografia nesta sala", + "Enable encryption?": "Ativar criptografia?", + "Once enabled, encryption for a room cannot be disabled. Messages sent in an encrypted room cannot be seen by the server, only by the participants of the room. Enabling encryption may prevent many bots and bridges from working correctly. Learn more about encryption.": "Uma vez ativada, a criptografia da sala não poderá ser desabilitada. Mensagens enviadas em uma sala criptografada não podem ser vistas pelo servidor, apenas pelas/os participantes da sala. Habilitar a criptografia poderá impedir que vários bots e bridges funcionem corretamente. Saiba mais sobre criptografia.", + "Encryption": "Criptografia", + "Once enabled, encryption cannot be disabled.": "Uma vez ativada, a criptografia não poderá ser desabilitada.", + "Encrypted": "Criptografada", + "Click the link in the email you received to verify and then click continue again.": "Clique no link no email que você recebeu para verificar e então clique novamente em continuar.", + "Verify the link in your inbox": "Verifique o link na sua caixa de emails", + "This room is end-to-end encrypted": "Esta sala é criptografada ponta-a-ponta", + "Your key share request has been sent - please check your other sessions for key share requests.": "Sua solicitação de compartilhamento de chaves foi enviada - por favor, verifique a existência de solicitações de compartilhamento de chaves em suas outras sessões .", + "Key share requests are sent to your other sessions automatically. If you rejected or dismissed the key share request on your other sessions, click here to request the keys for this session again.": "Solicitações de compartilhamento de chaves são enviadas para suas outras sessões automaticamente. Se você rejeitou ou ignorou a solicitação de compartilhamento de chaves em suas outras sessões, clique aqui para solicitar as chaves para esta sessão novamente.", + "If your other sessions do not have the key for this message you will not be able to decrypt them.": "Se suas outras sessões não possuem a chave para esta mensagem, você não será capaz de descriptografá-la.", + "Re-request encryption keys from your other sessions.": "Solicitar novamente as chaves de criptografia das suas outras sessões.", + "This message cannot be decrypted": "Esta mensagem não pode ser descriptografada", + "Encrypted by an unverified session": "Criptografada por uma sessão não verificada", + "Unencrypted": "Descriptografada", + "Encrypted by a deleted session": "Criptografada por uma sessão já apagada", + "The authenticity of this encrypted message can't be guaranteed on this device.": "A autenticidade desta mensagem criptografada não pode ser garantida neste aparelho.", + "People": "Pessoas", + "Create room": "Criar sala", + "Start chatting": "Começar a conversa", + "Try again later, or ask a room admin to check if you have access.": "Tente novamente mais tarde, ou peça a um(a) administrador(a) da sala para verificar se você tem acesso.", + "Never lose encrypted messages": "Nunca perca mensagens criptografadas", + "Messages in this room are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Mensagens nesta sala estão seguras com criptografia ponta-a-ponta. Apenas você e a(s) demais pessoa(s) desta sala têm a chave para ler estas mensagens.", + "Upgrading this room will shut down the current instance of the room and create an upgraded room with the same name.": "Atualizar esta sala irá fechar a instância atual da sala e criar uma sala atualizada com o mesmo nome.", + "Hint: Begin your message with // to start it with a slash.": "Dica: Inicie sua mensagem com // para iniciar com uma barra.", + "Start Verification": "Iniciar verificação", + "Messages in this room are end-to-end encrypted.": "Mensagens nesta sala são criptografadas ponta-a-ponta.", + "Messages in this room are not end-to-end encrypted.": "Mensagens nesta sala não são criptografadas ponta-a-ponta.", + "In encrypted rooms, your messages are secured and only you and the recipient have the unique keys to unlock them.": "Em salas criptografadas, suas mensagens estão seguras e apenas você e a pessoa que a recebe têm as chaves únicas que permitem a sua leitura.", + "Verify User": "Verificar usuária(o)", + "For extra security, verify this user by checking a one-time code on both of your devices.": "Para maior segurança, verifique esta(e) usuária(o) verificando um código único em ambos aparelhos.", + "You are about to remove %(count)s messages by %(user)s. This cannot be undone. Do you wish to continue?|other": "Você está a ponto de remover %(count)s mensagens de %(user)s. Isso não poderá ser desfeito. Quer continuar?", + "You are about to remove %(count)s messages by %(user)s. This cannot be undone. Do you wish to continue?|one": "Você está a ponto de remover 1 mensagem de %(user)s. Isso não poderá ser desfeito. Quer continuar?", + "This client does not support end-to-end encryption.": "Este cliente não suporte criptografia ponta-a-ponta.", + "The session you are trying to verify doesn't support scanning a QR code or emoji verification, which is what %(brand)s supports. Try with a different client.": "A sessão que você está tentando verificar não permite escanear QR code ou verificação via emojis, que é o que %(brand)s permite. Tente um cliente diferente.", + "Verify by scanning": "Verificar através de QR Code", + "If you can't scan the code above, verify by comparing unique emoji.": "Se você não consegue escanear o código acima, verifique comparando os emojis únicos.", + "Verify by comparing unique emoji.": "Verificar comparando emoji único.", + "Verify by emoji": "Verificar por emoji", + "Verify all users in a room to ensure it's secure.": "Verificar todas(os) as(os) usuárias(os) em uma sala para se certificar que ela é segura.", + "In encrypted rooms, verify all users to ensure it’s secure.": "Em salas criptografadas, verificar todas(os) as(os) usuárias(os) para garantir que elas são seguras.", + "Start verification again from the notification.": "Iniciar verificação novamente, após a notificação.", + "Start verification again from their profile.": "Iniciar a verificação novamente a partir do seu perfil.", + "Encryption enabled": "Criptografia habilitada", + "Messages in this room are end-to-end encrypted. Learn more & verify this user in their user profile.": "Mensagens nesta sala são criptografadas ponta-a-ponta. Saiba mais e verifique o este(a) usuário(a) em seu perfil.", + "Encryption not enabled": "Criptografia não habilitada", + "The encryption used by this room isn't supported.": "A criptografia usada nesta sala não é suportada.", + "%(name)s wants to verify": "%(name)s deseja verificar", + "Smileys & People": "Emoticons e Pessoas", + "Widgets do not use message encryption.": "Widgets não usam criptografia de mensagens.", + "Please create a new issue on GitHub so that we can investigate this bug.": "Por favor, crie um novo bilhete de erro no GitHub para que possamos investigar esta falha.", + "Enter the name of a new server you want to explore.": "Entre com o nome do novo servidor que você quer explorar.", + "Please tell us what went wrong or, better, create a GitHub issue that describes the problem.": "Por favor, diga-nos o que aconteceu de errado ou, ainda melhor, crie um bilhete de erro no GitHub que descreva o problema.", + "Clearing all data from this session is permanent. Encrypted messages will be lost unless their keys have been backed up.": "Apagar todos os dados desta sessão é uma ação permanente. Mensagens criptografadas serão perdidas, a não ser que suas chaves tenham sido copiadas para o backup.", + "Set a room address to easily share your room with other people.": "Defina um endereço de sala para facilmente compartilhar sua sala com outras pessoas.", + "You can’t disable this later. Bridges & most bots won’t work yet.": "Você não poderá desabilitar depois. Pontes e a maioria dos bots não funcionarão no momento.", + "Enable end-to-end encryption": "Ativar criptografia ponta-a-ponta", + "Create a public room": "Criar uma sala pública", + "Create a private room": "Criar uma sala privada", + "Block users on other matrix homeservers from joining this room (This setting cannot be changed later!)": "Impedir usuárias(os) de outros servidores matrix de entrar nesta sala (Esta configuração não poderá ser desfeita depois!)", + "You've previously used a newer version of %(brand)s with this session. To use this version again with end to end encryption, you will need to sign out and back in again.": "Você usou antes uma versão mais nova do %(brand)s com esta sessão. Para usar esta versão novamente, com criptografia ponta-a-ponta, você terá que sair e entrar novamente.", + "Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.": "Verificar esta(e) usuária(o) para marcá-la(o) como confiável. Usuárias(os) de confiança dão a você mais tranquilidade mental quando estiver usando mensagens criptografadas.", + "Verify this device to mark it as trusted. Trusting this device gives you and other users extra peace of mind when using end-to-end encrypted messages.": "Verifique este aparelho para marcá-lo como confiável. Confiar neste aparelho dá a você e às(aos) outras(os) usuárias(os) maior tranquilidade mental quando estiverem usando mensagens criptografadas.", + "We couldn't create your DM. Please check the users you want to invite and try again.": "Não conseguimos criar sua mensagem direta. Por favor, verifique as(os) usuárias(os) que você quer convidar e tente novamente.", + "Start a conversation with someone using their name, username (like ) or email address.": "Comece uma conversa com alguém usando seu nome, nome de usuária (como ) ou endereço de email.", + "a new master key signature": "uma nova chave mestra de assinatura", + "a new cross-signing key signature": "uma nova chave de assinatura cruzada", + "a key signature": "uma assinatura de chave", + "I don't want my encrypted messages": "Não quero minhas mensagens criptografadas", + "You'll lose access to your encrypted messages": "Você perderá acesso às suas mensagens criptografadas", + "Session key": "Chave da sessão", + "Verify session": "Verificar sessão", + "We recommend you change your password and recovery key in Settings immediately": "Nós recomendamos que você altere imediatamente sua senha e chave de recuperação nas Configurações", + "Use this session to verify your new one, granting it access to encrypted messages:": "Use esta sessão para verificar a sua nova sessão, dando a ela acesso às mensagens criptografadas:", + "You’re already signed in and good to go here, but you can also grab the latest versions of the app on all platforms at element.io/get-started.": "Você já está logada(o) e pode começar a usar à vontade, mas você também pode buscar pelas últimas versões do app em todas as plataformas em element.io/get-started.", + "Go to Element": "Ir a Element", + "We’re excited to announce Riot is now Element!": "Estamos muito felizes de anunciar que agora Riot é Element!", + "Learn more at element.io/previously-riot": "Saiba mais em element.io/previously-riot", + "To help avoid duplicate issues, please view existing issues first (and add a +1) or create a new issue if you can't find it.": "Para evitar a duplicação de registro de problemas, por favor veja os problemas existentes antes e adicione um +1, ou então crie um novo item se seu problema ainda não foi reportado.", + "Reporting this message will send its unique 'event ID' to the administrator of your homeserver. If messages in this room are encrypted, your homeserver administrator will not be able to read the message text or view any files or images.": "Reportar esta mensagem enviará o seu 'event ID' único para o/a administrador/a do seu Homeserver. Se as mensagens nesta sala são criptografadas, o/a administrador/a não conseguirá ler o texto da mensagem nem ver nenhuma imagem ou arquivo.", + "Sign out and remove encryption keys?": "Fazer logout e remover as chaves de criptografia?", + "Some session data, including encrypted message keys, is missing. Sign out and sign in to fix this, restoring keys from backup.": "Alguns dados de sessão, incluindo chaves de mensagens criptografadas, estão faltando. Faça logout e entre novamente para resolver isso, restaurando as chaves do backup.", + "Verify other session": "Verificar outra sessão", + "A widget would like to verify your identity": "Um Widget quer verificar sua identidade", + "A widget located at %(widgetUrl)s would like to verify your identity. By allowing this, the widget will be able to verify your user ID, but not perform actions as you.": "Um widget localizado em %(widgetUrl)s deseja verificar sua identidade. Permitindo isso, o widget poderá verificar seu ID de usuária(o), mas não poderá fazer permissões passando-se por você.", + "Wrong Recovery Key": "Chave de recuperação errada", + "Invalid Recovery Key": "Chave de recuperação inválida", + "Unable to access secret storage. Please verify that you entered the correct recovery passphrase.": "Não foi possível acessar o armazenamento secreto. Por favor, verifique que você entrou com a frase de recuperação correta.", + "Enter your Security Phrase or to continue.": "Entre com sua Frase de Segurança ou para continuar.", + "Security Key": "Chave de Segurança", + "Use your Security Key to continue.": "Use sua Chave de Segurança para continuar.", + "Recovery key mismatch": "A chave de segurança não corresponde à correta", + "Backup could not be decrypted with this recovery key: please verify that you entered the correct recovery key.": "O backup não pôde ser descriptografado com esta chave de recuperação: por favor, verifique se você entrou com a chave de recuperação correta.", + "Backup could not be decrypted with this recovery passphrase: please verify that you entered the correct recovery passphrase.": "O backup não pôde ser descriptografado com esta frase de recuperação: por favor, verifique se você entrou com a frase de recuperação correta.", + "Warning: you should only set up key backup from a trusted computer.": "Atenção: você só deve configurar a cópia de segurança (backup) das chaves em um computador de sua confiança.", + "Enter recovery key": "Entre com a chave de recuperação", + "Warning: You should only set up key backup from a trusted computer.": "Atenção: Você só deve configurar a cópia de segurança (backup) das chaves em um computador de sua confiança.", + "If you've forgotten your recovery key you can ": "Se você esqueceu sua chave de recuperação, pode ", + "Missing captcha public key in homeserver configuration. Please report this to your homeserver administrator.": "Está faltando a chave pública do captcha no Servidor (homeserver). Por favor, reporte isso aos(às) administradores(as) do servidor.", + "Enter the location of your Element Matrix Services homeserver. It may use your own domain name or be a subdomain of element.io.": "Entre com a localização do seu Servidor Matrix. Pode ser seu próprio domínio ou ser um subdomínio de element.io.", + "Create your Matrix account on %(serverName)s": "Criar sua conta Matrix em %(serverName)s", + "Create your Matrix account on ": "Crie sua conta Matrix em ", + "Welcome to %(appName)s": "Desejamos boas vindas ao %(appName)s", + "Liberate your communication": "Liberte sua comunicação", + "Send a Direct Message": "Envie uma mensagem direta", + "Explore Public Rooms": "Explore as salas públicas", + "Create a Group Chat": "Criar um chat de grupo", + "Explore rooms": "Explorar salas", + "Data from an older version of %(brand)s has been detected. This will have caused end-to-end cryptography to malfunction in the older version. End-to-end encrypted messages exchanged recently whilst using the older version may not be decryptable in this version. This may also cause messages exchanged with this version to fail. If you experience problems, log out and back in again. To retain message history, export and re-import your keys.": "Detectamos uma versão mais antiga do %(brand)s. Isso fará com que a criptografia ponta-a-ponta não funcione corretamente. Mensagens criptografadas ponta-a-ponta trocadas recentemente enquanto você usava a versão mais antiga talvez não sejam descriptografáveis nesta versão. Isso poderá também fazer com que mensagens trocadas nesta sessão falhem na outra. Se você experimentar problemas, por favor faça logout e entre novamente. Para manter o histórico de mensagens, exporte e reimporte suas chaves.", + "%(creator)s created and configured the room.": "%(creator)s criou e configurou esta sala.", + "If you can't find the room you're looking for, ask for an invite or Create a new room.": "Se você não consegue encontrar a sala que está buscando, peça para ser convidada(o) ou então crie uma sala nova.", + "Verify this login": "Verificar este login", + "Changing your password will reset any end-to-end encryption keys on all of your sessions, making encrypted chat history unreadable. Set up Key Backup or export your room keys from another session before resetting your password.": "Alterar a sua senha implicará na perda de quaisquer chaves de criptografia ponta-a-ponta existentes em todas as suas sessões, fazendo com que o histórico de mensagens criptografadas se torne ilegível. Faça uma cópia (backup) das suas chaves ou exporte as chaves de outra sessão antes de alterar sua senha.", + "Create account": "Criar conta", + "Create your account": "Criar sua conta", + "Use Recovery Key or Passphrase": "Use a Chave ou a Frase de Recuperação", + "Use Recovery Key": "Use a Chave de Recuperação", + "Confirm your identity by verifying this login from one of your other sessions, granting it access to encrypted messages.": "Confirme sua identidade através da verificação deste login em qualquer uma de suas outras sessões, garantindo a elas acesso a mensagens criptografadas.", + "Your new session is now verified. It has access to your encrypted messages, and other users will see it as trusted.": "Sua nova sessão está agora verificada. Ela tem acesso às suas mensagens criptografadas, e outras(os) usuárias(os) poderão ver esta sessão como confiável.", + "Without completing security on this session, it won’t have access to encrypted messages.": "Sem completar os procedimentos de segurança nesta sessão, você não terá acesso a mensagens criptografadas.", + "Regain access to your account and recover encryption keys stored in this session. Without them, you won’t be able to read all of your secure messages in any session.": "Recupere acesso à sua conta e restaure as chaves de criptografia armazenadas nesta sessão. Sem elas, você não conseguirá ler todas as suas mensagens seguras em nenhuma sessão.", + "Warning: Your personal data (including encryption keys) is still stored in this session. Clear it if you're finished using this session, or want to sign in to another account.": "Atenção: Seus dados pessoais (incluindo chaves de criptografia) ainda estão armazenados nesta sessão. Apague-os quando tiver finalizado esta sessão, ou se quer entrar com outra conta.", + "Confirm encryption setup": "Confirmar a configuração de criptografia", + "Click the button below to confirm setting up encryption.": "Clique no botão abaixo para confirmar a configuração da criptografia.", + "Safeguard against losing access to encrypted messages & data by backing up encryption keys on your server.": "Proteja-se contra a perda de acesso a mensagens e dados criptografados fazendo a cópia segura (backup) das chaves de criptografia no seu servidor.", + "Generate a Security Key": "Gerar uma Chave de Segurança", + "We’ll generate a Security Key for you to store somewhere safe, like a password manager or a safe.": "Nós geramos uma Chave de Segurança para você. Por favor, guarde-a em um lugar seguro, como um gerenciador de senhas ou um cofre.", + "Use a secret phrase only you know, and optionally save a Security Key to use for backup.": "Use uma frase secreta que apenas você conhece, e opcionalmente salve uma Chave de Segurança para usar como cópia de segurança (backup).", + "Restore your key backup to upgrade your encryption": "Restaurar a sua cópia segura (backup) de chaves para atualizar a sua criptografia", + "Upgrade this session to allow it to verify other sessions, granting them access to encrypted messages and marking them as trusted for other users.": "Atualize esta sessão para permitir que ela verifique outras sessões, dando a elas acesso às mensagens criptografadas e marcando-as como confiáveis para as(os) demais usuárias(os).", + "Store your Security Key somewhere safe, like a password manager or a safe, as it’s used to safeguard your encrypted data.": "Guarde sua Chave de Segurança em algum lugar seguro, como por exemplo um gestor de senhas ou um cofre, já que esta chave é a proteção para seus dados criptografados.", + "If you cancel now, you may lose encrypted messages & data if you lose access to your logins.": "Se você cancelar agora, poderá perder mensagens e dados criptografados se você perder acesso aos seus logins atuais.", + "Upgrade your encryption": "Atualizar sua criptografia", + "Save your Security Key": "Salve sua Chave de Segurança", + "We'll store an encrypted copy of your keys on our server. Secure your backup with a recovery passphrase.": "Nós vamos armazenar uma cópia criptografada de suas chaves no nosso servidor. Por favor, proteja esta cópia (backup) com uma frase de recuperação.", + "Set up with a recovery key": "Configurar com uma chave de recuperação", + "Your recovery key is a safety net - you can use it to restore access to your encrypted messages if you forget your recovery passphrase.": "Sua chave de recuperação é uma rede de proteção - você pode usá-la para restaurar o acesso às suas mensagens criptografadas se você esquecer sua frase de recuperação.", + "Your recovery key": "Sua chave de recuperação", + "Your recovery key has been copied to your clipboard, paste it to:": "Sua chave de recuperação foi copiada para sua área de transferência. Cole-a para:", + "Your recovery key is in your Downloads folder.": "Sua chave de recuperação está na sua pasta de Downloads.", + "Without setting up Secure Message Recovery, you won't be able to restore your encrypted message history if you log out or use another session.": "Sem configurar a Recuperação Segura de Mensagens, você não será capaz de restaurar seu histórico de mensagens criptografadas e fizer logout ou usar outra sessão.", + "Make a copy of your recovery key": "Fazer uma cópia de sua chave de recuperação", + "Starting backup...": "Iniciando cópia de segurança (backup)...", + "Create key backup": "Criar cópia de segurança (backup) da chave", + "A new recovery passphrase and key for Secure Messages have been detected.": "Uma nova frase e chave de recuperação para Mensagens Seguras foram detectadas.", + "This session is encrypting history using the new recovery method.": "Esta sessão está criptografando o histórico de mensagens usando o novo método de restauração.", + "This session has detected that your recovery passphrase and key for Secure Messages have been removed.": "Esta sessão detectou que sua frase e chave de recuperação para Mensagens Seguras foram removidas.", + "If you did this accidentally, you can setup Secure Messages on this session which will re-encrypt this session's message history with a new recovery method.": "Se você fez isso acidentalmente, você pode configurar Mensagens Seguras nesta sessão, o que vai re-criptografar o histórico de mensagens desta sessão com um novo método de recuperação.", + "If disabled, messages from encrypted rooms won't appear in search results.": "Se desabilitado, as mensagens de salas criptografadas não aparecerão em resultados de buscas.", + "%(brand)s is securely caching encrypted messages locally for them to appear in search results:": "%(brand)s está armazenando de forma segura as mensagens criptografadas localmente, para que possam aparecer em resultados das buscas:", + "%(doneRooms)s out of %(totalRooms)s": "%(doneRooms)s de %(totalRooms)s", + "Jump to start/end of the composer": "Pule para o início/fim do compositor", + "Click the button below to confirm adding this phone number.": "Clique no botão abaixo para confirmar a adição deste número de telefone.", + "Clear notifications": "Limpar notificações", + "There are advanced notifications which are not shown here.": "Existem notificações avançadas que não são mostradas aqui.", + "Enable desktop notifications for this session": "Ativar notificações na área de trabalho para esta sessão", + "Mentions & Keywords": "Menções & Palavras-Chave", + "Notification options": "Opções de notificação", + "Leave Room": "Sair da Sala", + "Forget Room": "Esquecer Sala", + "Favourited": "Favoritado", + "You cancelled verifying %(name)s": "Você cancelou a verificação do %(name)s", + "You accepted": "Você aceitou", + "%(name)s accepted": "%(name)s aceitou", + "You declined": "Você recusou", + "You cancelled": "Você cancelou", + "%(name)s declined": "%(name)s recusou", + "%(name)s cancelled": "%(name)s cancelou", + "Accepting …": "Aceitando…", + "Declining …": "Recusando…", + "You sent a verification request": "Você enviou uma solicitação de verificação", + "Show all": "Mostrar tudo", + "Reactions": "Reações", + " reacted with %(content)s": " reagiu com %(content)s", + "reacted with %(shortName)s": "reagiu com %(shortName)s", + "Message deleted": "Mensagem apagada", + "Message deleted by %(name)s": "Mensagem apagada por %(name)s", + "Message deleted on %(date)s": "Mensagem apagada em %(date)s", + "Edited at %(date)s": "Editado em %(date)s", + "Click to view edits": "Clicar para ver edições", + "Edited at %(date)s. Click to view edits.": "Editado em %(date)s. Clique para ver edições.", + "edited": "editado", + "Can't load this message": "Não foi possível carregar esta mensagem", + "Submit logs": "Enviar registros", + "Frequently Used": "Usado Frequentemente", + "Animals & Nature": "Animais e Natureza", + "Food & Drink": "Alimentação e Bebida", + "Activities": "Atividades", + "Travel & Places": "Viagens & Lugares", + "Objects": "Objetos", + "Symbols": "Símbolos", + "Flags": "Bandeiras", + "Categories": "Categorias", + "Quick Reactions": "Reações Rápidas", + "Cancel search": "Cancelar busca", + "Any of the following data may be shared:": "Qualquer um dos seguintes dados pode ser compartilhado:", + "Your theme": "Seu tema", + "Room ID": "ID da sala", + "Widget ID": "ID do widget", + "Widget added by": "Widget adicionado por", + "This widget may use cookies.": "Este widget pode usar cookies.", + "Maximize apps": "Maximizar apps", + "More options": "Mais opções", + "Join": "Entrar", + "Rotate Left": "Girar para a esquerda", + "Rotate counter-clockwise": "Girar no sentido anti-horário", + "Rotate Right": "Girar para a direita", + "Rotate clockwise": "Girar no sentido horário", + "Language Dropdown": "Menu suspenso de idiomas", + "QR Code": "Código QR", + "Room address": "Endereço da sala", + "e.g. my-room": "por exemplo: minha-sala", + "Some characters not allowed": "Alguns caracteres não são permitidos", + "This address is available to use": "Este endereço está disponível para uso", + "This address is already in use": "Este endereço já está em uso", + "Enter a server name": "Digite um nome de servidor", + "Can't find this server or its room list": "Não foi possível encontrar este servidor ou sua lista de salas", + "All rooms": "Todas as salas", + "Your server": "Seu servidor", + "Remove server": "Remover servidor", + "Matrix": "Matrix", + "Add a new server": "Adicionar um novo servidor", + "Server name": "Nome do servidor", + "Add a new server...": "Adicionar um novo servidor...", + "Reminder: Your browser is unsupported, so your experience may be unpredictable.": "Lembrete: seu navegador não é compatível; portanto, sua experiência pode ser imprevisível.", + "Notes": "Notas", + "Removing…": "Removendo…", + "Clear all data in this session?": "Limpar todos os dados nesta sessão?", + "Clear all data": "Limpar todos os dados", + "Please enter a name for the room": "Digite um nome para a sala", + "This room is private, and can only be joined by invitation.": "Esta sala é privada, e só pode ser acessada por convite.", + "Make this room public": "Tornar pública esta sala", + "Hide advanced": "Esconder configurações avançadas", + "Show advanced": "Mostrar configurações avançadas", + "Are you sure you want to deactivate your account? This is irreversible.": "Tem certeza de que deseja desativar sua conta? Isso é irreversível.", + "Confirm account deactivation": "Confirmar desativação da conta", + "Server did not return valid authentication information.": "O servidor não retornou informações de autenticação válidas.", + "View Servers in Room": "Ver Servidores na Sala", + "Verification Requests": "Solicitações de verificação", + "Integrations are disabled": "As integrações estão desativadas", + "Integrations not allowed": "As integrações não estão permitidas", + "End": "Fim", + "List options": "Opções da Lista", + "Jump to first unread room.": "Ir para a primeira sala não lida.", + "Jump to first invite.": "Ir para o primeiro convite.", + "Add room": "Adicionar sala", + "Show %(count)s more|other": "Mostrar %(count)s a mais", + "Show %(count)s more|one": "Mostrar %(count)s a mais", + "Use default": "Usar o padrão", + "Room options": "Opções da Sala", + "%(count)s unread messages including mentions.|other": "%(count)s mensagens não lidas, incluindo menções.", + "%(count)s unread messages including mentions.|one": "1 menção não lida.", + "%(count)s unread messages.|other": "%(count)s mensagens não lidas.", + "%(count)s unread messages.|one": "1 mensagem não lida.", + "Unread messages.": "Mensagens não lidas.", + "This room is public": "Esta sala é pública", + "Away": "Ausente", + "This room has already been upgraded.": "Esta sala já foi atualizada.", + "This room is running room version , which this homeserver has marked as unstable.": "Esta sala está executando a versão , que este servidor marcou como instável.", + "Local address": "Endereço local", + "Published Addresses": "Endereços publicados", + "Published addresses can be used by anyone on any server to join your room. To publish an address, it needs to be set as a local address first.": "Os endereços publicados podem ser usados por qualquer pessoa em qualquer servidor para entrar na sala. Para publicar um endereço, primeiramente ele precisa ser definido como um endereço local.", + "Other published addresses:": "Outros endereços publicados:", + "New published address (e.g. #alias:server)": "Novo endereço publicado (por exemplo, #apelido:server)", + "Local Addresses": "Endereços locais", + "%(name)s cancelled verifying": "%(name)s cancelou a verificação", + "Your display name": "Seu nome de exibição", + "Your avatar URL": "A URL da sua foto de perfil", + "Your user ID": "Sua ID de usuário", + "%(brand)s URL": "URL de %(brand)s", + "Using this widget may share data with %(widgetDomain)s & your Integration Manager.": "Se você usar esse widget, os dados poderão ser compartilhados com %(widgetDomain)s & seu Gerenciador de Integrações.", + "Using this widget may share data with %(widgetDomain)s.": "Se você usar esse widget, os dados poderão ser compartilhados com %(widgetDomain)s.", + "%(severalUsers)smade no changes %(count)s times|other": "%(severalUsers)s não fizeram alterações %(count)s vezes", + "%(severalUsers)smade no changes %(count)s times|one": "%(severalUsers)s não fizeram alterações", + "%(oneUser)smade no changes %(count)s times|other": "%(oneUser)s não fez alteraçõe s%(count)s vezes", + "%(oneUser)smade no changes %(count)s times|one": "%(oneUser)s não fez alterações", + "Power level": "Nível de permissão", + "Please provide a room address": "Digite um endereço para a sala", + "Looks good": "Muito bem", + "Are you sure you want to remove %(serverName)s": "Tem certeza de que deseja remover %(serverName)s", + "%(networkName)s rooms": "Salas em %(networkName)s", + "Matrix rooms": "Salas em Matrix", + "Close dialog": "Fechar caixa de diálogo", + "GitHub issue": "Bilhete de erro no GitHub", + "If there is additional context that would help in analysing the issue, such as what you were doing at the time, room IDs, user IDs, etc., please include those things here.": "Se houver um contexto adicional que ajude a analisar o problema, tal como o que você estava fazendo no momento, IDs de salas, IDs de usuários etc, inclua essas coisas aqui.", + "Topic (optional)": "Descrição (opcional)", + "There was a problem communicating with the server. Please try again.": "Ocorreu um problema na comunicação com o servidor. Por favor, tente novamente.", + "Server did not require any authentication": "O servidor não exigiu autenticação", + "Verifying this user will mark their session as trusted, and also mark your session as trusted to them.": "Se você verificar esse usuário, a sessão será marcada como confiável para você e para ele.", + "Verifying this device will mark it as trusted, and users who have verified with you will trust this device.": "Verificar este aparelho o marcará como confiável, e os usuários que confirmaram com você também confiarão neste aparelho.", + "Keep going...": "Continue...", + "The username field must not be blank.": "O campo do nome de usuário não pode ficar em branco.", + "Username": "Nome de usuário", + "Use an email address to recover your account": "Use um endereço de e-mail para recuperar sua conta", + "Enter email address (required on this homeserver)": "Digite o endereço de e-mail (necessário neste servidor)", + "Doesn't look like a valid email address": "Este não parece ser um endereço de email válido", + "Passwords don't match": "As senhas não correspondem", + "Other users can invite you to rooms using your contact details": "Outros usuários podem convidá-lo para salas usando seus detalhes de contato", + "Enter phone number (required on this homeserver)": "Digite o número de celular (necessário neste servidor)", + "Doesn't look like a valid phone number": "Este não parece ser um número de telefone válido", + "Use lowercase letters, numbers, dashes and underscores only": "Use apenas letras minúsculas, números, traços e sublinhados", + "Enter username": "Digite o nome de usuário", + "Email (optional)": "E-mail (opcional)", + "Phone (optional)": "Número de celular (opcional)", + "Set an email for account recovery. Use email or phone to optionally be discoverable by existing contacts.": "Defina um e-mail para recuperação da conta. Opcionalmente, use e-mail ou número de celular para ser encontrado por seus contatos.", + "You cannot sign in to your account. Please contact your homeserver admin for more information.": "Você não pôde se conectar na sua conta. Entre em contato com o administrador do servidor para obter mais informações.", + "Confirm adding this phone number by using Single Sign On to prove your identity.": "Confirme a adição deste número de telefone usando o Login Único para provar sua identidade.", + "Use an identity server to invite by email. Click continue to use the default identity server (%(defaultIdentityServerName)s) or manage in Settings.": "Use um servidor de identidade para convidar por e-mail. Clique em continuar para usar o servidor de identidade padrão (%(defaultIdentityServerName)s) ou gerencie nas Configurações.", + "You might have configured them in a client other than %(brand)s. You cannot tune them in %(brand)s but they still apply.": "Você pode ter configurado estas opções em um cliente que não seja %(brand)s. Você não pode ajustar essas opções no %(brand)s, mas elas ainda se aplicam.", + "Enable audible notifications for this session": "Ativar notificações sonoras para esta sessão", + "Display Name": "Nome em exibição", + "Identity Server URL must be HTTPS": "O URL do Servidor de Identidade deve ser HTTPS", + "Not a valid Identity Server (status code %(code)s)": "Servidor de Identidade inválido (código de status %(code)s)", + "Could not connect to Identity Server": "Não foi possível conectar-se ao Servidor de Identidade", + "Checking server": "Verificando servidor", + "Change identity server": "Mudar o servidor de identidade", + "Disconnect from the identity server and connect to instead?": "Desconectar-se do servidor de identidade e conectar-se em em vez disso?", + "Terms of service not accepted or the identity server is invalid.": "Termos de serviço não aceitos ou o servidor de identidade é inválido.", + "The identity server you have chosen does not have any terms of service.": "O servidor de identidade que você escolheu não possui nenhum termo de serviço.", + "Disconnect identity server": "Desconectar servidor de identidade", + "Disconnect from the identity server ?": "Desconectar-se do servidor de identidade ?", + "Disconnect": "Desconectar", + "You should remove your personal data from identity server before disconnecting. Unfortunately, identity server is currently offline or cannot be reached.": "Você deve remover seus dados pessoais do servidor de identidade antes de desconectar. Infelizmente, o servidor de identidade está atualmente offline ou não pode ser acessado.", + "You should:": "Você deveria:", + "check your browser plugins for anything that might block the identity server (such as Privacy Badger)": "verifique se há extensões no seu navegador que possam bloquear o servidor de identidade (por exemplo, Privacy Badger)", + "contact the administrators of identity server ": "entre em contato com os administradores do servidor de identidade ", + "Disconnect anyway": "Desconectar de qualquer maneira", + "You are still sharing your personal data on the identity server .": "Você ainda está compartilhando seus dados pessoais no servidor de identidade .", + "We recommend that you remove your email addresses and phone numbers from the identity server before disconnecting.": "Recomendamos que você remova seus endereços de e-mail e números de telefone do servidor de identidade antes de desconectar.", + "Go back": "Voltar", + "Identity Server (%(server)s)": "Servidor de identidade (%(server)s)", + "You are currently using to discover and be discoverable by existing contacts you know. You can change your identity server below.": "No momento, você está usando para descobrir e ser descoberto pelos contatos existentes que você conhece. Você pode alterar seu servidor de identidade abaixo.", + "If you don't want to use to discover and be discoverable by existing contacts you know, enter another identity server below.": "Se você não quiser usar para descobrir e ser detectável pelos contatos existentes, digite outro servidor de identidade abaixo.", + "Identity Server": "Servidor de identidade", + "You are not currently using an identity server. To discover and be discoverable by existing contacts you know, add one below.": "No momento, você não está usando um servidor de identidade. Para descobrir e ser descoberto pelos contatos existentes, adicione um abaixo.", + "Disconnecting from your identity server will mean you won't be discoverable by other users and you won't be able to invite others by email or phone.": "Desconectar-se do servidor de identidade significa que você não poderá ser descoberto por outros usuários e não poderá convidar outras pessoas por e-mail ou número de celular.", + "Using an identity server is optional. If you choose not to use an identity server, you won't be discoverable by other users and you won't be able to invite others by email or phone.": "Usar um servidor de identidade é opcional. Se você optar por não usar um servidor de identidade, não poderá ser descoberto por outros usuários e não poderá convidar outras pessoas por e-mail ou por número de celular.", + "Do not use an identity server": "Não usar um servidor de identidade", + "Enter a new identity server": "Digitar um novo servidor de identidade", + "Change": "Alterar", + "Manage integrations": "Gerenciar integrações", + "New version available. Update now.": "Nova versão disponível. Atualize agora.", + "Hey you. You're the best!": "Ei, você aí. Você é incrível!", + "Size must be a number": "O tamanho deve ser um número", + "Custom font size can only be between %(min)s pt and %(max)s pt": "O tamanho da fonte personalizada só pode estar entre %(min)s pt e %(max)s pt", + "Use between %(min)s pt and %(max)s pt": "Use entre %(min)s pt e %(max)s pt", + "Invalid theme schema.": "Esquema inválido de tema.", + "Error downloading theme information.": "Erro ao baixar as informações do tema.", + "Theme added!": "Tema adicionado!", + "Custom theme URL": "URL do tema personalizado", + "Add theme": "Adicionar tema", + "Message layout": "Aparência da mensagem", + "Compact": "Compacto", + "Modern": "Moderno", + "Set the name of a font installed on your system & %(brand)s will attempt to use it.": "Defina o nome de uma fonte instalada no seu sistema e %(brand)s tentará usá-la.", + "Customise your appearance": "Personalize sua aparência", + "Appearance Settings only affect this %(brand)s session.": "As Configurações de aparência afetam apenas esta sessão do %(brand)s.", + "Your password was successfully changed. You will not receive push notifications on other sessions until you log back in to them": "Sua senha foi alterada com sucesso. Você não receberá notificações por push em outras sessões até fazer login novamente nelas", + "Agree to the identity server (%(serverName)s) Terms of Service to allow yourself to be discoverable by email address or phone number.": "Concordar com os Termos de Serviço do servidor de identidade (%(serverName)s), para permitir aos seus contatos encontrarem-na(no) por endereço de e-mail ou por número de celular.", + "Discovery": "Contatos", + "Deactivate account": "Desativar conta", + "Clear cache and reload": "Limpar cache e recarregar", + "To report a Matrix-related security issue, please read the Matrix.org Security Disclosure Policy.": "Para relatar um problema de segurança relacionado à tecnologia Matrix, leia a Política de Divulgação de Segurança da Matrix.org.", + "Always show the window menu bar": "Sempre mostrar a barra de menu na janela", + "Show tray icon and minimize window to it on close": "Mostrar ícone na barra de tarefas, que permanece visível ao fechar a janela", + "Read Marker lifetime (ms)": "Duração do marcador de leitura (ms)", + "Read Marker off-screen lifetime (ms)": "Vida útil do marcador de leitura fora da tela (ms)", + "Change settings": "Alterar configurações", + "Send %(eventType)s events": "Enviar eventos de %(eventType)s", + "Roles & Permissions": "Papeis & Permissões", + "Select the roles required to change various parts of the room": "Selecione as permissões necessárias para alterar várias partes da sala", + "Emoji picker": "Seletor de emoji", + "Room %(name)s": "Sala %(name)s", + "No recently visited rooms": "Não há salas visitadas recentemente", + "Custom Tag": "Etiqueta personalizada", + "Joining room …": "Entrando na sala…", + "Loading …": "Carregando…", + "Rejecting invite …": "Rejeitando convite…", + "Join the conversation with an account": "Participar da conversa com uma conta", + "Sign Up": "Inscrever-se", + "Loading room preview": "Carregando visualização da sala", + "You were kicked from %(roomName)s by %(memberName)s": "Você foi removida(o) de %(roomName)s por %(memberName)s", + "Reason: %(reason)s": "Razão: %(reason)s", + "Forget this room": "Esquecer esta sala", + "Re-join": "Entrar novamente", + "You were banned from %(roomName)s by %(memberName)s": "Você foi banida(o) de %(roomName)s por %(memberName)s", + "Something went wrong with your invite to %(roomName)s": "Ocorreu um erro no seu convite para %(roomName)s", + "An error (%(errcode)s) was returned while trying to validate your invite. You could try to pass this information on to a room admin.": "Ocorreu um erro (%(errcode)s) ao validar seu convite. Você pode passar essas informações para um administrador da sala.", + "You can only join it with a working invite.": "Você só pode participar com um convite válido.", + "Try to join anyway": "Tentar entrar mesmo assim", + "You can still join it because this is a public room.": "Você ainda pode entrar, porque esta é uma sala pública.", + "Join the discussion": "Participar da discussão", + "This invite to %(roomName)s was sent to %(email)s which is not associated with your account": "Este convite para %(roomName)s foi enviado para %(email)s, que não está associado à sua conta", + "Link this email with your account in Settings to receive invites directly in %(brand)s.": "Vincule esse e-mail à sua conta em Configurações, para receber convites diretamente em %(brand)s.", + "This invite to %(roomName)s was sent to %(email)s": "Este convite para %(roomName)s foi enviado para %(email)s", + "Use an identity server in Settings to receive invites directly in %(brand)s.": "Use um servidor de identidade em Configurações para receber convites diretamente em %(brand)s.", + "Share this email in Settings to receive invites directly in %(brand)s.": "Compartilhe este e-mail em Configurações para receber convites diretamente em %(brand)s.", + "Do you want to chat with %(user)s?": "Deseja conversar com %(user)s?", + " wants to chat": " quer conversar", + "Do you want to join %(roomName)s?": "Deseja se juntar a %(roomName)s?", + " invited you": " convidou você", + "Reject & Ignore user": "Rejeitar e ignorar usuário", + "You're previewing %(roomName)s. Want to join it?": "Você está visualizando %(roomName)s. Deseja participar?", + "%(roomName)s can't be previewed. Do you want to join it?": "%(roomName)s não pode ser visualizado. Deseja participar?", + "This room doesn't exist. Are you sure you're at the right place?": "Esta sala não existe. Tem certeza de que você está no lugar certo?", + "Securely back up your keys to avoid losing them. Learn more.": "Faça backup de suas chaves com segurança para evitar perdê-las. Saiba mais.", + "Not now": "Agora não", + "Don't ask me again": "Não me pergunte novamente", + "Appearance": "Aparência", + "Show rooms with unread messages first": "Mostrar salas com mensagens não lidas primeiro", + "Show previews of messages": "Mostrar pré-visualizações de mensagens", + "Sort by": "Ordenar por", + "Activity": "Atividade", + "A-Z": "A-Z", + "Unknown Command": "Comando desconhecido", + "Unrecognised command: %(commandText)s": "Comando não reconhecido: %(commandText)s", + "You can use /help to list available commands. Did you mean to send this as a message?": "Você pode usar /help para listar os comandos disponíveis. Você quis enviar isso como uma mensagem?", + "Send as message": "Enviar como mensagem", + "Room Topic": "Descrição da sala", + "React": "Reagir", + "If you run into any bugs or have feedback you'd like to share, please let us know on GitHub.": "Se você encontrar algum erro ou tiver um comentário que gostaria de compartilhar, informe-nos no GitHub.", + "Resend %(unsentCount)s reaction(s)": "Reenviar %(unsentCount)s reações", + "Notification settings": "Configurar notificações", + "Want more than a community? Get your own server": "Quer mais do que uma comunidade? Obtenha seu próprio servidor", + "Switch to light mode": "Alternar para o modo claro", + "Switch to dark mode": "Alternar para o modo escuro", + "Security & privacy": "Segurança & privacidade", + "All settings": "Todas as configurações", + "You're signed out": "Você foi desconectada(o)", + "Clear personal data": "Limpar dados pessoais", + "Command Autocomplete": "Preenchimento automático de comandos", + "Community Autocomplete": "Preenchimento automático da comunidade", + "DuckDuckGo Results": "Resultados no DuckDuckGo", + "If you didn't remove the recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "Se você não excluiu o método de recuperação, um invasor pode estar tentando acessar sua conta. Altere a senha da sua conta e defina imediatamente um novo método de recuperação nas Configurações.", + "Room List": "Lista de salas", + "Autocomplete": "Autocompletar", + "Alt": "Alt", + "Alt Gr": "Alt Gr", + "Shift": "Shift", + "Super": "Super", + "Ctrl": "Ctrl", + "Toggle Bold": "Negrito", + "Toggle Italics": "Itálico", + "Toggle Quote": "Citar", + "New line": "Nova linha", + "Navigate recent messages to edit": "Navegue pelas mensagens recentes para editar", + "Cancel replying to a message": "Cancelar resposta à mensagem", + "Toggle microphone mute": "Ativar/desativar som do microfone", + "Toggle video on/off": "Ativar/desativar o vídeo", + "Scroll up/down in the timeline": "Rolar para cima/baixo na linha do tempo", + "Dismiss read marker and jump to bottom": "Ignorar o marcador de leitura e ir para o final", + "Jump to oldest unread message": "Ir para a mensagem não lida mais antiga", + "Upload a file": "Enviar um arquivo", + "Jump to room search": "Ir para a pesquisa de salas", + "Navigate up/down in the room list": "Navegue para cima/baixo na lista de salas", + "Select room from the room list": "Selecionar sala da lista de salas", + "Collapse room list section": "Esconder seção da lista de salas", + "Expand room list section": "Mostrar seção da lista de salas", + "The person who invited you already left the room.": "A pessoa que convidou você já saiu da sala.", + "The person who invited you already left the room, or their server is offline.": "A pessoa que convidou você já saiu da sala, ou o servidor dela está offline.", + "Use an Integration Manager (%(serverName)s) to manage bots, widgets, and sticker packs.": "Use o Gerenciador de Integrações em (%(serverName)s) para gerenciar bots, widgets e pacotes de adesivos.", + "Use an Integration Manager to manage bots, widgets, and sticker packs.": "Use o Gerenciador de Integrações para gerenciar bots, widgets e pacotes de adesivos.", + "Integration Managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "O Gerenciador de Integrações recebe dados de configuração e pode modificar widgets, enviar convites para salas e definir níveis de permissão em seu nome.", + "Keyboard Shortcuts": "Atalhos do teclado", + "Customise your experience with experimental labs features. Learn more.": "Personalize sua experiência com os recursos experimentais. Saiba mais.", + "Ignored/Blocked": "Ignorado/Bloqueado", + "Error adding ignored user/server": "Erro ao adicionar usuário/servidor ignorado", + "Something went wrong. Please try again or view your console for hints.": "Algo deu errado. Por favor, tente novamente ou veja seu console para obter dicas.", + "Error subscribing to list": "Erro ao inscrever-se na lista", + "Error removing ignored user/server": "Erro ao remover usuário/servidor ignorado", + "Error unsubscribing from list": "Erro ao cancelar a inscrição da lista", + "Please try again or view your console for hints.": "Por favor, tente novamente ou veja seu console para obter dicas.", + "None": "Nenhum", + "Server rules": "Regras do servidor", + "User rules": "Regras do usuário", + "You have not ignored anyone.": "Você não ignorou ninguém.", + "You are currently ignoring:": "Você está atualmente ignorando:", + "You are not subscribed to any lists": "Você não está inscrito em nenhuma lista", + "Unsubscribe": "Desinscrever-se", + "View rules": "Ver regras", + "You are currently subscribed to:": "No momento, você está inscrito em:", + "⚠ These settings are meant for advanced users.": "⚠ Essas configurações são destinadas a usuários avançados.", + "Add users and servers you want to ignore here. Use asterisks to have %(brand)s match any characters. For example, @bot:* would ignore all users that have the name 'bot' on any server.": "Adicione aqui os usuários e servidores que você deseja ignorar. Use asteriscos para fazer com que o %(brand)s corresponda a qualquer caractere. Por exemplo, @bot:* ignorará todos os usuários em qualquer servidor que tenham 'bot' no nome.", + "Server or user ID to ignore": "Servidor ou ID de usuário para ignorar", + "Subscribe": "Inscrever-se", + "Session ID:": "ID da sessão:", + "Message search": "Pesquisa de mensagens", + "Where you’re logged in": "Onde você está conectado", + "Set a new custom sound": "Definir um novo som personalizado", + "Browse": "Buscar", + "Upgrade the room": "Atualizar a sala", + "Kick users": "Remover usuários", + "Ban users": "Banir usuários", + "Remove messages": "Remover mensagens", + "Notify everyone": "Notificar todo mundo", + "Your email address hasn't been verified yet": "Seu endereço de e-mail ainda não foi verificado", + "Revoke": "Revogar", + "Share": "Compartilhar", + "Unable to revoke sharing for phone number": "Não foi possível revogar o compartilhamento do número de celular", + "Unable to share phone number": "Não foi possível compartilhar o número de celular", + "Please enter verification code sent via text.": "Digite o código de verificação enviado por mensagem de texto.", + "Remove %(email)s?": "Remover %(email)s?", + "Remove %(phone)s?": "Remover %(phone)s?", + "A text message has been sent to +%(msisdn)s. Please enter the verification code it contains.": "Digite o código de verificação enviado por mensagem de texto para +%(msisdn)s.", + "This user has not verified all of their sessions.": "Este usuário não verificou todas suas próprias sessões.", + "You have not verified this user.": "Você não verificou este usuário.", + "You have verified this user. This user has verified all of their sessions.": "Você confirmou este usuário. Este usuário verificou todas as próprias sessões.", + "Someone is using an unknown session": "Alguém está usando uma sessão desconhecida", + "Everyone in this room is verified": "Todo mundo nesta sala está verificado", + "Edit message": "Editar mensagem", + "Mod": "Moderador", + "Scroll to most recent messages": "Ir para as mensagens mais recentes", + "Close preview": "Fechar a visualização", + "Send a reply…": "Enviar uma resposta…", + "Send a message…": "Enviar uma mensagem…", + "Bold": "Negrito", + "Italics": "Itálico", + "Strikethrough": "Riscado", + "Code block": "Bloco de código", + "Failed to connect to integration manager": "Falha ao conectar-se ao gerenciador de integrações", + "Failed to revoke invite": "Falha ao revogar o convite", + "Could not revoke the invite. The server may be experiencing a temporary problem or you do not have sufficient permissions to revoke the invite.": "Não foi possível revogar o convite. O servidor pode estar com um problema temporário ou você não tem permissões suficientes para revogar o convite.", + "Revoke invite": "Revogar o convite", + "Invited by %(sender)s": "Convidado por %(sender)s", + "Mark all as read": "Marcar tudo como lido", + "Error updating main address": "Erro ao atualizar o endereço principal", + "There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.": "Ocorreu um erro ao atualizar o endereço principal da sala. Isso pode não ser permitido pelo servidor ou houve um problema temporário.", + "There was an error updating the room's alternative addresses. It may not be allowed by the server or a temporary failure occurred.": "Ocorreu um erro ao atualizar o endereço alternativo da sala. Isso pode não ser permitido pelo servidor ou houve um problema temporário.", + "Error creating address": "Erro ao criar o endereço", + "There was an error creating that address. It may not be allowed by the server or a temporary failure occurred.": "Ocorreu um erro ao criar esse endereço. Isso pode não ser permitido pelo servidor ou houve um problema temporário.", + "You don't have permission to delete the address.": "Você não tem permissão para excluir este endereço.", + "There was an error removing that address. It may no longer exist or a temporary error occurred.": "Ocorreu um erro ao remover esse endereço. Ele pode não mais existir ou houve um problema temporário.", + "Error removing address": "Erro ao remover o endereço", + "Main address": "Endereço principal", + "Room Name": "Nome da sala", + "Room avatar": "Foto da sala", + "Waiting for you to accept on your other session…": "Aguardando sua confirmação na sua outra sessão…", + "Waiting for %(displayName)s to accept…": "Aguardando %(displayName)s aceitar…", + "Accepting…": "Aceitando…", + "Your messages are secured and only you and the recipient have the unique keys to unlock them.": "Suas mensagens são protegidas e somente você e o destinatário têm as chaves exclusivas para desbloqueá-las.", + "Your messages are not secure": "Suas mensagens não estão seguras", + "Your homeserver": "Seu servidor local", + "Trusted": "Confiável", + "Not trusted": "Não confiável", + "%(count)s verified sessions|other": "%(count)s sessões verificadas", + "%(count)s verified sessions|one": "1 sessão verificada", + "Hide verified sessions": "Esconder sessões verificadas", + "%(count)s sessions|other": "%(count)s sessões", + "%(count)s sessions|one": "%(count)s sessão", + "Hide sessions": "Esconder sessões", + "No recent messages by %(user)s found": "Nenhuma mensagem recente de %(user)s foi encontrada", + "Remove recent messages by %(user)s": "Remover mensagens recentes de %(user)s", + "Remove %(count)s messages|other": "Remover %(count)s mensagens", + "Remove %(count)s messages|one": "Remover 1 mensagem", + "Remove recent messages": "Remover mensagens recentes", + "%(role)s in %(roomName)s": "%(role)s em %(roomName)s", + "Deactivate user?": "Desativar usuário?", + "Deactivate user": "Desativar usuário", + "Failed to deactivate user": "Falha ao desativar o usuário", + "Security": "Segurança", + "You've successfully verified your device!": "Você verificou o seu aparelho com êxito!", + "Verification timed out.": "O tempo de verificação se esgotou.", + "You cancelled verification on your other session.": "Você cancelou a verificação em sua outra sessão.", + "%(displayName)s cancelled verification.": "%(displayName)s cancelou a verificação.", + "You cancelled verification.": "Você cancelou a verificação.", + "Verification cancelled": "Verificação cancelada", + "Compare emoji": "Comparar emojis", + "Show image": "Mostrar imagem", + "You have ignored this user, so their message is hidden. Show anyways.": "Você ignorou este usuário, portanto, a mensagem dele está oculta. Mostrar mesmo assim.", + "You verified %(name)s": "Você verificou %(name)s", + "Use an identity server to invite by email. Use the default (%(defaultIdentityServerName)s) or manage in Settings.": "Use um servidor de identidade para convidar por e-mail. Use o padrão (%(defaultIdentityServerName)s) ou um servidor personalizado em Configurações.", + "Use an identity server to invite by email. Manage in Settings.": "Use um servidor de identidade para convidar por e-mail. Gerencie o servidor em Configurações.", + "Destroy cross-signing keys?": "Destruir chaves de assinatura cruzada?", + "Waiting for partner to confirm...": "Esperando a outra pessoa confirmar...", + "Enable 'Manage Integrations' in Settings to do this.": "Para fazer isso, ative 'Gerenciar Integrações' nas Configurações.", + "Your %(brand)s doesn't allow you to use an Integration Manager to do this. Please contact an admin.": "Seu %(brand)s não permite que você use o Gerenciador de Integrações para fazer isso. Entre em contato com um administrador.", + "Confirm to continue": "Confirme para continuar", + "Click the button below to confirm your identity.": "Clique no botão abaixo para confirmar sua identidade.", + "Failed to invite the following users to chat: %(csvUsers)s": "Falha ao convidar os seguintes usuários para a conversa: %(csvUsers)s", + "Something went wrong trying to invite the users.": "Ocorreu um erro ao tentar convidar os usuários.", + "We couldn't invite those users. Please check the users you want to invite and try again.": "Não foi possível convidar esses usuários. Por favor, tente novamente.", + "Failed to find the following users": "Falha ao encontrar os seguintes usuários", + "The following users might not exist or are invalid, and cannot be invited: %(csvNames)s": "Os seguintes usuários não puderam ser convidados porque não existem ou são inválidos: %(csvNames)s", + "Recent Conversations": "Conversas recentes", + "Suggestions": "Sugestões", + "Invite someone using their name, username (like ), email address or share this room.": "Convide alguém com seu nome, nome de usuário (por exemplo: ), endereço de e-mail ou compartilhe esta sala.", + "Use your account to sign in to the latest version of the app at ": "Use sua conta para fazer login na versão mais recente do aplicativo em ", + "Report bugs & give feedback": "Relatar erros & enviar comentários", + "Room Settings - %(roomName)s": "Configurações da sala - %(roomName)s", + "Automatically invite users": "Convidar usuários automaticamente", + "Upgrade private room": "Atualizar a sala privada", + "Upgrade public room": "Atualizar a sala pública", + "Upgrading a room is an advanced action and is usually recommended when a room is unstable due to bugs, missing features or security vulnerabilities.": "Atualizar uma sala é uma ação avançada e geralmente é recomendada quando uma sala está instável devido a erros, recursos ausentes ou vulnerabilidades de segurança.", + "This usually only affects how the room is processed on the server. If you're having problems with your %(brand)s, please report a bug.": "Isso geralmente afeta apenas como a sala é processada no servidor. Se você tiver problemas com o %(brand)s, informe um erro.", + "You'll upgrade this room from to .": "Você atualizará esta sala de para .", + "A username can only contain lower case letters, numbers and '=_-./'": "Um nome de usuário só pode ter letras minúsculas, números e '=_-./'", + "Command Help": "Ajuda com Comandos", + "To help us prevent this in future, please send us logs.": "Para nos ajudar a evitar isso no futuro, envie-nos os registros.", + "Your browser likely removed this data when running low on disk space.": "O seu navegador provavelmente removeu esses dados quando o espaço de armazenamento ficou insuficiente.", + "Integration Manager": "Gerenciador de Integrações", + "Find others by phone or email": "Encontre outras pessoas por telefone ou e-mail", + "Use bots, bridges, widgets and sticker packs": "Use bots, pontes, widgets e pacotes de adesivos", + "Terms of Service": "Termos de serviço", + "To continue you need to accept the terms of this service.": "Para continuar, você precisa aceitar os termos deste serviço.", + "Service": "Serviço", + "Summary": "Resumo", + "Document": "Documento", + "Upload files (%(current)s of %(total)s)": "Enviar arquivos (%(current)s de %(total)s)", + "Upload files": "Enviar arquivos", + "Upload all": "Enviar tudo", + "This file is too large to upload. The file size limit is %(limit)s but this file is %(sizeOfThisFile)s.": "Este arquivo é muito grande para ser enviado. O limite do tamanho de arquivos é %(limit)s, enquanto que o tamanho desse arquivo é %(sizeOfThisFile)s.", + "These files are too large to upload. The file size limit is %(limit)s.": "Esses arquivos são muito grandes para serem enviados. O limite do tamanho de arquivos é %(limit)s.", + "Some files are too large to be uploaded. The file size limit is %(limit)s.": "Alguns arquivos são muito grandes para serem enviados. O limite do tamanho de arquivos é %(limit)s.", + "Upload %(count)s other files|other": "Enviar %(count)s outros arquivos", + "Upload %(count)s other files|one": "Enviar %(count)s outros arquivos", + "Cancel All": "Cancelar tudo", + "Upload Error": "Erro no envio", + "Verification Request": "Solicitação de verificação", + "Remember my selection for this widget": "Lembrar minha escolha para este widget", + "Deny": "Rejeitar", + "Wrong file type": "Tipo errado de arquivo", + "Address (optional)": "Endereço (opcional)", + "Report Content": "Reportar conteúdo", + "Update status": "Atualizar status", + "Set status": "Definir status", + "Hide": "Esconder", + "Help": "Ajuda", + "Remove for everyone": "Remover para todo mundo", + "Remove for me": "Remover para mim", + "User Status": "Status do usuário", + "This homeserver would like to make sure you are not a robot.": "Este servidor local gostaria se certificar de que você não é um robô.", + "Confirm your identity by entering your account password below.": "Confirme sua identidade digitando sua senha abaixo.", + "Unable to validate homeserver/identity server": "Não foi possível validar seu servidor local/servidor de identidade", + "Server Name": "Nome do servidor", + "Enter password": "Digite a senha", + "Nice, strong password!": "Muito bem, uma senha forte!", + "Password is allowed, but unsafe": "Esta senha é permitida, mas não é segura", + "Not sure of your password? Set a new one": "Esqueceu sua senha? Defina uma nova", + "Set an email for account recovery. Use email to optionally be discoverable by existing contacts.": "Defina um e-mail para poder recuperar a conta. Este e-mail também pode ser usado para encontrar seus contatos.", + "Enter your custom homeserver URL What does this mean?": "Digite o URL de um servidor local O que isso significa?", + "Homeserver URL": "URL do servidor local", + "Identity Server URL": "URL do servidor de identidade", + "Other servers": "Outros servidores", + "Free": "Gratuito", + "Find other public servers or use a custom server": "Encontre outros servidores públicos ou use um servidor personalizado", + "Sign in to your Matrix account on %(serverName)s": "Faça login com sua conta Matrix em %(serverName)s", + "Sign in to your Matrix account on ": "Faça login com sua conta Matrix em ", + "Sign in with SSO": "Faça login com SSO (Login Único)", + "Please install Chrome, Firefox, or Safari for the best experience.": "Por favor, instale o Chrome, o Firefox ou o Safari para obter a melhor experiência de uso.", + "Couldn't load page": "Não foi possível carregar a página", + "This homeserver does not support communities": "Este servidor local não suporta o recurso de comunidades", + "%(brand)s failed to get the protocol list from the homeserver. The homeserver may be too old to support third party networks.": "%(brand)s não conseguiu obter a lista de protocolos do servidor local. O servidor local pode ser muito antigo para suportar redes de terceiros.", + "%(brand)s failed to get the public room list.": "%(brand)s não conseguiu obter a lista de salas públicas.", + "The homeserver may be unavailable or overloaded.": "O servidor local pode estar indisponível ou sobrecarregado.", + "Delete the room address %(alias)s and remove %(name)s from the directory?": "Excluir o endereço da sala %(alias)s e remover %(name)s da lista de salas?", + "delete the address.": "exclui o endereço.", + "%(brand)s does not know how to join a room on this network": "%(brand)s não sabe como entrar em uma sala desta rede", + "View": "Ver", + "Find a room…": "Encontrar uma sala…", + "Find a room… (e.g. %(exampleRoom)s)": "Encontrar uma sala… (por exemplo: %(exampleRoom)s)", + "Search rooms": "Buscar salas", + "You have %(count)s unread notifications in a prior version of this room.|other": "Você tem %(count)s notificações não lidas em uma versão anterior desta sala.", + "You have %(count)s unread notifications in a prior version of this room.|one": "Você tem %(count)s notificações não lidas em uma versão anterior desta sala.", + "Feedback": "Feedback", + "User menu": "Menu do usuário", + "Could not load user profile": "Não foi possível carregar o perfil do usuário", + "Session verified": "Sessão verificada", + "Your Matrix account on %(serverName)s": "Sua conta Matrix em %(serverName)s", + "Your Matrix account on ": "Sua conta Matrix em ", + "No identity server is configured: add one in server settings to reset your password.": "Nenhum servidor de identidade está configurado: adicione um nas configurações do servidor para redefinir sua senha.", + "A verification email will be sent to your inbox to confirm setting your new password.": "Um e-mail de verificação será enviado para sua caixa de entrada para confirmar sua nova senha.", + "Your password has been reset.": "Sua senha foi alterada.", + "You have been logged out of all sessions and will no longer receive push notifications. To re-enable notifications, sign in again on each device.": "Você foi desconectado de todas as sessões e não receberá mais notificações. Para reativar as notificações, faça login novamente em cada aparelho.", + "Set a new password": "Digite uma nova senha", + "Invalid base_url for m.homeserver": "base_url inválido para m.homeserver", + "Invalid base_url for m.identity_server": "base_url inválido para m.identity_server", + "This account has been deactivated.": "Esta conta foi desativada.", + "Syncing...": "Sincronizando...", + "%(brand)s Web": "%(brand)s Web", + "Your new session is now verified. Other users will see it as trusted.": "Sua nova sessão agora está confirmada. Para outros usuários ela será vista como confiável.", + "Forgotten your password?": "Esqueceu sua senha?", + "Restore": "Restaurar", + "Copy": "Copiar", + "For maximum security, this should be different from your account password.": "Para segurança máxima, essa deve ser diferente da senha da sua conta.", + "Success!": "Pronto!", + "Disable": "Desativar", + "Space used:": "Espaço usado:", + "Navigation": "Navegação", + "Calls": "Chamadas", + "Esc": "Esc", + "Enter": "Enter" } diff --git a/src/i18n/strings/ru.json b/src/i18n/strings/ru.json index 01700c0e8e..5e29bfed09 100644 --- a/src/i18n/strings/ru.json +++ b/src/i18n/strings/ru.json @@ -22,7 +22,7 @@ "Error": "Ошибка", "Export E2E room keys": "Экспорт ключей шифрования", "Failed to change password. Is your password correct?": "Не удалось сменить пароль. Вы правильно ввели текущий пароль?", - "Failed to leave room": "Не удалось выйти из комнаты", + "Failed to leave room": "Не удалось покинуть комнату", "Failed to reject invitation": "Не удалось отклонить приглашение", "Failed to send email": "Ошибка отправки email", "Failed to unban": "Не удалось разблокировать", @@ -232,7 +232,7 @@ "Room": "Комната", "Cancel": "Отмена", "Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or enable unsafe scripts.": "Не удается подключиться к домашнему серверу через HTTP, так как в адресной строке браузера указан адрес HTTPS. Используйте HTTPS или включите небезопасные скрипты.", - "Dismiss": "Отклонить", + "Dismiss": "Закрыть", "Custom Server Options": "Параметры другого сервера", "Mute": "Приглушить", "Operation failed": "Сбой операции", @@ -347,7 +347,7 @@ "Something went wrong!": "Что-то пошло не так!", "This will be your account name on the homeserver, or you can pick a different server.": "Это будет имя вашей учётной записи на домашнем сервере, либо вы можете выбрать другой сервер.", "If you already have a Matrix account you can log in instead.": "Если у вас уже есть учётная запись Matrix, вы можете войти.", - "Home": "Начало", + "Home": "Home", "Accept": "Принять", "Active call (%(roomName)s)": "Текущий вызов (%(roomName)s)", "Admin Tools": "Инструменты администратора", @@ -998,14 +998,14 @@ "Download": "Скачать", "Create your account": "Создать учётную запись", "Username": "Имя пользователя", - "Not sure of your password? Set a new one": "Не уверены в пароле? Установите новый", + "Not sure of your password? Set a new one": "Не помните пароль? Установите новый", "The username field must not be blank.": "Имя пользователя не должно быть пустым.", "Server Name": "Название сервера", "Your Modular server": "Ваш Модульный сервер", "Email (optional)": "Адрес электронной почты (не обязательно)", "Phone (optional)": "Телефон (не обязательно)", "Confirm": "Подтвердить", - "Other servers": "Другие сервера", + "Other servers": "Другие серверы", "Homeserver URL": "URL сервера", "Identity Server URL": "URL сервера идентификации", "Free": "Бесплатный", @@ -1514,8 +1514,8 @@ "Close dialog": "Закрыть диалог", "Please enter a name for the room": "Пожалуйста, введите название комнаты", "This room is private, and can only be joined by invitation.": "Эта комната приватная, в неё можно войти только по приглашению.", - "Hide advanced": "Скрыть расширения", - "Show advanced": "Показать расширения", + "Hide advanced": "Скрыть дополнительные настройки", + "Show advanced": "Показать дополнительные настройки", "Please fill why you're reporting.": "Пожалуйста, заполните, почему вы сообщаете.", "Report Content to Your Homeserver Administrator": "Сообщите о содержании своему администратору домашнего сервера", "Send report": "Отослать отчёт", @@ -1547,9 +1547,9 @@ "%(creator)s created and configured the room.": "%(creator)s создал и настроил комнату.", "Preview": "Заглянуть", "View": "Просмотр", - "Find a room…": "Найди комнату…", - "Find a room… (e.g. %(exampleRoom)s)": "Найди комнату... (напр. %(exampleRoom)s)", - "Explore rooms": "Исследуйте комнаты", + "Find a room…": "Поиск комнат…", + "Find a room… (e.g. %(exampleRoom)s)": "Поиск комнат... (напр. %(exampleRoom)s)", + "Explore rooms": "Список комнат", "No identity server is configured: add one in server settings to reset your password.": "Идентификационный сервер не настроен: добавьте его в настройки сервера, чтобы сбросить пароль.", "Command Autocomplete": "Автозаполнение команды", "Community Autocomplete": "Автозаполнение сообщества", @@ -1609,13 +1609,13 @@ "Verifies a user, session, and pubkey tuple": "Проверяет пользователя, сессию и публичные ключи", "Unknown (user, session) pair:": "Неизвестная (пользователь:сессия) пара:", "Session already verified!": "Сессия уже подтверждена!", - "Never send encrypted messages to unverified sessions from this session": "Никогда не отправляйте зашифрованные сообщения в непроверенные сессий из этой сессии", - "Never send encrypted messages to unverified sessions in this room from this session": "Никогда не отправляйте зашифрованные сообщения в непроверенные сессии в эту комнату из этой сессии", + "Never send encrypted messages to unverified sessions from this session": "Никогда не отправлять зашифрованные сообщения непроверенным сессиям в этой сессии", + "Never send encrypted messages to unverified sessions in this room from this session": "Никогда не отправлять зашифрованные сообщения непроверенным сессиям в этой комнате и в этой сессии", "Your keys are not being backed up from this session.": "Ваши ключи не резервируются с этой сессии.", "Server or user ID to ignore": "Сервер или ID пользователя для игнорирования", "Subscribed lists": "Подписанные списки", "Subscribe": "Подписаться", - "A session's public name is visible to people you communicate with": "Публичное имя сессии видны людям, с которыми вы общаетесь", + "A session's public name is visible to people you communicate with": "Ваши собеседники видят публичные имена сессий", "If you cancel now, you won't complete verifying the other user.": "Если вы сейчас отмените, у вас не будет завершена проверка других пользователей.", "Cancel entering passphrase?": "Отмена ввода пароль?", "Setting up keys": "Настройка ключей", @@ -1993,5 +1993,187 @@ "Signature upload success": "Отпечаток успешно отправлен", "Signature upload failed": "Сбой отправки отпечатка", "Room name or address": "Имя или адрес комнаты", - "Unrecognised room address:": "Не удалось найти адрес комнаты:" + "Unrecognised room address:": "Не удалось найти адрес комнаты:", + "Use your account to sign in to the latest version": "Используйте свой аккаунт для входа в последнюю версию", + "We’re excited to announce Riot is now Element": "Мы рады объявить, что Riot теперь Element", + "Riot is now Element!": "Riot теперь Element!", + "Learn More": "Узнать больше", + "Joins room with given address": "Присоединиться к комнате с указанным адресом", + "Opens chat with the given user": "Открыть чат с данным пользователем", + "Sends a message to the given user": "Отправить сообщение данному пользователю", + "You signed in to a new session without verifying it:": "Вы вошли в новый сеанс, не подтвердив его:", + "Verify your other session using one of the options below.": "Проверьте другой сеанс, используя один из вариантов ниже.", + "Help us improve %(brand)s": "Помогите нам улучшить %(brand)s", + "Send anonymous usage data which helps us improve %(brand)s. This will use a cookie.": "Отправьте анонимные данные об использовании, которые помогут нам улучшить %(brand)s. Для этого будеть использоваться cookie.", + "I want to help": "Я хочу помочь", + "Review where you’re logged in": "Проверьте, где вы вошли", + "Verify all your sessions to ensure your account & messages are safe": "Проверьте все свои сеансы, чтобы убедиться, что ваша учетная запись и сообщения в безопасности", + "Your homeserver has exceeded its user limit.": "Ваш домашний сервер превысил свой лимит пользователей.", + "Your homeserver has exceeded one of its resource limits.": "Ваш домашний сервер превысил один из своих лимитов ресурсов.", + "Are you sure you want to cancel entering passphrase?": "Вы уверены, что хотите отменить ввод пароля?", + "Go Back": "Назад", + "Contact your server admin.": "Обратитесь к администратору сервера.", + "Ok": "Хорошо", + "Set password": "Установить пароль", + "To return to your account in future you need to set a password": "Чтобы вернуться в свой аккаунт в будущем, вам необходимо установить пароль", + "New login. Was this you?": "Новый вход в вашу учётную запись. Это были Вы?", + "Verify the new login accessing your account: %(name)s": "Проверьте новый вход в вашу учётную запись: %(name)s", + "Restart": "Перезапустить", + "Upgrade your %(brand)s": "Обновите ваш %(brand)s", + "A new version of %(brand)s is available!": "Доступна новая версия %(brand)s!", + "You joined the call": "Вы присоединились к звонку", + "%(senderName)s joined the call": "%(senderName)s присоединился к звонку", + "Call in progress": "Звонок в процессе", + "You left the call": "Вы покинули звонок", + "%(senderName)s left the call": "%(senderName)s покинул звонок", + "Call ended": "Звонок завершён", + "You started a call": "Вы начали звонок", + "%(senderName)s started a call": "%(senderName)s начал(а) звонок", + "Waiting for answer": "Ждём ответа", + "%(senderName)s is calling": "%(senderName)s звонит", + "You created the room": "Вы создали комнату", + "%(senderName)s created the room": "%(senderName)s создал(а) комнату", + "You made the chat encrypted": "Вы включили шифрование в комнате", + "%(senderName)s made the chat encrypted": "%(senderName)s включил(а) шифрование в комнате", + "You made history visible to new members": "Вы сделали историю видимой для новых участников", + "%(senderName)s made history visible to new members": "%(senderName)s сделал(а) историю видимой для новых участников", + "You made history visible to anyone": "Вы сделали историю видимой для всех", + "%(senderName)s made history visible to anyone": "%(senderName)s сделал(а) историю видимой для всех", + "You made history visible to future members": "Вы сделали историю видимой для будущих участников", + "%(senderName)s made history visible to future members": "%(senderName)s сделал(а) историю видимой для будущих участников", + "You were invited": "Вы были приглашены", + "%(targetName)s was invited": "%(targetName)s был(а) приглашен(а)", + "You left": "Вы покинули комнату", + "%(targetName)s left": "%(targetName)s покинул комнату", + "You were kicked (%(reason)s)": "Вас исключили из комнаты (%(reason)s)", + "%(targetName)s was kicked (%(reason)s)": "%(targetName)s был(а) исключен(а) из комнаты (%(reason)s)", + "You were kicked": "Вас исключили из комнаты", + "%(targetName)s was kicked": "%(targetName)s был(а) исключен(а) из комнаты", + "You rejected the invite": "Вы отклонили приглашение", + "%(targetName)s rejected the invite": "%(targetName)s отклонил(а) приглашение", + "You were uninvited": "Вам отменили приглашение", + "%(targetName)s was uninvited": "Приглашение для %(targetName)s отменено", + "You were banned (%(reason)s)": "Вас забанили (%(reason)s)", + "%(targetName)s was banned (%(reason)s)": "%(targetName)s был(а) исключен(а) из комнаты (%(reason)s)", + "You were banned": "Вас заблокировали", + "%(targetName)s was banned": "%(targetName)s был(а) забанен(а)", + "You joined": "Вы вошли", + "%(targetName)s joined": "%(targetName)s присоединился(ась)", + "You changed your name": "Вы поменяли своё имя", + "%(targetName)s changed their name": "%(targetName)s поменял(а) своё имя", + "You changed your avatar": "Вы поменяли свой аватар", + "%(targetName)s changed their avatar": "%(targetName)s поменял(а) свой аватар", + "You changed the room name": "Вы поменяли имя комнаты", + "Enable experimental, compact IRC style layout": "Включите экспериментальный, компактный стиль IRC", + "Unknown caller": "Неизвестный абонент", + "Incoming call": "Входящий звонок", + "Waiting for your other session to verify…": "В ожидании вашего другого сеанса, чтобы проверить…", + "%(brand)s can't securely cache encrypted messages locally while running in a web browser. Use %(brand)s Desktop for encrypted messages to appear in search results.": "%(brand)s не может безопасно кэшировать зашифрованные сообщения локально во время работы в веб-браузере. Используйте %(brand)s Desktop, чтобы зашифрованные сообщения появились в результатах поиска.", + "There are advanced notifications which are not shown here.": "Есть расширенные уведомления, которые здесь не отображаются.", + "You might have configured them in a client other than %(brand)s. You cannot tune them in %(brand)s but they still apply.": "Возможно, вы настроили их на клиенте, отличном от %(brand)s. Вы не можете настроить их на %(brand)s, но они все еще применяются.", + "New version available. Update now.": "Доступна новая версия. Обновить сейчас.", + "Hey you. You're the best!": "Эй! Ты лучший!", + "Size must be a number": "Размер должен быть числом", + "Custom font size can only be between %(min)s pt and %(max)s pt": "Пользовательский размер шрифта может быть только между %(min)s pt и %(max)s pt", + "Use between %(min)s pt and %(max)s pt": "Введите значение между %(min)s pt и %(max)s pt", + "Message layout": "Макет сообщения", + "Compact": "Компактно", + "Modern": "Новый", + "Set the name of a font installed on your system & %(brand)s will attempt to use it.": "Установите имя шрифта, установленного в вашей системе, и %(brand)s попытается его использовать.", + "Customise your appearance": "Настройка внешнего вида", + "Reload": "Перезагрузить", + "Take picture": "Сделать снимок", + "Remove for everyone": "Убрать для всех", + "Remove for me": "Убрать для меня", + "User Status": "Статус пользователя", + "Country Dropdown": "Выпадающий список стран", + "%(senderName)s %(emote)s": "%(senderName)s %(emote)s", + "%(senderName)s: %(message)s": "%(senderName)s: %(message)s", + "%(senderName)s changed the room name": "%(senderName)s изменил(а) название комнаты", + "%(senderName)s: %(reaction)s": "%(senderName)s: %(reaction)s", + "%(senderName)s: %(stickerName)s": "%(senderName)s: %(stickerName)s", + "You uninvited %(targetName)s": "Вы отозвали приглашение %(targetName)s", + "%(senderName)s uninvited %(targetName)s": "%(senderName)s отозвал(а) приглашение %(targetName)s", + "You invited %(targetName)s": "Вы пригласили %(targetName)s", + "%(senderName)s invited %(targetName)s": "%(senderName)s пригласил(а) %(targetName)s", + "You changed the room topic": "Вы изменили тему комнаты", + "%(senderName)s changed the room topic": "%(senderName)s изменил(а) тему комнаты", + "Enable advanced debugging for the room list": "Разрешить расширенную отладку списка комнат", + "Font size": "Размер шрифта", + "Use custom size": "Использовать другой размер", + "Use a more compact ‘Modern’ layout": "Использовать компактную 'современную' тему оформления", + "Use a system font": "Использовать системный шрифт", + "System font name": "Название системного шрифта", + "Incoming voice call": "Входящий звонок", + "Incoming video call": "Входящий видеозвонок", + "Please verify the room ID or address and try again.": "Проверьте ID комнаты или адрес и попробуйте снова.", + "Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.": "Администратор вашего сервера отключил сквозное шифрование по умолчанию в приватных комнатах и диалогах.", + "Make this room low priority": "Сделать эту комнату маловажной", + "Low priority rooms show up at the bottom of your room list in a dedicated section at the bottom of your room list": "Маловажные комнаты отображаются в конце списка в отдельной секции", + "People": "Люди", + "%(networkName)s rooms": "Комнаты %(networkName)s", + "Explore Public Rooms": "Просмотреть публичные комнаты", + "Search rooms": "Поиск комнат", + "Where you’re logged in": "Где вы вошли", + "Manage the names of and sign out of your sessions below or verify them in your User Profile.": "Ниже вы можете изменить названия сессий или выйти из них, либо подтвердите их в своём профиле.", + "Create room": "Создать комнату", + "Custom Tag": "Пользовательский тег", + "Appearance": "Внешний вид", + "Show rooms with unread messages first": "Комнаты с непрочитанными сообщениями в начале", + "Show previews of messages": "Показывать последнее сообщение", + "Sort by": "Сортировать", + "Activity": "По активности", + "A-Z": "А-Я", + "List options": "Настройки списка", + "Show %(count)s more|other": "Показать ещё %(count)s", + "Notification options": "Настройки уведомлений", + "Favourited": "В избранном", + "Leave Room": "Покинуть комнату", + "Room options": "Настройки комнаты", + "Set a room address to easily share your room with other people.": "Присвойте комнате адрес, чтобы поделиться ею с другими людьми.", + "You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use %(brand)s with an existing Matrix account on a different homeserver.": "Вы можете ввести адрес домашнего сервера вручную, чтобы войти на другой сервер. Таким образом, вы сможете использовать %(brand)s с существующей учётной записью Matrix на другом сервере.", + "Welcome to %(appName)s": "Добро пожаловать в %(appName)s", + "Liberate your communication": "Освободите общение", + "Create a Group Chat": "Создать групповой чат", + "Security & privacy": "Безопасность и конфиденциальность", + "All settings": "Все настройки", + "Feedback": "Отзыв", + "* %(senderName)s %(emote)s": "* %(senderName)s %(emote)s", + "New spinner design": "Новый дизайн спиннера", + "Appearance Settings only affect this %(brand)s session.": "Настройки внешнего вида работают только в этой сессии %(brand)s.", + "Emoji picker": "Смайлики", + "Show %(count)s more|one": "Показать ещё %(count)s", + "Mentions & Keywords": "Упоминания и ключевые слова", + "Forget Room": "Забыть комнату", + "This room is public": "Это публичная комната", + "Away": "Отошёл(ла)", + "You can use /help to list available commands. Did you mean to send this as a message?": "Введите /help для списка доступных команд. Хотите отправить это сообщение как есть?", + "Error creating address": "Ошибка при создании адреса", + "You don't have permission to delete the address.": "У вас нет прав для удаления этого адреса.", + "Error removing address": "Ошибка при удалении адреса", + "Your messages are secured and only you and the recipient have the unique keys to unlock them.": "Ваши сообщения в безопасности, ключи для расшифровки есть только у вас и получателя.", + "In encrypted rooms, your messages are secured and only you and the recipient have the unique keys to unlock them.": "В зашифрованных комнатах ваши сообщения в безопасности, только у вас и у получателя есть ключи для расшифровки.", + "You've successfully verified your device!": "Вы успешно подтвердили это устройство!", + "Start verification again from the notification.": "Начните подтверждение заново с уведомления.", + "You have ignored this user, so their message is hidden. Show anyways.": "Вы заигнорировали этого пользователя, сообщение скрыто. Показать", + "Message deleted": "Сообщение удалено", + "Message deleted by %(name)s": "Сообщение удалено %(name)s", + "Message deleted on %(date)s": "Сообщение удалено %(date)s", + "Edited at %(date)s": "Отредактировано %(date)s", + "Click to view edits": "Нажмите для просмотра правок", + "Can't load this message": "Не удалось загрузить это сообщение", + "Submit logs": "Отправить логи", + "Categories": "Категории", + "Widgets do not use message encryption.": "Виджеты не используют шифрование сообщений.", + "QR Code": "QR код", + "Room address": "Адрес комнаты", + "Please provide a room address": "Укажите адрес комнаты", + "This address is available to use": "Этот адрес доступен", + "This address is already in use": "Этот адрес уже используется", + "Are you sure you want to remove %(serverName)s": "Вы уверены, что хотите удалить %(serverName)s", + "Enter the name of a new server you want to explore.": "Введите имя нового сервера для просмотра.", + "Reminder: Your browser is unsupported, so your experience may be unpredictable.": "Напоминание: ваш браузер не поддерживается, возможны непредвиденные проблемы.", + "Notification settings": "Настройки уведомлений", + "Switch to light mode": "Переключить в светлый режим", + "Switch to dark mode": "Переключить в тёмный режим" } diff --git a/src/i18n/strings/si.json b/src/i18n/strings/si.json new file mode 100644 index 0000000000..11da7b7e4c --- /dev/null +++ b/src/i18n/strings/si.json @@ -0,0 +1,8 @@ +{ + "This email address is already in use": "මෙම විද්‍යුත් තැපැල් ලිපිනය දැනටමත් භාවිතයේ පවතී", + "This phone number is already in use": "මෙම දුරකථන අංකය දැනටමත් භාවිතයේ පවතී", + "Use Single Sign On to continue": "ඉදිරියට යාමට තනි පුරනය වීම භාවිතා කරන්න", + "Confirm adding this email address by using Single Sign On to prove your identity.": "ඔබගේ අනන්‍යතාවය සනාථ කිරීම සඳහා තනි පුරනය භාවිතා කිරීමෙන් මෙම විද්‍යුත් තැපැල් ලිපිනය එක් කිරීම තහවුරු කරන්න.", + "Confirm": "තහවුරු කරන්න", + "Add Email Address": "විද්‍යුත් තැපැල් ලිපිනය එක් කරන්න" +} diff --git a/src/i18n/strings/sk.json b/src/i18n/strings/sk.json index 6cdc74bf05..063a3ff9ba 100644 --- a/src/i18n/strings/sk.json +++ b/src/i18n/strings/sk.json @@ -1266,7 +1266,7 @@ "Show hidden events in timeline": "Zobrazovať skryté udalosti v histórii obsahu miestností", "Low bandwidth mode": "Režim šetrenia údajov", "Allow fallback call assist server turn.matrix.org when your homeserver does not offer one (your IP address would be shared during a call)": "Ak váš domovský server neposkytuje pomocný server pri uskutočňovaní hovorov, povoliť použitie záložného servera turn.matrix.org (týmto počas hovoru zdieľate svoju adresu IP)", - "When rooms are upgraded": "Keď sú miestnosti aktualizované", + "When rooms are upgraded": "Keď sú miestnosti upgradované", "Accept to continue:": "Ak chcete pokračovať, musíte prijať :", "ID": "ID", "Public Name": "Verejný názov", @@ -1594,5 +1594,180 @@ "To return to your account in future you need to set a password": "Aby ste sa k účtu mohli vrátiť aj neskôr, je potrebné nastaviť heslo", "Restart": "Reštartovať", "Upgrade your %(brand)s": "Upgradujte svoj %(brand)s", - "A new version of %(brand)s is available!": "Nová verzia %(brand)su je dostupná!" + "A new version of %(brand)s is available!": "Nová verzia %(brand)su je dostupná!", + "Which officially provided instance you are using, if any": "Ktorú oficiálne poskytovanú inštanciu používate, pokiaľ nejakú", + "Use your account to sign in to the latest version": "Použite svoj účet na prihlásenie sa do najnovšej verzie", + "We’re excited to announce Riot is now Element": "Sme nadšený oznámiť, že Riot je odteraz Element", + "Riot is now Element!": "Riot je odteraz Element!", + "Learn More": "Dozvedieť sa viac", + "Light": "Svetlý", + "Dark": "Tmavý", + "Ask your %(brand)s admin to check your config for incorrect or duplicate entries.": "Požiadajte správcu vášho %(brand)su, aby skontroloval vašu konfiguráciu. Pravdepodobne obsahuje chyby alebo duplikáty.", + "You joined the call": "Pridali ste sa do hovoru", + "%(senderName)s joined the call": "%(senderName)s sa pridal/a do hovoru", + "Call in progress": "Práve prebieha hovor", + "You left the call": "Opustili ste hovor", + "%(senderName)s left the call": "%(senderName)s opustil/a hovor", + "Call ended": "Hovor skončil", + "You started a call": "Začali ste hovor", + "%(senderName)s started a call": "%(senderName)s začal/a hovor", + "Waiting for answer": "Čakám na odpoveď", + "%(senderName)s is calling": "%(senderName)s volá", + "You created the room": "Vytvorili ste miestnosť", + "%(senderName)s created the room": "%(senderName)s vytvoril/a miestnosť", + "You made the chat encrypted": "Zašifrovali ste čet", + "%(senderName)s made the chat encrypted": "%(senderName)s zašifroval/a čet", + "You made history visible to new members": "Zviditeľnili ste históriu pre nových členov", + "%(senderName)s made history visible to new members": "%(senderName)s zviditeľnil/a históriu pre nových členov", + "You made history visible to anyone": "Zviditeľnili ste históriu pre všetkých", + "%(senderName)s made history visible to anyone": "%(senderName)s zviditeľnil/a históriu pre všetkých", + "You made history visible to future members": "Zviditeľnili ste históriu pre budúcich členov", + "%(senderName)s made history visible to future members": "%(senderName)s zviditeľnil/a históriu pre budúcich členov", + "You were invited": "Boli ste pozvaný/á", + "%(targetName)s was invited": "%(targetName)s vás pozval/a", + "You left": "Odišli ste", + "%(targetName)s left": "%(targetName)s odišiel/odišla", + "You were kicked (%(reason)s)": "Boli ste vykopnutý/á (%(reason)s)", + "%(targetName)s was kicked (%(reason)s)": "%(targetName)s bol vykopnutý/á (%(reason)s)", + "You were kicked": "Boli ste vykopnutý/á", + "%(targetName)s was kicked": "%(targetName)s bol vykopnutý/á", + "You rejected the invite": "Odmietli ste pozvánku", + "%(targetName)s rejected the invite": "%(targetName)s odmietol/odmietla pozvánku", + "You were uninvited": "Boli ste odpozvaný/á", + "%(targetName)s was uninvited": "%(targetName)s bol odpozvaný/á", + "You were banned (%(reason)s)": "Boli ste vyhostený/á (%(reason)s)", + "%(targetName)s was banned (%(reason)s)": "%(targetName)s bol vyhostený/á (%(reason)s)", + "You were banned": "Boli ste vyhostený/á", + "%(targetName)s was banned": "%(targetName)s bol vyhostený/á", + "You joined": "Pridali ste sa", + "%(targetName)s joined": "%(targetName)s sa pridal/a", + "You changed your name": "Zmenili ste vaše meno", + "%(targetName)s changed their name": "%(targetName)s zmenil/a svoje meno", + "You changed your avatar": "Zmenili ste svojho avatara", + "%(targetName)s changed their avatar": "%(targetName)s zmenil/a svojho avatara", + "%(senderName)s %(emote)s": "%(senderName)s %(emote)s", + "%(senderName)s: %(message)s": "%(senderName)s: %(message)s", + "You changed the room name": "Zmenili ste meno miestnosti", + "%(senderName)s changed the room name": "%(senderName)s zmenil/a meno miestnosti", + "%(senderName)s: %(reaction)s": "%(senderName)s: %(reaction)s", + "%(senderName)s: %(stickerName)s": "%(senderName)s: %(stickerName)s", + "You uninvited %(targetName)s": "Odpozvali ste používateľa %(targetName)s", + "%(senderName)s uninvited %(targetName)s": "%(senderName)s odpozval/a používateľa %(targetName)s", + "You invited %(targetName)s": "Pozvali ste používateľa %(targetName)s", + "%(senderName)s invited %(targetName)s": "%(senderName)s pozval/a používateľa %(targetName)s", + "You changed the room topic": "Zmenili ste tému miestnosti", + "%(senderName)s changed the room topic": "%(senderName)s zmenil/a tému miestnosti", + "New spinner design": "Nový točivý štýl", + "Use the improved room list (will refresh to apply changes)": "Použiť vylepšený list miestností (obnový stránku, aby sa aplikovali zmeny)", + "Use custom size": "Použiť vlastnú veľkosť", + "Use a more compact ‘Modern’ layout": "Použiť kompaktnejšie 'moderné' rozloženie", + "Use a system font": "Použiť systémové písmo", + "System font name": "Meno systémového písma", + "Enable experimental, compact IRC style layout": "Povoliť experimentálne, kompaktné rozloženie v štýle IRC", + "Unknown caller": "Neznámy volajúci", + "Incoming voice call": "Prichádzajúci hovor", + "Incoming video call": "Prichádzajúci video hovor", + "Incoming call": "Prichádzajúci hovor", + "To set up a filter, drag a community avatar over to the filter panel on the far left hand side of the screen. You can click on an avatar in the filter panel at any time to see only the rooms and people associated with that community.": "Vytvorte si filter, potiahnite avatara komunity do panelu filtrov na ľavý okraj obrazovky. Môžete kliknúť na avatara v paneli filtorv, aby ste videli len miestnosti a ľudí patriacich do danej komunity.", + "%(num)s minutes ago": "pred %(num)s minútami", + "%(num)s hours ago": "pred %(num)s hodinami", + "%(num)s days ago": "pred %(num)s dňami", + "%(brand)s can't securely cache encrypted messages locally while running in a web browser. Use %(brand)s Desktop for encrypted messages to appear in search results.": "%(brand)s nemôže bezpečne cachovať šiforvané správy lokálne pomocou prehlliadača. Použite %(brand)s Desktop na zobrazenie výsledkov vyhľadávania šiforavných správ.", + "There are advanced notifications which are not shown here.": "Sú tam pokročilé notifikácie, ktoré tu nie sú zobrazené.", + "You might have configured them in a client other than %(brand)s. You cannot tune them in %(brand)s but they still apply.": "Možno ste ich nakonfigurovali v inom kliente než v %(brand)se. Nemôžete ich napasovať do %(brand)su, ale stále platia.", + "New version available. Update now.": "Je dostupná nová verzia. Aktualizovať.", + "Hey you. You're the best!": "Hej, ty. Si borec/borka!", + "Use between %(min)s pt and %(max)s pt": "Použite veľkosť mezi %(min)s pt a %(max)s pt", + "Invalid theme schema.": "Neplatná schéma vzhľadu.", + "Error downloading theme information.": "Chyba pri stiahnutí informácií o vzhľade.", + "Theme added!": "Vzhľad pridaný!", + "Custom theme URL": "URL adresa vlastného vzhľadu", + "Add theme": "Pridať vzhľad", + "Message layout": "Rozloženie správy", + "Compact": "Kompaktný", + "Modern": "Moderný", + "Set the name of a font installed on your system & %(brand)s will attempt to use it.": "Nastavte meno písma, ktoré máte nainštalované na vašom systéme & %(brand)s sa ho pokúsi použiť.", + "Customise your appearance": "Upravte si svoj výzor", + "Appearance Settings only affect this %(brand)s session.": "Nastavenia Výzoru ovplyvnia len túto reláciu %(brand)su.", + "Your password was successfully changed. You will not receive push notifications on other sessions until you log back in to them": "Vaše heslo bolo úspešne zmenené. Nebudete dostávať žiadne notifikácie z iných relácií, dokiaľ sa na nich znovu neprihlásite", + "To report a Matrix-related security issue, please read the Matrix.org Security Disclosure Policy.": "Pre nahlásenie bezpečnostnej chyby súvisiacu s Matrixom si prosím prečítajte Bezpečnostnú Politiku Matrix.org-u (anglicky).", + "Keyboard Shortcuts": "Klávesové skratky", + "Please verify the room ID or address and try again.": "Prosím, overte ID miestnosti alebo adresu a skúste to znovu.", + "Error unsubscribing from list": "Chyba pri zrušení odberu z listu", + "Please try again or view your console for hints.": "Skúste to prosím znovu alebo nahliadnite do konzoly po nápovedy.", + "None": "Žiadne", + "Ban list rules - %(roomName)s": "Pravidlá vyhosťovania - %(roomName)s", + "Server rules": "Pravidlá serveru", + "User rules": "Pravidlá používateľa", + "You have not ignored anyone.": "Nikoho neignorujete.", + "You are currently ignoring:": "Ignorujete:", + "You are not subscribed to any lists": "Neodbreráte žiadne listy", + "Unsubscribe": "Prestať odberať", + "View rules": "Zobraziť pravidlá", + "You are currently subscribed to:": "Odberáte:", + "⚠ These settings are meant for advanced users.": "⚠ Tieto nastavenia sú určené pre pokročilých používateľov.", + "Add users and servers you want to ignore here. Use asterisks to have %(brand)s match any characters. For example, @bot:* would ignore all users that have the name 'bot' on any server.": "Pridajte používateľov a servery, ktorých chcete ignorovať. Použite hviezdičku '*', aby %(brand)s ju priradil každému symbolu. Napríklad @bot:* by odignoroval všetkých používateľov s menom 'bot' na akomkoľvek serveri.", + "Ignoring people is done through ban lists which contain rules for who to ban. Subscribing to a ban list means the users/servers blocked by that list will be hidden from you.": "Ľudia a servery sú ignorovaný pomocou vyhosťovacích listov obsahujúce pravidlá, koho vyhostiť. Odberom vyhosťovacieho listu skryjete používateľov a servery, ktorý sú v ňom blokovaný.", + "Personal ban list": "Osobný zoznam vyhostených", + "Server or user ID to ignore": "Server alebo ID používateľa na odignorovanie", + "eg: @bot:* or example.org": "napr.: @bot:* alebo example.org", + "Subscribed lists": "Odberané listy", + "Subscribing to a ban list will cause you to join it!": "Odbraním listu vyhostených sa pridáte do jeho miestnosti!", + "If this isn't what you want, please use a different tool to ignore users.": "Pokiaľ to nechcete, tak prosím použite iný nástroj na ignorovanie používateľov.", + "Room ID or address of ban list": "ID miestnosti alebo adresa listu vyhostených", + "Subscribe": "Odberať", + "Always show the window menu bar": "Vždy zobraziť hornú lištu okna", + "Show tray icon and minimize window to it on close": "Zobraziť systémovú ikonu a minimalizovať pri zavretí", + "Read Marker lifetime (ms)": "Platnosť značky Prečítané (ms)", + "Read Marker off-screen lifetime (ms)": "Platnosť značky Prečítané mimo obrazovku (ms)", + "Session ID:": "ID relácie:", + "Session key:": "Kľúč relácie:", + "Message search": "Vyhľadávanie v správach", + "Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.": "Váš administrátor serveru zakázal predvolené E2E šifrovanie súkromných miestností & Priamych konverzácií.", + "Where you’re logged in": "Kde ste prihlásený", + "Manage the names of and sign out of your sessions below or verify them in your User Profile.": "Spravujte mená a odhláste sa z vašich relácií nižšie alebo ich overte vo vašom profile používateľa.", + "A session's public name is visible to people you communicate with": "Verejné meno relácie je viditeľné ľudom, s ktorými komunikujete", + "Upgrade this room to the recommended room version": "Upgradujte túto miestnosť na odporúčanú verziu", + "this room": "táto miestnosť", + "View older messages in %(roomName)s.": "Zobraziť staršie správy v miestnosti %(roomName)s.", + "Make this room low priority": "Priradiť tejto miestnosti nízku prioritu", + "Low priority rooms show up at the bottom of your room list in a dedicated section at the bottom of your room list": "Miestnosti s nízkou prioritou sa zobrazia vo vyhradenej sekcií na konci vášho zoznamu miestností", + "This room is bridging messages to the following platforms. Learn more.": "Táto miestnosť premosťuje správy s nasledujúcimi platformami. Viac informácií", + "This room isn’t bridging messages to any platforms. Learn more.": "Táto miestnosť nepremosťuje správy so žiadnymi ďalšími platformami. Viac informácií", + "Bridges": "Mosty", + "Uploaded sound": "Nahratý zvuk", + "Sounds": "Zvuky", + "Notification sound": "Zvuk oznámenia", + "Reset": "Obnoviť predvolené", + "Set a new custom sound": "Nastaviť vlastný zvuk", + "Browse": "Prechádzať", + "Upgrade the room": "Upgradovať miestnosť", + "Enable room encryption": "Povoliť v miestnosti šifrovanie", + "Error changing power level requirement": "Chyba pri zmene požiadavky na úroveň moci", + "An error occurred changing the room's power level requirements. Ensure you have sufficient permissions and try again.": "Došlo k chybe pri zmene požiadavok na úroveň moci miestnosti. Ubezpečte sa, že na to máte dostatočné povolenia a skúste to znovu.", + "Error changing power level": "Chyba pri zmene úrovne moci", + "An error occurred changing the user's power level. Ensure you have sufficient permissions and try again.": "Došlo k chybe pri zmene úrovne moci používateľa. Ubezpečte sa, že na to máte dostatočné povolenia a skúste to znova.", + "To link to this room, please add an address.": "Na prepojenie s touto miestnosťou pridajte prosím adresu.", + "Unable to revoke sharing for email address": "Nepodarilo sa zrušiť zdieľanie emailovej adresy", + "Unable to share email address": "Nepodarilo sa zdieľať emailovú adresu", + "Your email address hasn't been verified yet": "Vaša emailová adresa nebola zatiaľ overená", + "Click the link in the email you received to verify and then click continue again.": "Pre overenie kliknite na odkaz v emaile, ktorý ste dostali, a potom znova kliknite pokračovať.", + "Verify the link in your inbox": "Overte si odkaz v emailovej schránke", + "Complete": "Dokončiť", + "Revoke": "Odvolať", + "Share": "Zdieľať", + "Unable to revoke sharing for phone number": "Nepodarilo sa zrušiť zdieľanie telefónneho čísla", + "Unable to share phone number": "Nepodarilo sa zdieľanie telefónneho čísla", + "Please enter verification code sent via text.": "Zadajte prosím overovací SMS kód.", + "Remove %(email)s?": "Odstrániť adresu %(email)s?", + "Remove %(phone)s?": "Odstrániť číslo %(phone)s?", + "A text message has been sent to +%(msisdn)s. Please enter the verification code it contains.": "SMSka vám bola zaslaná na +%(msisdn)s. Zadajte prosím overovací kód, ktorý obsahuje.", + "This user has not verified all of their sessions.": "Tento používateľ si neoveril všetky svoje relácie.", + "You have not verified this user.": "Tohto používateľa ste neoverili.", + "You have verified this user. This user has verified all of their sessions.": "Tohto používateľa ste overili. Tento používateľ si overil všetky svoje relácie.", + "Someone is using an unknown session": "Niekto používa neznámu reláciu", + "This room is end-to-end encrypted": "Táto miestnosť je E2E šifrovaná", + "Everyone in this room is verified": "Všetci v tejto miestnosti sú overení", + "Edit message": "Upraviť správu", + "Mod": "Moderátor" } diff --git a/src/i18n/strings/sq.json b/src/i18n/strings/sq.json index 1eda92480b..3750d4d768 100644 --- a/src/i18n/strings/sq.json +++ b/src/i18n/strings/sq.json @@ -2345,5 +2345,49 @@ "Set up Secure backup": "Ujdisni kopjeruajtje të Sigurt", "Set a Security Phrase": "Caktoni një Frazë Sigurie", "Confirm Security Phrase": "Ripohoni Frazë Sigurie", - "Save your Security Key": "Ruani Kyçin tuaj të Sigurisë" + "Save your Security Key": "Ruani Kyçin tuaj të Sigurisë", + "Use your account to sign in to the latest version": "Përdorni llogarinë tuaj për të bërë hyrjen te versioni më i ri", + "We’re excited to announce Riot is now Element": "Jemi të ngazëllyer t’ju njoftojmë se Riot tanimë është Element", + "Riot is now Element!": "Riot-i tani është Element!", + "Learn More": "Mësoni Më Tepër", + "Are you sure you want to cancel entering passphrase?": "Jeni i sigurt se doni të anulohet dhënie frazëkalimi?", + "Enable advanced debugging for the room list": "Aktivizo diagnostikim të thelluar për listën e dhomave", + "Enable experimental, compact IRC style layout": "Aktivizo skemë eksperimentale, kompakte, IRC-je", + "Unknown caller": "Thirrës i panjohur", + "Incoming voice call": "Thirrje zanore ardhëse", + "Incoming video call": "Thirrje video ardhëse", + "Incoming call": "Thirrje ardhëse", + "%(brand)s can't securely cache encrypted messages locally while running in a web browser. Use %(brand)s Desktop for encrypted messages to appear in search results.": "%(brand)s s’mund të ruajë lokalisht në fshehtinë në mënyrë të siguruar mesazhe të fshehtëzuar, teksa xhirohet në një shfletues. Që mesazhet e fshehtëzuar të shfaqen te përfundime kërkimi, përdorni %(brand)s Desktop.", + "There are advanced notifications which are not shown here.": "Ka njoftime të thelluara që s’janë shfaqur këtu.", + "You might have configured them in a client other than %(brand)s. You cannot tune them in %(brand)s but they still apply.": "Mund t’i keni formësuar në një klient tjetër nga %(brand)s. S’mund t’i përimtoni në %(brand)s, por janë ende të vlefshëm.", + "Set the name of a font installed on your system & %(brand)s will attempt to use it.": "Caktoni emrin e një palë shkronjash të instaluara në sistemin tuaj & %(brand)s do të provojë t’i përdorë.", + "Make this room low priority": "Bëje këtë dhomë të përparësisë së ulët", + "Low priority rooms show up at the bottom of your room list in a dedicated section at the bottom of your room list": "Dhomat me përparësi të ulët shfaqen në fund të listës tuaj të dhomave, në një ndarje enkas në fund të listës tuaj të dhomave", + "Show rooms with unread messages first": "Së pari shfaq dhoma me mesazhe të palexuar", + "Show previews of messages": "Shfaq paraparje mesazhesh", + "Use default": "Përdor parazgjedhjen", + "Mentions & Keywords": "Përmendje & Fjalëkyçe", + "Notification options": "Mundësi njoftimesh", + "Forget Room": "Harroje Dhomën", + "This room is public": "Kjo dhomë është publike", + "Away": "I larguar", + "Edited at %(date)s": "Përpunuar më %(date)s", + "Click to view edits": "Klikoni që të shihni përpunime", + "Use your account to sign in to the latest version of the app at ": "Përdorni llogarinë tuaj për të hyrë te versioni më i ri i aplikacionit te ", + "You’re already signed in and good to go here, but you can also grab the latest versions of the app on all platforms at element.io/get-started.": "Keni bërë tashmë hyrjen këtu dhe jeni në rregull, por mundeni edhe të merrnit versionet më të reja të aplikacioneve në krejt platformat, te element.io/get-started.", + "Go to Element": "Shko te Element-i", + "We’re excited to announce Riot is now Element!": "Jemi të ngazëllyer të njoftojmë se Riot-i tani e tutje është Element-i!", + "Learn more at element.io/previously-riot": "Mësoni më tepër te element.io/previously-riot", + "You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use %(brand)s with an existing Matrix account on a different homeserver.": "Mund të përdorni mundësitë vetjake për shërbyesin Që të bëni hyrjen te shërbyes të tjerë Matrix, duke specifikuar një URL të një shërbyesi Home tjetër. Kjo ju lejon të përdorni %(brand)s në një tjetër shërbyes Home me një llogari Matrix ekzistuese.", + "Enter the location of your Element Matrix Services homeserver. It may use your own domain name or be a subdomain of element.io.": "Jepni vendndodhjen e shërbyesit tuaj vatër Element Matrix Services. Mund të përdorë emrin e përkatësisë tuaj vetjake ose të jetë një nënpërkatësi e element.io.", + "Search rooms": "Kërkoni në dhoma", + "User menu": "Menu përdoruesi", + "%(brand)s Web": "%(brand)s Web", + "%(brand)s Desktop": "%(brand)s Desktop", + "%(brand)s iOS": "%(brand)s iOS", + "%(brand)s X for Android": "%(brand)s X për Android", + "* %(senderName)s %(emote)s": "* %(senderName)s %(emote)s", + "Custom Tag": "Etiketë Vetjake", + "The person who invited you already left the room.": "Personi që ju ftoi ka dalë nga dhoma tashmë.", + "The person who invited you already left the room, or their server is offline.": "Personi që ju ftoi, ka dalë nga dhoma tashmë, ose shërbyesi i tij është jashtë funksionimi." } diff --git a/src/i18n/strings/sr.json b/src/i18n/strings/sr.json index d1a15e0686..9aee401085 100644 --- a/src/i18n/strings/sr.json +++ b/src/i18n/strings/sr.json @@ -420,7 +420,7 @@ "Custom level": "Прилагођени ниво", "Quote": "Цитат", "Room directory": "Фасцикла са собама", - "Start chat": "Започни ћаскање", + "Start chat": "Започни разговор", "And %(count)s more...|other": "И %(count)s других...", "ex. @bob:example.com": "нпр.: @pera:domen.rs", "Add User": "Додај корисника", @@ -732,7 +732,7 @@ "Invite to this room": "Позови у ову собу", "You cannot delete this message. (%(code)s)": "Не можете обрисати ову поруку. (%(code)s)", "Thursday": "Четвртак", - "I understand the risks and wish to continue": "Разумем опасност и желим да наставим", + "I understand the risks and wish to continue": "Разумем могуће последице и желим наставити", "Back": "Назад", "Reply": "Одговори", "Show message in desktop notification": "Прикажи поруку у стоном обавештењу", @@ -867,5 +867,116 @@ "Call failed due to misconfigured server": "Позив није успео због погрешно подешеног сервера", "Please ask the administrator of your homeserver (%(homeserverDomain)s) to configure a TURN server in order for calls to work reliably.": "Замолите администратора вашег сервера (%(homeserverDomain)s) да подеси TURN сервер како би позиви радили поуздано.", "Alternatively, you can try to use the public server at turn.matrix.org, but this will not be as reliable, and it will share your IP address with that server. You can also manage this in Settings.": "Или, можете покушати да користите јавни сервер на turn.matrix.org, али ово неће бити толико поуздано, и поделиће вашу IP адресу са тим сервером. Ово такође можете мењати у Подешавањима.", - "Try using turn.matrix.org": "Покушајте да користите turn.matrix.org" + "Try using turn.matrix.org": "Покушајте да користите turn.matrix.org", + "Use Single Sign On to continue": "Користи јединствену пријаву за наставак", + "Confirm adding this email address by using Single Sign On to prove your identity.": "Потврдите додавање ове е-адресе коришћењем јединствене пријаве за доказивање вашег идентитета.", + "Single Sign On": "Јединствена пријава", + "Confirm adding email": "Потврди додавање е-адресе", + "Click the button below to confirm adding this email address.": "Кликните на дугме испод за потврђивање додавања ове е-адресе.", + "Add Email Address": "Додај е-адресу", + "Room name or address": "Назив собе или адреса", + "Identity server has no terms of service": "Идентитетски сервер нема услове коришћења", + "Changes your avatar in all rooms": "Промените ваш аватар у свим собама", + "%(senderName)s placed a voice call.": "Корисник %(senderName)s је започео гласовни позив.", + "%(senderName)s placed a voice call. (not supported by this browser)": "Корисник %(senderName)s је започео гласовни позив. (није подржано од стране овог прегледача)", + "%(senderName)s placed a video call.": "Корисник %(senderName)s је започео видео позив.", + "%(senderName)s placed a video call. (not supported by this browser)": "Корисник %(senderName)s је започео видео позив. (није подржано од стране овог прегледача)", + "You do not have permission to invite people to this room.": "Немате дозволу за позивање људи у ову собу.", + "Set up encryption": "Подеси шифровање", + "Encryption upgrade available": "Надоградња шифровања је доступна", + "You changed the room name": "Променили сте назив собе", + "%(senderName)s changed the room name": "Корисник %(senderName)s је променио назив собе", + "%(senderName)s: %(reaction)s": "%(senderName)s: %(reaction)s", + "You changed the room topic": "Променили сте тему собе", + "%(senderName)s changed the room topic": "Корисник %(senderName)s је променио тему собе", + "Multiple integration managers": "Више управника уградњи", + "Try out new ways to ignore people (experimental)": "Испробајте нове начине за игнорисање људи (у пробној фази)", + "Show info about bridges in room settings": "Прикажи податке о мостовима у подешавањима собе", + "Enable Emoji suggestions while typing": "Омогући предлоге емоџија приликом куцања", + "Upload": "Отпреми", + "Show more": "Прикажи више", + "Connecting to integration manager...": "Повезујем се на управника уградњи…", + "Cannot connect to integration manager": "Не могу се повезати на управника уградњи", + "Upgrade to your own domain": "Искористите ваш сопствени домен", + "Email addresses": "Мејл адресе", + "Phone numbers": "Бројеви телефона", + "Set a new account password...": "Подеси нову лозинку налога…", + "Language and region": "Језик и област", + "General": "Опште", + "Discovery": "Откривање", + "None": "Ништа", + "Security & Privacy": "Безбедност и приватност", + "Change room name": "Промени назив собе", + "Enable room encryption": "Омогући шифровање собе", + "Roles & Permissions": "Улоге и дозволе", + "Enable encryption?": "Омогућити шифровање?", + "Encryption": "Шифровање", + "Once enabled, encryption cannot be disabled.": "Након омогућавања, шифровање се не можете онемогућити.", + "Discovery options will appear once you have added an email above.": "Опције откривања појавиће се након што додате мејл адресу изнад.", + "Discovery options will appear once you have added a phone number above.": "Опције откривања појавиће се након што додате број телефона изнад.", + "Email Address": "Е-адреса", + "Phone Number": "Број телефона", + "Encrypted by an unverified session": "Шифровано од стране непотврђене сесије", + "Scroll to most recent messages": "Пребаци на најновије поруке", + "Emoji picker": "Бирач емоџија", + "Send a message…": "Пошаљи поруку…", + "Direct Messages": "Непосредне поруке", + "Create room": "Направи собу", + "People": "Људи", + "Forget this room": "Заборави ову собу", + "Start chatting": "Започни ћаскање", + "Messages in this room are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Поруке у овој соби су обезбеђене шифровањем с краја на крај. Само ви и ваши саговорници имате кључеве потребне за читање ових порука.", + "List options": "Прикажи опције", + "Use default": "Користи подразумевано", + "Mentions & Keywords": "Спомињања и кључне речи", + "Notification options": "Опције обавештавања", + "Forget Room": "Заборави собу", + "Room options": "Опције собе", + "Mark all as read": "Означи све као прочитано", + "Room Name": "Назив собе", + "Room Topic": "Тема собе", + "Messages in this room are end-to-end encrypted.": "Поруке у овој соби су шифроване с краја на крај.", + "Messages in this room are not end-to-end encrypted.": "Поруке у овој соби нису шифроване с краја на крај.", + "%(count)s verified sessions|other": "Укупно потврђених сесија: %(count)s", + "%(count)s verified sessions|one": "Једна потврђена сесија", + "Hide verified sessions": "Сакриј потврђене сесије", + "Remove recent messages by %(user)s": "Уклони недавне поруке корисника %(user)s", + "Remove recent messages": "Уклони недавне поруке", + "Encryption enabled": "Шифровање омогућено", + "Messages in this room are end-to-end encrypted. Learn more & verify this user in their user profile.": "Поруке у овој соби су шифроване с краја на крај. Сазнајте више и потврдите овог корисника у његовом корисничком профилу.", + "Encryption not enabled": "Шифровање није омогућено", + "The encryption used by this room isn't supported.": "Начин шифровања унутар ове собе није подржан.", + "React": "Реагуј", + "Reactions": "Реакције", + " reacted with %(content)s": " реаговали са %(content)s", + "reacted with %(shortName)s": "реаговали са %(shortName)s", + "Smileys & People": "Смешци и особе", + "Quick Reactions": "Брзе реакције", + "Widgets do not use message encryption.": "Виџети не користе шифровање порука.", + "Join": "Приступи", + "Enable end-to-end encryption": "Омогући шифровање с краја на крај", + "Suggestions": "Предлози", + "Invite someone using their name, username (like ), email address or share this room.": "Позовите некога уз помоћ њихово имена, корисничког имена (типа ), мејл адресе или поделите ову собу.", + "Report bugs & give feedback": "Пријави грешке и пошаљи повратне податке", + "Report Content to Your Homeserver Administrator": "Пријави садржај администратору вашег кућног сервера", + "Room Settings - %(roomName)s": "Подешавања собе - %(roomName)s", + "Terms of Service": "Услови коришћења", + "To continue you need to accept the terms of this service.": "За наставак, морате прихватити услове коришћења ове услуге.", + "Service": "Услуга", + "Summary": "Сажетак", + "Document": "Документ", + "Resend %(unsentCount)s reaction(s)": "Поново пошаљи укупно %(unsentCount)s реакција", + "Share Permalink": "Подели трајну везу", + "Report Content": "Пријави садржај", + "Notification settings": "Подешавања обавештења", + "Please install Chrome, Firefox, or Safari for the best experience.": "Инсталирајте Хром, Фајерфокс, или Сафари за најбољи доживљај.", + "%(creator)s created and configured the room.": "Корисник %(creator)s је направио и подесио собу.", + "Preview": "Претпреглед", + "Switch to light mode": "Пребаци на светлу тему", + "Switch to dark mode": "Пребаци на тамну тему", + "Security & privacy": "Безбедност и приватност", + "All settings": "Сва подешавања", + "Feedback": "Повратни подаци", + "General failure": "Општа грешка", + "Copy": "Копирај" } diff --git a/src/i18n/strings/tr.json b/src/i18n/strings/tr.json index b14af3abab..48c051004a 100644 --- a/src/i18n/strings/tr.json +++ b/src/i18n/strings/tr.json @@ -1692,5 +1692,70 @@ "Verify by comparing unique emoji.": "Eşsiz emoji eşleştirme ile doğrulama.", "Edited at %(date)s. Click to view edits.": "%(date)s tarihinde düzenlendi. Düzenlemeleri görmek için tıkla.", "Failed to load group members": "Grup üyeleri yüklenirken başarısız", - "Visibility in Room List": "Oda Listesindeki Görünürlük" + "Visibility in Room List": "Oda Listesindeki Görünürlük", + "Confirm adding email": "E-posta adresini eklemeyi onayla", + "Click the button below to confirm adding this email address.": "E-posta adresini eklemeyi kabul etmek için aşağıdaki tuşa tıklayın.", + "Confirm adding phone number": "Telefon numayasını ekleyi onayla", + "Click the button below to confirm adding this phone number.": "Telefon numarasını eklemeyi kabul etmek için aşağıdaki tuşa tıklayın.", + "Are you sure you want to cancel entering passphrase?": "Parola girmeyi iptal etmek istediğinizden emin misiniz?", + "Room name or address": "Oda adı ya da adresi", + "%(name)s is requesting verification": "%(name)s doğrulama istiyor", + "Use your account to sign in to the latest version": "En son sürümde oturum açmak için hesabınızı kullanın", + "We’re excited to announce Riot is now Element": "Riot'ın artık Element olduğunu duyurmaktan heyecan duyuyoruz", + "Riot is now Element!": "Riot artık Element!", + "Learn More": "", + "Sends a message as html, without interpreting it as markdown": "İletiyi MarkDown olarak göndermek yerine HTML olarak gönderir", + "Failed to set topic": "Konu belirlenemedi", + "Joins room with given address": "Belirtilen adres ile odaya katılır", + "Unrecognised room address:": "Tanımlanamayan oda adresi:", + "Command failed": "Komut başarısız", + "Could not find user in room": "Kullanıcı odada bulunamadı", + "Send a bug report with logs": "Günlükler (log) ile hata raporu gönderin", + "Opens chat with the given user": "Belirtilen kullanıcı ile sohbet başlatır", + "Sends a message to the given user": "Belirtilen kullanıcıya ileti gönderir", + "Light": "Aydınlık", + "Dark": "Karanlık", + "You signed in to a new session without verifying it:": "Yeni bir oturuma, doğrulamadan oturum açtınız:", + "Verify your other session using one of the options below.": "Diğer oturumunuzu aşağıdaki seçeneklerden birini kullanarak doğrulayın.", + "I want to help": "Yardım etmek istiyorum", + "Review where you’re logged in": "Nerelerde oturum açığınızı inceleyin", + "Verify all your sessions to ensure your account & messages are safe": "Hesabınızın ve iletileriniz güvenliği için bütün oturumlarınızı doğrulayın", + "Your homeserver has exceeded its user limit.": "Homeserver'ınız kullanıcı limitini aştı.", + "Your homeserver has exceeded one of its resource limits.": "Homeserver'ınız kaynaklarından birisinin sınırını aştı.", + "Contact your server admin.": "Sunucu yöneticinize başvurun.", + "Ok": "Tamam", + "Set password": "Parola belirle", + "To return to your account in future you need to set a password": "İleride hesabınızı tekrar kullanabilmek için bir parola belirlemeniz gerek", + "New login. Was this you?": "", + "Restart": "Yeniden başlat", + "You joined the call": "Çağrıya katıldınız", + "%(senderName)s joined the call": "%(senderName)s çağrıya katıldı", + "Call in progress": "Çağrı devam ediyor", + "You left the call": "Çağrıdan ayrıldınız", + "%(senderName)s left the call": "%(senderName)s çağrıdan ayrıldı", + "Call ended": "Çağrı sonlandı", + "You started a call": "Bir çağrı başlattınız", + "%(senderName)s started a call": "%(senderName)s bir çağrı başlattı", + "Waiting for answer": "Yanıt bekleniyor", + "%(senderName)s is calling": "%(senderName)s arıyor", + "You created the room": "Odayı oluşturdunuz", + "%(senderName)s created the room": "%(senderName)s odayı oluşturdu", + "You made the chat encrypted": "Sohbeti şifrelediniz", + "%(senderName)s made the chat encrypted": "%(senderName)s sohbeti şifreledi", + "You made history visible to new members": "Yeni üyelere sohbet geçmişini görünür yaptınız", + "%(senderName)s made history visible to new members": "%(senderName)s yeni üyelere sohbet geçmişini görünür yaptı", + "You made history visible to anyone": "Sohbet geçmişini herkese görünür yaptınız", + "%(senderName)s made history visible to anyone": "%(senderName)s sohbet geçmişini herkese görünür yaptı", + "You made history visible to future members": "Sohbet geçmişini gelecek kullanıcılara görünür yaptınız", + "%(senderName)s made history visible to future members": "%(senderName)s sohbet geçmişini gelecek kullanıcılara görünür yaptı", + "You were invited": "Davet edildiniz", + "%(targetName)s was invited": "%(targetName)s davet edildi", + "You left": "Ayrıldınız", + "%(targetName)s left": "%(targetName)s ayrıldı", + "You were kicked (%(reason)s)": "Atıldınız (%(reason)s)", + "%(targetName)s was kicked (%(reason)s)": "%(targetName)s atıldı (%(reason)s)", + "You were kicked": "Atıldınız", + "%(targetName)s was kicked": "%(targetName)s atıldı", + "You rejected the invite": "Daveti reddettiniz", + "%(targetName)s rejected the invite": "%(targetName)s daveti reddetti" } diff --git a/src/i18n/strings/uk.json b/src/i18n/strings/uk.json index bb9accf870..2272ed49eb 100644 --- a/src/i18n/strings/uk.json +++ b/src/i18n/strings/uk.json @@ -6,7 +6,7 @@ "Dismiss": "Відхилити", "Error": "Помилка", "Failed to forget room %(errCode)s": "Не вдалось видалити кімнату %(errCode)s", - "Favourite": "Вибране", + "Favourite": "Улюблені", "Mute": "Стишити", "Notifications": "Сповіщення", "Operation failed": "Не вдалося виконати дію", @@ -21,7 +21,7 @@ "Failed to change password. Is your password correct?": "Не вдалось змінити пароль. Ви впевнені, що пароль введено правильно?", "Continue": "Продовжити", "Accept": "Прийняти", - "Account": "Обліківка", + "Account": "Обліковий запис", "%(targetName)s accepted an invitation.": "%(targetName)s приймає запрошення.", "%(targetName)s accepted the invitation for %(displayName)s.": "%(targetName)s приймає запрошення від %(displayName)s.", "Access Token:": "Токен доступу:", @@ -67,7 +67,7 @@ "Cannot add any more widgets": "Неможливо додати більше віджетів", "Change Password": "Змінити пароль", "%(senderName)s changed their profile picture.": "%(senderName)s змінив/ла зображення профілю.", - "%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s змінив(ла) рівень доступу для %(powerLevelDiffText)s.", + "%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s змінив(ла) рівень повноважень %(powerLevelDiffText)s.", "%(senderDisplayName)s changed the room name to %(roomName)s.": "%(senderDisplayName)s змінив/ла назву кімнати на %(roomName)s.", "%(senderDisplayName)s removed the room name.": "%(senderDisplayName)s видалив ім'я кімнати.", "%(senderDisplayName)s changed the topic to \"%(topic)s\".": "%(senderDisplayName)s змінив тему на %(topic)s.", @@ -78,12 +78,12 @@ "Unpin Message": "Відкріпити повідомлення", "Register": "Зареєструватися", "Rooms": "Кімнати", - "Add rooms to this community": "Добавити кімнати в це суспільство", + "Add rooms to this community": "Додати кімнати в цю спільноту", "This email address is already in use": "Ця е-пошта вже використовується", "This phone number is already in use": "Цей телефонний номер вже використовується", "Fetching third party location failed": "Не вдалось отримати стороннє місцеперебування", "Messages in one-to-one chats": "Повідомлення у чатах \"сам на сам\"", - "Send Account Data": "Відправити данні аккаунта", + "Send Account Data": "Надіслати дані облікового запису", "Advanced notification settings": "Додаткові налаштування сповіщень", "Uploading report": "Завантаження звіту", "Sunday": "Неділя", @@ -92,7 +92,7 @@ "Notification targets": "Цілі сповіщень", "Failed to set direct chat tag": "Не вдалося встановити мітку прямого чату", "Today": "Сьогодні", - "You are not receiving desktop notifications": "Ви не отримуєте сповіщення на стільниці", + "You are not receiving desktop notifications": "Ви не отримуєте системні сповіщення", "Friday": "П'ятниця", "Update": "Оновити", "What's New": "Що нового", @@ -101,7 +101,7 @@ "Waiting for response from server": "Очікується відповідь від сервера", "Leave": "Вийти", "Send Custom Event": "Відправити приватний захід", - "All notifications are currently disabled for all targets.": "Сповіщення для усіх цілей на даний момент вимкнені.", + "All notifications are currently disabled for all targets.": "Сповіщення для усіх цілей наразі момент вимкнені.", "Failed to send logs: ": "Не вдалося відправити журнали: ", "Forget": "Забути", "World readable": "Відкрито для світу", @@ -112,7 +112,7 @@ "Noisy": "Шумний", "Error saving email notification preferences": "Помилка при збереженні параметрів сповіщень е-поштою", "Messages containing my display name": "Повідомлення, вміщає моє ім'я", - "Remember, you can always set an email address in user settings if you change your mind.": "Пам'ятайте, що ви завжди можете встановити адресу е-пошти у налаштуваннях, якщо передумаєте.", + "Remember, you can always set an email address in user settings if you change your mind.": "Пам'ятайте, що ви завжди можете встановити адресу е-пошти у користувацьких налаштуваннях, якщо передумаєте.", "Unavailable": "Нема в наявності", "View Decrypted Source": "Переглянути розшифроване джерело", "Failed to update keywords": "Не вдалось оновити ключові слова", @@ -125,13 +125,13 @@ "Source URL": "Джерельне посилання", "Messages sent by bot": "Повідомлення, надіслані ботом", "Filter results": "Фільтр результатів", - "Members": "Члени", + "Members": "Учасники", "No update available.": "Оновлення відсутні.", "Resend": "Перенадіслати", "Files": "Файли", "Collecting app version information": "Збір інформації про версію застосунка", "Keywords": "Ключові слова", - "Enable notifications for this account": "Увімкнути сповіщення для цієї обліківки", + "Enable notifications for this account": "Увімкнути сповіщення для цього облікового запису", "Invite to this community": "Запросити в це суспільство", "Messages containing keywords": "Повідомлення, що містять ключові слова", "When I'm invited to a room": "Коли мене запрошено до кімнати", @@ -144,7 +144,7 @@ "Developer Tools": "Інструменти розробника", "Preparing to send logs": "Підготовка до відправки журланлу", "Unnamed room": "Неназвана кімната", - "Explore Account Data": "Продивитись данні аккаунта", + "Explore Account Data": "Переглянути дані облікового запису", "All messages (noisy)": "Усі повідомлення (гучно)", "Saturday": "Субота", "I understand the risks and wish to continue": "Я усвідомлюю ризик і бажаю продовжити", @@ -168,7 +168,7 @@ "Send logs": "Надіслати журнали", "All messages": "Усі повідомлення", "Call invitation": "Запрошення до виклику", - "Downloading update...": "Звантаженя оновлення…", + "Downloading update...": "Завантаженя оновлення…", "State Key": "Ключ стану", "Failed to send custom event.": "Не вдалося відправити приватний захід.", "What's new?": "Що нового?", @@ -198,7 +198,7 @@ "%(brand)s does not know how to join a room on this network": "%(brand)s не знає як приєднатись до кімнати у цій мережі", "Mentions only": "Тільки згадки", "Failed to remove tag %(tagName)s from room": "Не вдалося прибрати з кімнати мітку %(tagName)s", - "You can now return to your account after signing out, and sign in on other devices.": "Тепер ви можете повернутися до своєї обліковки після виходу з неї, та зайти з інших пристроїв.", + "You can now return to your account after signing out, and sign in on other devices.": "Тепер ви можете повернутися до свого облікового запису після виходу з нього, а також зайти з інших пристроїв.", "Enable email notifications": "Увімкнути сповіщення е-поштою", "Event Type": "Тип західу", "No rooms to show": "Кімнати відсутні", @@ -240,33 +240,33 @@ "You cannot place a call with yourself.": "Ви не можете подзвонити самим собі.", "Warning!": "Увага!", "Upload Failed": "Помилка відвантаження", - "Sun": "Нд", - "Mon": "Пн", - "Tue": "Вт", - "Wed": "Ср", - "Thu": "Чт", - "Fri": "Пт", - "Sat": "Сб", - "Jan": "Січ", - "Feb": "Лют", - "Mar": "Бер", - "Apr": "Квіт", - "May": "Трав", - "Jun": "Чер", - "Jul": "Лип", - "Aug": "Сер", - "Sep": "Вер", - "Oct": "Жов", - "Nov": "Лис", - "Dec": "Гру", - "PM": "PM", - "AM": "AM", + "Sun": "нд", + "Mon": "пн", + "Tue": "вт", + "Wed": "ср", + "Thu": "чт", + "Fri": "пт", + "Sat": "сб", + "Jan": "січ.", + "Feb": "лют.", + "Mar": "бер.", + "Apr": "квіт.", + "May": "трав.", + "Jun": "черв.", + "Jul": "лип.", + "Aug": "серп.", + "Sep": "вер.", + "Oct": "жовт.", + "Nov": "лист.", + "Dec": "груд.", + "PM": "пп", + "AM": "дп", "%(weekDayName)s %(time)s": "%(weekDayName)s %(time)s", - "%(weekDayName)s, %(monthName)s %(day)s %(time)s": "%(weekDayName)s, %(monthName)s, %(day)s, %(time)s", - "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": "%(weekDayName)s, %(monthName)s, %(day)s, %(fullYear)s", - "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s": "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s", + "%(weekDayName)s, %(monthName)s %(day)s %(time)s": "%(weekDayName)s, %(day)s %(monthName)s %(time)s", + "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": "%(weekDayName)s, %(day)s %(monthName)s %(fullYear)s", + "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s": "%(weekDayName)s, %(day)s %(monthName)s %(fullYear)s %(time)s", "Who would you like to add to this community?": "Кого ви хочете додати до цієї спільноти?", - "Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": "Якщо дана сторінка містить особисту інформацію, як то назва кімнати, користувача чи групи, ці дані будуть вилучені перед надсиланням на сервер.", + "Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": "Там, де ця сторінка містить ототожненну інформацію, як-от назва кімнати, користувача чи групи, ці дані будуть вилучені перед надсиланням на сервер.", "Call in Progress": "Іде виклик", "A call is currently being placed!": "Зараз іде виклик!", "A call is already in progress!": "Вже здійснюється дзвінок!", @@ -298,7 +298,7 @@ "Missing roomId.": "Бракує ідентифікатора кімнати.", "Failed to send request.": "Не вдалося надіслати запит.", "This room is not recognised.": "Кімнату не знайдено.", - "Power level must be positive integer.": "Рівень прав мусить бути додатнім цілим числом.", + "Power level must be positive integer.": "Рівень повноважень мусить бути додатнім цілим числом.", "You are not in this room.": "Вас немає в цій кімнаті.", "You do not have permission to do that in this room.": "У вас немає прав виконувати для цього в цій кімнаті.", "Missing room_id in request": "У запиті бракує room_id", @@ -311,18 +311,18 @@ "Changes your display nickname": "Змінює ваш нік", "Invites user with given id to current room": "Запрошує користувача з вказаним ідентифікатором до кімнати", "Leave room": "Покинути кімнату", - "Kicks user with given id": "Вилучити з кімнати користувача з вказаним ідентифікатором", - "Ignores a user, hiding their messages from you": "Ігнорує користувача, приховуючи повідомлення від них", - "Ignored user": "Користувача ігноровано", + "Kicks user with given id": "Викидає з кімнати користувача з вказаним ідентифікатором", + "Ignores a user, hiding their messages from you": "Ігнорує користувача, приховуючи його повідомлення від вас", + "Ignored user": "Зігнорований користувач", "You are now ignoring %(userId)s": "Ви ігноруєте %(userId)s", "Stops ignoring a user, showing their messages going forward": "Припиняє ігнорувати користувача, від цього моменту показуючи їхні повідомлення", "Unignored user": "Припинено ігнорування користувача", "You are no longer ignoring %(userId)s": "Ви більше не ігноруєте %(userId)s", - "Define the power level of a user": "Вказати рівень прав користувача", + "Define the power level of a user": "Вказати рівень повноважень користувача", "Deops user with given id": "Знімає права оператора з користувача з вказаним ідентифікатором", "Opens the Developer Tools dialog": "Відкриває вікно інструментів розробника", - "Verified key": "Перевірений ключ", - "Displays action": "Показує дію", + "Verified key": "Звірений ключ", + "Displays action": "Відбиває дію", "Reason": "Причина", "%(senderName)s requested a VoIP conference.": "%(senderName)s бажає розпочати дзвінок-конференцію.", "%(senderName)s invited %(targetName)s.": "%(senderName)s запросив/ла %(targetName)s.", @@ -339,9 +339,9 @@ "%(senderName)s unbanned %(targetName)s.": "%(senderName)s розблокував/ла %(targetName)s.", "%(senderName)s kicked %(targetName)s.": "%(senderName)s викинув/ла %(targetName)s.", "%(senderName)s withdrew %(targetName)s's invitation.": "%(senderName)s відкликав/ла запрошення %(targetName)s.", - "%(senderDisplayName)s sent an image.": "%(senderDisplayName)s надіслав/ла зображення.", - "%(senderName)s set the main address for this room to %(address)s.": "%(senderName)s призначив/ла основну адресу цієї кімнати: %(address)s.", - "%(senderName)s removed the main address for this room.": "%(senderName)s вилучив/ла основу адресу цієї кімнати.", + "%(senderDisplayName)s sent an image.": "%(senderDisplayName)s надіслав(-ла) зображення.", + "%(senderName)s set the main address for this room to %(address)s.": "%(senderName)s призначив(-ла) основну адресу цієї кімнати: %(address)s.", + "%(senderName)s removed the main address for this room.": "%(senderName)s прибрав(-ла) основу адресу цієї кімнати.", "Someone": "Хтось", "(not supported by this browser)": "(не підтримується цією веб-переглядачкою)", "(could not connect media)": "(не можливо під'єднати медіа)", @@ -374,7 +374,7 @@ "Sorry, your homeserver is too old to participate in this room.": "Вибачте, ваш домашній сервер занадто старий, щоб приєднатися до цієї кімнати.", "Please contact your homeserver administrator.": "Будь ласка, зв'яжіться з адміністратором вашого домашнього сервера.", "Failed to join room": "Не вдалося приєднатися до кімнати", - "Message Pinning": "Прикріплені повідомлення", + "Message Pinning": "Закріплені повідомлення", "Show timestamps in 12 hour format (e.g. 2:30pm)": "Показувати час у 12-годинному форматі (напр. 2:30 pm)", "Always show encryption icons": "Завжди показувати значки шифрування", "Enable automatic language detection for syntax highlighting": "Показувати автоматичне визначення мови для підсвічування синтаксису", @@ -398,12 +398,12 @@ "New passwords don't match": "Нові паролі не збігаються", "Passwords can't be empty": "Пароль не може бути пустим", "Export E2E room keys": "Експортувати ключі наскрізного шифрування кімнат", - "Do you want to set an email address?": "Бажаєте вказати адресу електронної пошти?", + "Do you want to set an email address?": "Бажаєте вказати адресу е-пошти?", "Current password": "Поточний пароль", "Password": "Пароль", "New Password": "Новий пароль", "Confirm password": "Підтвердження пароля", - "Last seen": "Востаннє з'являвся", + "Last seen": "Востаннє в мережі", "Failed to set display name": "Не вдалося встановити ім'я для показу", "The maximum permitted number of widgets have already been added to this room.": "Максимально дозволену кількість віджетів уже додано до цієї кімнати.", "Drop File Here": "Киньте файл сюди", @@ -460,7 +460,7 @@ "Sends a message as plain text, without interpreting it as markdown": "Надсилає повідомлення як чистий текст, не використовуючи markdown", "Upgrades a room to a new version": "Покращує кімнату до нової версії", "You do not have the required permissions to use this command.": "Вам бракує дозволу на використання цієї команди.", - "Warning: Upgrading a room will not automatically migrate room members to the new version of the room. We'll post a link to the new room in the old version of the room - room members will have to click this link to join the new room.": "Увага!: Покращення кімнати не перенесе автоматично усіх учасників до нової версії кімнати. Ми опублікуємо посилання на нову кімнату у старій версії кімнати, а учасники мають власноруч клацнути це посилання, щоб приєднатися до нової кімнати.", + "Warning: Upgrading a room will not automatically migrate room members to the new version of the room. We'll post a link to the new room in the old version of the room - room members will have to click this link to join the new room.": "Увага!: Поліпшення кімнати не перенесе автоматично усіх учасників до нової версії кімнати. Ми опублікуємо посилання на нову кімнату у старій версії кімнати, а учасники мають власноруч клацнути це посилання, щоб приєднатися до нової кімнати.", "Changes your display nickname in the current room only": "Змінює ваше псевдо тільки для поточної кімнати", "Changes the avatar of the current room": "Змінює аватар поточної кімнати", "Changes your avatar in this current room only": "Змінює ваш аватар для поточної кімнати", @@ -469,16 +469,16 @@ "This room has no topic.": "Ця кімната не має теми.", "Sets the room name": "Встановлює назву кімнати", "Use an identity server": "Використовувати сервер ідентифікації", - "Use an identity server to invite by email. Manage in Settings.": "Використовувати сервер ідентифікації для запрошень через е-пошту. Керується у налаштуваннях.", + "Use an identity server to invite by email. Manage in Settings.": "Використовувати сервер ідентифікації для запрошень через е-пошту. Керуйте у налаштуваннях.", "Unbans user with given ID": "Розблоковує користувача з вказаним ідентифікатором", "Adds a custom widget by URL to the room": "Додає власний віджет до кімнати за посиланням", "Please supply a https:// or http:// widget URL": "Вкажіть посилання на віджет — https:// або http://", "You cannot modify widgets in this room.": "Ви не можете змінювати віджети у цій кімнаті.", - "Forces the current outbound group session in an encrypted room to be discarded": "Примусово відкидає поточний вихідний груповий сеанс у шифрованій кімнаті", - "Sends the given message coloured as a rainbow": "Надсилає вказане повідомлення розфарбоване веселкою", + "Forces the current outbound group session in an encrypted room to be discarded": "Примусово відкидає поточний вихідний груповий сеанс у зашифрованій кімнаті", + "Sends the given message coloured as a rainbow": "Надсилає вказане повідомлення, розфарбоване веселкою", "Your %(brand)s is misconfigured": "Ваш %(brand)s налаштовано неправильно", "Join the discussion": "Приєднатися до обговорення", - "Upload": "Відвантажити", + "Upload": "Обрати", "Upload file": "Відвантажити файл", "Send an encrypted message…": "Надіслати зашифроване повідомлення…", "The conversation continues here.": "Розмова триває тут.", @@ -525,7 +525,7 @@ "This room is used for important messages from the Homeserver, so you cannot leave it.": "Ця кімната використовується для важливих повідомлень з домашнього сервера, тож ви не можете її залишити.", "Use Single Sign On to continue": "Використати Single Sign On для продовження", "Confirm adding this email address by using Single Sign On to prove your identity.": "Підтвердьте додавання цієї адреси е-пошти через використання Single Sign On аби довести вашу ідентичність.", - "Single Sign On": "Single Sign On", + "Single Sign On": "Єдиний вхід", "Confirm adding email": "Підтвердити додавання е-пошти", "Click the button below to confirm adding this email address.": "Клацніть на кнопці нижче щоб підтвердити додавання цієї адреси е-пошти.", "Confirm": "Підтвердити", @@ -542,49 +542,49 @@ "Enter passphrase": "Введіть парольну фразу", "Setting up keys": "Налаштовування ключів", "Verify this session": "Звірити цю сесію", - "Sign In or Create Account": "Увійти або створити обліківку", - "Use your account or create a new one to continue.": "Скористайтесь вашою обліківкою або створіть нову щоб продовжити.", - "Create Account": "Створити обліківку", + "Sign In or Create Account": "Увійти або створити обліковий запис", + "Use your account or create a new one to continue.": "Скористайтесь вашим обліковим записом або створіть нову, щоб продовжити.", + "Create Account": "Створити обліковий запис", "Sign In": "Увійти", - "Verify all your sessions to ensure your account & messages are safe": "Звірте усі ваші сесії аби переконатись, що ваші обліківка та повідомлення у безпеці", + "Verify all your sessions to ensure your account & messages are safe": "Звірте усі ваші сеанси, аби переконатись, що ваш обліковий запис і повідомлення у безпеці", "Later": "Пізніше", "Review": "Переглянути", - "Verify yourself & others to keep your chats safe": "Звірте себе й інших щоб зберегти ваше спілкування у безпеці", + "Verify yourself & others to keep your chats safe": "Верифікуйте себе й інших щоб зберегти ваше спілкування у безпеці", "Verify": "Звірити", - "Verify the new login accessing your account: %(name)s": "Звірити новий вхід, що доступається до вашої обліківки: %(name)s", + "Verify the new login accessing your account: %(name)s": "Звірити новий вхід, що доступається до вашого облікового запису: %(name)s", "From %(deviceName)s (%(deviceId)s)": "Від %(deviceName)s (%(deviceId)s)", "Decline (%(counter)s)": "Відхилити (%(counter)s)", "Language and region": "Мова та регіон", - "Account management": "Керування обліківкою", - "Deactivating your account is a permanent action - be careful!": "Деактивація вашої обліківки є безповоротною дією — будьте обережні!", - "Deactivate Account": "Знедіяти обліківку", + "Account management": "Керування обліковим записом", + "Deactivating your account is a permanent action - be careful!": "Деактивація вашого облікового запису є безповоротною дією — будьте обережні!", + "Deactivate Account": "Деактивувати обліковий запис", "Deactivate account": "Знедіяти обліківку", "Legal": "Правова інформація", "Credits": "Подяки", "For help with using %(brand)s, click here.": "Якщо необхідна допомога у користуванні %(brand)s'ом, клацніть тут.", "For help with using %(brand)s, click here or start a chat with our bot using the button below.": "Якщо необхідна допомога у користуванні %(brand)s'ом, клацніть тут або розпочніть балачку з нашим ботом, клацнувши на кнопці нижче.", - "Join the conversation with an account": "Приєднатись до бесіди з обліківкою", + "Join the conversation with an account": "Приєднатись до бесіди з обліковим записом", "Unable to restore session": "Неможливо відновити сесію", "We encountered an error trying to restore your previous session.": "Ми натрапили на помилку, намагаючись відновити вашу попередню сесію.", "Please install Chrome, Firefox, or Safari for the best experience.": "Для найкращих вражень від користування встановіть, будь ласка, Chrome, Firefox, або Safari.", - "Your account has a cross-signing identity in secret storage, but it is not yet trusted by this session.": "Ваша обліківка має перехресно-підписувану ідентичність у таємному сховищі, але вона ще не є довіреною у цій сесії.", - "in account data": "у даних обліківки", + "Your account has a cross-signing identity in secret storage, but it is not yet trusted by this session.": "Ваш обліковий запис має перехресно-підписувану ідентичність у таємному сховищі, але вона ще не є довіреною у цій сесії.", + "in account data": "у даних облікового запису", "Clear notifications": "Очистити сповіщення", "Add an email address to configure email notifications": "Додати адресу е-пошти для налаштування поштових сповіщень", "Theme added!": "Тему додано!", - "Email addresses": "Адреси е-пошти", + "Email addresses": "Адреса е-пошти", "Phone numbers": "Номери телефонів", - "Set a new account password...": "Встановити новий пароль обліківки…", + "Set a new account password...": "Встановити новий пароль облікового запису…", "Forget this room": "Забути цю кімнату", "Re-join": "Перепід'єднатись", - "This invite to %(roomName)s was sent to %(email)s which is not associated with your account": "Це запрошення до %(roomName)s було надіслане на %(email)s, яка не пов'язана з вашою обліківкою", - "Link this email with your account in Settings to receive invites directly in %(brand)s.": "Зв'яжіть цю е-пошту з вашою обліківкою у Налаштуваннях щоб отримувати сповіщення прямо у %(brand)s.", + "This invite to %(roomName)s was sent to %(email)s which is not associated with your account": "Це запрошення до %(roomName)s було надіслане на %(email)s, яка не пов'язана з вашим обліковим записом", + "Link this email with your account in Settings to receive invites directly in %(brand)s.": "Зв'яжіть цю е-пошту з вашим обліковим записом у Налаштуваннях щоб отримувати сповіщення прямо у %(brand)s.", "This invite to %(roomName)s was sent to %(email)s": "Це запрошення до %(roomName)s було надіслане на %(email)s", "Use an identity server in Settings to receive invites directly in %(brand)s.": "Використовувати сервер ідентифікації у Налаштуваннях щоб отримувати запрошення прямо у %(brand)s.", - "Are you sure you want to deactivate your account? This is irreversible.": "Ви впевнені у тому, що бажаєте знедіяти вашу обліківку? Це є безповоротним.", - "Confirm account deactivation": "Підтвердьте деактивацію обліківки", + "Are you sure you want to deactivate your account? This is irreversible.": "Ви впевнені у тому, що бажаєте знедіяти ваш обліковий запис? Ця дія безповоротна.", + "Confirm account deactivation": "Підтвердьте деактивацію облікового запису", "To continue, please enter your password:": "Щоб продовжити, введіть, будь ласка, ваш пароль:", - "This will make your account permanently unusable. You will not be able to log in, and no one will be able to re-register the same user ID. This will cause your account to leave all rooms it is participating in, and it will remove your account details from your identity server. This action is irreversible.": "Ваша обліківка стане назавжди невикористовною. Ви не матимете змоги увійти в неї і ніхто не зможе перереєструватись під цим користувацьким ID. Це призведе до виходу вашої обліківки з усіх кімнат та до видалення деталей вашої обліківки з вашого серверу ідентифікації. Ця дія є безповоротною.", + "This will make your account permanently unusable. You will not be able to log in, and no one will be able to re-register the same user ID. This will cause your account to leave all rooms it is participating in, and it will remove your account details from your identity server. This action is irreversible.": "Ваш обліковий запис стане назавжди невикористовним. Ви не матимете змоги увійти в нього і ніхто не зможе перереєструватись під цим користувацьким ID. Це призведе до виходу вашого облікового запису з усіх кімнат та до видалення деталей вашого облікового запису з вашого серверу ідентифікації. Ця дія є безповоротною.", "Verify session": "Звірити сесію", "Session name": "Назва сесії", "Session ID": "ID сесії", @@ -607,12 +607,498 @@ "Room": "Кімната", "Failed to reject invite": "Не вдалось відхилити запрошення", "You have %(count)s unread notifications in a prior version of this room.|other": "Ви маєте %(count)s непрочитаних сповіщень у попередній версії цієї кімнати.", - "You have %(count)s unread notifications in a prior version of this room.|one": "У вас одне непрочитане сповіщення у попередній версії цієї кімнати.", + "You have %(count)s unread notifications in a prior version of this room.|one": "У вас %(count)s непрочитане сповіщення у попередній версії цієї кімнати.", "Deactivate user?": "Знедіяти користувача?", "Deactivating this user will log them out and prevent them from logging back in. Additionally, they will leave all the rooms they are in. This action cannot be reversed. Are you sure you want to deactivate this user?": "Знедіювання цього користувача виведе їх з системи і унеможливить вхід у майбутньому. До того ж, вони залишать усі кімнати, в яких перебувають. Ця дія є безповоротною. Ви впевнені, що хочете знедіяти цього користувача?", "Deactivate user": "Знедіяти користувача", "Failed to deactivate user": "Не вдалось знедіяти користувача", - "Deactivating your account does not by default cause us to forget messages you have sent. If you would like us to forget your messages, please tick the box below.": "Знедіювання вашої обліківки типово не призводить до забуття надісланих вами повідомлень. Якщо ви бажаєте щоб ми забули ваші повідомлення, поставте прапорець внизу.", + "Deactivating your account does not by default cause us to forget messages you have sent. If you would like us to forget your messages, please tick the box below.": "Знедіювання вашого облікового запису типово не призводить до забуття надісланих вами повідомлень. Якщо ви бажаєте, щоб ми забули ваші повідомлення, поставте прапорець внизу.", "Message visibility in Matrix is similar to email. Our forgetting your messages means that messages you have sent will not be shared with any new or unregistered users, but registered users who already have access to these messages will still have access to their copy.": "Видність повідомлень у Matrix є схожою до е-пошти. Забування нами ваших повідомлень означає, що надіслані вами повідомлення не будуть поширені будь-яким новим чи незареєстрованим користувачам, але зареєстровані користувачі, які мають доступ до цих повідомлень, і надалі матимуть доступ до їхніх копій.", - "Please forget all messages I have sent when my account is deactivated (Warning: this will cause future users to see an incomplete view of conversations)": "Забудьте, будь ласка, усі надіслані мною повідомлення після знедіювання моєї обліківки. (Попередження: після цього майбутні користувачі бачитимуть неповні бесіди)" + "Please forget all messages I have sent when my account is deactivated (Warning: this will cause future users to see an incomplete view of conversations)": "Забудьте, будь ласка, усі надіслані мною повідомлення після знедіювання мого облікового запису. (Попередження: після цього майбутні користувачі бачитимуть неповні бесіди)", + "Are you sure you want to cancel entering passphrase?": "Ви точно хочете скасувати введення парольної фрази?", + "Go Back": "Назад", + "Room name or address": "Назва та адреса кімнати", + "%(name)s is requesting verification": "%(name)s робить запит на звірення", + "Use your account to sign in to the latest version": "Увійдіть до останньої версії через свій обліковий запис", + "We’re excited to announce Riot is now Element": "Ми раді повідомити, що Riot тепер називається Element", + "Riot is now Element!": "Riot тепер - Element!", + "Learn More": "Дізнатися більше", + "Command error": "Помилка команди", + "Sends a message as html, without interpreting it as markdown": "Надсилає повідомлення як HTML, не інтерпритуючи Markdown", + "Failed to set topic": "Не вдалося встановити тему", + "Once enabled, encryption cannot be disabled.": "Після увімкнення шифрування не можна буде вимкнути.", + "Please enter verification code sent via text.": "Будь ласка, введіть звірювальний код, відправлений у текстовому повідомленні.", + "A text message has been sent to +%(msisdn)s. Please enter the verification code it contains.": "Текстове повідомлення було відправлено на номер +%(msisdn)s. Будь ласка, введіть звірювальний код, який воно містить.", + "Messages in this room are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Повідомлення у цій кімнаті захищені наскрізним шифруванням. Тільки ви та одержувачі мають ключі для прочитання цих повідомлень.", + "Messages in this room are end-to-end encrypted.": "Повідомлення у цій кімнаті захищені наскрізним шифруванням.", + "Messages in this room are not end-to-end encrypted.": "Повідомлення у цій кімнаті не захищені наскрізним шифруванням.", + "Encryption enabled": "Шифрування увімкнено", + "Messages in this room are end-to-end encrypted. Learn more & verify this user in their user profile.": "Повідомлення у цій кімнаті захищені наскрізним шифруванням. Дізнайтеся більше та звіртеся з цим користувачем через його профіль.", + "You sent a verification request": "Ви відправили звірювальний запит", + "Direct Messages": "Особисті повідомлення", + "Room Settings - %(roomName)s": "Налаштування кімнати - %(roomName)s", + "A verification email will be sent to your inbox to confirm setting your new password.": "Ми відправимо перевіряльний електронний лист до вас для підтвердження зміни пароля.", + "To return to your account in future you need to set a password": "Щоб повернутися до своєї обліківки в майбутньому, вам потрібно встановити пароль", + "Use an identity server to invite by email. Click continue to use the default identity server (%(defaultIdentityServerName)s) or manage in Settings.": "Використовувати сервер ідентифікації, щоб запрошувати через е-пошту. Натисніть \"Продовжити\", щоб використовувати типовий сервер ідентифікації (%(defaultIdentityServerName)s) або змініть його у налаштуваннях.", + "Joins room with given address": "Приєднатися до кімнати зі вказаною адресою", + "Unrecognised room address:": "Невпізнана адреса кімнати:", + "Command failed": "Не вдалося виконати команду", + "Could not find user in room": "Не вдалося знайти користувача в кімнаті", + "Please supply a widget URL or embed code": "Вкажіть URL або код вставки віджету", + "Verifies a user, session, and pubkey tuple": "Звіряє користувача, сеанс та кортеж відкритого ключа", + "Unknown (user, session) pair:": "Невідома пара (користувача, сеансу):", + "Session already verified!": "Сеанс вже підтверджений!", + "WARNING: Session already verified, but keys do NOT MATCH!": "УВАГА: Сеанс вже підтверджений, проте ключі НЕ ЗБІГАЮТЬСЯ!", + "WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and session %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!": "УВАГА: НЕ ВДАЛОСЯ ЗДІЙСНИТИ ЗВІРЯННЯ КЛЮЧА! Ключем для %(userId)s та сеансу %(deviceId)s є \"%(fprint)s\", що не відповідає наданому ключу \"%(fingerprint)s\". Це може означати, що ваші повідомлення перехоплюють!", + "The signing key you provided matches the signing key you received from %(userId)s's session %(deviceId)s. Session marked as verified.": "Наданий вами ключ підпису збігається з ключем підпису, що ви отримали від сеансу %(deviceId)s %(userId)s. Сеанс позначено як звірений.", + "Sends the given emote coloured as a rainbow": "Надсилає вказаний смайлик, розфарбований веселкою", + "Displays list of commands with usages and descriptions": "Відбиває перелік команд із прикладами вжитку та описом", + "Displays information about a user": "Відбиває інформацію про користувача", + "Send a bug report with logs": "Надіслати звіт про ваду разом з журналами", + "Opens chat with the given user": "Відкриває балачку з вказаним користувачем", + "Sends a message to the given user": "Надсилає повідомлення вказаному користувачеві", + "%(senderName)s made no change.": "%(senderName)s не запровадив(-ла) жодних змін.", + "%(senderDisplayName)s changed the room name from %(oldRoomName)s to %(newRoomName)s.": "%(senderDisplayName)s змінив(ла) назву кімнати з %(oldRoomName)s на %(newRoomName)s.", + "%(senderDisplayName)s upgraded this room.": "%(senderDisplayName)s поліпшив(-ла) цю кімнату.", + "%(senderDisplayName)s made the room public to whoever knows the link.": "%(senderDisplayName)s зробив(-ла) кімнату відкритою для всіх, хто знає посилання.", + "%(senderDisplayName)s made the room invite only.": "%(senderDisplayName)s зробив(-ла) кімнату доступною лише за запрошеннями.", + "%(senderDisplayName)s changed the join rule to %(rule)s": "%(senderDisplayName)s змінив(-ла) правило приєднування на \"%(rule)s\"", + "%(senderDisplayName)s has allowed guests to join the room.": "%(senderDisplayName)s дозволив(-ла) гостям приєднуватися до кімнати.", + "%(senderDisplayName)s has prevented guests from joining the room.": "%(senderDisplayName)s заборонив(-ла) гостям приєднуватися до кімнати.", + "%(senderDisplayName)s changed guest access to %(rule)s": "%(senderDisplayName)s змінив(-ла) гостьовий доступ на \"%(rule)s\"", + "%(senderDisplayName)s enabled flair for %(groups)s in this room.": "%(senderDisplayName)s увімкнув(-ла) значок для %(groups)s у цій кімнаті.", + "%(senderDisplayName)s disabled flair for %(groups)s in this room.": "%(senderDisplayName)s вимкнув(-ла) значок для %(groups)s в цій кімнаті.", + "%(senderName)s added the alternative addresses %(addresses)s for this room.|other": "%(senderName)s додав(-ла) альтернативні адреси %(addresses)s для цієї кімнати.", + "%(senderName)s added the alternative addresses %(addresses)s for this room.|one": "%(senderName)s додав(-ла) альтернативні адреси %(addresses)s для цієї кімнати.", + "%(senderName)s removed the alternative addresses %(addresses)s for this room.|other": "%(senderName)s прибрав(-ла) альтернативні адреси %(addresses)s для цієї кімнати.", + "%(senderName)s removed the alternative addresses %(addresses)s for this room.|one": "%(senderName)s прибрав(-ла) альтернативні адреси %(addresses)s для цієї кімнати.", + "%(senderName)s changed the alternative addresses for this room.": "%(senderName)s змінив(-ла) альтернативні адреси для цієї кімнати.", + "%(senderName)s changed the main and alternative addresses for this room.": "%(senderName)s змінив(-ла) головні та альтернативні адреси для цієї кімнати.", + "%(senderName)s changed the addresses for this room.": "%(senderName)s змінив(-ла) адреси для цієї кімнати.", + "%(senderName)s placed a voice call.": "%(senderName)s розпочав(-ла) голосовий виклик.", + "%(senderName)s placed a voice call. (not supported by this browser)": "%(senderName)s розпочав(-ла) голосовий виклик. (не підтримується цим переглядачем)", + "%(senderName)s placed a video call.": "%(senderName)s розпочав(-ла) відеовиклик.", + "%(senderName)s placed a video call. (not supported by this browser)": "%(senderName)s розпочав(-ла) відеовиклик. (не підтримується цим переглядачем)", + "%(senderName)s revoked the invitation for %(targetDisplayName)s to join the room.": "%(senderName)s відкликав(-ла) запрошення %(targetDisplayName)s приєднання до кімнати.", + "%(senderName)s removed the rule banning users matching %(glob)s": "%(senderName)s видалив(ла) правило блокування користувачів по шаблону %(glob)s", + "%(senderName)s removed the rule banning rooms matching %(glob)s": "%(senderName)s видалив(ла) правило блокування кімнат по шаблону %(glob)s", + "%(senderName)s removed the rule banning servers matching %(glob)s": "%(senderName)s видалив(ла) правило блокування серверів по шаблону %(glob)s", + "%(senderName)s removed a ban rule matching %(glob)s": "%(senderName)s видалив(ла) правило блокування по шаблону %(glob)s", + "%(senderName)s updated an invalid ban rule": "%(senderName)s оновив(ла) неправильне правило блокування", + "%(senderName)s updated the rule banning users matching %(glob)s for %(reason)s": "%(senderName)s оновив(ла) правило блокування користувачів по шаблону %(glob)s за %(reason)s", + "%(senderName)s updated the rule banning rooms matching %(glob)s for %(reason)s": "%(senderName)s оновив(ла) правило блокування кімнат по шаблону %(glob)s за %(reason)s", + "%(senderName)s updated the rule banning servers matching %(glob)s for %(reason)s": "%(senderName)s оновив(ла) правило блокування серверів по шаблону %(glob)s за %(reason)s", + "%(senderName)s updated a ban rule matching %(glob)s for %(reason)s": "%(senderName)s оновив(ла) правило блокування по шаблону %(glob)s за %(reason)s", + "%(senderName)s created a rule banning users matching %(glob)s for %(reason)s": "%(senderName)s створив(ла) правило блокування користувачів по шаблону %(glob)s за %(reason)s", + "%(senderName)s created a rule banning rooms matching %(glob)s for %(reason)s": "%(senderName)s створив(ла) правило блокування кімнат по шаблону %(glob)s за %(reason)s", + "%(senderName)s created a rule banning servers matching %(glob)s for %(reason)s": "%(senderName)s створив(ла) правило блокування серверів по шаблону %(glob)s за %(reason)s", + "Light": "Світла", + "Dark": "Темна", + "You signed in to a new session without verifying it:": "Ви увійшли в нову сесію, не підтвердивши її:", + "Verify your other session using one of the options below.": "Перевірте іншу сесію, використвуючи один із варіантів нижче.", + "%(name)s (%(userId)s) signed in to a new session without verifying it:": "%(name)s (%(userId)s) почав(ла) нову сесію без її підтвердження:", + "Ask this user to verify their session, or manually verify it below.": "Попросіть цього користувача підтвердити сесію, або підтвердіть її власноруч нижче.", + "Not Trusted": "Недовірене", + "Manually Verify by Text": "Ручна перевірка за допомогою тексту", + "Interactively verify by Emoji": "Інтерактивна перевірка з емодзі", + "Done": "Зроблено", + "%(displayName)s is typing …": "%(displayName)s друкує…", + "%(names)s and %(count)s others are typing …|other": "%(names)s та %(count)s інших друкують…", + "%(names)s and %(count)s others are typing …|one": "%(names)s та ще один(на) друкують…", + "%(names)s and %(lastPerson)s are typing …": "%(names)s та %(lastPerson)s друкують…", + "Ask your %(brand)s admin to check your config for incorrect or duplicate entries.": "Попросіть адміністратора %(brand)s перевірити конфігураційний файл на наявність неправильних або повторюваних записів.", + "Cannot reach identity server": "Не вдається зв'язатися із сервером ідентифікаціїї", + "No homeserver URL provided": "URL адресу домашнього сервера не вказано", + "Unexpected error resolving homeserver configuration": "Неочікувана помилка в налаштуваннях домашнього серверу", + "Unexpected error resolving identity server configuration": "Незрозуміла помилка при розборі параметру сервера ідентифікації", + "The message you are trying to send is too large.": "Ваше повідомлення було занадто велике.", + "%(items)s and %(count)s others|other": "%(items)s та ще %(count)s учасника(ів)", + "%(items)s and %(count)s others|one": "%(items)s і ще хтось", + "a few seconds ago": "Декілька секунд тому", + "about a minute ago": "близько хвилини тому", + "%(num)s minutes ago": "%(num)s хвилин тому", + "about an hour ago": "близько години тому", + "%(num)s hours ago": "%(num)s годин тому", + "%(num)s days ago": "%(num)s днів тому", + "a few seconds from now": "декілька секунд тому", + "about a minute from now": "приблизно через хвилинку", + "%(num)s minutes from now": "%(num)s хвилин по тому", + "about an hour from now": "приблизно через годинку", + "%(num)s hours from now": "%(num)s годин по тому", + "about a day from now": "приблизно через день", + "%(num)s days from now": "%(num)s днів по тому", + "Unrecognised address": "Нерозпізнана адреса", + "You do not have permission to invite people to this room.": "У вас немає прав запрошувати людей у цю кімнату.", + "User %(userId)s is already in the room": "Користувач %(userId)s вже знаходиться серед вас", + "User %(user_id)s does not exist": "Користувача %(user_id)s не існує", + "The user must be unbanned before they can be invited.": "Користувач має бути розблокованим(ою), перед тим як може бути запрошений(ая).", + "The user's homeserver does not support the version of the room.": "Домашній сервер користувача не підтримує версію кімнати.", + "Unknown server error": "Невідома помилка з боку сервера", + "Use a few words, avoid common phrases": "Використовуйте декілька слів, уникайте звичайних фраз", + "Use a longer keyboard pattern with more turns": "Використовуйте довшу комбінацію клавіш з більшою кількістю поворотів", + "Avoid repeated words and characters": "Уникайте повторюваних слів та символів", + "Avoid sequences": "Уникайте послідовностей", + "Avoid recent years": "Уникайте останніх років", + "Avoid years that are associated with you": "Уникайте років, які зв'язані з вами", + "Avoid dates and years that are associated with you": "Уникайте дат і років, які зв'язані з вами", + "All-uppercase is almost as easy to guess as all-lowercase": "Все прописними буквами так само легко вгадується як і все малими", + "Reversed words aren't much harder to guess": "Вгадувати перевернуті слова не сильно важче", + "Predictable substitutions like '@' instead of 'a' don't help very much": "Передбачувані заміни типу «@» замість «a» не особливо допомагають", + "Add another word or two. Uncommon words are better.": "Додайте ще один-два слова. Краще використовувати рідкісні слова.", + "Repeats like \"aaa\" are easy to guess": "Повтори типу \"ааа\" легко вгадувані", + "Repeats like \"abcabcabc\" are only slightly harder to guess than \"abc\"": "Повтори типу «abcabcabc», лише трішки складніше вгадати, ніж «abc»", + "Sequences like abc or 6543 are easy to guess": "Послідовності типу abc або 6543 легко вгадувані", + "Recent years are easy to guess": "Останні роки легко вгадувані", + "Dates are often easy to guess": "Часто, дати вгадувати легко", + "This is a top-10 common password": "Це топ-10 легких та звичайних паролів", + "This is a top-100 common password": "Це топ-100 легких та розповсюджених паролів", + "This is a very common password": "Це дуже розповсюджений пароль", + "This is similar to a commonly used password": "Це занадто простий пароль", + "A word by itself is easy to guess": "Загальновживані слова легко вгадувані", + "Names and surnames by themselves are easy to guess": "Імена та прізвища легко вгадувані", + "Common names and surnames are easy to guess": "Розповсюджені імена та прізвища легко вгадувані", + "Straight rows of keys are easy to guess": "Прямі ради клавіш легко вгадувані", + "Short keyboard patterns are easy to guess": "Короткі клавіатурні шаблони легко вгадувані", + "Help us improve %(brand)s": "Допоможіть нам покращити %(brand)s", + "I want to help": "Я хочу допомогти", + "No": "НІ", + "Review where you’re logged in": "Перевірте, де ви ввійшли", + "Your homeserver has exceeded its user limit.": "Ваш домашній сервер перевищив свій ліміт користувачів.", + "Your homeserver has exceeded one of its resource limits.": "Ваш домашній сервер перевищив один із своїх ресурсних лімітів.", + "Contact your server admin.": "Зверніться до адміністратора серверу.", + "Ok": "Гаразд", + "Set password": "Встановити пароль", + "Set up encryption": "Налаштування шифрування", + "Encryption upgrade available": "Доступне поліпшене шифрування", + "Set up": "Налаштувати", + "Upgrade": "Поліпшити", + "Other users may not trust it": "Інші користувачі можуть не довіряти цьому", + "New login. Was this you?": "Новий вхід у вашу обліківку. Це були Ви?", + "Restart": "Перезапустити", + "Upgrade your %(brand)s": "Оновіть ваш %(brand)s", + "A new version of %(brand)s is available!": "Нова версія %(brand)s вже доступна!", + "Guest": "Гість", + "There was an error joining the room": "Помилка при вході в кімнату", + "You joined the call": "Ви приєднались до дзвінку", + "%(senderName)s joined the call": "%(senderName)s приєднався(лась) до дзвінку", + "Call in progress": "Дзвінок у процесі", + "You left the call": "Ви покинули дзвінок", + "%(senderName)s left the call": "%(senderName)s покинув(ла) дзвінок", + "Call ended": "Дзвінок завершено", + "You started a call": "Ви почали дзвінок", + "%(senderName)s started a call": "%(senderName)s почав(ла) дзвінок", + "Waiting for answer": "Чекаємо відповіді", + "%(senderName)s is calling": "%(senderName)s баламкає", + "* %(senderName)s %(emote)s": "*%(senderName)s %(emote)s", + "%(senderName)s: %(message)s": "%(senderName)s: %(message)s", + "%(senderName)s: %(reaction)s": "%(senderName)s: %(reaction)s", + "%(senderName)s: %(stickerName)s": "%(senderName)s: %(stickerName)s", + "Custom user status messages": "користувацький статус", + "Group & filter rooms by custom tags (refresh to apply changes)": "Групувати та фільтрувати кімнати за кастомними тегами (оновіть для застосування змін)", + "Multiple integration managers": "Декілька менджерів інтеграції", + "Try out new ways to ignore people (experimental)": "Спробуйте нові способи ігнорувати людей (експериментальні)", + "Support adding custom themes": "Підтримка користувацьких тем", + "Enable advanced debugging for the room list": "Увімкнути просунуте зневаджування для переліку кімнат", + "Show info about bridges in room settings": "Показувати інформацію про мости в налаштуваннях кімнати", + "Font size": "Розмір шрифту", + "Use custom size": "Використовувати нетиповий розмір", + "Enable Emoji suggestions while typing": "Увімкнути пропонування смайлів при друкуванні", + "Use a more compact ‘Modern’ layout": "Використовувати компактнішу \"Сучасну\" тему", + "General": "Загальні", + "Discovery": "Відкриття", + "Help & About": "Допомога та про програму", + "Bug reporting": "Повідомити про помилку", + "If you've submitted a bug via GitHub, debug logs can help us track down the problem. Debug logs contain application usage data including your username, the IDs or aliases of the rooms or groups you have visited and the usernames of other users. They do not contain messages.": "Якщо ви відправляли помилки через GitHub, журнали можуть допомогти нам виявити проблеми. Журнали відладки, що містять інформацію про використані додатки, включають ваше ім’я користувача, ідентифікатори або псевдоніми кімнат або груп, які ви відвідували, а також імена інших користувачів. Вони не містять повідомлень.", + "Submit debug logs": "Відправити відладочні журнали (debug logs)", + "Clear cache and reload": "Очистити кеш та перезавантажити", + "To report a Matrix-related security issue, please read the Matrix.org Security Disclosure Policy.": "Щоб повідомити про проблеми безпеки Matrix, будь ласка, прочитайте Політику розкриття інформації Matrix.org.", + "FAQ": "Часті питання", + "Keyboard Shortcuts": "Гарячі клавіші", + "Versions": "Версії", + "%(brand)s version:": "версія %(brand)s:", + "olm version:": "Версія olm:", + "Identity Server is": "Сервер ідентифікації", + "Labs": "Лабораторія", + "Customise your experience with experimental labs features. Learn more.": "Спробуйте експериментальні можливості. Більше.", + "Ignored/Blocked": "Ігноровані/Заблоковані", + "Error adding ignored user/server": "Помилка при додаванні ігнорованого користувача/сервера", + "Something went wrong. Please try again or view your console for hints.": "Щось пішло не так. Спробуйте знову, або пошукайте підказки в консолі.", + "Error subscribing to list": "Помилка при підписці на список", + "Please verify the room ID or address and try again.": "Перевірте ID кімнати, або адресу та попробуйте знову.", + "Error removing ignored user/server": "Помилка при видаленні ігнорованого користувача/сервера", + "Error unsubscribing from list": "Не вдалося відписатися від списку", + "Please try again or view your console for hints.": "Спробуйте знову, або подивіться повідомлення в консолі.", + "Ban list rules - %(roomName)s": "Правила блокування - %(roomName)s", + "Server rules": "Правила серверу", + "User rules": "Правила користування", + "You have not ignored anyone.": "Ви нікого не ігноруєте.", + "You are currently ignoring:": "Ви ігноруєте:", + "You are not subscribed to any lists": "Ви не підписані ні на один список", + "Unsubscribe": "Відписатись", + "View rules": "Подивитись правила", + "You are currently subscribed to:": "Ви підписані на:", + "⚠ These settings are meant for advanced users.": "⚠ Ці налаштування розраховані на досвідчених користувачів.", + "Ignoring people is done through ban lists which contain rules for who to ban. Subscribing to a ban list means the users/servers blocked by that list will be hidden from you.": "Ігнорування людей реалізовано через списки правил блокування. Підписка на список блокування призведе до приховування від вас користувачів і серверів, які в ньому перераховані.", + "Personal ban list": "Особистий бан-ліст", + "Your personal ban list holds all the users/servers you personally don't want to see messages from. After ignoring your first user/server, a new room will show up in your room list named 'My Ban List' - stay in this room to keep the ban list in effect.": "Ваш особистий список блокування містить всіх користувачів і сервери, повідомлення яких ви не хочете бачити. Після внесення туди першого користувача / сервера в списку кімнат з'явиться нова кімната 'Мій список блокування' - не покидає цю кімнату, щоб список блокування працював.", + "Server or user ID to ignore": "Сервер або ID користувача для ігнорування", + "eg: @bot:* or example.org": "наприклад: @bot:* або example.org", + "Ignore": "Ігнорувати", + "Subscribed lists": "Підписані списки", + "Subscribing to a ban list will cause you to join it!": "При підписці на список блокування ви приєднаєтесь до нього!", + "If this isn't what you want, please use a different tool to ignore users.": "Якщо вас це не влаштовує, спробуйте інший інструмент для ігнорування користувачів.", + "Room ID or address of ban list": "Ідентифікатор номера або адреса бан-лісту", + "Subscribe": "Підписатись", + "Start automatically after system login": "Автозапуск при вході в систему", + "Always show the window menu bar": "Завжди показуввати рядок меню", + "Show tray icon and minimize window to it on close": "Показати іконку в панелі завдань та згорнути вікно при закритті", + "Preferences": "Параметри", + "Room list": "Перелік кімнат", + "Composer": "Редактор", + "Security & Privacy": "Безпека та конфіденційність", + "Where you’re logged in": "Де ви ввійшли", + "Skip": "Пропустити", + "Notification settings": "Налаштування сповіщень", + "Appearance Settings only affect this %(brand)s session.": "Налаштування вигляду впливають тільки на цей сеанс %(brand)s.", + "Error changing power level requirement": "Помилка під час зміни вимог до рівня повноважень", + "An error occurred changing the room's power level requirements. Ensure you have sufficient permissions and try again.": "Під час зміни вимог рівня повноважень кімнати трапилась помилка. Переконайтесь, що ви маєте необхідні дозволи і спробуйте ще раз.", + "Error changing power level": "Помилка під час зміни рівня повноважень", + "An error occurred changing the user's power level. Ensure you have sufficient permissions and try again.": "Під час зміни рівня повноважень користувача трапилась помилка. Переконайтесь, що ви маєте необхідні дозволи і спробуйте ще раз.", + "Change settings": "Змінити налаштування", + "Only people who have been invited": "Тільки люди, що були запрошені", + "%(userName)s (power %(powerLevelNumber)s)": "%(userName)s (повноваження %(powerLevelNumber)s)", + "Send a message…": "Надіслати повідомлення…", + "People": "Люди", + "Share this email in Settings to receive invites directly in %(brand)s.": "Поширте цю адресу е-пошти у налаштуваннях щоб отримувати запрошення прямо у %(brand)s.", + "Room options": "Параметри кімнати", + "Send as message": "Надіслати як повідомлення", + "You will not be able to undo this change as you are promoting the user to have the same power level as yourself.": "Ви не зможете скасувати цю зміну через те, що ви підвищуєте рівень повноважень користувача до свого рівня.", + "React": "Відреагувати", + "Message deleted": "Повідомлення видалено", + "Message deleted by %(name)s": "Повідомлення видалено від %(name)s", + "Message deleted on %(date)s": "Повідомлення видалено %(date)s", + "Power level": "Рівень повноважень", + "Use an identity server to invite by email. Manage in Settings.": "Використовуйте сервер ідентифікації щоб запрошувати через е-пошту. Керується у налаштуваннях.", + "Enable 'Manage Integrations' in Settings to do this.": "Щоб зробити це увімкніть \"Керувати інтеграціями\" у налаштуваннях.", + "Confirm by comparing the following with the User Settings in your other session:": "Підтвердьте шляхом порівняння наступного рядка з рядком у користувацьких налаштуваннях вашого іншого сеансу:", + "Confirm this user's session by comparing the following with their User Settings:": "Підтвердьте сеанс цього користувача шляхом порівняння наступного рядка з рядком з їхніх користувацьких налаштувань:", + "We recommend you change your password and recovery key in Settings immediately": "Ми радимо невідкладно змінити ваші пароль та відновлювальний ключ у налаштуваннях", + "Share Message": "Поширити повідомлення", + "Community Settings": "Налаштування спільноти", + "All settings": "Усі налаштування", + "User menu": "Користувацьке меню", + "If you don't want to set this up now, you can later in Settings.": "Якщо ви не бажаєте налаштовувати це зараз, ви можете зробити це пізніше у налаштуваннях.", + "Go to Settings": "Перейти до налаштувань", + "Compare unique emoji": "Порівняйте унікальні смайлики", + "Cancelling…": "Скасування…", + "Dog": "Собака", + "Cat": "Кіт", + "Lion": "Лев", + "Horse": "Кінь", + "Pig": "Свиня", + "Elephant": "Слон", + "Rabbit": "Кріль", + "Panda": "Панда", + "Rooster": "Півень", + "Penguin": "Пінгвін", + "Turtle": "Черепаха", + "Fish": "Риба", + "Octopus": "Восьминіг", + "Moon": "Місяць", + "Cloud": "Хмара", + "Fire": "Вогонь", + "Banana": "Банан", + "Apple": "Яблуко", + "Strawberry": "Полуниця", + "Corn": "Кукурудза", + "Pizza": "Піца", + "Heart": "Серце", + "Smiley": "Смайлик", + "Robot": "Робот", + "Hat": "Капелюх", + "Glasses": "Окуляри", + "Spanner": "Гайковий ключ", + "Thumbs up": "Великий палець вгору", + "Umbrella": "Парасоля", + "Hourglass": "Пісковий годинник", + "Clock": "Годинник", + "Light bulb": "Лампа", + "Book": "Книга", + "Pencil": "Олівець", + "Paperclip": "Спиначка", + "Scissors": "Ножиці", + "Key": "Ключ", + "Hammer": "Молоток", + "Telephone": "Телефон", + "Flag": "Прапор", + "Train": "Потяг", + "Bicycle": "Велоcипед", + "Aeroplane": "Літак", + "Rocket": "Ракета", + "Trophy": "Трофей", + "Ball": "М'яч", + "Guitar": "Гітара", + "Trumpet": "Труба", + "Bell": "Дзвін", + "Anchor": "Якір", + "Headphones": "Навушники", + "Folder": "Тека", + "Pin": "Кнопка", + "Accept to continue:": "Прийміть для продовження:", + "Flower": "Квітка", + "Unicorn": "Одноріг", + "Butterfly": "Метелик", + "Cake": "Пиріг", + "Tree": "Дерево", + "Cactus": "Кактус", + "Mushroom": "Гриб", + "Globe": "Глобус", + "This bridge was provisioned by .": "Цей місток був підготовленим .", + "This bridge is managed by .": "Цей міст керується .", + "Workspace: %(networkName)s": "Робочий простір: %(networkName)s", + "Channel: %(channelName)s": "Канал: %(channelName)s", + "Show less": "Показати менше", + "Show more": "Показати більше", + "Changing password will currently reset any end-to-end encryption keys on all sessions, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "Якщо ви не експортуєте ключі для цієї комнати і не імпортуєте їх у майбутньому, зміна пароля приведе до скидання всіх ключів наскрізного шифрування і зробить неможилвимим читання історії чату. У майбутньому це буде вдосконалено.", + "Santa": "Санта Клаус", + "Gift": "Подарунок", + "Lock": "Замок", + "Cross-signing and secret storage are not yet set up.": "Перехресне підписування та таємне сховище ще не налагоджені.", + "Your homeserver does not support cross-signing.": "Ваш домашній сервер не підтримує кросс-підпис.", + "Cross-signing and secret storage are enabled.": "Кросс-підпис та секретне сховище дозволені.", + "well formed": "добре сформований", + "unexpected type": "несподіваний тип", + "Cross-signing public keys:": "Перехресно-підписувальні відкриті ключі:", + "in memory": "у пам'яті", + "not found": "не знайдено", + "Cross-signing private keys:": "Приватні ключі для кросс-підпису:", + "exists": "існує", + "Delete sessions|other": "Видалити сесії", + "Delete sessions|one": "Видалити сесію", + "Delete %(count)s sessions|other": "Видалити %(count)s сесій", + "Delete %(count)s sessions|one": "Видалити %(count)s сесій", + "ID": "ID", + "Public Name": "Публічне ім'я", + " to store messages from ": " зберігання повідомлень від ", + "rooms.": "кімнати.", + "Manage": "Керування", + "Enable": "Дозволити", + "Connecting to integration manager...": "З'єднання з менджером інтеграцій...", + "Cannot connect to integration manager": "Не вдалося з'єднатися з менджером інтеграцій", + "Delete Backup": "Видалити резервну копію", + "Restore from Backup": "Відновити з резервної копії", + "not stored": "не збережено", + "All keys backed up": "Усі ключі збережено", + "Backup version: ": "Версія резервної копії: ", + "Algorithm: ": "Алгоритм: ", + "Backup key stored: ": "Резервна копія ключа збережена ", + "Enable audible notifications for this session": "Ввімкнути звукові сповіщення для цього сеансу", + "Save": "Зберегти", + "Checking server": "Перевірка серверу", + "Disconnect": "Відключити", + "You should:": "Вам варто:", + "Disconnect anyway": "Відключити в будь-якому випадку", + "Identity Server (%(server)s)": "Сервер ідентифікації (%(server)s)", + "Identity Server": "Сервер ідентифікації", + "Do not use an identity server": "Не використовувати сервер ідентифікації", + "Enter a new identity server": "Введіть новий сервер ідентифікації", + "Change": "Змінити", + "Manage integrations": "Керування інтеграціями", + "Size must be a number": "Розмір повинен бути числом", + "Incoming voice call": "Входовий голосовий виклик", + "Incoming video call": "Входовий відеовиклик", + "Upgrade to your own domain": "Поліпшити до свого власного домену", + "No Audio Outputs detected": "Звуковий вивід не виявлено", + "Audio Output": "Звуковий вивід", + "Voice & Video": "Голос та відео", + "Upgrade this room to the recommended room version": "Поліпшити цю кімнату до рекомендованої версії", + "this room": "ця кімната", + "Upgrade the room": "Поліпшити кімнату", + "Unable to revoke sharing for email address": "Не вдалось відкликати оприлюднювання адреси е-пошти", + "Revoke": "Відкликати", + "Unable to revoke sharing for phone number": "Не вдалось відкликати оприлюднювання телефонного номеру", + "Filter room members": "Відфільтрувати учасників кімнати", + "Voice call": "Голосовий виклик", + "Video call": "Відеовиклик", + "Not now": "Не зараз", + "Don't ask me again": "Не запитувати мене знову", + "Appearance": "Вигляд", + "Show rooms with unread messages first": "Показувати вгорі кімнати з непрочитаними повідомленнями", + "Show previews of messages": "Показувати попередній перегляд повідомлень", + "Sort by": "Упорядкувати за", + "Activity": "Активністю", + "A-Z": "А-Я", + "List options": "Параметри переліку", + "Use default": "Типово", + "Mentions & Keywords": "Згадки та ключові слова", + "Notification options": "Параметри сповіщень", + "Leave Room": "Вийти з кімнати", + "Forget Room": "Забути кімнату", + "Favourited": "Улюблено", + "%(count)s unread messages including mentions.|other": "%(count)s непрочитаних повідомлень включно зі згадками.", + "%(count)s unread messages including mentions.|one": "1 непрочитана згадка.", + "%(count)s unread messages.|other": "%(count)s непрочитаних повідомлень.", + "%(count)s unread messages.|one": "1 непрочитане повідомлення.", + "Unread messages.": "Непрочитані повідомлення.", + "This room is public": "Ця кімната є прилюдною", + "Show Stickers": "Показати наліпки", + "Failed to revoke invite": "Не вдалось відкликати запрошення", + "Could not revoke the invite. The server may be experiencing a temporary problem or you do not have sufficient permissions to revoke the invite.": "Не вдалось відкликати запрошення. Сервер може мати тимчасові збої або у вас немає достатніх дозволів щоб відкликати запрошення.", + "Revoke invite": "Відкликати запрошення", + "Security": "Безпека", + "Report bugs & give feedback": "Відзвітувати про вади та залишити відгук", + "Report Content to Your Homeserver Administrator": "Поскаржитись на зміст адміністратору вашого домашнього сервера", + "Failed to upgrade room": "Не вдалось поліпшити кімнату", + "The room upgrade could not be completed": "Поліпшення кімнати не може бути завершене", + "Upgrade this room to version %(version)s": "Поліпшити цю кімнату до версії %(version)s", + "Upgrade Room Version": "Поліпшити версію кімнати", + "Upgrade private room": "Поліпшити закриту кімнату", + "You'll upgrade this room from to .": "Ви поліпшите цю кімнату з до версії.", + "Share Room Message": "Поширити повідомлення кімнати", + "Report Content": "Поскаржитись на зміст", + "Feedback": "Зворотній зв'язок", + "General failure": "Загальний збій", + "Enter your account password to confirm the upgrade:": "Введіть пароль вашого облікового запису щоб підтвердити поліпшення:", + "Security & privacy": "Безпека та конфіденційність", + "Secret storage public key:": "Таємне сховище відкритого ключа:", + "Key backup": "Резервне копіювання ключів", + "Message search": "Пошук повідомлень", + "Cross-signing": "Перехресне підписування", + "Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.": "Адміністратором вашого сервера було вимкнено початкове наскрізне шифрування у закритих кімнатах та особистих повідомленнях.", + "Something went wrong!": "Щось пішло не так!", + "expand": "розгорнути", + "Wrong Recovery Key": "Неправильний відновлювальний ключ", + "Invalid Recovery Key": "Нечинний відновлювальний ключ", + "Recovery key mismatch": "Незбіг відновлювального ключа", + "Backup could not be decrypted with this recovery key: please verify that you entered the correct recovery key.": "Резервна копія не може бути дешифрована з цим відновлювальним ключем: переконайтесь, будь ласка, що ви ввели правильний відновлювальний ключ.", + "If you've forgotten your recovery passphrase you can use your recovery key or set up new recovery options": "Якщо ви забули відновлювальну парольну фразу, ви можете скористатись вашим відновлювальним ключем або налаштувати нові параметри відновлювання", + "Enter recovery key": "Введіть відновлювальний ключ", + "This looks like a valid recovery key!": "Це скидається на чинний відновлювальний ключ!", + "Not a valid recovery key": "Нечинний відновлювальний ключ", + "Access your secure message history and set up secure messaging by entering your recovery key.": "Доступіться до вашої захищеної історії повідомлень та налаштуйте захищене листування шляхом вводження вашого відновлювального ключа.", + "If you've forgotten your recovery key you can ": "Якщо ви забули ваш відновлювальний ключ, ви можете ", + "Switch to light mode": "Світла тема", + "Switch to dark mode": "Темна тема", + "Use Recovery Key or Passphrase": "Скористуйтесь відновлювальними ключем або парольною фразою", + "Use Recovery Key": "Скористуйтесь відновлювальним ключем", + "Set up with a recovery key": "Налаштувати з відновлювальним ключем", + "Your recovery key is a safety net - you can use it to restore access to your encrypted messages if you forget your recovery passphrase.": "Ваш відновлювальний ключ — це убезпека. Ви можете використовувати його щоб доступитись до ваших зашифрованих повідомлень у разі втрати вашої відновлювальної парольної фрази.", + "Your recovery key": "Ваш відновлювальний ключ", + "Your recovery key has been copied to your clipboard, paste it to:": "Ваш відновлювальний ключ було скопійовано до буферу обміну, вставте його у:", + "Your recovery key is in your Downloads folder.": "Ваш відновлювальний ключ у вашій теці Завантаження.", + "Make a copy of your recovery key": "Зробити копію вашого відновлювального ключа", + "Don't ask again": "Не запитувати знову", + "New Recovery Method": "Новий відновлювальний засіб", + "A new recovery passphrase and key for Secure Messages have been detected.": "Було виявлено нові відновлювальні парольну фразу та ключ від захищених повідомлень.", + "This session is encrypting history using the new recovery method.": "Цей сеанс зашифровує історію новим відновлювальним засобом.", + "Set up Secure Messages": "Налаштувати захищені повідомлення", + "Recovery Method Removed": "Відновлювальний засіб було видалено", + "This session has detected that your recovery passphrase and key for Secure Messages have been removed.": "Цей сеанс виявив, що ваші відновлювальні парольна фраза та ключ від захищених повідомлень були видалені.", + "%(senderDisplayName)s enabled flair for %(newGroups)s and disabled flair for %(oldGroups)s in this room.": "%(senderDisplayName)s увімкнув(-ла) значок для %(newGroups)s та вимкнув(-ла) значок для %(oldGroups)s у цій кімнаті.", + "New version available. Update now.": "Доступна нова версія. Оновити зараз", + "Upgrade public room": "Поліпшити відкриту кімнату", + "Restore your key backup to upgrade your encryption": "Відновіть резервну копію вашого ключа щоб поліпшити шифрування", + "You'll need to authenticate with the server to confirm the upgrade.": "Ви матимете пройти розпізнання на сервері щоб підтвердити поліпшування.", + "Upgrade this session to allow it to verify other sessions, granting them access to encrypted messages and marking them as trusted for other users.": "Поліпште цей сеанс щоб уможливити звіряння інших сеансів, надаючи їм доступ до зашифрованих повідомлень та позначуючи їх довіреними для інших користувачів.", + "Upgrade your encryption": "Поліпшити ваше шифрування" } diff --git a/src/i18n/strings/zh_Hans.json b/src/i18n/strings/zh_Hans.json index ee2af983cb..f4ad52a8f2 100644 --- a/src/i18n/strings/zh_Hans.json +++ b/src/i18n/strings/zh_Hans.json @@ -31,7 +31,7 @@ "Failed to send request.": "请求发送失败。", "Failed to set display name": "设置昵称失败", "Failed to unban": "解除封禁失败", - "Failed to verify email address: make sure you clicked the link in the email": "邮箱验证失败: 请确保你已点击邮件中的链接", + "Failed to verify email address: make sure you clicked the link in the email": "邮箱验证失败:请确保你已点击邮件中的链接", "Failure to create room": "创建聊天室失败", "Favourite": "收藏", "Favourites": "收藏夹", @@ -333,7 +333,7 @@ "Verification Pending": "验证等待中", "(unknown failure: %(reason)s)": "(未知错误:%(reason)s)", "%(senderName)s withdrew %(targetName)s's invitation.": "%(senderName)s 收回了 %(targetName)s 的邀请。", - "You cannot place a call with yourself.": "你怎么寂寞到要和自己打电话,不支持的啦。", + "You cannot place a call with yourself.": "您无法向自己发起通话。", "You have disabled URL previews by default.": "你已经默认 禁用 链接预览。", "You have enabled URL previews by default.": "你已经默认 启用 链接预览。", "Set a display name:": "设置昵称:", @@ -456,11 +456,11 @@ "Warning": "警告", "Room Notification": "聊天室通知", "The platform you're on": "您使用的平台是", - "The version of %(brand)s": "%(brand)s版本", + "The version of %(brand)s": "%(brand)s 版本", "Your language of choice": "您选择的语言是", "Whether or not you're using the Richtext mode of the Rich Text Editor": "您是否正在使用富文本编辑器的富文本模式", "Your homeserver's URL": "您的主服务器的链接", - "The information being sent to us to help make %(brand)s better includes:": "发送信息给我们以帮助%(brand)s:", + "The information being sent to us to help make %(brand)s better includes:": "正在给我们发送信息以帮助 %(brand)s:", "Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": "此页面中含有可用于识别您身份的信息,比如聊天室、用户或群组 ID,这些数据会在发送到服务器前被移除。", "%(weekDayName)s %(time)s": "%(weekDayName)s %(time)s", "%(weekDayName)s, %(monthName)s %(day)s %(time)s": "%(monthName)s %(day)s %(time)s, %(weekDayName)s", @@ -716,7 +716,7 @@ "Downloading update...": "正在下载更新…", "State Key": "状态密钥", "Failed to send custom event.": "自定义事件发送失败。", - "What's new?": "更新了什么?", + "What's new?": "更新内容", "Notify me for anything else": "通知所有消息", "When I'm invited to a room": "当我被邀请进入聊天室", "Can't update user notification settings": "不能更新用户通知设置", @@ -777,7 +777,7 @@ "Enable widget screenshots on supported widgets": "对支持的小挂件启用小挂件截图", "Demote yourself?": "是否降低您自己的权限?", "Demote": "降权", - "A call is currently being placed!": "已发起一次通话!", + "A call is currently being placed!": "正在发起通话!", "Permission Required": "需要权限", "You do not have permission to start a conference call in this room": "您没有在此聊天室发起通话会议的权限", "This event could not be displayed": "无法显示此事件", @@ -836,7 +836,7 @@ "An email has been sent to %(emailAddress)s. Once you've followed the link it contains, click below.": "已向 %(emailAddress)s 发送了一封电子邮件。点开邮件中的链接后,请点击下面。", "Forces the current outbound group session in an encrypted room to be discarded": "强制丢弃加密聊天室中的当前出站群组会话", "Unable to connect to Homeserver. Retrying...": "无法连接至主服务器。正在重试…", - "Sorry, your homeserver is too old to participate in this room.": "对不起,您的主服务器的程序版本过旧以至于无法加入此聊天室。", + "Sorry, your homeserver is too old to participate in this room.": "抱歉,因您的主服务器的程序版本过旧,无法加入此聊天室。", "Mirror local video feed": "镜像翻转本地视频源", "This room has been replaced and is no longer active.": "此聊天室已被取代,且不再活跃。", "The conversation continues here.": "对话在这里继续。", @@ -858,7 +858,7 @@ "Your message wasn't sent because this homeserver has exceeded a resource limit. Please contact your service administrator to continue using the service.": "您的消息未被发送,因为本主服务器已达到其使用量限制之一。请 联系您的服务管理员 以继续使用本服务。", "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. Please contact your service administrator to continue using the service.": "您的消息未被发送,因为本主服务器已达到其每月活跃用户限制。请 联系您的服务管理员 以继续使用本服务。", "Please contact your service administrator to continue using the service.": "请 联系您的服务管理员 以继续使用本服务。", - "Please contact your homeserver administrator.": "请 联系您主服务器的管理员。", + "Please contact your homeserver administrator.": "请 联系您的主服务器管理员。", "%(senderName)s set the main address for this room to %(address)s.": "%(senderName)s 将此聊天室的主地址设为了 %(address)s。", "%(senderName)s removed the main address for this room.": "%(senderName)s 移除了此聊天室的主地址。", "Unable to load! Check your network connectivity and try again.": "无法加载!请检查您的网络连接并重试。", @@ -1030,7 +1030,7 @@ "Folder": "文件夹", "Pin": "别针", "Yes": "是", - "No": "否", + "No": "拒绝", "We've sent you an email to verify your address. Please follow the instructions there and then click the button below.": "我们已向您发送了一封电子邮件,以验证您的地址。 请按照里面的说明操作,然后单击下面的按钮。", "Email Address": "电子邮箱地址", "Are you sure? You will lose your encrypted messages if your keys are not backed up properly.": "您确定吗?如果密钥没有正确地备份您将失去您的加密消息。", @@ -1267,12 +1267,12 @@ "Confirm adding this phone number by using Single Sign On to prove your identity.": "通过单点确认添加此电话号码以确认您的身份。", "Confirm adding phone number": "确认添加电话号码", "Click the button below to confirm adding this phone number.": "点击下面的按钮,确认添加此电话号码。", - "Whether you're using %(brand)s on a device where touch is the primary input mechanism": "是否在触屏设备上使用%(brand)s", - "Whether you're using %(brand)s as an installed Progressive Web App": "您是否已经安装%(brand)s作为一种渐进式的Web应用", + "Whether you're using %(brand)s on a device where touch is the primary input mechanism": "是否在触屏设备上使用 %(brand)s", + "Whether you're using %(brand)s as an installed Progressive Web App": "您是否已经安装 %(brand)s 作为一种渐进式的 Web 应用", "Your user agent": "您的代理用户", "Replying With Files": "回复文件", - "At this time it is not possible to reply with a file. Would you like to upload this file without replying?": "无法回复此文件。您要上传此文件但无需回复吗?", - "The file '%(fileName)s' failed to upload.": "上传文件 ‘%(fileName)s’失败。", + "At this time it is not possible to reply with a file. Would you like to upload this file without replying?": "当前无法在回复中附加文件。您想要仅上传此文件而不回复吗?", + "The file '%(fileName)s' failed to upload.": "上传文件 ‘%(fileName)s’ 失败。", "The server does not support the room version specified.": "服务器不支持指定的聊天室版本。", "If you cancel now, you won't complete verifying the other user.": "如果现在取消,您将无法完成验证其他用户。", "If you cancel now, you won't complete verifying your other session.": "如果现在取消,您将无法完成验证您的其他会话。", @@ -1371,5 +1371,94 @@ "Room name or address": "房间名称或地址", "Joins room with given address": "使用给定地址加入房间", "Verify this login": "验证此登录名", - "Confirm your identity by verifying this login from one of your other sessions, granting it access to encrypted messages.": "通过从其他会话之一验证此登录名并授予其访问加密信息的权限来确认您的身份" + "Confirm your identity by verifying this login from one of your other sessions, granting it access to encrypted messages.": "通过从其他会话之一验证此登录名并授予其访问加密信息的权限来确认您的身份", + "Which officially provided instance you are using, if any": "如果您在使用官方实例,是哪一个", + "Every page you use in the app": "您在应用中使用的每个页面", + "Are you sure you want to cancel entering passphrase?": "确定要取消输入密码?", + "Go Back": "后退", + "Use your account to sign in to the latest version": "使用您的帐户登录到最新版本", + "We’re excited to announce Riot is now Element": "我们很高兴地宣布Riot现在更名为Element", + "Learn More": "了解更多", + "Unrecognised room address:": "无法识别的聊天室地址:", + "Light": "浅色", + "Dark": "深色", + "You can register, but some features will be unavailable until the identity server is back online. If you keep seeing this warning, check your configuration or contact a server admin.": "您可以注册,但部分功能在身份服务器重新上线之前不可用。如果持续看到此警告,请检查配置或联系服务器管理员。", + "You can reset your password, but some features will be unavailable until the identity server is back online. If you keep seeing this warning, check your configuration or contact a server admin.": "您可以重置密码,但部分功能在身份服务器重新上线之前不可用。如果持续看到此警告,请检查配置或联系服务器管理员。", + "You can log in, but some features will be unavailable until the identity server is back online. If you keep seeing this warning, check your configuration or contact a server admin.": "您可以登录,但部分功能在身份服务器重新上线之前不可用。如果持续看到此警告,请检查配置或联系服务器管理员。", + "No homeserver URL provided": "未输入主服务器链接", + "Unexpected error resolving homeserver configuration": "解析主服务器配置时发生未知错误", + "Unexpected error resolving identity server configuration": "解析身份服务器配置时发生未知错误", + "The message you are trying to send is too large.": "您正发送的信息过大。", + "a few seconds ago": "数秒前", + "about a minute ago": "约一分钟前", + "%(num)s minutes ago": "%(num)s分钟前", + "about an hour ago": "约一小时前", + "%(num)s hours ago": "%(num)s小时前", + "about a day ago": "约一天前", + "%(num)s days ago": "%(num)s天前", + "a few seconds from now": "从现在开始数秒", + "about a minute from now": "从现在开始约一分钟", + "%(num)s minutes from now": "从现在开始%(num)s分钟", + "about an hour from now": "从现在开始约一小时", + "%(num)s hours from now": "从现在开始%(num)s小时", + "about a day from now": "从现在开始约一天", + "%(num)s days from now": "从现在开始%(num)s天", + "%(name)s (%(userId)s)": "%(name)s%(userId)s", + "Your browser does not support the required cryptography extensions": "您的浏览器不支持必需的加密插件", + "The user's homeserver does not support the version of the room.": "用户的主服务器不支持该聊天室版本。", + "Help us improve %(brand)s": "请协助我们改进%(brand)s", + "Send anonymous usage data which helps us improve %(brand)s. This will use a cookie.": "发送匿名使用情况数据,以协助我们改进%(brand)s。这将使用cookie。", + "I want to help": "我乐意协助", + "Verify all your sessions to ensure your account & messages are safe": "验证您的所有会话,以确保帐户和消息安全", + "Review": "开始验证", + "Later": "稍后再说", + "Your homeserver has exceeded its user limit.": "您的主服务器已超过用户限制。", + "Your homeserver has exceeded one of its resource limits.": "您的主服务器已超过某项资源限制。", + "Contact your server admin.": "请联系您的服务器管理员。", + "Ok": "确定", + "Set password": "设置密码", + "To return to your account in future you need to set a password": "要在之后取回您的帐户,您需要设置密码", + "Upgrade": "升级加密", + "Verify": "验证", + "Verify yourself & others to keep your chats safe": "验证您自己和他人身份,以确保您的聊天安全", + "Other users may not trust it": "其他用户可能不信任它", + "Verify the new login accessing your account: %(name)s": "验证正访问您帐户的新登录:%(name)s", + "Restart": "重启应用", + "Upgrade your %(brand)s": "升级您的%(brand)s", + "A new version of %(brand)s is available!": "发现%(brand)s的新版本!", + "You joined the call": "您加入通话", + "%(senderName)s joined the call": "%(senderName)s加入通话", + "Call in progress": "通话中", + "You left the call": "您离开了通话", + "%(senderName)s left the call": "%(senderName)s离开了通话", + "Call ended": "通话结束", + "You started a call": "您开始了通话", + "%(senderName)s started a call": "%(senderName)s开始了通话", + "Waiting for answer": "等待接听", + "%(senderName)s is calling": "%(senderName)s正在通话", + "You created the room": "您创建了聊天室", + "%(senderName)s created the room": "%(senderName)s创建了聊天室", + "You made the chat encrypted": "您启用了聊天加密", + "%(senderName)s made the chat encrypted": "%(senderName)s启用了聊天加密", + "You made history visible to new members": "您设置了历史记录对新成员可见", + "%(senderName)s made history visible to new members": "%(senderName)s设置了历史记录对新成员可见", + "You made history visible to anyone": "您设置了历史记录对所有人可见", + "Riot is now Element!": "Riot现在是Element了!", + "Support adding custom themes": "支持添加自定义主题", + "Font size": "字体大小", + "Use custom size": "使用自定义大小", + "Match system theme": "匹配系统主题", + "Use a system font": "使用系统字体", + "System font name": "系统字体名称", + "Never send encrypted messages to unverified sessions from this session": "永不从本会话向未验证的会话发送加密信息", + "Never send encrypted messages to unverified sessions in this room from this session": "永不从本会话在本房间中向未验证的会话发送加密信息", + "Order rooms by name": "按名称排列房间", + "Show rooms with unread notifications first": "优先显示有未读通知的房间", + "Show previews/thumbnails for images": "显示图片的预览图", + "Enable message search in encrypted rooms": "在加密房间中启用消息搜索", + "Enable experimental, compact IRC style layout": "启用实验性的、紧凑的IRC式布局", + "Verify this session by completing one of the following:": "完成以下之一以验证这一会话:", + "or": "或者", + "Start": "开始", + "Confirm the emoji below are displayed on both sessions, in the same order:": "确认两个会话上都以同样顺序显示了下面的emoji:" } diff --git a/src/i18n/strings/zh_Hant.json b/src/i18n/strings/zh_Hant.json index 2fd8aac537..4278515ffd 100644 --- a/src/i18n/strings/zh_Hant.json +++ b/src/i18n/strings/zh_Hant.json @@ -2346,5 +2346,50 @@ "Set up Secure backup": "設定安全備份", "Set a Security Phrase": "設定安全密語", "Confirm Security Phrase": "確認安全密語", - "Save your Security Key": "儲存您的安全金鑰" + "Save your Security Key": "儲存您的安全金鑰", + "Are you sure you want to cancel entering passphrase?": "您確定您想要取消輸入通關密語嗎?", + "Use your account to sign in to the latest version": "使用您的帳號以登入到最新版本", + "We’re excited to announce Riot is now Element": "我們很高興地宣佈 Riot 現在變為 Element 了", + "Riot is now Element!": "Riot 現在變為 Element 了!", + "Learn More": "取得更多資訊", + "Enable advanced debugging for the room list": "啟用聊天室清單的進階除錯", + "Enable experimental, compact IRC style layout": "啟用實驗性、簡潔的 IRC 風格佈局", + "Unknown caller": "未知的來電者", + "Incoming voice call": "語音來電", + "Incoming video call": "視訊來電", + "Incoming call": "來電", + "%(brand)s can't securely cache encrypted messages locally while running in a web browser. Use %(brand)s Desktop for encrypted messages to appear in search results.": "%(brand)s 無法在網路瀏覽器中執行時安全地在本機快取加密訊息。使用 %(brand)s 桌面版以讓加密訊息出現在搜尋結果中。", + "There are advanced notifications which are not shown here.": "有些進階通知未在此處顯示。", + "You might have configured them in a client other than %(brand)s. You cannot tune them in %(brand)s but they still apply.": "您可能已在 %(brand)s 以外的客戶端設定它們了。您無法以 %(brand)s 調整,但仍然適用。", + "Set the name of a font installed on your system & %(brand)s will attempt to use it.": "設定您系統上安裝的字型名稱,%(brand)s 將會嘗試使用它。", + "%(brand)s version:": "%(brand)s 版本:", + "Make this room low priority": "將此聊天室設為較低優先程度", + "Low priority rooms show up at the bottom of your room list in a dedicated section at the bottom of your room list": "低優先程度的聊天室會顯示在您聊天室清單底部的專用區域中", + "Show rooms with unread messages first": "先顯示有未讀訊息的聊天室", + "Show previews of messages": "顯示訊息預覽", + "Use default": "使用預設值", + "Mentions & Keywords": "提及與關鍵字", + "Notification options": "通知選項", + "Favourited": "最愛", + "Forget Room": "忘記聊天室", + "This room is public": "此聊天室是公開的", + "Away": "離開", + "Edited at %(date)s": "編輯於 %(date)s", + "Click to view edits": "點擊以檢視編輯", + "If the other version of %(brand)s is still open in another tab, please close it as using %(brand)s on the same host with both lazy loading enabled and disabled simultaneously will cause issues.": "如果其他版本的 %(brand)s 仍在其他分頁中開啟,請關閉它,因為在同一主機上使用同時啟用與停用惰性載入的 %(brand)s 可能會造成問題。", + "Use your account to sign in to the latest version of the app at ": "使用您的帳號以登入到最新版本的應用程式於 ", + "You’re already signed in and good to go here, but you can also grab the latest versions of the app on all platforms at element.io/get-started.": "您已登入並可在此處進行存取,但您可以在 element.io/get-started 取得所有平臺的最新版本的應用程式。", + "Go to Element": "到 Element", + "We’re excited to announce Riot is now Element!": "我們很高興地宣佈 Riot 現在變為 Element 了!", + "Learn more at element.io/previously-riot": "在 element.io/previously-riot 取得更多資訊", + "You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use %(brand)s with an existing Matrix account on a different homeserver.": "您可以透過指定不同的家伺服器 URL 來使用自訂伺服器選項以登入到其他 Matrix 伺服器。這讓您可以與既有的 Matrix 帳號在不同的家伺服器一起使用 %(brand)s。", + "Enter the location of your Element Matrix Services homeserver. It may use your own domain name or be a subdomain of element.io.": "輸入您的 Element Matrix 服務家伺服器位置。它可能使用您的域名或 element.io 的子網域。", + "Search rooms": "搜尋聊天室", + "User menu": "使用者選單", + "%(brand)s Web": "%(brand)s 網頁版", + "%(brand)s Desktop": "%(brand)s 桌面版", + "%(brand)s iOS": "%(brand)s iOS", + "%(brand)s X for Android": "Android 的 %(brand)s X", + "Custom Tag": "自訂標籤", + "* %(senderName)s %(emote)s": "* %(senderName)s %(emote)s" } diff --git a/src/indexing/EventIndex.js b/src/indexing/EventIndex.js index 1dc31869c9..d5abb3f2d2 100644 --- a/src/indexing/EventIndex.js +++ b/src/indexing/EventIndex.js @@ -18,8 +18,9 @@ import PlatformPeg from "../PlatformPeg"; import {MatrixClientPeg} from "../MatrixClientPeg"; import {EventTimeline, RoomMember} from 'matrix-js-sdk'; import {sleep} from "../utils/promise"; -import SettingsStore, {SettingLevel} from "../settings/SettingsStore"; +import SettingsStore from "../settings/SettingsStore"; import {EventEmitter} from "events"; +import {SettingLevel} from "../settings/SettingLevel"; /* * Event indexing class that wraps the platform specific event indexing. diff --git a/src/indexing/EventIndexPeg.js b/src/indexing/EventIndexPeg.js index 20e05f985d..58e8430825 100644 --- a/src/indexing/EventIndexPeg.js +++ b/src/indexing/EventIndexPeg.js @@ -21,7 +21,8 @@ limitations under the License. import PlatformPeg from "../PlatformPeg"; import EventIndex from "../indexing/EventIndex"; -import SettingsStore, {SettingLevel} from '../settings/SettingsStore'; +import SettingsStore from '../settings/SettingsStore'; +import {SettingLevel} from "../settings/SettingLevel"; const INDEX_VERSION = 1; diff --git a/src/languageHandler.tsx b/src/languageHandler.tsx index 91d90d4e6c..9d28b7d07d 100644 --- a/src/languageHandler.tsx +++ b/src/languageHandler.tsx @@ -21,11 +21,12 @@ import request from 'browser-request'; import counterpart from 'counterpart'; import React from 'react'; -import SettingsStore, {SettingLevel} from "./settings/SettingsStore"; +import SettingsStore from "./settings/SettingsStore"; import PlatformPeg from "./PlatformPeg"; // @ts-ignore - $webapp is a webpack resolve alias pointing to the output directory, see webpack config import webpackLangJsonUrl from "$webapp/i18n/languages.json"; +import { SettingLevel } from "./settings/SettingLevel"; const i18nFolder = 'i18n/'; diff --git a/src/mjolnir/Mjolnir.js b/src/mjolnir/Mjolnir.js index 9876cb1f7f..891438bbb9 100644 --- a/src/mjolnir/Mjolnir.js +++ b/src/mjolnir/Mjolnir.js @@ -16,9 +16,10 @@ limitations under the License. import {MatrixClientPeg} from "../MatrixClientPeg"; import {ALL_RULE_TYPES, BanList} from "./BanList"; -import SettingsStore, {SettingLevel} from "../settings/SettingsStore"; +import SettingsStore from "../settings/SettingsStore"; import {_t} from "../languageHandler"; import dis from "../dispatcher/dispatcher"; +import {SettingLevel} from "../settings/SettingLevel"; // TODO: Move this and related files to the js-sdk or something once finalized. diff --git a/src/rageshake/submit-rageshake.ts b/src/rageshake/submit-rageshake.ts index 64a1ea0c33..350602aa5d 100644 --- a/src/rageshake/submit-rageshake.ts +++ b/src/rageshake/submit-rageshake.ts @@ -141,7 +141,7 @@ export default async function sendBugReport(bugReportEndpoint: string, opts: IOp } // add labs options - const enabledLabs = SettingsStore.getLabsFeatures().filter(SettingsStore.isFeatureEnabled); + const enabledLabs = SettingsStore.getLabsFeatures().filter(f => SettingsStore.isFeatureEnabled(f)); if (enabledLabs.length) { body.append('enabled_labs', enabledLabs.join(', ')); } diff --git a/src/settings/SettingLevel.ts b/src/settings/SettingLevel.ts new file mode 100644 index 0000000000..e4703be1a9 --- /dev/null +++ b/src/settings/SettingLevel.ts @@ -0,0 +1,29 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/** + * Represents the various setting levels supported by the SettingsStore. + */ +export enum SettingLevel { + // TODO: [TS] Follow naming convention + DEVICE = "device", + ROOM_DEVICE = "room-device", + ROOM_ACCOUNT = "room-account", + ACCOUNT = "account", + ROOM = "room", + CONFIG = "config", + DEFAULT = "default", +} diff --git a/src/settings/Settings.js b/src/settings/Settings.ts similarity index 80% rename from src/settings/Settings.js rename to src/settings/Settings.ts index a8b6310b90..1989bd7a34 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.ts @@ -1,7 +1,6 @@ /* Copyright 2017 Travis Ralston -Copyright 2018, 2019 New Vector Ltd. -Copyright 2019, 2020 The Matrix.org Foundation C.I.C. +Copyright 2018, 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,9 +15,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {MatrixClient} from 'matrix-js-sdk'; +import { MatrixClient } from 'matrix-js-sdk/src/client'; -import {_td} from '../languageHandler'; +import { _td } from '../languageHandler'; import { AudioNotificationsEnabledController, NotificationBodyEnabledController, @@ -28,75 +27,89 @@ import CustomStatusController from "./controllers/CustomStatusController"; import ThemeController from './controllers/ThemeController'; import PushToMatrixClientController from './controllers/PushToMatrixClientController'; import ReloadOnChangeController from "./controllers/ReloadOnChangeController"; -import {RIGHT_PANEL_PHASES} from "../stores/RightPanelStorePhases"; import FontSizeController from './controllers/FontSizeController'; import SystemFontController from './controllers/SystemFontController'; import UseSystemFontController from './controllers/UseSystemFontController'; +import { SettingLevel } from "./SettingLevel"; +import SettingController from "./controllers/SettingController"; +import { RightPanelPhases } from "../stores/RightPanelStorePhases"; // These are just a bunch of helper arrays to avoid copy/pasting a bunch of times -const LEVELS_ROOM_SETTINGS = ['device', 'room-device', 'room-account', 'account', 'config']; -const LEVELS_ROOM_OR_ACCOUNT = ['room-account', 'account']; -const LEVELS_ROOM_SETTINGS_WITH_ROOM = ['device', 'room-device', 'room-account', 'account', 'config', 'room']; -const LEVELS_ACCOUNT_SETTINGS = ['device', 'account', 'config']; -const LEVELS_FEATURE = ['device', 'config']; -const LEVELS_DEVICE_ONLY_SETTINGS = ['device']; -const LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG = ['device', 'config']; +const LEVELS_ROOM_SETTINGS = [ + SettingLevel.DEVICE, + SettingLevel.ROOM_DEVICE, + SettingLevel.ROOM_ACCOUNT, + SettingLevel.ACCOUNT, + SettingLevel.CONFIG, +]; +const LEVELS_ROOM_OR_ACCOUNT = [ + SettingLevel.ROOM_ACCOUNT, + SettingLevel.ACCOUNT, +]; +const LEVELS_ROOM_SETTINGS_WITH_ROOM = [ + SettingLevel.DEVICE, + SettingLevel.ROOM_DEVICE, + SettingLevel.ROOM_ACCOUNT, + SettingLevel.ACCOUNT, + SettingLevel.CONFIG, + SettingLevel.ROOM, +]; +const LEVELS_ACCOUNT_SETTINGS = [ + SettingLevel.DEVICE, + SettingLevel.ACCOUNT, + SettingLevel.CONFIG, +]; +const LEVELS_FEATURE = [ + SettingLevel.DEVICE, + SettingLevel.CONFIG, +]; +const LEVELS_DEVICE_ONLY_SETTINGS = [ + SettingLevel.DEVICE, +]; +const LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG = [ + SettingLevel.DEVICE, + SettingLevel.CONFIG, +]; -export const SETTINGS = { - // EXAMPLE SETTING: - // "my-setting": { - // // Must be set to true for features. Default is 'false'. - // isFeature: false, - // - // // Display names are strongly recommended for clarity. - // displayName: _td("Cool Name"), - // - // // Display name can also be an object for different levels. - // //displayName: { - // // "device": _td("Name for when the setting is used at 'device'"), - // // "room": _td("Name for when the setting is used at 'room'"), - // // "default": _td("The name for all other levels"), - // //} - // - // // The supported levels are required. Preferably, use the preset arrays - // // at the top of this file to define this rather than a custom array. - // supportedLevels: [ - // // The order does not matter. - // - // "device", // Affects the current device only - // "room-device", // Affects the current room on the current device - // "room-account", // Affects the current room for the current account - // "account", // Affects the current account - // "room", // Affects the current room (controlled by room admins) - // "config", // Affects the current application - // - // // "default" is always supported and does not get listed here. - // ], - // - // // Required. Can be any data type. The value specified here should match - // // the data being stored (ie: if a boolean is used, the setting should - // // represent a boolean). - // default: { - // your: "value", - // }, - // - // // Optional settings controller. See SettingsController for more information. - // controller: new MySettingController(), - // - // // Optional flag to make supportedLevels be respected as the order to handle - // // settings. The first element is treated as "most preferred". The "default" - // // level is always appended to the end. - // supportedLevelsAreOrdered: false, - // - // // Optional value to invert a boolean setting's value. The string given will - // // be read as the setting's ID instead of the one provided as the key for the - // // setting definition. By setting this, the returned value will automatically - // // be inverted, except for when the default value is returned. Inversion will - // // occur after the controller is asked for an override. This should be used by - // // historical settings which we don't want existing user's values be wiped. Do - // // not use this for new settings. - // invertedSettingName: "my-negative-setting", - // }, +export interface ISetting { + // Must be set to true for features. Default is 'false'. + isFeature?: boolean; + + // Display names are strongly recommended for clarity. + // Display name can also be an object for different levels. + displayName?: string | { + // @ts-ignore - TS wants the key to be a string, but we know better + [level: SettingLevel]: string; + }; + + // The supported levels are required. Preferably, use the preset arrays + // at the top of this file to define this rather than a custom array. + supportedLevels?: SettingLevel[]; + + // Required. Can be any data type. The value specified here should match + // the data being stored (ie: if a boolean is used, the setting should + // represent a boolean). + default: any; + + // Optional settings controller. See SettingsController for more information. + controller?: SettingController; + + // Optional flag to make supportedLevels be respected as the order to handle + // settings. The first element is treated as "most preferred". The "default" + // level is always appended to the end. + supportedLevelsAreOrdered?: boolean; + + // Optional value to invert a boolean setting's value. The string given will + // be read as the setting's ID instead of the one provided as the key for the + // setting definition. By setting this, the returned value will automatically + // be inverted, except for when the default value is returned. Inversion will + // occur after the controller is asked for an override. This should be used by + // historical settings which we don't want existing user's values be wiped. Do + // not use this for new settings. + invertedSettingName?: string; +} + +export const SETTINGS: {[setting: string]: ISetting} = { "feature_new_spinner": { isFeature: true, displayName: _td("New spinner design"), @@ -153,11 +166,11 @@ export const SETTINGS = { default: false, }, "mjolnirRooms": { - supportedLevels: ['account'], + supportedLevels: [SettingLevel.ACCOUNT], default: [], }, "mjolnirPersonalRoom": { - supportedLevels: ['account'], + supportedLevels: [SettingLevel.ACCOUNT], default: null, }, "feature_bridge_state": { @@ -166,6 +179,10 @@ export const SETTINGS = { displayName: _td("Show info about bridges in room settings"), default: false, }, + "RoomList.backgroundImage": { + supportedLevels: LEVELS_ACCOUNT_SETTINGS, + default: null, + }, "baseFontSize": { displayName: _td("Font size"), supportedLevels: LEVELS_ACCOUNT_SETTINGS, @@ -350,24 +367,24 @@ export const SETTINGS = { }, "breadcrumb_rooms": { // not really a setting - supportedLevels: ['account'], + supportedLevels: [SettingLevel.ACCOUNT], default: [], }, "recent_emoji": { // not really a setting - supportedLevels: ['account'], + supportedLevels: [SettingLevel.ACCOUNT], default: [], }, "room_directory_servers": { - supportedLevels: ['account'], + supportedLevels: [SettingLevel.ACCOUNT], default: [], }, "integrationProvisioning": { - supportedLevels: ['account'], + supportedLevels: [SettingLevel.ACCOUNT], default: true, }, "allowedWidgets": { - supportedLevels: ['room-account'], + supportedLevels: [SettingLevel.ROOM_ACCOUNT], default: {}, // none allowed }, "analyticsOptIn": { @@ -394,7 +411,7 @@ export const SETTINGS = { "blacklistUnverifiedDevices": { // We specifically want to have room-device > device so that users may set a device default // with a per-room override. - supportedLevels: ['room-device', 'device'], + supportedLevels: [SettingLevel.ROOM_DEVICE, SettingLevel.DEVICE], supportedLevelsAreOrdered: true, displayName: { "default": _td('Never send encrypted messages to unverified sessions from this session'), @@ -412,7 +429,7 @@ export const SETTINGS = { default: true, }, "urlPreviewsEnabled_e2ee": { - supportedLevels: ['room-device', 'room-account'], + supportedLevels: [SettingLevel.ROOM_DEVICE, SettingLevel.ROOM_ACCOUNT], displayName: { "room-account": _td("Enable URL previews for this room (only affects you)"), }, @@ -451,7 +468,7 @@ export const SETTINGS = { default: false, }, "PinnedEvents.isOpen": { - supportedLevels: ['room-device'], + supportedLevels: [SettingLevel.ROOM_DEVICE], default: false, }, "promptBeforeInviteUnknownUsers": { @@ -530,11 +547,11 @@ export const SETTINGS = { }, "lastRightPanelPhaseForRoom": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, - default: RIGHT_PANEL_PHASES.RoomMemberInfo, + default: RightPanelPhases.RoomMemberInfo, }, "lastRightPanelPhaseForGroup": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, - default: RIGHT_PANEL_PHASES.GroupMemberList, + default: RightPanelPhases.GroupMemberList, }, "enableEventIndexing": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, @@ -561,7 +578,8 @@ export const SETTINGS = { "ircDisplayNameWidth": { // We specifically want to have room-device > device so that users may set a device default // with a per-room override. - supportedLevels: ['room-device', 'device'], + supportedLevels: [SettingLevel.ROOM_DEVICE, SettingLevel.DEVICE], + supportedLevelsAreOrdered: true, displayName: _td("IRC display name width"), default: 80, }, diff --git a/src/settings/SettingsStore.js b/src/settings/SettingsStore.ts similarity index 78% rename from src/settings/SettingsStore.js rename to src/settings/SettingsStore.ts index dcdde46631..e64de8af16 100644 --- a/src/settings/SettingsStore.js +++ b/src/settings/SettingsStore.ts @@ -1,6 +1,6 @@ /* Copyright 2017 Travis Ralston -Copyright 2019 New Vector Ltd. +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,27 +22,14 @@ import RoomAccountSettingsHandler from "./handlers/RoomAccountSettingsHandler"; import AccountSettingsHandler from "./handlers/AccountSettingsHandler"; import RoomSettingsHandler from "./handlers/RoomSettingsHandler"; import ConfigSettingsHandler from "./handlers/ConfigSettingsHandler"; -import {_t} from '../languageHandler'; +import { _t } from '../languageHandler'; import SdkConfig from "../SdkConfig"; import dis from '../dispatcher/dispatcher'; -import {SETTINGS} from "./Settings"; +import { ISetting, SETTINGS } from "./Settings"; import LocalEchoWrapper from "./handlers/LocalEchoWrapper"; -import {WatchManager} from "./WatchManager"; - -/** - * Represents the various setting levels supported by the SettingsStore. - */ -export const SettingLevel = { - // Note: This enum is not used in this class or in the Settings file - // This should always be used elsewhere in the project. - DEVICE: "device", - ROOM_DEVICE: "room-device", - ROOM_ACCOUNT: "room-account", - ACCOUNT: "account", - ROOM: "room", - CONFIG: "config", - DEFAULT: "default", -}; +import { WatchManager } from "./WatchManager"; +import { SettingLevel } from "./SettingLevel"; +import SettingsHandler from "./handlers/SettingsHandler"; const defaultWatchManager = new WatchManager(); @@ -61,13 +48,13 @@ for (const key of Object.keys(SETTINGS)) { } const LEVEL_HANDLERS = { - "device": new DeviceSettingsHandler(featureNames, defaultWatchManager), - "room-device": new RoomDeviceSettingsHandler(defaultWatchManager), - "room-account": new RoomAccountSettingsHandler(defaultWatchManager), - "account": new AccountSettingsHandler(defaultWatchManager), - "room": new RoomSettingsHandler(defaultWatchManager), - "config": new ConfigSettingsHandler(), - "default": new DefaultSettingsHandler(defaultSettings, invertedDefaultSettings), + [SettingLevel.DEVICE]: new DeviceSettingsHandler(featureNames, defaultWatchManager), + [SettingLevel.ROOM_DEVICE]: new RoomDeviceSettingsHandler(defaultWatchManager), + [SettingLevel.ROOM_ACCOUNT]: new RoomAccountSettingsHandler(defaultWatchManager), + [SettingLevel.ACCOUNT]: new AccountSettingsHandler(defaultWatchManager), + [SettingLevel.ROOM]: new RoomSettingsHandler(defaultWatchManager), + [SettingLevel.CONFIG]: new ConfigSettingsHandler(), + [SettingLevel.DEFAULT]: new DefaultSettingsHandler(defaultSettings, invertedDefaultSettings), }; // Wrap all the handlers with local echo @@ -76,20 +63,41 @@ for (const key of Object.keys(LEVEL_HANDLERS)) { } const LEVEL_ORDER = [ - 'device', 'room-device', 'room-account', 'account', 'room', 'config', 'default', + SettingLevel.DEVICE, + SettingLevel.ROOM_DEVICE, + SettingLevel.ROOM_ACCOUNT, + SettingLevel.ACCOUNT, + SettingLevel.ROOM, + SettingLevel.CONFIG, + SettingLevel.DEFAULT, ]; +export type CallbackFn = ( + settingName: string, + roomId: string, + atLevel: SettingLevel, + newValAtLevel: any, + newVal: any, +) => void; + +interface IHandlerMap { + // @ts-ignore - TS wants this to be a string key but we know better + [level: SettingLevel]: SettingsHandler; +} + +export type LabsFeatureState = "labs" | "disable" | "enable" | string; + /** * Controls and manages application settings by providing varying levels at which the * setting value may be specified. The levels are then used to determine what the setting * value should be given a set of circumstances. The levels, in priority order, are: - * - "device" - Values are determined by the current device - * - "room-device" - Values are determined by the current device for a particular room - * - "room-account" - Values are determined by the current account for a particular room - * - "account" - Values are determined by the current account - * - "room" - Values are determined by a particular room (by the room admins) - * - "config" - Values are determined by the config.json - * - "default" - Values are determined by the hardcoded defaults + * - SettingLevel.DEVICE - Values are determined by the current device + * - SettingLevel.ROOM_DEVICE - Values are determined by the current device for a particular room + * - SettingLevel.ROOM_ACCOUNT - Values are determined by the current account for a particular room + * - SettingLevel.ACCOUNT - Values are determined by the current account + * - SettingLevel.ROOM - Values are determined by a particular room (by the room admins) + * - SettingLevel.CONFIG - Values are determined by the config.json + * - SettingLevel.DEFAULT - Values are determined by the hardcoded defaults * * Each level has a different method to storing the setting value. For implementation * specific details, please see the handlers. The "config" and "default" levels are @@ -110,11 +118,11 @@ export default class SettingsStore { // We also maintain a list of monitors which are special watchers: they cause dispatches // when the setting changes. We track which rooms we're monitoring though to ensure we // don't duplicate updates on the bus. - static _watchers = {}; // { callbackRef => { callbackFn } } - static _monitors = {}; // { settingName => { roomId => callbackRef } } + private static watchers = {}; // { callbackRef => { callbackFn } } + private static monitors = {}; // { settingName => { roomId => callbackRef } } // Counter used for generation of watcher IDs - static _watcherCount = 1; + private static watcherCount = 1; /** * Watches for changes in a particular setting. This is done without any local echo @@ -132,7 +140,7 @@ export default class SettingsStore { * if the change in value is worthwhile enough to react upon. * @returns {string} A reference to the watcher that was employed. */ - static watchSetting(settingName, roomId, callbackFn) { + public static watchSetting(settingName: string, roomId: string, callbackFn: CallbackFn): string { const setting = SETTINGS[settingName]; const originalSettingName = settingName; if (!setting) throw new Error(`${settingName} is not a setting`); @@ -141,15 +149,14 @@ export default class SettingsStore { settingName = setting.invertedSettingName; } - const watcherId = `${new Date().getTime()}_${SettingsStore._watcherCount++}_${settingName}_${roomId}`; + const watcherId = `${new Date().getTime()}_${SettingsStore.watcherCount++}_${settingName}_${roomId}`; const localizedCallback = (changedInRoomId, atLevel, newValAtLevel) => { const newValue = SettingsStore.getValue(originalSettingName); callbackFn(originalSettingName, changedInRoomId, atLevel, newValAtLevel, newValue); }; - console.log(`Starting watcher for ${settingName}@${roomId || ''} as ID ${watcherId}`); - SettingsStore._watchers[watcherId] = localizedCallback; + SettingsStore.watchers[watcherId] = localizedCallback; defaultWatchManager.watchSetting(settingName, roomId, localizedCallback); return watcherId; @@ -161,15 +168,14 @@ export default class SettingsStore { * @param {string} watcherReference The watcher reference (received from #watchSetting) * to cancel. */ - static unwatchSetting(watcherReference) { - if (!SettingsStore._watchers[watcherReference]) { + public static unwatchSetting(watcherReference: string) { + if (!SettingsStore.watchers[watcherReference]) { console.warn(`Ending non-existent watcher ID ${watcherReference}`); return; } - console.log(`Ending watcher ID ${watcherReference}`); - defaultWatchManager.unwatchSetting(SettingsStore._watchers[watcherReference]); - delete SettingsStore._watchers[watcherReference]; + defaultWatchManager.unwatchSetting(SettingsStore.watchers[watcherReference]); + delete SettingsStore.watchers[watcherReference]; } /** @@ -180,13 +186,13 @@ export default class SettingsStore { * @param {string} settingName The setting name to monitor. * @param {String} roomId The room ID to monitor for changes in. Use null for all rooms. */ - static monitorSetting(settingName, roomId) { + public static monitorSetting(settingName: string, roomId: string) { roomId = roomId || null; // the thing wants null specifically to work, so appease it. - if (!this._monitors[settingName]) this._monitors[settingName] = {}; + if (!this.monitors[settingName]) this.monitors[settingName] = {}; const registerWatcher = () => { - this._monitors[settingName][roomId] = SettingsStore.watchSetting( + this.monitors[settingName][roomId] = SettingsStore.watchSetting( settingName, roomId, (settingName, inRoomId, level, newValueAtLevel, newValue) => { dis.dispatch({ action: 'setting_updated', @@ -200,16 +206,16 @@ export default class SettingsStore { ); }; - const hasRoom = Object.keys(this._monitors[settingName]).find((r) => r === roomId || r === null); + const hasRoom = Object.keys(this.monitors[settingName]).find((r) => r === roomId || r === null); if (!hasRoom) { registerWatcher(); } else { if (roomId === null) { // Unregister all existing watchers and register the new one - for (const roomId of Object.keys(this._monitors[settingName])) { - SettingsStore.unwatchSetting(this._monitors[settingName][roomId]); + for (const roomId of Object.keys(this.monitors[settingName])) { + SettingsStore.unwatchSetting(this.monitors[settingName][roomId]); } - this._monitors[settingName] = {}; + this.monitors[settingName] = {}; registerWatcher(); } // else a watcher is already registered for the room, so don't bother registering it again } @@ -218,11 +224,11 @@ export default class SettingsStore { /** * Gets the translated display name for a given setting * @param {string} settingName The setting to look up. - * @param {"device"|"room-device"|"room-account"|"account"|"room"|"config"|"default"} atLevel + * @param {SettingLevel} atLevel * The level to get the display name for; Defaults to 'default'. * @return {String} The display name for the setting, or null if not found. */ - static getDisplayName(settingName, atLevel = "default") { + public static getDisplayName(settingName: string, atLevel = SettingLevel.DEFAULT) { if (!SETTINGS[settingName] || !SETTINGS[settingName].displayName) return null; let displayName = SETTINGS[settingName].displayName; @@ -231,20 +237,20 @@ export default class SettingsStore { else displayName = displayName["default"]; } - return _t(displayName); + return _t(displayName as string); } /** * Returns a list of all available labs feature names * @returns {string[]} The list of available feature names */ - static getLabsFeatures() { + public static getLabsFeatures(): string[] { const possibleFeatures = Object.keys(SETTINGS).filter((s) => SettingsStore.isFeature(s)); const enableLabs = SdkConfig.get()["enableLabs"]; if (enableLabs) return possibleFeatures; - return possibleFeatures.filter((s) => SettingsStore._getFeatureState(s) === "labs"); + return possibleFeatures.filter((s) => SettingsStore.getFeatureState(s) === "labs"); } /** @@ -252,7 +258,7 @@ export default class SettingsStore { * @param {string} settingName The setting to look up. * @return {boolean} True if the setting is a feature. */ - static isFeature(settingName) { + public static isFeature(settingName: string) { if (!SETTINGS[settingName]) return false; return SETTINGS[settingName].isFeature; } @@ -264,7 +270,7 @@ export default class SettingsStore { * @param {String} roomId The optional room ID to validate in, may be null. * @return {boolean} True if the feature is enabled, false otherwise */ - static isFeatureEnabled(settingName, roomId = null) { + public static isFeatureEnabled(settingName: string, roomId: string = null) { if (!SettingsStore.isFeature(settingName)) { throw new Error("Setting " + settingName + " is not a feature"); } @@ -278,7 +284,7 @@ export default class SettingsStore { * @param {boolean} value True to enable the feature, false otherwise. * @returns {Promise} Resolves when the setting has been set. */ - static setFeatureEnabled(settingName, value) { + public static setFeatureEnabled(settingName: string, value: any): Promise { // Verify that the setting is actually a setting if (!SETTINGS[settingName]) { throw new Error("Setting '" + settingName + "' does not appear to be a setting."); @@ -287,7 +293,7 @@ export default class SettingsStore { throw new Error("Setting " + settingName + " is not a feature"); } - return SettingsStore.setValue(settingName, null, "device", value); + return SettingsStore.setValue(settingName, null, SettingLevel.DEVICE, value); } /** @@ -298,7 +304,7 @@ export default class SettingsStore { * @param {boolean} excludeDefault True to disable using the default value. * @return {*} The value, or null if not found */ - static getValue(settingName, roomId = null, excludeDefault = false) { + public static getValue(settingName: string, roomId: string = null, excludeDefault = false): any { // Verify that the setting is actually a setting if (!SETTINGS[settingName]) { throw new Error("Setting '" + settingName + "' does not appear to be a setting."); @@ -312,7 +318,7 @@ export default class SettingsStore { /** * Gets a setting's value at a particular level, ignoring all levels that are more specific. - * @param {"device"|"room-device"|"room-account"|"account"|"room"|"config"|"default"} level The + * @param {SettingLevel|"config"|"default"} level The * level to look at. * @param {string} settingName The name of the setting to read. * @param {String} roomId The room ID to read the setting value in, may be null. @@ -321,7 +327,13 @@ export default class SettingsStore { * @param {boolean} excludeDefault True to disable using the default value. * @return {*} The value, or null if not found. */ - static getValueAt(level, settingName, roomId = null, explicit = false, excludeDefault = false) { + public static getValueAt( + level: SettingLevel, + settingName: string, + roomId: string = null, + explicit = false, + excludeDefault = false, + ): any { // Verify that the setting is actually a setting const setting = SETTINGS[settingName]; if (!setting) { @@ -329,19 +341,19 @@ export default class SettingsStore { } const levelOrder = (setting.supportedLevelsAreOrdered ? setting.supportedLevels : LEVEL_ORDER); - if (!levelOrder.includes("default")) levelOrder.push("default"); // always include default + if (!levelOrder.includes(SettingLevel.DEFAULT)) levelOrder.push(SettingLevel.DEFAULT); // always include default const minIndex = levelOrder.indexOf(level); if (minIndex === -1) throw new Error("Level " + level + " is not prioritized"); if (SettingsStore.isFeature(settingName)) { - const configValue = SettingsStore._getFeatureState(settingName); + const configValue = SettingsStore.getFeatureState(settingName); if (configValue === "enable") return true; if (configValue === "disable") return false; // else let it fall through the default process } - const handlers = SettingsStore._getHandlers(settingName); + const handlers = SettingsStore.getHandlers(settingName); // Check if we need to invert the setting at all. Do this after we get the setting // handlers though, otherwise we'll fail to read the value. @@ -353,10 +365,10 @@ export default class SettingsStore { if (explicit) { const handler = handlers[level]; if (!handler) { - return SettingsStore._getFinalValue(setting, level, roomId, null, null); + return SettingsStore.getFinalValue(setting, level, roomId, null, null); } const value = handler.getValue(settingName, roomId); - return SettingsStore._getFinalValue(setting, level, roomId, value, level); + return SettingsStore.getFinalValue(setting, level, roomId, value, level); } for (let i = minIndex; i < levelOrder.length; i++) { @@ -366,10 +378,10 @@ export default class SettingsStore { const value = handler.getValue(settingName, roomId); if (value === null || value === undefined) continue; - return SettingsStore._getFinalValue(setting, level, roomId, value, levelOrder[i]); + return SettingsStore.getFinalValue(setting, level, roomId, value, levelOrder[i]); } - return SettingsStore._getFinalValue(setting, level, roomId, null, null); + return SettingsStore.getFinalValue(setting, level, roomId, null, null); } /** @@ -378,7 +390,7 @@ export default class SettingsStore { * @param {String} roomId The room ID to read the setting value in, may be null. * @return {*} The default value */ - static getDefaultValue(settingName) { + public static getDefaultValue(settingName: string): any { // Verify that the setting is actually a setting if (!SETTINGS[settingName]) { throw new Error("Setting '" + settingName + "' does not appear to be a setting."); @@ -387,7 +399,13 @@ export default class SettingsStore { return SETTINGS[settingName].default; } - static _getFinalValue(setting, level, roomId, calculatedValue, calculatedAtLevel) { + private static getFinalValue( + setting: ISetting, + level: SettingLevel, + roomId: string, + calculatedValue: any, + calculatedAtLevel: SettingLevel, + ): any { let resultingValue = calculatedValue; if (setting.controller) { @@ -406,20 +424,21 @@ export default class SettingsStore { * to indicate that the level should no longer have an override. * @param {string} settingName The name of the setting to change. * @param {String} roomId The room ID to change the value in, may be null. - * @param {"device"|"room-device"|"room-account"|"account"|"room"} level The level + * @param {SettingLevel} level The level * to change the value at. * @param {*} value The new value of the setting, may be null. * @return {Promise} Resolves when the setting has been changed. */ + /* eslint-enable valid-jsdoc */ - static async setValue(settingName, roomId, level, value) { + public static async setValue(settingName: string, roomId: string, level: SettingLevel, value: any): Promise { // Verify that the setting is actually a setting const setting = SETTINGS[settingName]; if (!setting) { throw new Error("Setting '" + settingName + "' does not appear to be a setting."); } - const handler = SettingsStore._getHandler(settingName, level); + const handler = SettingsStore.getHandler(settingName, level); if (!handler) { throw new Error("Setting " + settingName + " does not have a handler for " + level); } @@ -451,28 +470,28 @@ export default class SettingsStore { * set for a particular room, otherwise it should be supplied. * @param {string} settingName The name of the setting to check. * @param {String} roomId The room ID to check in, may be null. - * @param {"device"|"room-device"|"room-account"|"account"|"room"} level The level to + * @param {SettingLevel} level The level to * check at. * @return {boolean} True if the user may set the setting, false otherwise. */ - static canSetValue(settingName, roomId, level) { + public static canSetValue(settingName: string, roomId: string, level: SettingLevel): boolean { // Verify that the setting is actually a setting if (!SETTINGS[settingName]) { throw new Error("Setting '" + settingName + "' does not appear to be a setting."); } - const handler = SettingsStore._getHandler(settingName, level); + const handler = SettingsStore.getHandler(settingName, level); if (!handler) return false; return handler.canSetValue(settingName, roomId); } /** * Determines if the given level is supported on this device. - * @param {"device"|"room-device"|"room-account"|"account"|"room"} level The level + * @param {SettingLevel} level The level * to check the feasibility of. * @return {boolean} True if the level is supported, false otherwise. */ - static isLevelSupported(level) { + public static isLevelSupported(level: SettingLevel): boolean { if (!LEVEL_HANDLERS[level]) return false; return LEVEL_HANDLERS[level].isSupported(); } @@ -484,7 +503,7 @@ export default class SettingsStore { * @param {string} realSettingName The setting name to try and read. * @param {string} roomId Optional room ID to test the setting in. */ - static debugSetting(realSettingName, roomId) { + public static debugSetting(realSettingName: string, roomId: string) { console.log(`--- DEBUG ${realSettingName}`); // Note: we intentionally use JSON.stringify here to avoid the console masking the @@ -572,13 +591,13 @@ export default class SettingsStore { console.log(`--- END DEBUG`); } - static _getHandler(settingName, level) { - const handlers = SettingsStore._getHandlers(settingName); + private static getHandler(settingName: string, level: SettingLevel): SettingsHandler { + const handlers = SettingsStore.getHandlers(settingName); if (!handlers[level]) return null; return handlers[level]; } - static _getHandlers(settingName) { + private static getHandlers(settingName: string): IHandlerMap { if (!SETTINGS[settingName]) return {}; const handlers = {}; @@ -593,7 +612,7 @@ export default class SettingsStore { return handlers; } - static _getFeatureState(settingName) { + private static getFeatureState(settingName: string): LabsFeatureState { const featuresConfig = SdkConfig.get()['features']; const enableLabs = SdkConfig.get()['enableLabs']; // we'll honour the old flag @@ -613,4 +632,4 @@ export default class SettingsStore { } // For debugging purposes -global.mxSettingsStore = SettingsStore; +window.mxSettingsStore = SettingsStore; diff --git a/src/settings/WatchManager.js b/src/settings/WatchManager.ts similarity index 56% rename from src/settings/WatchManager.js rename to src/settings/WatchManager.ts index 3f54ca929e..d51439459c 100644 --- a/src/settings/WatchManager.js +++ b/src/settings/WatchManager.ts @@ -14,41 +14,52 @@ See the License for the specific language governing permissions and limitations under the License. */ +import { SettingLevel } from "./SettingLevel"; + +export type CallbackFn = (changedInRoomId: string, atLevel: SettingLevel, newValAtLevel: any) => void; + +const IRRELEVANT_ROOM = Symbol("any room"); + +interface RoomWatcherMap { + // @ts-ignore - TS wants string-only keys but we know better - https://github.com/Microsoft/TypeScript/issues/1863 + [roomId: string | symbol]: CallbackFn[]; +} + /** * Generalized management class for dealing with watchers on a per-handler (per-level) * basis without duplicating code. Handlers are expected to push updates through this * class, which are then proxied outwards to any applicable watchers. */ export class WatchManager { - _watchers = {}; // { settingName: { roomId: callbackFns[] } } + private watchers: {[settingName: string]: RoomWatcherMap} = {}; // Proxy for handlers to delegate changes to this manager - watchSetting(settingName, roomId, cb) { - if (!this._watchers[settingName]) this._watchers[settingName] = {}; - if (!this._watchers[settingName][roomId]) this._watchers[settingName][roomId] = []; - this._watchers[settingName][roomId].push(cb); + public watchSetting(settingName: string, roomId: string | null, cb: CallbackFn) { + if (!this.watchers[settingName]) this.watchers[settingName] = {}; + if (!this.watchers[settingName][roomId]) this.watchers[settingName][roomId] = []; + this.watchers[settingName][roomId].push(cb); } // Proxy for handlers to delegate changes to this manager - unwatchSetting(cb) { - for (const settingName of Object.keys(this._watchers)) { - for (const roomId of Object.keys(this._watchers[settingName])) { + public unwatchSetting(cb: CallbackFn) { + for (const settingName of Object.keys(this.watchers)) { + for (const roomId of Object.keys(this.watchers[settingName])) { let idx; - while ((idx = this._watchers[settingName][roomId].indexOf(cb)) !== -1) { - this._watchers[settingName][roomId].splice(idx, 1); + while ((idx = this.watchers[settingName][roomId].indexOf(cb)) !== -1) { + this.watchers[settingName][roomId].splice(idx, 1); } } } } - notifyUpdate(settingName, inRoomId, atLevel, newValueAtLevel) { + public notifyUpdate(settingName: string, inRoomId: string | null, atLevel: SettingLevel, newValueAtLevel: any) { // Dev note: We could avoid raising changes for ultimately inconsequential changes, but // we also don't have a reliable way to get the old value of a setting. Instead, we'll just // let it fall through regardless and let the receiver dedupe if they want to. - if (!this._watchers[settingName]) return; + if (!this.watchers[settingName]) return; - const roomWatchers = this._watchers[settingName]; + const roomWatchers = this.watchers[settingName]; const callbacks = []; if (inRoomId !== null && roomWatchers[inRoomId]) { @@ -59,8 +70,8 @@ export class WatchManager { // Fire updates to all the individual room watchers too, as they probably // care about the change higher up. callbacks.push(...Object.values(roomWatchers).reduce((r, a) => [...r, ...a], [])); - } else if (roomWatchers[null]) { - callbacks.push(...roomWatchers[null]); + } else if (roomWatchers[IRRELEVANT_ROOM]) { + callbacks.push(...roomWatchers[IRRELEVANT_ROOM]); } for (const callback of callbacks) { diff --git a/src/settings/controllers/CustomStatusController.js b/src/settings/controllers/CustomStatusController.ts similarity index 84% rename from src/settings/controllers/CustomStatusController.js rename to src/settings/controllers/CustomStatusController.ts index 031387bb6a..c7dfad0b3b 100644 --- a/src/settings/controllers/CustomStatusController.js +++ b/src/settings/controllers/CustomStatusController.ts @@ -1,5 +1,5 @@ /* -Copyright 2019 New Vector Ltd +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,9 +16,10 @@ limitations under the License. import SettingController from "./SettingController"; import dis from "../../dispatcher/dispatcher"; +import { SettingLevel } from "../SettingLevel"; export default class CustomStatusController extends SettingController { - onChange(level, roomId, newValue) { + public onChange(level: SettingLevel, roomId: string, newValue: any) { // Dispatch setting change so that some components that are still visible when the // Settings page is open (such as RoomTiles) can reflect the change. dis.dispatch({ diff --git a/src/settings/controllers/FontSizeController.ts b/src/settings/controllers/FontSizeController.ts index 6440fd32fe..b86d596040 100644 --- a/src/settings/controllers/FontSizeController.ts +++ b/src/settings/controllers/FontSizeController.ts @@ -18,13 +18,14 @@ import SettingController from "./SettingController"; import dis from "../../dispatcher/dispatcher"; import { UpdateFontSizePayload } from "../../dispatcher/payloads/UpdateFontSizePayload"; import { Action } from "../../dispatcher/actions"; +import { SettingLevel } from "../SettingLevel"; export default class FontSizeController extends SettingController { constructor() { super(); } - onChange(level, roomId, newValue) { + public onChange(level: SettingLevel, roomId: string, newValue: any) { // Dispatch font size change so that everything open responds to the change. dis.dispatch({ action: Action.UpdateFontSize, diff --git a/src/settings/controllers/NotificationControllers.js b/src/settings/controllers/NotificationControllers.ts similarity index 77% rename from src/settings/controllers/NotificationControllers.js rename to src/settings/controllers/NotificationControllers.ts index e38a5bded1..fc50af6096 100644 --- a/src/settings/controllers/NotificationControllers.js +++ b/src/settings/controllers/NotificationControllers.ts @@ -1,5 +1,6 @@ /* Copyright 2017 Travis Ralston +Copyright 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,13 +17,14 @@ limitations under the License. import SettingController from "./SettingController"; import {MatrixClientPeg} from '../../MatrixClientPeg'; +import { SettingLevel } from "../SettingLevel"; // XXX: This feels wrong. import {PushProcessor} from "matrix-js-sdk/src/pushprocessor"; // .m.rule.master being enabled means all events match that push rule // default action on this rule is dont_notify, but it could be something else -function isPushNotifyDisabled() { +function isPushNotifyDisabled(): boolean { // Return the value of the master push rule as a default const processor = new PushProcessor(MatrixClientPeg.get()); const masterRule = processor.getPushRuleById(".m.rule.master"); @@ -36,14 +38,20 @@ function isPushNotifyDisabled() { return masterRule.enabled && !masterRule.actions.includes("notify"); } -function getNotifier() { +function getNotifier(): any { // TODO: [TS] Formal type that doesn't cause a cyclical reference. + // eslint-disable-next-line @typescript-eslint/no-var-requires let Notifier = require('../../Notifier'); // avoids cyclical references if (Notifier.default) Notifier = Notifier.default; // correct for webpack require() weirdness return Notifier; } export class NotificationsEnabledController extends SettingController { - getValueOverride(level, roomId, calculatedValue, calculatedAtLevel) { + public getValueOverride( + level: SettingLevel, + roomId: string, + calculatedValue: any, + calculatedAtLevel: SettingLevel, + ): any { if (!getNotifier().isPossible()) return false; if (calculatedValue === null || calculatedAtLevel === "default") { @@ -53,7 +61,7 @@ export class NotificationsEnabledController extends SettingController { return calculatedValue; } - onChange(level, roomId, newValue) { + public onChange(level: SettingLevel, roomId: string, newValue: any) { if (getNotifier().supportsDesktopNotifications()) { getNotifier().setEnabled(newValue); } @@ -61,7 +69,7 @@ export class NotificationsEnabledController extends SettingController { } export class NotificationBodyEnabledController extends SettingController { - getValueOverride(level, roomId, calculatedValue) { + public getValueOverride(level: SettingLevel, roomId: string, calculatedValue: any): any { if (!getNotifier().isPossible()) return false; if (calculatedValue === null) { @@ -73,7 +81,7 @@ export class NotificationBodyEnabledController extends SettingController { } export class AudioNotificationsEnabledController extends SettingController { - getValueOverride(level, roomId, calculatedValue) { + public getValueOverride(level: SettingLevel, roomId: string, calculatedValue: any): any { if (!getNotifier().isPossible()) return false; // Note: Audio notifications are *not* enabled by default. diff --git a/src/settings/controllers/PushToMatrixClientController.js b/src/settings/controllers/PushToMatrixClientController.ts similarity index 67% rename from src/settings/controllers/PushToMatrixClientController.js rename to src/settings/controllers/PushToMatrixClientController.ts index b7c285227f..8fbf7eb34c 100644 --- a/src/settings/controllers/PushToMatrixClientController.js +++ b/src/settings/controllers/PushToMatrixClientController.ts @@ -15,23 +15,20 @@ limitations under the License. */ import { MatrixClientPeg } from '../../MatrixClientPeg'; +import { SettingLevel } from "../SettingLevel"; +import SettingController from "./SettingController"; /** * When the value changes, call a setter function on the matrix client with the new value */ -export default class PushToMatrixClientController { - constructor(setter, inverse) { - this._setter = setter; - this._inverse = inverse; +export default class PushToMatrixClientController extends SettingController { + constructor(private setter: Function, private inverse: boolean) { + super(); } - getValueOverride(level, roomId, calculatedValue, calculatedAtLevel) { - return null; // no override - } - - onChange(level, roomId, newValue) { + public onChange(level: SettingLevel, roomId: string, newValue: any) { // XXX does this work? This surely isn't necessarily the effective value, // but it's what NotificationsEnabledController does... - this._setter.call(MatrixClientPeg.get(), this._inverse ? !newValue : newValue); + this.setter.call(MatrixClientPeg.get(), this.inverse ? !newValue : newValue); } } diff --git a/src/settings/controllers/ReloadOnChangeController.js b/src/settings/controllers/ReloadOnChangeController.ts similarity index 80% rename from src/settings/controllers/ReloadOnChangeController.js rename to src/settings/controllers/ReloadOnChangeController.ts index eadaee89ca..12bc23ef6c 100644 --- a/src/settings/controllers/ReloadOnChangeController.js +++ b/src/settings/controllers/ReloadOnChangeController.ts @@ -1,5 +1,5 @@ /* -Copyright 2019 The Matrix.org Foundation C.I.C. +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,9 +16,10 @@ limitations under the License. import SettingController from "./SettingController"; import PlatformPeg from "../../PlatformPeg"; +import { SettingLevel } from "../SettingLevel"; export default class ReloadOnChangeController extends SettingController { - onChange(level, roomId, newValue) { + public onChange(level: SettingLevel, roomId: string, newValue: any) { PlatformPeg.get().reload(); } } diff --git a/src/settings/controllers/SettingController.js b/src/settings/controllers/SettingController.ts similarity index 79% rename from src/settings/controllers/SettingController.js rename to src/settings/controllers/SettingController.ts index a7d0ccf21a..d90eba1e9e 100644 --- a/src/settings/controllers/SettingController.js +++ b/src/settings/controllers/SettingController.ts @@ -1,5 +1,6 @@ /* Copyright 2017 Travis Ralston +Copyright 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,6 +15,8 @@ See the License for the specific language governing permissions and limitations under the License. */ +import { SettingLevel } from "../SettingLevel"; + /** * Represents a controller for individual settings to alter the reading behaviour * based upon environmental conditions, or to react to changes and therefore update @@ -22,7 +25,7 @@ limitations under the License. * This is not intended to replace the functionality of a SettingsHandler, it is only * intended to handle environmental factors for specific settings. */ -export default class SettingController { +export default abstract class SettingController { /** * Gets the overridden value for the setting, if any. This must return null if the * value is not to be overridden, otherwise it must return the new value. @@ -30,11 +33,16 @@ export default class SettingController { * @param {String} roomId The room ID, may be null. * @param {*} calculatedValue The value that the handlers think the setting should be, * may be null. - * @param {string} calculatedAtLevel The level for which the calculated value was + * @param {SettingLevel} calculatedAtLevel The level for which the calculated value was * calculated at. May be null. * @return {*} The value that should be used, or null if no override is applicable. */ - getValueOverride(level, roomId, calculatedValue, calculatedAtLevel) { + public getValueOverride( + level: SettingLevel, + roomId: string, + calculatedValue: any, + calculatedAtLevel: SettingLevel, + ): any { return null; // no override } @@ -44,7 +52,7 @@ export default class SettingController { * @param {String} roomId The room ID, may be null. * @param {*} newValue The new value for the setting, may be null. */ - onChange(level, roomId, newValue) { + public onChange(level: SettingLevel, roomId: string, newValue: any) { // do nothing by default } } diff --git a/src/settings/controllers/SystemFontController.ts b/src/settings/controllers/SystemFontController.ts index 4f591efc17..f38dbdbbf6 100644 --- a/src/settings/controllers/SystemFontController.ts +++ b/src/settings/controllers/SystemFontController.ts @@ -19,13 +19,14 @@ import SettingsStore from "../SettingsStore"; import dis from "../../dispatcher/dispatcher"; import { UpdateSystemFontPayload } from "../../dispatcher/payloads/UpdateSystemFontPayload"; import { Action } from "../../dispatcher/actions"; +import { SettingLevel } from "../SettingLevel"; export default class SystemFontController extends SettingController { constructor() { super(); } - onChange(level, roomId, newValue) { + public onChange(level: SettingLevel, roomId: string, newValue: any) { // Dispatch font size change so that everything open responds to the change. dis.dispatch({ action: Action.UpdateSystemFont, diff --git a/src/settings/controllers/ThemeController.js b/src/settings/controllers/ThemeController.ts similarity index 79% rename from src/settings/controllers/ThemeController.js rename to src/settings/controllers/ThemeController.ts index 4098a5ca3e..15dd64c901 100644 --- a/src/settings/controllers/ThemeController.js +++ b/src/settings/controllers/ThemeController.ts @@ -1,6 +1,6 @@ /* -Copyright 2019 New Vector Ltd Copyright 2019 Michael Telatynski <7t3chguy@gmail.com> +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,11 +17,17 @@ limitations under the License. import SettingController from "./SettingController"; import {DEFAULT_THEME, enumerateThemes} from "../../theme"; +import { SettingLevel } from "../SettingLevel"; export default class ThemeController extends SettingController { - static isLogin = false; + public static isLogin = false; - getValueOverride(level, roomId, calculatedValue, calculatedAtLevel) { + public getValueOverride( + level: SettingLevel, + roomId: string, + calculatedValue: any, + calculatedAtLevel: SettingLevel, + ): any { if (!calculatedValue) return null; // Don't override null themes if (ThemeController.isLogin) return 'light'; diff --git a/src/settings/controllers/UseSystemFontController.ts b/src/settings/controllers/UseSystemFontController.ts index d598b25962..0b6acc590a 100644 --- a/src/settings/controllers/UseSystemFontController.ts +++ b/src/settings/controllers/UseSystemFontController.ts @@ -19,13 +19,14 @@ import SettingsStore from "../SettingsStore"; import dis from "../../dispatcher/dispatcher"; import { UpdateSystemFontPayload } from "../../dispatcher/payloads/UpdateSystemFontPayload"; import { Action } from "../../dispatcher/actions"; +import { SettingLevel } from "../SettingLevel"; export default class UseSystemFontController extends SettingController { constructor() { super(); } - onChange(level, roomId, newValue) { + public onChange(level: SettingLevel, roomId: string, newValue: any) { // Dispatch font size change so that everything open responds to the change. dis.dispatch({ action: Action.UpdateSystemFont, diff --git a/src/settings/handlers/AccountSettingsHandler.js b/src/settings/handlers/AccountSettingsHandler.ts similarity index 71% rename from src/settings/handlers/AccountSettingsHandler.js rename to src/settings/handlers/AccountSettingsHandler.ts index 4048d8ddea..53180aeba8 100644 --- a/src/settings/handlers/AccountSettingsHandler.js +++ b/src/settings/handlers/AccountSettingsHandler.ts @@ -1,6 +1,6 @@ /* Copyright 2017 Travis Ralston -Copyright 2019 New Vector Ltd. +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,14 +17,16 @@ limitations under the License. import {MatrixClientPeg} from '../../MatrixClientPeg'; import MatrixClientBackedSettingsHandler from "./MatrixClientBackedSettingsHandler"; -import {SettingLevel} from "../SettingsStore"; import {objectClone, objectKeyChanges} from "../../utils/objects"; +import {SettingLevel} from "../SettingLevel"; +import { WatchManager } from "../WatchManager"; +import { MatrixClient } from "matrix-js-sdk/src/client"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; const BREADCRUMBS_LEGACY_EVENT_TYPE = "im.vector.riot.breadcrumb_rooms"; const BREADCRUMBS_EVENT_TYPE = "im.vector.setting.breadcrumbs"; const BREADCRUMBS_EVENT_TYPES = [BREADCRUMBS_LEGACY_EVENT_TYPE, BREADCRUMBS_EVENT_TYPE]; const RECENT_EMOJI_EVENT_TYPE = "io.element.recent_emoji"; - const INTEG_PROVISIONING_EVENT_TYPE = "im.vector.setting.integration_provisioning"; /** @@ -32,22 +34,19 @@ const INTEG_PROVISIONING_EVENT_TYPE = "im.vector.setting.integration_provisionin * This handler does not make use of the roomId parameter. */ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHandler { - constructor(watchManager) { + constructor(private watchers: WatchManager) { super(); - - this._watchers = watchManager; - this._onAccountData = this._onAccountData.bind(this); } - initMatrixClient(oldClient, newClient) { + public initMatrixClient(oldClient: MatrixClient, newClient: MatrixClient) { if (oldClient) { - oldClient.removeListener("accountData", this._onAccountData); + oldClient.removeListener("accountData", this.onAccountData); } - newClient.on("accountData", this._onAccountData); + newClient.on("accountData", this.onAccountData); } - _onAccountData(event, prevEvent) { + private onAccountData = (event: MatrixEvent, prevEvent: MatrixEvent) => { if (event.getType() === "org.matrix.preview_urls") { let val = event.getContent()['disable']; if (typeof(val) !== "boolean") { @@ -56,30 +55,30 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa val = !val; } - this._watchers.notifyUpdate("urlPreviewsEnabled", null, SettingLevel.ACCOUNT, val); + this.watchers.notifyUpdate("urlPreviewsEnabled", null, SettingLevel.ACCOUNT, val); } else if (event.getType() === "im.vector.web.settings") { // Figure out what changed and fire those updates const prevContent = prevEvent ? prevEvent.getContent() : {}; const changedSettings = objectKeyChanges(prevContent, event.getContent()); for (const settingName of changedSettings) { const val = event.getContent()[settingName]; - this._watchers.notifyUpdate(settingName, null, SettingLevel.ACCOUNT, val); + this.watchers.notifyUpdate(settingName, null, SettingLevel.ACCOUNT, val); } } else if (BREADCRUMBS_EVENT_TYPES.includes(event.getType())) { - this._notifyBreadcrumbsUpdate(event); + this.notifyBreadcrumbsUpdate(event); } else if (event.getType() === INTEG_PROVISIONING_EVENT_TYPE) { const val = event.getContent()['enabled']; - this._watchers.notifyUpdate("integrationProvisioning", null, SettingLevel.ACCOUNT, val); + this.watchers.notifyUpdate("integrationProvisioning", null, SettingLevel.ACCOUNT, val); } else if (event.getType() === RECENT_EMOJI_EVENT_TYPE) { const val = event.getContent()['enabled']; - this._watchers.notifyUpdate("recent_emoji", null, SettingLevel.ACCOUNT, val); + this.watchers.notifyUpdate("recent_emoji", null, SettingLevel.ACCOUNT, val); } } - getValue(settingName, roomId) { + public getValue(settingName: string, roomId: string): any { // Special case URL previews if (settingName === "urlPreviewsEnabled") { - const content = this._getSettings("org.matrix.preview_urls") || {}; + const content = this.getSettings("org.matrix.preview_urls") || {}; // Check to make sure that we actually got a boolean if (typeof(content['disable']) !== "boolean") return null; @@ -88,9 +87,9 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa // Special case for breadcrumbs if (settingName === "breadcrumb_rooms") { - let content = this._getSettings(BREADCRUMBS_EVENT_TYPE); + let content = this.getSettings(BREADCRUMBS_EVENT_TYPE); if (!content || !content['recent_rooms']) { - content = this._getSettings(BREADCRUMBS_LEGACY_EVENT_TYPE); + content = this.getSettings(BREADCRUMBS_LEGACY_EVENT_TYPE); // This is a bit of a hack, but it makes things slightly easier if (content) content['recent_rooms'] = content['rooms']; @@ -101,17 +100,17 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa // Special case recent emoji if (settingName === "recent_emoji") { - const content = this._getSettings(RECENT_EMOJI_EVENT_TYPE); + const content = this.getSettings(RECENT_EMOJI_EVENT_TYPE); return content ? content["recent_emoji"] : null; } // Special case integration manager provisioning if (settingName === "integrationProvisioning") { - const content = this._getSettings(INTEG_PROVISIONING_EVENT_TYPE); + const content = this.getSettings(INTEG_PROVISIONING_EVENT_TYPE); return content ? content['enabled'] : null; } - const settings = this._getSettings() || {}; + const settings = this.getSettings() || {}; let preferredValue = settings[settingName]; if (preferredValue === null || preferredValue === undefined) { @@ -124,10 +123,10 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa return preferredValue; } - setValue(settingName, roomId, newValue) { + public setValue(settingName: string, roomId: string, newValue: any): Promise { // Special case URL previews if (settingName === "urlPreviewsEnabled") { - const content = this._getSettings("org.matrix.preview_urls") || {}; + const content = this.getSettings("org.matrix.preview_urls") || {}; content['disable'] = !newValue; return MatrixClientPeg.get().setAccountData("org.matrix.preview_urls", content); } @@ -135,9 +134,9 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa // Special case for breadcrumbs if (settingName === "breadcrumb_rooms") { // We read the value first just to make sure we preserve whatever random keys might be present. - let content = this._getSettings(BREADCRUMBS_EVENT_TYPE); + let content = this.getSettings(BREADCRUMBS_EVENT_TYPE); if (!content || !content['recent_rooms']) { - content = this._getSettings(BREADCRUMBS_LEGACY_EVENT_TYPE); + content = this.getSettings(BREADCRUMBS_LEGACY_EVENT_TYPE); } if (!content) content = {}; // If we still don't have content, make some @@ -147,33 +146,33 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa // Special case recent emoji if (settingName === "recent_emoji") { - const content = this._getSettings(RECENT_EMOJI_EVENT_TYPE) || {}; + const content = this.getSettings(RECENT_EMOJI_EVENT_TYPE) || {}; content["recent_emoji"] = newValue; return MatrixClientPeg.get().setAccountData(RECENT_EMOJI_EVENT_TYPE, content); } // Special case integration manager provisioning if (settingName === "integrationProvisioning") { - const content = this._getSettings(INTEG_PROVISIONING_EVENT_TYPE) || {}; + const content = this.getSettings(INTEG_PROVISIONING_EVENT_TYPE) || {}; content['enabled'] = newValue; return MatrixClientPeg.get().setAccountData(INTEG_PROVISIONING_EVENT_TYPE, content); } - const content = this._getSettings() || {}; + const content = this.getSettings() || {}; content[settingName] = newValue; return MatrixClientPeg.get().setAccountData("im.vector.web.settings", content); } - canSetValue(settingName, roomId) { + public canSetValue(settingName: string, roomId: string): boolean { return true; // It's their account, so they should be able to } - isSupported() { + public isSupported(): boolean { const cli = MatrixClientPeg.get(); return cli !== undefined && cli !== null; } - _getSettings(eventType = "im.vector.web.settings") { + private getSettings(eventType = "im.vector.web.settings"): any { // TODO: [TS] Types on return const cli = MatrixClientPeg.get(); if (!cli) return null; @@ -182,11 +181,11 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa return objectClone(event.getContent()); // clone to prevent mutation } - _notifyBreadcrumbsUpdate(event) { + private notifyBreadcrumbsUpdate(event: MatrixEvent) { let val = []; if (event.getType() === BREADCRUMBS_LEGACY_EVENT_TYPE) { // This seems fishy - try and get the event for the new rooms - const newType = this._getSettings(BREADCRUMBS_EVENT_TYPE); + const newType = this.getSettings(BREADCRUMBS_EVENT_TYPE); if (newType) val = newType['recent_rooms']; else val = event.getContent()['rooms']; } else if (event.getType() === BREADCRUMBS_EVENT_TYPE) { @@ -194,6 +193,6 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa } else { return; // for sanity, not because we expect to be here. } - this._watchers.notifyUpdate("breadcrumb_rooms", null, SettingLevel.ACCOUNT, val || []); + this.watchers.notifyUpdate("breadcrumb_rooms", null, SettingLevel.ACCOUNT, val || []); } } diff --git a/src/settings/handlers/ConfigSettingsHandler.js b/src/settings/handlers/ConfigSettingsHandler.ts similarity index 81% rename from src/settings/handlers/ConfigSettingsHandler.js rename to src/settings/handlers/ConfigSettingsHandler.ts index 3b5b4b626e..3e8b1724c1 100644 --- a/src/settings/handlers/ConfigSettingsHandler.js +++ b/src/settings/handlers/ConfigSettingsHandler.ts @@ -1,6 +1,6 @@ /* Copyright 2017 Travis Ralston -Copyright 2019 New Vector Ltd +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ import {isNullOrUndefined} from "matrix-js-sdk/src/utils"; * roomId parameter. */ export default class ConfigSettingsHandler extends SettingsHandler { - getValue(settingName, roomId) { + public getValue(settingName: string, roomId: string): any { const config = SdkConfig.get() || {}; // Special case themes @@ -37,15 +37,15 @@ export default class ConfigSettingsHandler extends SettingsHandler { return settingsConfig[settingName]; } - setValue(settingName, roomId, newValue) { + public async setValue(settingName: string, roomId: string, newValue: any): Promise { throw new Error("Cannot change settings at the config level"); } - canSetValue(settingName, roomId) { + public canSetValue(settingName: string, roomId: string): boolean { return false; } - isSupported() { + public isSupported(): boolean { return true; // SdkConfig is always there } } diff --git a/src/settings/handlers/DefaultSettingsHandler.js b/src/settings/handlers/DefaultSettingsHandler.ts similarity index 72% rename from src/settings/handlers/DefaultSettingsHandler.js rename to src/settings/handlers/DefaultSettingsHandler.ts index 37bc5b2348..f54c7eafe1 100644 --- a/src/settings/handlers/DefaultSettingsHandler.js +++ b/src/settings/handlers/DefaultSettingsHandler.ts @@ -1,6 +1,6 @@ /* Copyright 2017 Travis Ralston -Copyright 2019 New Vector Ltd. +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -27,29 +27,27 @@ export default class DefaultSettingsHandler extends SettingsHandler { * @param {object} defaults The default setting values, keyed by setting name. * @param {object} invertedDefaults The default inverted setting values, keyed by setting name. */ - constructor(defaults, invertedDefaults) { + constructor(private defaults: Record, private invertedDefaults: Record) { super(); - this._defaults = defaults; - this._invertedDefaults = invertedDefaults; } - getValue(settingName, roomId) { - let value = this._defaults[settingName]; + public getValue(settingName: string, roomId: string): any { + let value = this.defaults[settingName]; if (value === undefined) { - value = this._invertedDefaults[settingName]; + value = this.invertedDefaults[settingName]; } return value; } - setValue(settingName, roomId, newValue) { + public async setValue(settingName: string, roomId: string, newValue: any): Promise { throw new Error("Cannot set values on the default level handler"); } - canSetValue(settingName, roomId) { + public canSetValue(settingName: string, roomId: string) { return false; } - isSupported() { + public isSupported(): boolean { return true; } } diff --git a/src/settings/handlers/DeviceSettingsHandler.js b/src/settings/handlers/DeviceSettingsHandler.ts similarity index 71% rename from src/settings/handlers/DeviceSettingsHandler.js rename to src/settings/handlers/DeviceSettingsHandler.ts index 44f89b9086..2096203598 100644 --- a/src/settings/handlers/DeviceSettingsHandler.js +++ b/src/settings/handlers/DeviceSettingsHandler.ts @@ -18,7 +18,8 @@ limitations under the License. import SettingsHandler from "./SettingsHandler"; import {MatrixClientPeg} from "../../MatrixClientPeg"; -import {SettingLevel} from "../SettingsStore"; +import {SettingLevel} from "../SettingLevel"; +import { CallbackFn, WatchManager } from "../WatchManager"; /** * Gets and sets settings at the "device" level for the current device. @@ -29,17 +30,15 @@ export default class DeviceSettingsHandler extends SettingsHandler { /** * Creates a new device settings handler * @param {string[]} featureNames The names of known features. - * @param {WatchManager} watchManager The watch manager to notify updates to + * @param {WatchManager} watchers The watch manager to notify updates to */ - constructor(featureNames, watchManager) { + constructor(private featureNames: string[], private watchers: WatchManager) { super(); - this._featureNames = featureNames; - this._watchers = watchManager; } - getValue(settingName, roomId) { - if (this._featureNames.includes(settingName)) { - return this._readFeature(settingName); + public getValue(settingName: string, roomId: string): any { + if (this.featureNames.includes(settingName)) { + return this.readFeature(settingName); } // Special case notifications @@ -68,28 +67,28 @@ export default class DeviceSettingsHandler extends SettingsHandler { return val['value']; } - const settings = this._getSettings() || {}; + const settings = this.getSettings() || {}; return settings[settingName]; } - setValue(settingName, roomId, newValue) { - if (this._featureNames.includes(settingName)) { - this._writeFeature(settingName, newValue); + public setValue(settingName: string, roomId: string, newValue: any): Promise { + if (this.featureNames.includes(settingName)) { + this.writeFeature(settingName, newValue); return Promise.resolve(); } // Special case notifications if (settingName === "notificationsEnabled") { localStorage.setItem("notifications_enabled", newValue); - this._watchers.notifyUpdate(settingName, null, SettingLevel.DEVICE, newValue); + this.watchers.notifyUpdate(settingName, null, SettingLevel.DEVICE, newValue); return Promise.resolve(); } else if (settingName === "notificationBodyEnabled") { localStorage.setItem("notifications_body_enabled", newValue); - this._watchers.notifyUpdate(settingName, null, SettingLevel.DEVICE, newValue); + this.watchers.notifyUpdate(settingName, null, SettingLevel.DEVICE, newValue); return Promise.resolve(); } else if (settingName === "audioNotificationsEnabled") { localStorage.setItem("audio_notifications_enabled", newValue); - this._watchers.notifyUpdate(settingName, null, SettingLevel.DEVICE, newValue); + this.watchers.notifyUpdate(settingName, null, SettingLevel.DEVICE, newValue); return Promise.resolve(); } @@ -103,35 +102,35 @@ export default class DeviceSettingsHandler extends SettingsHandler { "lastRightPanelPhaseForGroup", ].includes(settingName)) { localStorage.setItem(`mx_${settingName}`, JSON.stringify({value: newValue})); - this._watchers.notifyUpdate(settingName, null, SettingLevel.DEVICE, newValue); + this.watchers.notifyUpdate(settingName, null, SettingLevel.DEVICE, newValue); return Promise.resolve(); } - const settings = this._getSettings() || {}; + const settings = this.getSettings() || {}; settings[settingName] = newValue; localStorage.setItem("mx_local_settings", JSON.stringify(settings)); - this._watchers.notifyUpdate(settingName, null, SettingLevel.DEVICE, newValue); + this.watchers.notifyUpdate(settingName, null, SettingLevel.DEVICE, newValue); return Promise.resolve(); } - canSetValue(settingName, roomId) { + public canSetValue(settingName: string, roomId: string): boolean { return true; // It's their device, so they should be able to } - isSupported() { + public isSupported(): boolean { return localStorage !== undefined && localStorage !== null; } - watchSetting(settingName, roomId, cb) { - this._watchers.watchSetting(settingName, roomId, cb); + public watchSetting(settingName: string, roomId: string, cb: CallbackFn) { + this.watchers.watchSetting(settingName, roomId, cb); } - unwatchSetting(cb) { - this._watchers.unwatchSetting(cb); + public unwatchSetting(cb: CallbackFn) { + this.watchers.unwatchSetting(cb); } - _getSettings() { + private getSettings(): any { // TODO: [TS] Type return const value = localStorage.getItem("mx_local_settings"); if (!value) return null; return JSON.parse(value); @@ -140,7 +139,7 @@ export default class DeviceSettingsHandler extends SettingsHandler { // Note: features intentionally don't use the same key as settings to avoid conflicts // and to be backwards compatible. - _readFeature(featureName) { + private readFeature(featureName: string): boolean | null { if (MatrixClientPeg.get() && MatrixClientPeg.get().isGuest()) { // Guests should not have any labs features enabled. return false; @@ -153,8 +152,8 @@ export default class DeviceSettingsHandler extends SettingsHandler { return null; } - _writeFeature(featureName, enabled) { - localStorage.setItem("mx_labs_feature_" + featureName, enabled); - this._watchers.notifyUpdate(featureName, null, SettingLevel.DEVICE, enabled); + private writeFeature(featureName: string, enabled: boolean | null) { + localStorage.setItem("mx_labs_feature_" + featureName, `${enabled}`); + this.watchers.notifyUpdate(featureName, null, SettingLevel.DEVICE, enabled); } } diff --git a/src/settings/handlers/LocalEchoWrapper.js b/src/settings/handlers/LocalEchoWrapper.ts similarity index 62% rename from src/settings/handlers/LocalEchoWrapper.js rename to src/settings/handlers/LocalEchoWrapper.ts index fd0510296a..5cfcd27aed 100644 --- a/src/settings/handlers/LocalEchoWrapper.js +++ b/src/settings/handlers/LocalEchoWrapper.ts @@ -1,6 +1,6 @@ /* Copyright 2017 Travis Ralston -Copyright 2019 New Vector Ltd. +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,47 +23,48 @@ import SettingsHandler from "./SettingsHandler"; * handler as much as possible to ensure values are not stale. */ export default class LocalEchoWrapper extends SettingsHandler { + private cache: { + [settingName: string]: { + [roomId: string]: any; + }; + } = {}; + /** * Creates a new local echo wrapper * @param {SettingsHandler} handler The handler to wrap */ - constructor(handler) { + constructor(private handler: SettingsHandler) { super(); - this._handler = handler; - this._cache = { - // settingName: { roomId: value } - }; } - getValue(settingName, roomId) { + public getValue(settingName: string, roomId: string): any { const cacheRoomId = roomId ? roomId : "UNDEFINED"; // avoid weird keys - const bySetting = this._cache[settingName]; + const bySetting = this.cache[settingName]; if (bySetting && bySetting.hasOwnProperty(cacheRoomId)) { return bySetting[cacheRoomId]; } - return this._handler.getValue(settingName, roomId); + return this.handler.getValue(settingName, roomId); } - setValue(settingName, roomId, newValue) { - if (!this._cache[settingName]) this._cache[settingName] = {}; - const bySetting = this._cache[settingName]; + public setValue(settingName: string, roomId: string, newValue: any): Promise { + if (!this.cache[settingName]) this.cache[settingName] = {}; + const bySetting = this.cache[settingName]; const cacheRoomId = roomId ? roomId : "UNDEFINED"; // avoid weird keys bySetting[cacheRoomId] = newValue; - const handlerPromise = this._handler.setValue(settingName, roomId, newValue); + const handlerPromise = this.handler.setValue(settingName, roomId, newValue); return Promise.resolve(handlerPromise).finally(() => { delete bySetting[cacheRoomId]; }); } - - canSetValue(settingName, roomId) { - return this._handler.canSetValue(settingName, roomId); + public canSetValue(settingName: string, roomId: string): boolean { + return this.handler.canSetValue(settingName, roomId); } - isSupported() { - return this._handler.isSupported(); + public isSupported(): boolean { + return this.handler.isSupported(); } } diff --git a/src/settings/handlers/MatrixClientBackedSettingsHandler.js b/src/settings/handlers/MatrixClientBackedSettingsHandler.ts similarity index 68% rename from src/settings/handlers/MatrixClientBackedSettingsHandler.js rename to src/settings/handlers/MatrixClientBackedSettingsHandler.ts index 63725b4dff..76825d1335 100644 --- a/src/settings/handlers/MatrixClientBackedSettingsHandler.js +++ b/src/settings/handlers/MatrixClientBackedSettingsHandler.ts @@ -1,5 +1,5 @@ /* -Copyright 2019 New Vector Ltd. +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ limitations under the License. */ import SettingsHandler from "./SettingsHandler"; +import { MatrixClient } from "matrix-js-sdk/src/client"; // Dev note: This whole class exists in the event someone logs out and back in - we want // to make sure the right MatrixClient is listening for changes. @@ -23,30 +24,30 @@ import SettingsHandler from "./SettingsHandler"; * Represents the base class for settings handlers which need access to a MatrixClient. * This class performs no logic and should be overridden. */ -export default class MatrixClientBackedSettingsHandler extends SettingsHandler { - static _matrixClient; - static _instances = []; +export default abstract class MatrixClientBackedSettingsHandler extends SettingsHandler { + private static _matrixClient: MatrixClient; + private static instances: MatrixClientBackedSettingsHandler[] = []; - static set matrixClient(client) { + public static set matrixClient(client: MatrixClient) { const oldClient = MatrixClientBackedSettingsHandler._matrixClient; MatrixClientBackedSettingsHandler._matrixClient = client; - for (const instance of MatrixClientBackedSettingsHandler._instances) { + for (const instance of MatrixClientBackedSettingsHandler.instances) { instance.initMatrixClient(oldClient, client); } } - constructor() { + protected constructor() { super(); - MatrixClientBackedSettingsHandler._instances.push(this); + MatrixClientBackedSettingsHandler.instances.push(this); } - get client() { + public get client(): MatrixClient { return MatrixClientBackedSettingsHandler._matrixClient; } - initMatrixClient() { + protected initMatrixClient(oldClient: MatrixClient, newClient: MatrixClient) { console.warn("initMatrixClient not overridden"); } } diff --git a/src/settings/handlers/RoomAccountSettingsHandler.js b/src/settings/handlers/RoomAccountSettingsHandler.ts similarity index 65% rename from src/settings/handlers/RoomAccountSettingsHandler.js rename to src/settings/handlers/RoomAccountSettingsHandler.ts index b2af81779b..e3449e76c3 100644 --- a/src/settings/handlers/RoomAccountSettingsHandler.js +++ b/src/settings/handlers/RoomAccountSettingsHandler.ts @@ -1,6 +1,6 @@ /* Copyright 2017 Travis Ralston -Copyright 2019 New Vector Ltd. +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,10 +15,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {MatrixClientPeg} from '../../MatrixClientPeg'; +import { MatrixClientPeg } from '../../MatrixClientPeg'; import MatrixClientBackedSettingsHandler from "./MatrixClientBackedSettingsHandler"; -import {SettingLevel} from "../SettingsStore"; -import {objectClone, objectKeyChanges} from "../../utils/objects"; +import { objectClone, objectKeyChanges } from "../../utils/objects"; +import { SettingLevel } from "../SettingLevel"; +import { WatchManager } from "../WatchManager"; +import { MatrixClient } from "matrix-js-sdk/src/client"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { Room } from "matrix-js-sdk/src/models/room"; const ALLOWED_WIDGETS_EVENT_TYPE = "im.vector.setting.allowed_widgets"; @@ -26,22 +30,19 @@ const ALLOWED_WIDGETS_EVENT_TYPE = "im.vector.setting.allowed_widgets"; * Gets and sets settings at the "room-account" level for the current user. */ export default class RoomAccountSettingsHandler extends MatrixClientBackedSettingsHandler { - constructor(watchManager) { + constructor(private watchers: WatchManager) { super(); - - this._watchers = watchManager; - this._onAccountData = this._onAccountData.bind(this); } - initMatrixClient(oldClient, newClient) { + protected initMatrixClient(oldClient: MatrixClient, newClient: MatrixClient) { if (oldClient) { - oldClient.removeListener("Room.accountData", this._onAccountData); + oldClient.removeListener("Room.accountData", this.onAccountData); } - newClient.on("Room.accountData", this._onAccountData); + newClient.on("Room.accountData", this.onAccountData); } - _onAccountData(event, room, prevEvent) { + private onAccountData = (event: MatrixEvent, room: Room, prevEvent: MatrixEvent) => { const roomId = room.roomId; if (event.getType() === "org.matrix.room.preview_urls") { @@ -52,29 +53,29 @@ export default class RoomAccountSettingsHandler extends MatrixClientBackedSettin val = !val; } - this._watchers.notifyUpdate("urlPreviewsEnabled", roomId, SettingLevel.ROOM_ACCOUNT, val); + this.watchers.notifyUpdate("urlPreviewsEnabled", roomId, SettingLevel.ROOM_ACCOUNT, val); } else if (event.getType() === "org.matrix.room.color_scheme") { - this._watchers.notifyUpdate("roomColor", roomId, SettingLevel.ROOM_ACCOUNT, event.getContent()); + this.watchers.notifyUpdate("roomColor", roomId, SettingLevel.ROOM_ACCOUNT, event.getContent()); } else if (event.getType() === "im.vector.web.settings") { // Figure out what changed and fire those updates const prevContent = prevEvent ? prevEvent.getContent() : {}; const changedSettings = objectKeyChanges(prevContent, event.getContent()); for (const settingName of changedSettings) { const val = event.getContent()[settingName]; - this._watchers.notifyUpdate(settingName, roomId, SettingLevel.ROOM_ACCOUNT, val); + this.watchers.notifyUpdate(settingName, roomId, SettingLevel.ROOM_ACCOUNT, val); } } else if (event.getType() === ALLOWED_WIDGETS_EVENT_TYPE) { - this._watchers.notifyUpdate("allowedWidgets", roomId, SettingLevel.ROOM_ACCOUNT, event.getContent()); + this.watchers.notifyUpdate("allowedWidgets", roomId, SettingLevel.ROOM_ACCOUNT, event.getContent()); } - } + }; - getValue(settingName, roomId) { + public getValue(settingName: string, roomId: string): any { // Special case URL previews if (settingName === "urlPreviewsEnabled") { - const content = this._getSettings(roomId, "org.matrix.room.preview_urls") || {}; + const content = this.getSettings(roomId, "org.matrix.room.preview_urls") || {}; // Check to make sure that we actually got a boolean - if (typeof(content['disable']) !== "boolean") return null; + if (typeof (content['disable']) !== "boolean") return null; return !content['disable']; } @@ -83,22 +84,22 @@ export default class RoomAccountSettingsHandler extends MatrixClientBackedSettin // The event content should already be in an appropriate format, we just need // to get the right value. // don't fallback to {} because thats truthy and would imply there is an event specifying tint - return this._getSettings(roomId, "org.matrix.room.color_scheme"); + return this.getSettings(roomId, "org.matrix.room.color_scheme"); } // Special case allowed widgets if (settingName === "allowedWidgets") { - return this._getSettings(roomId, ALLOWED_WIDGETS_EVENT_TYPE); + return this.getSettings(roomId, ALLOWED_WIDGETS_EVENT_TYPE); } - const settings = this._getSettings(roomId) || {}; + const settings = this.getSettings(roomId) || {}; return settings[settingName]; } - setValue(settingName, roomId, newValue) { + public setValue(settingName: string, roomId: string, newValue: any): Promise { // Special case URL previews if (settingName === "urlPreviewsEnabled") { - const content = this._getSettings(roomId, "org.matrix.room.preview_urls") || {}; + const content = this.getSettings(roomId, "org.matrix.room.preview_urls") || {}; content['disable'] = !newValue; return MatrixClientPeg.get().setRoomAccountData(roomId, "org.matrix.room.preview_urls", content); } @@ -114,24 +115,24 @@ export default class RoomAccountSettingsHandler extends MatrixClientBackedSettin return MatrixClientPeg.get().setRoomAccountData(roomId, ALLOWED_WIDGETS_EVENT_TYPE, newValue); } - const content = this._getSettings(roomId) || {}; + const content = this.getSettings(roomId) || {}; content[settingName] = newValue; return MatrixClientPeg.get().setRoomAccountData(roomId, "im.vector.web.settings", content); } - canSetValue(settingName, roomId) { + public canSetValue(settingName: string, roomId: string): boolean { const room = MatrixClientPeg.get().getRoom(roomId); // If they have the room, they can set their own account data return room !== undefined && room !== null; } - isSupported() { + public isSupported(): boolean { const cli = MatrixClientPeg.get(); return cli !== undefined && cli !== null; } - _getSettings(roomId, eventType = "im.vector.web.settings") { + private getSettings(roomId: string, eventType = "im.vector.web.settings"): any { // TODO: [TS] Type return const room = MatrixClientPeg.get().getRoom(roomId); if (!room) return null; diff --git a/src/settings/handlers/RoomDeviceSettingsHandler.js b/src/settings/handlers/RoomDeviceSettingsHandler.ts similarity index 66% rename from src/settings/handlers/RoomDeviceSettingsHandler.js rename to src/settings/handlers/RoomDeviceSettingsHandler.ts index a9cf686c4c..2fcd58c27c 100644 --- a/src/settings/handlers/RoomDeviceSettingsHandler.js +++ b/src/settings/handlers/RoomDeviceSettingsHandler.ts @@ -1,6 +1,6 @@ /* Copyright 2017 Travis Ralston -Copyright 2019 New Vector Ltd. +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,71 +16,70 @@ limitations under the License. */ import SettingsHandler from "./SettingsHandler"; -import {SettingLevel} from "../SettingsStore"; +import { SettingLevel } from "../SettingLevel"; +import { WatchManager } from "../WatchManager"; /** * Gets and sets settings at the "room-device" level for the current device in a particular * room. */ export default class RoomDeviceSettingsHandler extends SettingsHandler { - constructor(watchManager) { + constructor(private watchers: WatchManager) { super(); - - this._watchers = watchManager; } - getValue(settingName, roomId) { + public getValue(settingName: string, roomId: string): any { // Special case blacklist setting to use legacy values if (settingName === "blacklistUnverifiedDevices") { - const value = this._read("mx_local_settings"); + const value = this.read("mx_local_settings"); if (value && value['blacklistUnverifiedDevicesPerRoom']) { return value['blacklistUnverifiedDevicesPerRoom'][roomId]; } } - const value = this._read(this._getKey(settingName, roomId)); + const value = this.read(this.getKey(settingName, roomId)); if (value) return value.value; return null; } - setValue(settingName, roomId, newValue) { + public setValue(settingName: string, roomId: string, newValue: any): Promise { // Special case blacklist setting for legacy structure if (settingName === "blacklistUnverifiedDevices") { - let value = this._read("mx_local_settings"); + let value = this.read("mx_local_settings"); if (!value) value = {}; if (!value["blacklistUnverifiedDevicesPerRoom"]) value["blacklistUnverifiedDevicesPerRoom"] = {}; value["blacklistUnverifiedDevicesPerRoom"][roomId] = newValue; localStorage.setItem("mx_local_settings", JSON.stringify(value)); - this._watchers.notifyUpdate(settingName, roomId, SettingLevel.ROOM_DEVICE, newValue); + this.watchers.notifyUpdate(settingName, roomId, SettingLevel.ROOM_DEVICE, newValue); return Promise.resolve(); } if (newValue === null) { - localStorage.removeItem(this._getKey(settingName, roomId)); + localStorage.removeItem(this.getKey(settingName, roomId)); } else { newValue = JSON.stringify({value: newValue}); - localStorage.setItem(this._getKey(settingName, roomId), newValue); + localStorage.setItem(this.getKey(settingName, roomId), newValue); } - this._watchers.notifyUpdate(settingName, roomId, SettingLevel.ROOM_DEVICE, newValue); + this.watchers.notifyUpdate(settingName, roomId, SettingLevel.ROOM_DEVICE, newValue); return Promise.resolve(); } - canSetValue(settingName, roomId) { + public canSetValue(settingName: string, roomId: string): boolean { return true; // It's their device, so they should be able to } - isSupported() { + public isSupported(): boolean { return localStorage !== undefined && localStorage !== null; } - _read(key) { + private read(key: string): any { const rawValue = localStorage.getItem(key); if (!rawValue) return null; return JSON.parse(rawValue); } - _getKey(settingName, roomId) { + private getKey(settingName: string, roomId: string): string { return "mx_setting_" + settingName + "_" + roomId; } } diff --git a/src/settings/handlers/RoomSettingsHandler.js b/src/settings/handlers/RoomSettingsHandler.ts similarity index 66% rename from src/settings/handlers/RoomSettingsHandler.js rename to src/settings/handlers/RoomSettingsHandler.ts index 00dd5b8bec..4b4d4c4ad9 100644 --- a/src/settings/handlers/RoomSettingsHandler.js +++ b/src/settings/handlers/RoomSettingsHandler.ts @@ -1,6 +1,6 @@ /* Copyright 2017 Travis Ralston -Copyright 2019 New Vector Ltd. +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,31 +15,32 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {MatrixClientPeg} from '../../MatrixClientPeg'; +import { MatrixClientPeg } from '../../MatrixClientPeg'; import MatrixClientBackedSettingsHandler from "./MatrixClientBackedSettingsHandler"; -import {SettingLevel} from "../SettingsStore"; -import {objectClone, objectKeyChanges} from "../../utils/objects"; +import { objectClone, objectKeyChanges } from "../../utils/objects"; +import { SettingLevel } from "../SettingLevel"; +import { WatchManager } from "../WatchManager"; +import { MatrixClient } from "matrix-js-sdk/src/client"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { RoomState } from "matrix-js-sdk/src/models/room-state"; /** * Gets and sets settings at the "room" level. */ export default class RoomSettingsHandler extends MatrixClientBackedSettingsHandler { - constructor(watchManager) { + constructor(private watchers: WatchManager) { super(); - - this._watchers = watchManager; - this._onEvent = this._onEvent.bind(this); } - initMatrixClient(oldClient, newClient) { + protected initMatrixClient(oldClient: MatrixClient, newClient: MatrixClient) { if (oldClient) { - oldClient.removeListener("RoomState.events", this._onEvent); + oldClient.removeListener("RoomState.events", this.onEvent); } - newClient.on("RoomState.events", this._onEvent); + newClient.on("RoomState.events", this.onEvent); } - _onEvent(event, state, prevEvent) { + private onEvent = (event: MatrixEvent, state: RoomState, prevEvent: MatrixEvent) => { const roomId = event.getRoomId(); const room = this.client.getRoom(roomId); @@ -60,45 +61,45 @@ export default class RoomSettingsHandler extends MatrixClientBackedSettingsHandl val = !val; } - this._watchers.notifyUpdate("urlPreviewsEnabled", roomId, SettingLevel.ROOM, val); + this.watchers.notifyUpdate("urlPreviewsEnabled", roomId, SettingLevel.ROOM, val); } else if (event.getType() === "im.vector.web.settings") { // Figure out what changed and fire those updates const prevContent = prevEvent ? prevEvent.getContent() : {}; const changedSettings = objectKeyChanges(prevContent, event.getContent()); for (const settingName of changedSettings) { - this._watchers.notifyUpdate(settingName, roomId, SettingLevel.ROOM, event.getContent()[settingName]); + this.watchers.notifyUpdate(settingName, roomId, SettingLevel.ROOM, event.getContent()[settingName]); } } - } + }; - getValue(settingName, roomId) { + public getValue(settingName: string, roomId: string): any { // Special case URL previews if (settingName === "urlPreviewsEnabled") { - const content = this._getSettings(roomId, "org.matrix.room.preview_urls") || {}; + const content = this.getSettings(roomId, "org.matrix.room.preview_urls") || {}; // Check to make sure that we actually got a boolean - if (typeof(content['disable']) !== "boolean") return null; + if (typeof (content['disable']) !== "boolean") return null; return !content['disable']; } - const settings = this._getSettings(roomId) || {}; + const settings = this.getSettings(roomId) || {}; return settings[settingName]; } - setValue(settingName, roomId, newValue) { + public setValue(settingName: string, roomId: string, newValue: any): Promise { // Special case URL previews if (settingName === "urlPreviewsEnabled") { - const content = this._getSettings(roomId, "org.matrix.room.preview_urls") || {}; + const content = this.getSettings(roomId, "org.matrix.room.preview_urls") || {}; content['disable'] = !newValue; return MatrixClientPeg.get().sendStateEvent(roomId, "org.matrix.room.preview_urls", content); } - const content = this._getSettings(roomId) || {}; + const content = this.getSettings(roomId) || {}; content[settingName] = newValue; return MatrixClientPeg.get().sendStateEvent(roomId, "im.vector.web.settings", content, ""); } - canSetValue(settingName, roomId) { + public canSetValue(settingName: string, roomId: string): boolean { const cli = MatrixClientPeg.get(); const room = cli.getRoom(roomId); @@ -109,12 +110,12 @@ export default class RoomSettingsHandler extends MatrixClientBackedSettingsHandl return room.currentState.maySendStateEvent(eventType, cli.getUserId()); } - isSupported() { + public isSupported(): boolean { const cli = MatrixClientPeg.get(); return cli !== undefined && cli !== null; } - _getSettings(roomId, eventType = "im.vector.web.settings") { + private getSettings(roomId: string, eventType = "im.vector.web.settings"): any { const room = MatrixClientPeg.get().getRoom(roomId); if (!room) return null; diff --git a/src/settings/handlers/SettingsHandler.js b/src/settings/handlers/SettingsHandler.ts similarity index 82% rename from src/settings/handlers/SettingsHandler.js rename to src/settings/handlers/SettingsHandler.ts index 7d987fc136..ca9a068fd3 100644 --- a/src/settings/handlers/SettingsHandler.js +++ b/src/settings/handlers/SettingsHandler.ts @@ -1,6 +1,6 @@ /* Copyright 2017 Travis Ralston -Copyright 2019 New Vector Ltd. +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,7 +19,7 @@ limitations under the License. * Represents the base class for all level handlers. This class performs no logic * and should be overridden. */ -export default class SettingsHandler { +export default abstract class SettingsHandler { /** * Gets the value for a particular setting at this level for a particular room. * If no room is applicable, the roomId may be null. The roomId may not be @@ -28,10 +28,7 @@ export default class SettingsHandler { * @param {String} roomId The room ID to read from, may be null. * @returns {*} The setting value, or null if not found. */ - getValue(settingName, roomId) { - console.error("Invalid operation: getValue was not overridden"); - return null; - } + public abstract getValue(settingName: string, roomId: string): any; /** * Sets the value for a particular setting at this level for a particular room. @@ -44,10 +41,7 @@ export default class SettingsHandler { * @param {*} newValue The new value for the setting, may be null. * @returns {Promise} Resolves when the setting has been saved. */ - setValue(settingName, roomId, newValue) { - console.error("Invalid operation: setValue was not overridden"); - return Promise.reject(); - } + public abstract setValue(settingName: string, roomId: string, newValue: any): Promise; /** * Determines if the current user is able to set the value of the given setting @@ -56,15 +50,11 @@ export default class SettingsHandler { * @param {String} roomId The room ID to check in, may be null * @returns {boolean} True if the setting can be set by the user, false otherwise. */ - canSetValue(settingName, roomId) { - return false; - } + public abstract canSetValue(settingName: string, roomId: string): boolean; /** * Determines if this level is supported on this device. * @returns {boolean} True if this level is supported on the current device. */ - isSupported() { - return false; - } + public abstract isSupported(): boolean; } diff --git a/src/settings/watchers/FontWatcher.ts b/src/settings/watchers/FontWatcher.ts index 53ef999f9b..6a17bf2aa3 100644 --- a/src/settings/watchers/FontWatcher.ts +++ b/src/settings/watchers/FontWatcher.ts @@ -15,10 +15,11 @@ limitations under the License. */ import dis from '../../dispatcher/dispatcher'; -import SettingsStore, {SettingLevel} from '../SettingsStore'; +import SettingsStore from '../SettingsStore'; import IWatcher from "./Watcher"; import { toPx } from '../../utils/units'; import { Action } from '../../dispatcher/actions'; +import { SettingLevel } from "../SettingLevel"; export class FontWatcher implements IWatcher { public static readonly MIN_SIZE = 8; diff --git a/src/settings/watchers/ThemeWatcher.ts b/src/settings/watchers/ThemeWatcher.ts index ce0db881c0..4330a15f57 100644 --- a/src/settings/watchers/ThemeWatcher.ts +++ b/src/settings/watchers/ThemeWatcher.ts @@ -15,17 +15,15 @@ See the License for the specific language governing permissions and limitations under the License. */ -import SettingsStore, { SettingLevel } from '../SettingsStore'; +import SettingsStore from '../SettingsStore'; import dis from '../../dispatcher/dispatcher'; import { Action } from '../../dispatcher/actions'; import ThemeController from "../controllers/ThemeController"; import { setTheme } from "../../theme"; import { ActionPayload } from '../../dispatcher/payloads'; +import { SettingLevel } from "../SettingLevel"; export default class ThemeWatcher { - // XXX: I think this is unused. - static _instance = null; - private themeWatchRef: string; private systemThemeWatchRef: string; private dispatcherRef: string; diff --git a/src/stores/AsyncStore.ts b/src/stores/AsyncStore.ts index 1977e808dc..1f310f003c 100644 --- a/src/stores/AsyncStore.ts +++ b/src/stores/AsyncStore.ts @@ -42,7 +42,7 @@ export const UPDATE_EVENT = "update"; * help prevent lock conflicts. */ export abstract class AsyncStore extends EventEmitter { - private storeState: T; + private storeState: Readonly; private lock = new AwaitLock(); private readonly dispatcherRef: string; @@ -62,7 +62,7 @@ export abstract class AsyncStore extends EventEmitter { * The current state of the store. Cannot be mutated. */ protected get state(): T { - return Object.freeze(this.storeState); + return this.storeState; } /** @@ -79,7 +79,7 @@ export abstract class AsyncStore extends EventEmitter { protected async updateState(newState: T | Object) { await this.lock.acquireAsync(); try { - this.storeState = Object.assign({}, this.storeState, newState); + this.storeState = Object.freeze(Object.assign({}, this.storeState, newState)); this.emit(UPDATE_EVENT, this); } finally { await this.lock.release(); @@ -94,7 +94,7 @@ export abstract class AsyncStore extends EventEmitter { protected async reset(newState: T | Object = null, quiet = false) { await this.lock.acquireAsync(); try { - this.storeState = (newState || {}); + this.storeState = Object.freeze((newState || {})); if (!quiet) this.emit(UPDATE_EVENT, this); } finally { await this.lock.release(); diff --git a/src/stores/AsyncStoreWithClient.ts b/src/stores/AsyncStoreWithClient.ts index 5b9f95f991..1ed7c6a547 100644 --- a/src/stores/AsyncStoreWithClient.ts +++ b/src/stores/AsyncStoreWithClient.ts @@ -17,12 +17,25 @@ limitations under the License. import { MatrixClient } from "matrix-js-sdk/src/client"; import { AsyncStore } from "./AsyncStore"; import { ActionPayload } from "../dispatcher/payloads"; +import { Dispatcher } from "flux"; +import { MatrixClientPeg } from "../MatrixClientPeg"; export abstract class AsyncStoreWithClient extends AsyncStore { protected matrixClient: MatrixClient; protected abstract async onAction(payload: ActionPayload); + protected constructor(dispatcher: Dispatcher, initialState: T = {}) { + super(dispatcher, initialState); + + if (MatrixClientPeg.get()) { + this.matrixClient = MatrixClientPeg.get(); + + // noinspection JSIgnoredPromiseFromCall + this.onReady(); + } + } + protected async onReady() { // Default implementation is to do nothing. } @@ -35,13 +48,21 @@ export abstract class AsyncStoreWithClient extends AsyncStore< await this.onAction(payload); if (payload.action === 'MatrixActions.sync') { - // Filter out anything that isn't the first PREPARED sync. + // Only set the client on the transition into the PREPARED state. + // Everything after this is unnecessary (we only need to know once we have a client) + // and we intentionally don't set the client before this point to avoid stores + // updating for every event emitted during the cached sync. if (!(payload.prevState === 'PREPARED' && payload.state !== 'PREPARED')) { return; } - this.matrixClient = payload.matrixClient; - await this.onReady(); + if (this.matrixClient !== payload.matrixClient) { + if (this.matrixClient) { + await this.onNotReady(); + } + this.matrixClient = payload.matrixClient; + await this.onReady(); + } } else if (payload.action === 'on_client_not_viable' || payload.action === 'on_logged_out') { if (this.matrixClient) { await this.onNotReady(); diff --git a/src/stores/BreadcrumbsStore.ts b/src/stores/BreadcrumbsStore.ts index 34affbe746..24906f678c 100644 --- a/src/stores/BreadcrumbsStore.ts +++ b/src/stores/BreadcrumbsStore.ts @@ -14,13 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -import SettingsStore, { SettingLevel } from "../settings/SettingsStore"; +import SettingsStore from "../settings/SettingsStore"; import { Room } from "matrix-js-sdk/src/models/room"; import { ActionPayload } from "../dispatcher/payloads"; import { AsyncStoreWithClient } from "./AsyncStoreWithClient"; import defaultDispatcher from "../dispatcher/dispatcher"; import { arrayHasDiff } from "../utils/arrays"; import { isNullOrUndefined } from "matrix-js-sdk/src/utils"; +import { SettingLevel } from "../settings/SettingLevel"; const MAX_ROOMS = 20; // arbitrary const AUTOJOIN_WAIT_THRESHOLD_MS = 90000; // 90s, the time we wait for an autojoined room to show up @@ -55,7 +56,7 @@ export class BreadcrumbsStore extends AsyncStoreWithClient { } private get meetsRoomRequirement(): boolean { - return this.matrixClient.getVisibleRooms().length >= 20; + return this.matrixClient && this.matrixClient.getVisibleRooms().length >= 20; } protected async onAction(payload: ActionPayload) { diff --git a/src/stores/CustomRoomTagStore.js b/src/stores/CustomRoomTagStore.js index 9967708c29..1f24dc589a 100644 --- a/src/stores/CustomRoomTagStore.js +++ b/src/stores/CustomRoomTagStore.js @@ -22,6 +22,7 @@ import SettingsStore from "../settings/SettingsStore"; import RoomListStore, {LISTS_UPDATE_EVENT} from "./room-list/RoomListStore"; import {RoomNotificationStateStore} from "./notifications/RoomNotificationStateStore"; import {isCustomTag} from "./room-list/models"; +import {objectHasDiff} from "../utils/objects"; function commonPrefix(a, b) { const len = Math.min(a.length, b.length); @@ -107,7 +108,10 @@ class CustomRoomTagStore extends EventEmitter { } _onListsUpdated = () => { - this._setState({tags: this._getUpdatedTags()}); + const newTags = this._getUpdatedTags(); + if (!this._state.tags || objectHasDiff(this._state.tags, newTags)) { + this._setState({tags: newTags}); + } }; _onDispatch(payload) { @@ -134,7 +138,7 @@ class CustomRoomTagStore extends EventEmitter { _getUpdatedTags() { if (!SettingsStore.isFeatureEnabled("feature_custom_tags")) { - return; + return {}; // none } const newTagNames = Object.keys(RoomListStore.instance.orderedLists).filter(t => isCustomTag(t)).sort(); diff --git a/src/stores/NonUrgentToastStore.ts b/src/stores/NonUrgentToastStore.ts new file mode 100644 index 0000000000..72f896749c --- /dev/null +++ b/src/stores/NonUrgentToastStore.ts @@ -0,0 +1,50 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import EventEmitter from "events"; +import { ComponentClass } from "../@types/common"; +import { UPDATE_EVENT } from "./AsyncStore"; + +export type ToastReference = symbol; + +export default class NonUrgentToastStore extends EventEmitter { + private static _instance: NonUrgentToastStore; + + private toasts = new Map(); + + public static get instance(): NonUrgentToastStore { + if (!NonUrgentToastStore._instance) { + NonUrgentToastStore._instance = new NonUrgentToastStore(); + } + return NonUrgentToastStore._instance; + } + + public get components(): ComponentClass[] { + return Array.from(this.toasts.values()); + } + + public addToast(c: ComponentClass): ToastReference { + const ref: ToastReference = Symbol(); + this.toasts.set(ref, c); + this.emit(UPDATE_EVENT); + return ref; + } + + public removeToast(ref: ToastReference) { + this.toasts.delete(ref); + this.emit(UPDATE_EVENT); + } +} diff --git a/src/stores/OwnProfileStore.ts b/src/stores/OwnProfileStore.ts index 45d8829e30..1aa761e1c4 100644 --- a/src/stores/OwnProfileStore.ts +++ b/src/stores/OwnProfileStore.ts @@ -111,8 +111,6 @@ export class OwnProfileStore extends AsyncStoreWithClient { await this.updateState({displayName: profileInfo.displayname, avatarUrl: profileInfo.avatar_url}); }; - // TSLint wants this to be a member, but we don't want that. - // tslint:disable-next-line private onStateEvents = throttle(async (ev: MatrixEvent) => { const myUserId = MatrixClientPeg.get().getUserId(); if (ev.getType() === 'm.room.member' && ev.getSender() === myUserId && ev.getStateKey() === myUserId) { diff --git a/src/stores/RightPanelStore.js b/src/stores/RightPanelStore.ts similarity index 56% rename from src/stores/RightPanelStore.js rename to src/stores/RightPanelStore.ts index a73f3befbb..c1799978ad 100644 --- a/src/stores/RightPanelStore.js +++ b/src/stores/RightPanelStore.ts @@ -17,162 +17,179 @@ limitations under the License. import dis from '../dispatcher/dispatcher'; import {pendingVerificationRequestForUser} from '../verification'; import {Store} from 'flux/utils'; -import SettingsStore, {SettingLevel} from "../settings/SettingsStore"; -import {RIGHT_PANEL_PHASES, RIGHT_PANEL_PHASES_NO_ARGS} from "./RightPanelStorePhases"; +import SettingsStore from "../settings/SettingsStore"; +import {RightPanelPhases, RIGHT_PANEL_PHASES_NO_ARGS} from "./RightPanelStorePhases"; +import {ActionPayload} from "../dispatcher/payloads"; +import {Action} from '../dispatcher/actions'; +import { SettingLevel } from "../settings/SettingLevel"; -const INITIAL_STATE = { +interface RightPanelStoreState { // Whether or not to show the right panel at all. We split out rooms and groups // because they're different flows for the user to follow. - showRoomPanel: SettingsStore.getValue("showRightPanelInRoom"), - showGroupPanel: SettingsStore.getValue("showRightPanelInGroup"), + showRoomPanel: boolean; + showGroupPanel: boolean; // The last phase (screen) the right panel was showing - lastRoomPhase: SettingsStore.getValue("lastRightPanelPhaseForRoom"), - lastGroupPhase: SettingsStore.getValue("lastRightPanelPhaseForGroup"), + lastRoomPhase: RightPanelPhases; + lastGroupPhase: RightPanelPhases; // Extra information about the last phase + lastRoomPhaseParams: {[key: string]: any}; +} + +const INITIAL_STATE: RightPanelStoreState = { + showRoomPanel: SettingsStore.getValue("showRightPanelInRoom"), + showGroupPanel: SettingsStore.getValue("showRightPanelInGroup"), + lastRoomPhase: SettingsStore.getValue("lastRightPanelPhaseForRoom"), + lastGroupPhase: SettingsStore.getValue("lastRightPanelPhaseForGroup"), lastRoomPhaseParams: {}, }; -const GROUP_PHASES = Object.keys(RIGHT_PANEL_PHASES).filter(k => k.startsWith("Group")); +const GROUP_PHASES = [ + RightPanelPhases.GroupMemberList, + RightPanelPhases.GroupRoomList, + RightPanelPhases.GroupRoomInfo, + RightPanelPhases.GroupMemberInfo, +]; const MEMBER_INFO_PHASES = [ - RIGHT_PANEL_PHASES.RoomMemberInfo, - RIGHT_PANEL_PHASES.Room3pidMemberInfo, - RIGHT_PANEL_PHASES.EncryptionPanel, + RightPanelPhases.RoomMemberInfo, + RightPanelPhases.Room3pidMemberInfo, + RightPanelPhases.EncryptionPanel, ]; /** * A class for tracking the state of the right panel between layouts and * sessions. */ -export default class RightPanelStore extends Store { - static _instance; +export default class RightPanelStore extends Store { + private static instance: RightPanelStore; + private state: RightPanelStoreState; constructor() { super(dis); // Initialise state - this._state = INITIAL_STATE; + this.state = INITIAL_STATE; } get isOpenForRoom(): boolean { - return this._state.showRoomPanel; + return this.state.showRoomPanel; } get isOpenForGroup(): boolean { - return this._state.showGroupPanel; + return this.state.showGroupPanel; } - get roomPanelPhase(): string { - return this._state.lastRoomPhase; + get roomPanelPhase(): RightPanelPhases { + return this.state.lastRoomPhase; } - get groupPanelPhase(): string { - return this._state.lastGroupPhase; + get groupPanelPhase(): RightPanelPhases { + return this.state.lastGroupPhase; } - get visibleRoomPanelPhase(): string { + get visibleRoomPanelPhase(): RightPanelPhases { return this.isOpenForRoom ? this.roomPanelPhase : null; } - get visibleGroupPanelPhase(): string { + get visibleGroupPanelPhase(): RightPanelPhases { return this.isOpenForGroup ? this.groupPanelPhase : null; } get roomPanelPhaseParams(): any { - return this._state.lastRoomPhaseParams || {}; + return this.state.lastRoomPhaseParams || {}; } - _setState(newState) { - this._state = Object.assign(this._state, newState); + private setState(newState: Partial) { + this.state = Object.assign(this.state, newState); SettingsStore.setValue( "showRightPanelInRoom", null, SettingLevel.DEVICE, - this._state.showRoomPanel, + this.state.showRoomPanel, ); SettingsStore.setValue( "showRightPanelInGroup", null, SettingLevel.DEVICE, - this._state.showGroupPanel, + this.state.showGroupPanel, ); - if (RIGHT_PANEL_PHASES_NO_ARGS.includes(this._state.lastRoomPhase)) { + if (RIGHT_PANEL_PHASES_NO_ARGS.includes(this.state.lastRoomPhase)) { SettingsStore.setValue( "lastRightPanelPhaseForRoom", null, SettingLevel.DEVICE, - this._state.lastRoomPhase, + this.state.lastRoomPhase, ); } - if (RIGHT_PANEL_PHASES_NO_ARGS.includes(this._state.lastGroupPhase)) { + if (RIGHT_PANEL_PHASES_NO_ARGS.includes(this.state.lastGroupPhase)) { SettingsStore.setValue( "lastRightPanelPhaseForGroup", null, SettingLevel.DEVICE, - this._state.lastGroupPhase, + this.state.lastGroupPhase, ); } this.__emitChange(); } - __onDispatch(payload) { + __onDispatch(payload: ActionPayload) { switch (payload.action) { case 'view_room': case 'view_group': // Reset to the member list if we're viewing member info - if (MEMBER_INFO_PHASES.includes(this._state.lastRoomPhase)) { - this._setState({lastRoomPhase: RIGHT_PANEL_PHASES.RoomMemberList, lastRoomPhaseParams: {}}); + if (MEMBER_INFO_PHASES.includes(this.state.lastRoomPhase)) { + this.setState({lastRoomPhase: RightPanelPhases.RoomMemberList, lastRoomPhaseParams: {}}); } // Do the same for groups - if (this._state.lastGroupPhase === RIGHT_PANEL_PHASES.GroupMemberInfo) { - this._setState({lastGroupPhase: RIGHT_PANEL_PHASES.GroupMemberList}); + if (this.state.lastGroupPhase === RightPanelPhases.GroupMemberInfo) { + this.setState({lastGroupPhase: RightPanelPhases.GroupMemberList}); } break; - case 'set_right_panel_phase': { + case Action.SetRightPanelPhase: { let targetPhase = payload.phase; let refireParams = payload.refireParams; // redirect to EncryptionPanel if there is an ongoing verification request - if (targetPhase === RIGHT_PANEL_PHASES.RoomMemberInfo && payload.refireParams) { + if (targetPhase === RightPanelPhases.RoomMemberInfo && payload.refireParams) { const {member} = payload.refireParams; const pendingRequest = pendingVerificationRequestForUser(member); if (pendingRequest) { - targetPhase = RIGHT_PANEL_PHASES.EncryptionPanel; + targetPhase = RightPanelPhases.EncryptionPanel; refireParams = { verificationRequest: pendingRequest, member, }; } } - if (!RIGHT_PANEL_PHASES[targetPhase]) { + if (!RightPanelPhases[targetPhase]) { console.warn(`Tried to switch right panel to unknown phase: ${targetPhase}`); return; } if (GROUP_PHASES.includes(targetPhase)) { - if (targetPhase === this._state.lastGroupPhase) { - this._setState({ - showGroupPanel: !this._state.showGroupPanel, + if (targetPhase === this.state.lastGroupPhase) { + this.setState({ + showGroupPanel: !this.state.showGroupPanel, }); } else { - this._setState({ + this.setState({ lastGroupPhase: targetPhase, showGroupPanel: true, }); } } else { - if (targetPhase === this._state.lastRoomPhase && !refireParams) { - this._setState({ - showRoomPanel: !this._state.showRoomPanel, + if (targetPhase === this.state.lastRoomPhase && !refireParams) { + this.setState({ + showRoomPanel: !this.state.showRoomPanel, }); } else { - this._setState({ + this.setState({ lastRoomPhase: targetPhase, showRoomPanel: true, lastRoomPhaseParams: refireParams || {}, @@ -182,27 +199,27 @@ export default class RightPanelStore extends Store { // Let things like the member info panel actually open to the right member. dis.dispatch({ - action: 'after_right_panel_phase_change', + action: Action.AfterRightPanelPhaseChange, phase: targetPhase, ...(refireParams || {}), }); break; } - case 'toggle_right_panel': + case Action.ToggleRightPanel: if (payload.type === "room") { - this._setState({ showRoomPanel: !this._state.showRoomPanel }); + this.setState({ showRoomPanel: !this.state.showRoomPanel }); } else { // group - this._setState({ showGroupPanel: !this._state.showGroupPanel }); + this.setState({ showGroupPanel: !this.state.showGroupPanel }); } break; } } static getSharedInstance(): RightPanelStore { - if (!RightPanelStore._instance) { - RightPanelStore._instance = new RightPanelStore(); + if (!RightPanelStore.instance) { + RightPanelStore.instance = new RightPanelStore(); } - return RightPanelStore._instance; + return RightPanelStore.instance; } } diff --git a/src/stores/RightPanelStorePhases.js b/src/stores/RightPanelStorePhases.ts similarity index 57% rename from src/stores/RightPanelStorePhases.js rename to src/stores/RightPanelStorePhases.ts index d9af320233..9045b17193 100644 --- a/src/stores/RightPanelStorePhases.js +++ b/src/stores/RightPanelStorePhases.ts @@ -15,28 +15,28 @@ limitations under the License. */ // These are in their own file because of circular imports being a problem. -export const RIGHT_PANEL_PHASES = Object.freeze({ +export enum RightPanelPhases { // Room stuff - RoomMemberList: 'RoomMemberList', - FilePanel: 'FilePanel', - NotificationPanel: 'NotificationPanel', - RoomMemberInfo: 'RoomMemberInfo', - EncryptionPanel: 'EncryptionPanel', + RoomMemberList = 'RoomMemberList', + FilePanel = 'FilePanel', + NotificationPanel = 'NotificationPanel', + RoomMemberInfo = 'RoomMemberInfo', + EncryptionPanel = 'EncryptionPanel', - Room3pidMemberInfo: 'Room3pidMemberInfo', + Room3pidMemberInfo = 'Room3pidMemberInfo', // Group stuff - GroupMemberList: 'GroupMemberList', - GroupRoomList: 'GroupRoomList', - GroupRoomInfo: 'GroupRoomInfo', - GroupMemberInfo: 'GroupMemberInfo', -}); + GroupMemberList = 'GroupMemberList', + GroupRoomList = 'GroupRoomList', + GroupRoomInfo = 'GroupRoomInfo', + GroupMemberInfo = 'GroupMemberInfo', +} // These are the phases that are safe to persist (the ones that don't require additional // arguments). export const RIGHT_PANEL_PHASES_NO_ARGS = [ - RIGHT_PANEL_PHASES.NotificationPanel, - RIGHT_PANEL_PHASES.FilePanel, - RIGHT_PANEL_PHASES.RoomMemberList, - RIGHT_PANEL_PHASES.GroupMemberList, - RIGHT_PANEL_PHASES.GroupRoomList, + RightPanelPhases.NotificationPanel, + RightPanelPhases.FilePanel, + RightPanelPhases.RoomMemberList, + RightPanelPhases.GroupMemberList, + RightPanelPhases.GroupRoomList, ]; diff --git a/src/stores/RoomViewStore.tsx b/src/stores/RoomViewStore.tsx index 6a6468d5d0..bfcbaf9029 100644 --- a/src/stores/RoomViewStore.tsx +++ b/src/stores/RoomViewStore.tsx @@ -279,12 +279,22 @@ class RoomViewStore extends Store { console.log("Failed to join room:", msg); if (err.name === "ConnectionError") { msg = _t("There was an error joining the room"); - } - if (err.errcode === 'M_INCOMPATIBLE_ROOM_VERSION') { + } else if (err.errcode === 'M_INCOMPATIBLE_ROOM_VERSION') { msg =
    {_t("Sorry, your homeserver is too old to participate in this room.")}
    {_t("Please contact your homeserver administrator.")}
    ; + } else if (err.httpStatus === 404) { + const invitingUserId = this.getInvitingUserId(this._state.roomId); + // only provide a better error message for invites + if (invitingUserId) { + // if the inviting user is on the same HS, there can only be one cause: they left. + if (invitingUserId.endsWith(`:${MatrixClientPeg.get().getDomain()}`)) { + msg = _t("The person who invited you already left the room."); + } else { + msg = _t("The person who invited you already left the room, or their server is offline."); + } + } } const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createTrackedDialog('Failed to join room', '', ErrorDialog, { @@ -294,6 +304,16 @@ class RoomViewStore extends Store { }); } + private getInvitingUserId(roomId: string): string { + const cli = MatrixClientPeg.get(); + const room = cli.getRoom(roomId); + if (room && room.getMyMembership() === "invite") { + const myMember = room.getMember(cli.getUserId()); + const inviteEvent = myMember ? myMember.events.member : null; + return inviteEvent && inviteEvent.getSender(); + } + } + private joinRoomError(payload: ActionPayload) { this.setState({ joining: false, diff --git a/src/stores/ToastStore.ts b/src/stores/ToastStore.ts index afb9fe1f8c..038aebc7c9 100644 --- a/src/stores/ToastStore.ts +++ b/src/stores/ToastStore.ts @@ -15,9 +15,10 @@ limitations under the License. */ import EventEmitter from "events"; -import React, {JSXElementConstructor} from "react"; +import React from "react"; +import { ComponentClass } from "../@types/common"; -export interface IToast> { +export interface IToast { key: string; // higher priority number will be shown on top of lower priority priority: number; @@ -55,7 +56,7 @@ export default class ToastStore extends EventEmitter { * * @param {object} newToast The new toast */ - addOrReplaceToast>(newToast: IToast) { + addOrReplaceToast(newToast: IToast) { const oldIndex = this.toasts.findIndex(t => t.key === newToast.key); if (oldIndex === -1) { let newIndex = this.toasts.length; diff --git a/src/stores/local-echo/EchoChamber.ts b/src/stores/local-echo/EchoChamber.ts new file mode 100644 index 0000000000..f61e521728 --- /dev/null +++ b/src/stores/local-echo/EchoChamber.ts @@ -0,0 +1,31 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { RoomEchoChamber } from "./RoomEchoChamber"; +import { Room } from "matrix-js-sdk/src/models/room"; +import { EchoStore } from "./EchoStore"; + +/** + * Semantic access to local echo + */ +export class EchoChamber { + private constructor() { + } + + public static forRoom(room: Room): RoomEchoChamber { + return EchoStore.instance.getOrCreateChamberForRoom(room); + } +} diff --git a/src/stores/local-echo/EchoContext.ts b/src/stores/local-echo/EchoContext.ts new file mode 100644 index 0000000000..55d6e8020a --- /dev/null +++ b/src/stores/local-echo/EchoContext.ts @@ -0,0 +1,87 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { EchoTransaction, RunFn, TransactionStatus } from "./EchoTransaction"; +import { arrayFastClone } from "../../utils/arrays"; +import { IDestroyable } from "../../utils/IDestroyable"; +import { Whenable } from "../../utils/Whenable"; + +export enum ContextTransactionState { + NotStarted, + PendingErrors, + AllSuccessful +} + +export abstract class EchoContext extends Whenable implements IDestroyable { + private _transactions: EchoTransaction[] = []; + private _state = ContextTransactionState.NotStarted; + + public get transactions(): EchoTransaction[] { + return arrayFastClone(this._transactions); + } + + public get state(): ContextTransactionState { + return this._state; + } + + public get firstFailedTime(): Date { + const failedTxn = this.transactions.find(t => t.didPreviouslyFail || t.status === TransactionStatus.Error); + if (failedTxn) return failedTxn.startTime; + return null; + } + + public disownTransaction(txn: EchoTransaction) { + const idx = this._transactions.indexOf(txn); + if (idx >= 0) this._transactions.splice(idx, 1); + txn.destroy(); + this.checkTransactions(); + } + + public beginTransaction(auditName: string, runFn: RunFn): EchoTransaction { + const txn = new EchoTransaction(auditName, runFn); + this._transactions.push(txn); + txn.whenAnything(this.checkTransactions); + + // We have no intent to call the transaction again if it succeeds (in fact, it'll + // be really angry at us if we do), so call that the end of the road for the events. + txn.when(TransactionStatus.Success, () => txn.destroy()); + + return txn; + } + + private checkTransactions = () => { + let status = ContextTransactionState.AllSuccessful; + for (const txn of this.transactions) { + if (txn.status === TransactionStatus.Error || txn.didPreviouslyFail) { + status = ContextTransactionState.PendingErrors; + break; + } else if (txn.status === TransactionStatus.Pending) { + status = ContextTransactionState.NotStarted; + // no break as we might hit something which broke + } + } + this._state = status; + this.notifyCondition(status); + }; + + public destroy() { + for (const txn of this.transactions) { + txn.destroy(); + } + this._transactions = []; + super.destroy(); + } +} diff --git a/src/stores/local-echo/EchoStore.ts b/src/stores/local-echo/EchoStore.ts new file mode 100644 index 0000000000..76e90be45e --- /dev/null +++ b/src/stores/local-echo/EchoStore.ts @@ -0,0 +1,104 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { GenericEchoChamber } from "./GenericEchoChamber"; +import { Room } from "matrix-js-sdk/src/models/room"; +import { RoomEchoChamber } from "./RoomEchoChamber"; +import { RoomEchoContext } from "./RoomEchoContext"; +import { AsyncStoreWithClient } from "../AsyncStoreWithClient"; +import defaultDispatcher from "../../dispatcher/dispatcher"; +import { ActionPayload } from "../../dispatcher/payloads"; +import { ContextTransactionState, EchoContext } from "./EchoContext"; +import NonUrgentToastStore, { ToastReference } from "../NonUrgentToastStore"; +import NonUrgentEchoFailureToast from "../../components/views/toasts/NonUrgentEchoFailureToast"; + +interface IState { + toastRef: ToastReference; +} + +type ContextKey = string; + +const roomContextKey = (room: Room): ContextKey => `room-${room.roomId}`; + +export class EchoStore extends AsyncStoreWithClient { + private static _instance: EchoStore; + + private caches = new Map>(); + + constructor() { + super(defaultDispatcher); + } + + public static get instance(): EchoStore { + if (!EchoStore._instance) { + EchoStore._instance = new EchoStore(); + } + return EchoStore._instance; + } + + public get contexts(): EchoContext[] { + return Array.from(this.caches.values()).map(e => e.context); + } + + public getOrCreateChamberForRoom(room: Room): RoomEchoChamber { + if (this.caches.has(roomContextKey(room))) { + return this.caches.get(roomContextKey(room)) as RoomEchoChamber; + } + + const context = new RoomEchoContext(room); + context.whenAnything(() => this.checkContexts()); + + const echo = new RoomEchoChamber(context); + echo.setClient(this.matrixClient); + this.caches.set(roomContextKey(room), echo); + + return echo; + } + + private async checkContexts() { + let hasOrHadError = false; + for (const echo of this.caches.values()) { + hasOrHadError = echo.context.state === ContextTransactionState.PendingErrors; + if (hasOrHadError) break; + } + + if (hasOrHadError && !this.state.toastRef) { + const ref = NonUrgentToastStore.instance.addToast(NonUrgentEchoFailureToast); + await this.updateState({toastRef: ref}); + } else if (!hasOrHadError && this.state.toastRef) { + NonUrgentToastStore.instance.removeToast(this.state.toastRef); + await this.updateState({toastRef: null}); + } + } + + protected async onReady(): Promise { + if (!this.caches) return; // can only happen during initialization + for (const echo of this.caches.values()) { + echo.setClient(this.matrixClient); + } + } + + protected async onNotReady(): Promise { + for (const echo of this.caches.values()) { + echo.setClient(null); + } + } + + protected async onAction(payload: ActionPayload): Promise { + // We have nothing to actually listen for + return Promise.resolve(); + } +} diff --git a/src/stores/local-echo/EchoTransaction.ts b/src/stores/local-echo/EchoTransaction.ts new file mode 100644 index 0000000000..2e372136d0 --- /dev/null +++ b/src/stores/local-echo/EchoTransaction.ts @@ -0,0 +1,72 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { Whenable } from "../../utils/Whenable"; + +export type RunFn = () => Promise; + +export enum TransactionStatus { + Pending, + Success, + Error, +} + +export class EchoTransaction extends Whenable { + private _status = TransactionStatus.Pending; + private didFail = false; + + public readonly startTime = new Date(); + + public constructor( + public readonly auditName, + public runFn: RunFn, + ) { + super(); + } + + public get didPreviouslyFail(): boolean { + return this.didFail; + } + + public get status(): TransactionStatus { + return this._status; + } + + public run() { + if (this.status === TransactionStatus.Success) { + throw new Error("Cannot re-run a successful echo transaction"); + } + this.setStatus(TransactionStatus.Pending); + this.runFn() + .then(() => this.setStatus(TransactionStatus.Success)) + .catch(() => this.setStatus(TransactionStatus.Error)); + } + + public cancel() { + // Success basically means "done" + this.setStatus(TransactionStatus.Success); + } + + private setStatus(status: TransactionStatus) { + this._status = status; + if (status === TransactionStatus.Error) { + this.didFail = true; + } else if (status === TransactionStatus.Success) { + this.didFail = false; + } + this.notifyCondition(status); + } +} diff --git a/src/stores/local-echo/GenericEchoChamber.ts b/src/stores/local-echo/GenericEchoChamber.ts new file mode 100644 index 0000000000..7a2173f702 --- /dev/null +++ b/src/stores/local-echo/GenericEchoChamber.ts @@ -0,0 +1,91 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { EchoContext } from "./EchoContext"; +import { EchoTransaction, RunFn, TransactionStatus } from "./EchoTransaction"; +import { MatrixClient } from "matrix-js-sdk/src/client"; +import { EventEmitter } from "events"; + +export async function implicitlyReverted() { + // do nothing :D +} + +export const PROPERTY_UPDATED = "property_updated"; + +export abstract class GenericEchoChamber extends EventEmitter { + private cache = new Map(); + protected matrixClient: MatrixClient; + + protected constructor(public readonly context: C, private lookupFn: (key: K) => V) { + super(); + } + + public setClient(client: MatrixClient) { + const oldClient = this.matrixClient; + this.matrixClient = client; + this.onClientChanged(oldClient, client); + } + + protected abstract onClientChanged(oldClient: MatrixClient, newClient: MatrixClient); + + /** + * Gets a value. If the key is in flight, the cached value will be returned. If + * the key is not in flight then the lookupFn provided to this class will be + * called instead. + * @param key The key to look up. + * @returns The value for the key. + */ + public getValue(key: K): V { + return this.cache.has(key) ? this.cache.get(key).val : this.lookupFn(key); + } + + private cacheVal(key: K, val: V, txn: EchoTransaction) { + this.cache.set(key, {txn, val}); + this.emit(PROPERTY_UPDATED, key); + } + + private decacheKey(key: K) { + if (this.cache.has(key)) { + this.context.disownTransaction(this.cache.get(key).txn); + this.cache.delete(key); + this.emit(PROPERTY_UPDATED, key); + } + } + + protected markEchoReceived(key: K) { + if (this.cache.has(key)) { + const txn = this.cache.get(key).txn; + this.context.disownTransaction(txn); + txn.cancel(); + } + this.decacheKey(key); + } + + public setValue(auditName: string, key: K, targetVal: V, runFn: RunFn, revertFn: RunFn) { + // Cancel any pending transactions for the same key + if (this.cache.has(key)) { + this.cache.get(key).txn.cancel(); + } + + const ctxn = this.context.beginTransaction(auditName, runFn); + this.cacheVal(key, targetVal, ctxn); // set the cache now as it won't be updated by the .when() ladder below. + + ctxn.when(TransactionStatus.Pending, () => this.cacheVal(key, targetVal, ctxn)) + .when(TransactionStatus.Error, () => revertFn()); + + ctxn.run(); + } +} diff --git a/src/stores/local-echo/RoomEchoChamber.ts b/src/stores/local-echo/RoomEchoChamber.ts new file mode 100644 index 0000000000..e113f68c32 --- /dev/null +++ b/src/stores/local-echo/RoomEchoChamber.ts @@ -0,0 +1,78 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { GenericEchoChamber, implicitlyReverted, PROPERTY_UPDATED } from "./GenericEchoChamber"; +import { getRoomNotifsState, setRoomNotifsState } from "../../RoomNotifs"; +import { RoomEchoContext } from "./RoomEchoContext"; +import { _t } from "../../languageHandler"; +import { Volume } from "../../RoomNotifsTypes"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; + +export type CachedRoomValues = Volume; + +export enum CachedRoomKey { + NotificationVolume, +} + +export class RoomEchoChamber extends GenericEchoChamber { + private properties = new Map(); + + public constructor(context: RoomEchoContext) { + super(context, (k) => this.properties.get(k)); + } + + protected onClientChanged(oldClient, newClient) { + this.properties.clear(); + if (oldClient) { + oldClient.removeListener("accountData", this.onAccountData); + } + if (newClient) { + // Register the listeners first + newClient.on("accountData", this.onAccountData); + + // Then populate the properties map + this.updateNotificationVolume(); + } + } + + private onAccountData = (event: MatrixEvent) => { + if (event.getType() === "m.push_rules") { + const currentVolume = this.properties.get(CachedRoomKey.NotificationVolume) as Volume; + const newVolume = getRoomNotifsState(this.context.room.roomId) as Volume; + if (currentVolume !== newVolume) { + this.updateNotificationVolume(); + } + } + }; + + private updateNotificationVolume() { + this.properties.set(CachedRoomKey.NotificationVolume, getRoomNotifsState(this.context.room.roomId)); + this.markEchoReceived(CachedRoomKey.NotificationVolume); + this.emit(PROPERTY_UPDATED, CachedRoomKey.NotificationVolume); + } + + // ---- helpers below here ---- + + public get notificationVolume(): Volume { + return this.getValue(CachedRoomKey.NotificationVolume); + } + + public set notificationVolume(v: Volume) { + this.setValue(_t("Change notification settings"), CachedRoomKey.NotificationVolume, v, async () => { + return setRoomNotifsState(this.context.room.roomId, v); + }, implicitlyReverted); + } +} diff --git a/src/stores/local-echo/RoomEchoContext.ts b/src/stores/local-echo/RoomEchoContext.ts new file mode 100644 index 0000000000..4105f728c3 --- /dev/null +++ b/src/stores/local-echo/RoomEchoContext.ts @@ -0,0 +1,24 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { EchoContext } from "./EchoContext"; +import { Room } from "matrix-js-sdk/src/models/room"; + +export class RoomEchoContext extends EchoContext { + constructor(public readonly room: Room) { + super(); + } +} diff --git a/src/stores/notifications/RoomNotificationState.ts b/src/stores/notifications/RoomNotificationState.ts index dc38f8bf0f..3fadbe7d7a 100644 --- a/src/stores/notifications/RoomNotificationState.ts +++ b/src/stores/notifications/RoomNotificationState.ts @@ -31,6 +31,7 @@ export class RoomNotificationState extends NotificationState implements IDestroy this.room.on("Room.receipt", this.handleReadReceipt); this.room.on("Room.timeline", this.handleRoomEventUpdate); this.room.on("Room.redaction", this.handleRoomEventUpdate); + this.room.on("Room.myMembership", this.handleMembershipUpdate); MatrixClientPeg.get().on("Event.decrypted", this.handleRoomEventUpdate); MatrixClientPeg.get().on("accountData", this.handleAccountDataUpdate); this.updateNotificationState(); @@ -45,6 +46,7 @@ export class RoomNotificationState extends NotificationState implements IDestroy this.room.removeListener("Room.receipt", this.handleReadReceipt); this.room.removeListener("Room.timeline", this.handleRoomEventUpdate); this.room.removeListener("Room.redaction", this.handleRoomEventUpdate); + this.room.removeListener("Room.myMembership", this.handleMembershipUpdate); if (MatrixClientPeg.get()) { MatrixClientPeg.get().removeListener("Event.decrypted", this.handleRoomEventUpdate); MatrixClientPeg.get().removeListener("accountData", this.handleAccountDataUpdate); @@ -57,6 +59,10 @@ export class RoomNotificationState extends NotificationState implements IDestroy this.updateNotificationState(); }; + private handleMembershipUpdate = () => { + this.updateNotificationState(); + }; + private handleRoomEventUpdate = (event: MatrixEvent) => { const roomId = event.getRoomId(); diff --git a/src/stores/notifications/RoomNotificationStateStore.ts b/src/stores/notifications/RoomNotificationStateStore.ts index ed74d3bae6..8b5da674f5 100644 --- a/src/stores/notifications/RoomNotificationStateStore.ts +++ b/src/stores/notifications/RoomNotificationStateStore.ts @@ -21,37 +21,55 @@ import { DefaultTagID, TagID } from "../room-list/models"; import { FetchRoomFn, ListNotificationState } from "./ListNotificationState"; import { Room } from "matrix-js-sdk/src/models/room"; import { RoomNotificationState } from "./RoomNotificationState"; - -const INSPECIFIC_TAG = "INSPECIFIC_TAG"; -type INSPECIFIC_TAG = "INSPECIFIC_TAG"; +import { SummarizedNotificationState } from "./SummarizedNotificationState"; interface IState {} export class RoomNotificationStateStore extends AsyncStoreWithClient { private static internalInstance = new RoomNotificationStateStore(); - private roomMap = new Map>(); + private roomMap = new Map(); + private listMap = new Map(); private constructor() { super(defaultDispatcher, {}); } /** - * Creates a new list notification state. The consumer is expected to set the rooms - * on the notification state, and destroy the state when it no longer needs it. - * @param tagId The tag to create the notification state for. + * Gets a snapshot of notification state for all visible rooms. The number of states recorded + * on the SummarizedNotificationState is equivalent to rooms. + */ + public get globalState(): SummarizedNotificationState { + // If we're not ready yet, just return an empty state + if (!this.matrixClient) return new SummarizedNotificationState(); + + // Only count visible rooms to not torment the user with notification counts in rooms they can't see. + // This will include highlights from the previous version of the room internally + const globalState = new SummarizedNotificationState(); + for (const room of this.matrixClient.getVisibleRooms()) { + globalState.add(this.getRoomState(room)); + } + return globalState; + } + + /** + * Gets an instance of the list state class for the given tag. + * @param tagId The tag to get the notification state for. * @returns The notification state for the tag. */ public getListState(tagId: TagID): ListNotificationState { - // Note: we don't cache these notification states as the consumer is expected to call - // .setRooms() on the returned object, which could confuse other consumers. + if (this.listMap.has(tagId)) { + return this.listMap.get(tagId); + } // TODO: Update if/when invites move out of the room list. const useTileCount = tagId === DefaultTagID.Invite; const getRoomFn: FetchRoomFn = (room: Room) => { - return this.getRoomState(room, tagId); + return this.getRoomState(room); }; - return new ListNotificationState(useTileCount, tagId, getRoomFn); + const state = new ListNotificationState(useTileCount, tagId, getRoomFn); + this.listMap.set(tagId, state); + return state; } /** @@ -59,22 +77,13 @@ export class RoomNotificationStateStore extends AsyncStoreWithClient { * attempt to destroy the returned state as it may be shared with other * consumers. * @param room The room to get the notification state for. - * @param inTagId Optional tag ID to scope the notification state to. * @returns The room's notification state. */ - public getRoomState(room: Room, inTagId?: TagID): RoomNotificationState { + public getRoomState(room: Room): RoomNotificationState { if (!this.roomMap.has(room)) { - this.roomMap.set(room, new Map()); + this.roomMap.set(room, new RoomNotificationState(room)); } - - const targetTag = inTagId ? inTagId : INSPECIFIC_TAG; - - const forRoomMap = this.roomMap.get(room); - if (!forRoomMap.has(targetTag)) { - forRoomMap.set(inTagId ? inTagId : INSPECIFIC_TAG, new RoomNotificationState(room)); - } - - return forRoomMap.get(targetTag); + return this.roomMap.get(room); } public static get instance(): RoomNotificationStateStore { @@ -82,10 +91,8 @@ export class RoomNotificationStateStore extends AsyncStoreWithClient { } protected async onNotReady(): Promise { - for (const roomMap of this.roomMap.values()) { - for (const roomState of roomMap.values()) { - roomState.destroy(); - } + for (const roomState of this.roomMap.values()) { + roomState.destroy(); } } diff --git a/src/stores/notifications/SummarizedNotificationState.ts b/src/stores/notifications/SummarizedNotificationState.ts new file mode 100644 index 0000000000..372da74f36 --- /dev/null +++ b/src/stores/notifications/SummarizedNotificationState.ts @@ -0,0 +1,62 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { NotificationColor } from "./NotificationColor"; +import { NotificationState } from "./NotificationState"; + +/** + * Summarizes a number of states into a unique snapshot. To populate, call + * the add() function with the notification states to be included. + * + * Useful for community notification counts, global notification counts, etc. + */ +export class SummarizedNotificationState extends NotificationState { + private totalStatesWithUnread = 0; + + constructor() { + super(); + this._symbol = null; + this._count = 0; + this._color = NotificationColor.None; + } + + public get numUnreadStates(): number { + return this.totalStatesWithUnread; + } + + /** + * Append a notification state to this snapshot, taking the loudest NotificationColor + * of the two. By default this will not adopt the symbol of the other notification + * state to prevent the count from being lost in typical usage. + * @param other The other notification state to append. + * @param includeSymbol If true, the notification state's symbol will be taken if one + * is present. + */ + public add(other: NotificationState, includeSymbol = false) { + if (other.symbol && includeSymbol) { + this._symbol = other.symbol; + } + if (other.count) { + this._count += other.count; + } + if (other.color > this.color) { + this._color = other.color; + } + if (other.hasUnreadCount) { + this.totalStatesWithUnread++; + } + } +} diff --git a/src/stores/room-list/MessagePreviewStore.ts b/src/stores/room-list/MessagePreviewStore.ts index e5ef735927..2803f0a23e 100644 --- a/src/stores/room-list/MessagePreviewStore.ts +++ b/src/stores/room-list/MessagePreviewStore.ts @@ -19,42 +19,24 @@ import { ActionPayload } from "../../dispatcher/payloads"; import { AsyncStoreWithClient } from "../AsyncStoreWithClient"; import defaultDispatcher from "../../dispatcher/dispatcher"; import { MessageEventPreview } from "./previews/MessageEventPreview"; -import { NameEventPreview } from "./previews/NameEventPreview"; import { TagID } from "./models"; import { isNullOrUndefined } from "matrix-js-sdk/src/utils"; -import { TopicEventPreview } from "./previews/TopicEventPreview"; -import { MembershipEventPreview } from "./previews/MembershipEventPreview"; -import { HistoryVisibilityEventPreview } from "./previews/HistoryVisibilityEventPreview"; import { CallInviteEventPreview } from "./previews/CallInviteEventPreview"; import { CallAnswerEventPreview } from "./previews/CallAnswerEventPreview"; import { CallHangupEvent } from "./previews/CallHangupEvent"; -import { EncryptionEventPreview } from "./previews/EncryptionEventPreview"; -import { ThirdPartyInviteEventPreview } from "./previews/ThirdPartyInviteEventPreview"; import { StickerEventPreview } from "./previews/StickerEventPreview"; import { ReactionEventPreview } from "./previews/ReactionEventPreview"; -import { CreationEventPreview } from "./previews/CreationEventPreview"; +import { UPDATE_EVENT } from "../AsyncStore"; + +// Emitted event for when a room's preview has changed. First argument will the room for which +// the change happened. +export const ROOM_PREVIEW_CHANGED = "room_preview_changed"; const PREVIEWS = { 'm.room.message': { isState: false, previewer: new MessageEventPreview(), }, - 'm.room.name': { - isState: true, - previewer: new NameEventPreview(), - }, - 'm.room.topic': { - isState: true, - previewer: new TopicEventPreview(), - }, - 'm.room.member': { - isState: true, - previewer: new MembershipEventPreview(), - }, - 'm.room.history_visibility': { - isState: true, - previewer: new HistoryVisibilityEventPreview(), - }, 'm.call.invite': { isState: false, previewer: new CallInviteEventPreview(), @@ -67,14 +49,6 @@ const PREVIEWS = { isState: false, previewer: new CallHangupEvent(), }, - 'm.room.encryption': { - isState: true, - previewer: new EncryptionEventPreview(), - }, - 'm.room.third_party_invite': { - isState: true, - previewer: new ThirdPartyInviteEventPreview(), - }, 'm.sticker': { isState: false, previewer: new StickerEventPreview(), @@ -83,10 +57,6 @@ const PREVIEWS = { isState: false, previewer: new ReactionEventPreview(), }, - 'm.room.create': { - isState: true, - previewer: new CreationEventPreview(), - }, }; // The maximum number of events we're willing to look back on to get a preview. @@ -97,12 +67,15 @@ type TAG_ANY = "im.vector.any"; const TAG_ANY: TAG_ANY = "im.vector.any"; interface IState { - [roomId: string]: Map; // null indicates the preview is empty / irrelevant + // Empty because we don't actually use the state } export class MessagePreviewStore extends AsyncStoreWithClient { private static internalInstance = new MessagePreviewStore(); + // null indicates the preview is empty / irrelevant + private previews = new Map>(); + private constructor() { super(defaultDispatcher, {}); } @@ -120,10 +93,9 @@ export class MessagePreviewStore extends AsyncStoreWithClient { public getPreviewForRoom(room: Room, inTagId: TagID): string { if (!room) return null; // invalid room, just return nothing - const val = this.state[room.roomId]; - if (!val) this.generatePreview(room, inTagId); + if (!this.previews.has(room.roomId)) this.generatePreview(room, inTagId); - const previews = this.state[room.roomId]; + const previews = this.previews.get(room.roomId); if (!previews) return null; if (!previews.has(inTagId)) { @@ -136,11 +108,10 @@ export class MessagePreviewStore extends AsyncStoreWithClient { const events = room.timeline; if (!events) return; // should only happen in tests - let map = this.state[room.roomId]; + let map = this.previews.get(room.roomId); if (!map) { map = new Map(); - - // We set the state later with the map, so no need to send an update now + this.previews.set(room.roomId, map); } // Set the tags so we know what to generate @@ -176,16 +147,18 @@ export class MessagePreviewStore extends AsyncStoreWithClient { } if (changed) { - // Update state for good measure - causes emit for update - // noinspection JSIgnoredPromiseFromCall - the AsyncStore handles concurrent calls - this.updateState({[room.roomId]: map}); + // We've muted the underlying Map, so just emit that we've changed. + this.previews.set(room.roomId, map); + this.emit(UPDATE_EVENT, this); + this.emit(ROOM_PREVIEW_CHANGED, room); } return; // we're done } // At this point, we didn't generate a preview so clear it - // noinspection JSIgnoredPromiseFromCall - the AsyncStore handles concurrent calls - this.updateState({[room.roomId]: null}); + this.previews.set(room.roomId, new Map()); + this.emit(UPDATE_EVENT, this); + this.emit(ROOM_PREVIEW_CHANGED, room); } protected async onAction(payload: ActionPayload) { @@ -193,7 +166,7 @@ export class MessagePreviewStore extends AsyncStoreWithClient { if (payload.action === 'MatrixActions.Room.timeline' || payload.action === 'MatrixActions.Event.decrypted') { const event = payload.event; // TODO: Type out the dispatcher - if (!Object.keys(this.state).includes(event.getRoomId())) return; // not important + if (!this.previews.has(event.getRoomId())) return; // not important this.generatePreview(this.matrixClient.getRoom(event.getRoomId()), TAG_ANY); } } diff --git a/src/stores/room-list/RoomListStore.ts b/src/stores/room-list/RoomListStore.ts index 308296e8bb..c3e7fd5c51 100644 --- a/src/stores/room-list/RoomListStore.ts +++ b/src/stores/room-list/RoomListStore.ts @@ -32,6 +32,8 @@ import { isNullOrUndefined } from "matrix-js-sdk/src/utils"; import RoomListLayoutStore from "./RoomListLayoutStore"; import { MarkedExecution } from "../../utils/MarkedExecution"; import { AsyncStoreWithClient } from "../AsyncStoreWithClient"; +import { NameFilterCondition } from "./filters/NameFilterCondition"; +import { RoomNotificationStateStore } from "../notifications/RoomNotificationStateStore"; interface IState { tagsEnabled?: boolean; @@ -54,7 +56,12 @@ export class RoomListStoreClass extends AsyncStoreWithClient { private algorithm = new Algorithm(); private filterConditions: IFilterCondition[] = []; private tagWatcher = new TagWatcher(this); - private updateFn = new MarkedExecution(() => this.emit(LISTS_UPDATE_EVENT)); + private updateFn = new MarkedExecution(() => { + for (const tagId of Object.keys(this.unfilteredLists)) { + RoomNotificationStateStore.instance.getListState(tagId).setRooms(this.unfilteredLists[tagId]); + } + this.emit(LISTS_UPDATE_EVENT); + }); private readonly watchedSettings = [ 'feature_custom_tags', @@ -71,6 +78,11 @@ export class RoomListStoreClass extends AsyncStoreWithClient { this.algorithm.on(FILTER_CHANGED, this.onAlgorithmFilterUpdated); } + public get unfilteredLists(): ITagMap { + if (!this.algorithm) return {}; // No tags yet. + return this.algorithm.getUnfilteredRooms(); + } + public get orderedLists(): ITagMap { if (!this.algorithm) return {}; // No tags yet. return this.algorithm.getOrderedRooms(); @@ -168,6 +180,12 @@ export class RoomListStoreClass extends AsyncStoreWithClient { } protected async onAction(payload: ActionPayload) { + // If we're not remotely ready, don't even bother scheduling the dispatch handling. + // This is repeated in the handler just in case things change between a decision here and + // when the timer fires. + const logicallyReady = this.matrixClient && this.initialListsGenerated; + if (!logicallyReady) return; + // When we're running tests we can't reliably use setImmediate out of timing concerns. // As such, we use a more synchronous model. if (RoomListStoreClass.TEST_MODE) { @@ -582,6 +600,20 @@ export class RoomListStoreClass extends AsyncStoreWithClient { this.updateFn.trigger(); } + /** + * Gets the first (and ideally only) name filter condition. If one isn't present, + * this returns null. + * @returns The first name filter condition, or null if none. + */ + public getFirstNameFilterCondition(): NameFilterCondition | null { + for (const filter of this.filterConditions) { + if (filter instanceof NameFilterCondition) { + return filter; + } + } + return null; + } + /** * Gets the tags for a room identified by the store. The returned set * should never be empty, and will contain DefaultTagID.Untagged if diff --git a/src/stores/room-list/algorithms/Algorithm.ts b/src/stores/room-list/algorithms/Algorithm.ts index 667084d653..f1a7ab1613 100644 --- a/src/stores/room-list/algorithms/Algorithm.ts +++ b/src/stores/room-list/algorithms/Algorithm.ts @@ -212,7 +212,18 @@ export class Algorithm extends EventEmitter { // We specifically do NOT use the ordered rooms set as it contains the sticky room, which // means we'll be off by 1 when the user is switching rooms. This leads to visual jumping // when the user is moving south in the list (not north, because of math). - let position = this.getOrderedRoomsWithoutSticky()[tag].indexOf(val); + const tagList = this.getOrderedRoomsWithoutSticky()[tag] || []; // can be null if filtering + let position = tagList.indexOf(val); + + // We do want to see if a tag change happened though - if this did happen then we'll want + // to force the position to zero (top) to ensure we can properly handle it. + const wasSticky = this._lastStickyRoom.room ? this._lastStickyRoom.room.roomId === val.roomId : false; + if (this._lastStickyRoom.tag && tag !== this._lastStickyRoom.tag && wasSticky && position < 0) { + console.warn(`Sticky room ${val.roomId} changed tags during sticky room handling`); + position = 0; + } + + // Sanity check the position to make sure the room is qualified for being sticky if (position < 0) throw new Error(`${val.roomId} does not appear to be known and cannot be sticky`); // 🐉 Here be dragons. @@ -465,6 +476,10 @@ export class Algorithm extends EventEmitter { return this.filteredRooms; } + public getUnfilteredRooms(): ITagMap { + return this._cachedStickyRooms || this.cachedRooms; + } + /** * This returns the same as getOrderedRooms(), but without the sticky room * map as it causes issues for sticky room handling (see sticky room handling @@ -711,7 +726,9 @@ export class Algorithm extends EventEmitter { const algorithm: OrderingAlgorithm = this.algorithms[rmTag]; if (!algorithm) throw new Error(`No algorithm for ${rmTag}`); await algorithm.handleRoomUpdate(room, RoomUpdateCause.RoomRemoved); - this.cachedRooms[rmTag] = algorithm.orderedRooms; + this._cachedRooms[rmTag] = algorithm.orderedRooms; + this.recalculateFilteredRoomsForTag(rmTag); // update filter to re-sort the list + this.recalculateStickyRoom(rmTag); // update sticky room to make sure it moves if needed } for (const addTag of diff.added) { if (SettingsStore.getValue("advancedRoomListLogging")) { @@ -721,7 +738,7 @@ export class Algorithm extends EventEmitter { const algorithm: OrderingAlgorithm = this.algorithms[addTag]; if (!algorithm) throw new Error(`No algorithm for ${addTag}`); await algorithm.handleRoomUpdate(room, RoomUpdateCause.NewRoom); - this.cachedRooms[addTag] = algorithm.orderedRooms; + this._cachedRooms[addTag] = algorithm.orderedRooms; } // Update the tag map so we don't regen it in a moment @@ -817,7 +834,7 @@ export class Algorithm extends EventEmitter { if (!algorithm) throw new Error(`No algorithm for ${tag}`); await algorithm.handleRoomUpdate(room, cause); - this.cachedRooms[tag] = algorithm.orderedRooms; + this._cachedRooms[tag] = algorithm.orderedRooms; // Flag that we've done something this.recalculateFilteredRoomsForTag(tag); // update filter to re-sort the list diff --git a/src/stores/room-list/algorithms/list-ordering/ImportanceAlgorithm.ts b/src/stores/room-list/algorithms/list-ordering/ImportanceAlgorithm.ts index e3e0cdcac4..e4aa5ff06f 100644 --- a/src/stores/room-list/algorithms/list-ordering/ImportanceAlgorithm.ts +++ b/src/stores/room-list/algorithms/list-ordering/ImportanceAlgorithm.ts @@ -90,7 +90,7 @@ export class ImportanceAlgorithm extends OrderingAlgorithm { private getRoomCategory(room: Room): NotificationColor { // It's fine for us to call this a lot because it's cached, and we shouldn't be // wasting anything by doing so as the store holds single references - const state = RoomNotificationStateStore.instance.getRoomState(room, this.tagId); + const state = RoomNotificationStateStore.instance.getRoomState(room); return state.color; } @@ -123,6 +123,7 @@ export class ImportanceAlgorithm extends OrderingAlgorithm { const category = this.getRoomCategory(room); this.alterCategoryPositionBy(category, 1, this.indices); this.cachedOrderedRooms.splice(this.indices[category], 0, room); // splice in the new room (pre-adjusted) + await this.sortCategory(category); } else if (cause === RoomUpdateCause.RoomRemoved) { const roomIdx = this.getRoomIndex(room); if (roomIdx === -1) { @@ -135,6 +136,9 @@ export class ImportanceAlgorithm extends OrderingAlgorithm { } else { throw new Error(`Unhandled splice: ${cause}`); } + + // changes have been made if we made it here, so say so + return true; } public async handleRoomUpdate(room: Room, cause: RoomUpdateCause): Promise { diff --git a/src/stores/room-list/filters/NameFilterCondition.ts b/src/stores/room-list/filters/NameFilterCondition.ts index 6014a122f8..88edaecfb6 100644 --- a/src/stores/room-list/filters/NameFilterCondition.ts +++ b/src/stores/room-list/filters/NameFilterCondition.ts @@ -18,6 +18,7 @@ import { Room } from "matrix-js-sdk/src/models/room"; import { FILTER_CHANGED, FilterPriority, IFilterCondition } from "./IFilterCondition"; import { EventEmitter } from "events"; import { removeHiddenChars } from "matrix-js-sdk/src/utils"; +import { throttle } from "lodash"; /** * A filter condition for the room list which reveals rooms of a particular @@ -41,9 +42,13 @@ export class NameFilterCondition extends EventEmitter implements IFilterConditio public set search(val: string) { this._search = val; - this.emit(FILTER_CHANGED); + this.callUpdate(); } + private callUpdate = throttle(() => { + this.emit(FILTER_CHANGED); + }, 200, {trailing: true, leading: true}); + public isVisible(room: Room): boolean { const lcFilter = this.search.toLowerCase(); if (this.search[0] === '#') { diff --git a/src/stores/room-list/previews/EncryptionEventPreview.ts b/src/stores/room-list/previews/EncryptionEventPreview.ts deleted file mode 100644 index d00fd7e7f9..0000000000 --- a/src/stores/room-list/previews/EncryptionEventPreview.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* -Copyright 2020 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import { IPreview } from "./IPreview"; -import { TagID } from "../models"; -import { MatrixEvent } from "matrix-js-sdk/src/models/event"; -import { getSenderName, isSelf } from "./utils"; -import { _t } from "../../../languageHandler"; - -export class EncryptionEventPreview implements IPreview { - public getTextFor(event: MatrixEvent, tagId?: TagID): string { - if (isSelf(event)) { - return _t("You made the chat encrypted"); - } else { - return _t("%(senderName)s made the chat encrypted", {senderName: getSenderName(event)}); - } - } -} diff --git a/src/stores/room-list/previews/HistoryVisibilityEventPreview.ts b/src/stores/room-list/previews/HistoryVisibilityEventPreview.ts deleted file mode 100644 index ac77a181f8..0000000000 --- a/src/stores/room-list/previews/HistoryVisibilityEventPreview.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* -Copyright 2020 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import { IPreview } from "./IPreview"; -import { TagID } from "../models"; -import { MatrixEvent } from "matrix-js-sdk/src/models/event"; -import { getSenderName, isSelf } from "./utils"; -import { _t } from "../../../languageHandler"; - -export class HistoryVisibilityEventPreview implements IPreview { - public getTextFor(event: MatrixEvent, tagId?: TagID): string { - const visibility = event.getContent()['history_visibility']; - const isUs = isSelf(event); - - if (visibility === 'invited' || visibility === 'joined') { - return isUs - ? _t("You made history visible to new members") - : _t("%(senderName)s made history visible to new members", {senderName: getSenderName(event)}); - } else if (visibility === 'world_readable') { - return isUs - ? _t("You made history visible to anyone") - : _t("%(senderName)s made history visible to anyone", {senderName: getSenderName(event)}); - } else { // shared, default - return isUs - ? _t("You made history visible to future members") - : _t("%(senderName)s made history visible to future members", {senderName: getSenderName(event)}); - } - } -} diff --git a/src/stores/room-list/previews/MembershipEventPreview.ts b/src/stores/room-list/previews/MembershipEventPreview.ts deleted file mode 100644 index 44339aab5f..0000000000 --- a/src/stores/room-list/previews/MembershipEventPreview.ts +++ /dev/null @@ -1,90 +0,0 @@ -/* -Copyright 2020 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import { IPreview } from "./IPreview"; -import { TagID } from "../models"; -import { MatrixEvent } from "matrix-js-sdk/src/models/event"; -import { getTargetName, isSelfTarget } from "./utils"; -import { _t } from "../../../languageHandler"; - -export class MembershipEventPreview implements IPreview { - public getTextFor(event: MatrixEvent, tagId?: TagID): string { - const newMembership = event.getContent()['membership']; - const oldMembership = event.getPrevContent()['membership']; - const reason = event.getContent()['reason']; - const isUs = isSelfTarget(event); - - if (newMembership === 'invite') { - return isUs - ? _t("You were invited") - : _t("%(targetName)s was invited", {targetName: getTargetName(event)}); - } else if (newMembership === 'leave' && oldMembership !== 'invite') { - if (event.getSender() === event.getStateKey()) { - return isUs - ? _t("You left") - : _t("%(targetName)s left", {targetName: getTargetName(event)}); - } else { - if (reason) { - return isUs - ? _t("You were kicked (%(reason)s)", {reason}) - : _t("%(targetName)s was kicked (%(reason)s)", {targetName: getTargetName(event), reason}); - } else { - return isUs - ? _t("You were kicked") - : _t("%(targetName)s was kicked", {targetName: getTargetName(event)}); - } - } - } else if (newMembership === 'leave' && oldMembership === 'invite') { - if (event.getSender() === event.getStateKey()) { - return isUs - ? _t("You rejected the invite") - : _t("%(targetName)s rejected the invite", {targetName: getTargetName(event)}); - } else { - return isUs - ? _t("You were uninvited") - : _t("%(targetName)s was uninvited", {targetName: getTargetName(event)}); - } - } else if (newMembership === 'ban') { - if (reason) { - return isUs - ? _t("You were banned (%(reason)s)", {reason}) - : _t("%(targetName)s was banned (%(reason)s)", {targetName: getTargetName(event), reason}); - } else { - return isUs - ? _t("You were banned") - : _t("%(targetName)s was banned", {targetName: getTargetName(event)}); - } - } else if (newMembership === 'join' && oldMembership !== 'join') { - return isUs - ? _t("You joined") - : _t("%(targetName)s joined", {targetName: getTargetName(event)}); - } else { - const isDisplayNameChange = event.getContent()['displayname'] !== event.getPrevContent()['displayname']; - const isAvatarChange = event.getContent()['avatar_url'] !== event.getPrevContent()['avatar_url']; - if (isDisplayNameChange) { - return isUs - ? _t("You changed your name") - : _t("%(targetName)s changed their name", {targetName: getTargetName(event)}); - } else if (isAvatarChange) { - return isUs - ? _t("You changed your avatar") - : _t("%(targetName)s changed their avatar", {targetName: getTargetName(event)}); - } else { - return null; // no change - } - } - } -} diff --git a/src/stores/room-list/previews/MessageEventPreview.ts b/src/stores/room-list/previews/MessageEventPreview.ts index 86cb51ef15..deed7dcf2c 100644 --- a/src/stores/room-list/previews/MessageEventPreview.ts +++ b/src/stores/room-list/previews/MessageEventPreview.ts @@ -59,7 +59,7 @@ export class MessageEventPreview implements IPreview { } if (msgtype === 'm.emote') { - return _t("%(senderName)s %(emote)s", {senderName: getSenderName(event), emote: body}); + return _t("* %(senderName)s %(emote)s", {senderName: getSenderName(event), emote: body}); } if (isSelf(event) || !shouldPrefixMessagesIn(event.getRoomId(), tagId)) { diff --git a/src/stores/room-list/previews/ThirdPartyInviteEventPreview.ts b/src/stores/room-list/previews/ThirdPartyInviteEventPreview.ts deleted file mode 100644 index b22cd9fac9..0000000000 --- a/src/stores/room-list/previews/ThirdPartyInviteEventPreview.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* -Copyright 2020 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import { IPreview } from "./IPreview"; -import { TagID } from "../models"; -import { MatrixEvent } from "matrix-js-sdk/src/models/event"; -import { getSenderName, isSelf } from "./utils"; -import { _t } from "../../../languageHandler"; -import { isValid3pidInvite } from "../../../RoomInvite"; - -export class ThirdPartyInviteEventPreview implements IPreview { - public getTextFor(event: MatrixEvent, tagId?: TagID): string { - if (!isValid3pidInvite(event)) { - const targetName = event.getPrevContent().display_name || _t("Someone"); - if (isSelf(event)) { - return _t("You uninvited %(targetName)s", {targetName}); - } else { - return _t("%(senderName)s uninvited %(targetName)s", {senderName: getSenderName(event), targetName}); - } - } else { - const targetName = event.getContent().display_name; - if (isSelf(event)) { - return _t("You invited %(targetName)s", {targetName}); - } else { - return _t("%(senderName)s invited %(targetName)s", {senderName: getSenderName(event), targetName}); - } - } - } -} diff --git a/src/stores/room-list/previews/TopicEventPreview.ts b/src/stores/room-list/previews/TopicEventPreview.ts deleted file mode 100644 index 9b499aae8f..0000000000 --- a/src/stores/room-list/previews/TopicEventPreview.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* -Copyright 2020 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import { IPreview } from "./IPreview"; -import { TagID } from "../models"; -import { MatrixEvent } from "matrix-js-sdk/src/models/event"; -import { getSenderName, isSelf } from "./utils"; -import { _t } from "../../../languageHandler"; - -export class TopicEventPreview implements IPreview { - public getTextFor(event: MatrixEvent, tagId?: TagID): string { - if (isSelf(event)) { - return _t("You changed the room topic"); - } else { - return _t("%(senderName)s changed the room topic", {senderName: getSenderName(event)}); - } - } -} diff --git a/src/utils/Whenable.ts b/src/utils/Whenable.ts new file mode 100644 index 0000000000..49f2571965 --- /dev/null +++ b/src/utils/Whenable.ts @@ -0,0 +1,86 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +import { IDestroyable } from "./IDestroyable"; +import { arrayFastClone } from "./arrays"; + +export type WhenFn = (w: Whenable) => void; + +/** + * Whenables are a cheap way to have Observable patterns mixed with typical + * usage of Promises, without having to tear down listeners or calls. Whenables + * are intended to be used when a condition will be met multiple times and + * the consumer needs to know *when* that happens. + */ +export abstract class Whenable implements IDestroyable { + private listeners: {condition: T | null, fn: WhenFn}[] = []; + + /** + * Sets up a call to `fn` *when* the `condition` is met. + * @param condition The condition to match. + * @param fn The function to call. + * @returns This. + */ + public when(condition: T, fn: WhenFn): Whenable { + this.listeners.push({condition, fn}); + return this; + } + + /** + * Sets up a call to `fn` *when* any of the `conditions` are met. + * @param conditions The conditions to match. + * @param fn The function to call. + * @returns This. + */ + public whenAnyOf(conditions: T[], fn: WhenFn): Whenable { + for (const condition of conditions) { + this.when(condition, fn); + } + return this; + } + + /** + * Sets up a call to `fn` *when* any condition is met. + * @param fn The function to call. + * @returns This. + */ + public whenAnything(fn: WhenFn): Whenable { + this.listeners.push({condition: null, fn}); + return this; + } + + /** + * Notifies all the listeners of a given condition. + * @param condition The new condition that has been met. + */ + protected notifyCondition(condition: T) { + const listeners = arrayFastClone(this.listeners); // clone just in case the handler modifies us + for (const listener of listeners) { + if (listener.condition === null || listener.condition === condition) { + try { + listener.fn(this); + } catch (e) { + console.error(`Error calling whenable listener for ${condition}:`, e); + } + } + } + } + + public destroy() { + this.listeners = []; + } +} diff --git a/src/utils/arrays.ts b/src/utils/arrays.ts index 8175d89464..fa5515878f 100644 --- a/src/utils/arrays.ts +++ b/src/utils/arrays.ts @@ -14,11 +14,38 @@ See the License for the specific language governing permissions and limitations under the License. */ +/** + * Clones an array as fast as possible, retaining references of the array's values. + * @param a The array to clone. Must be defined. + * @returns A copy of the array. + */ +export function arrayFastClone(a: any[]): any[] { + return a.slice(0, a.length); +} + +/** + * Determines if the two arrays are different either in length, contents, + * or order of those contents. + * @param a The first array. Must be defined. + * @param b The second array. Must be defined. + * @returns True if they are different, false otherwise. + */ +export function arrayHasOrderChange(a: any[], b: any[]): boolean { + if (a.length === b.length) { + for (let i = 0; i < a.length; i++) { + if (a[i] !== b[i]) return true; + } + return false; + } else { + return true; // like arrayHasDiff, a difference in length is a natural change + } +} + /** * Determines if two arrays are different through a shallow comparison. * @param a The first array. Must be defined. * @param b The second array. Must be defined. - * @returns True if they are the same, false otherwise. + * @returns True if they are different, false otherwise. */ export function arrayHasDiff(a: any[], b: any[]): boolean { if (a.length === b.length) { @@ -26,6 +53,9 @@ export function arrayHasDiff(a: any[], b: any[]): boolean { // an element from the other. if (b.some(i => !a.includes(i))) return true; if (a.some(i => !b.includes(i))) return true; + + // if all the keys are common, say so + return false; } else { return true; // different lengths means they are naturally diverged } diff --git a/src/utils/objects.ts b/src/utils/objects.ts index 14fa928ce2..ddd9830832 100644 --- a/src/utils/objects.ts +++ b/src/utils/objects.ts @@ -14,7 +14,83 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { arrayDiff, arrayMerge, arrayUnion } from "./arrays"; +import { arrayDiff, arrayHasDiff, arrayMerge, arrayUnion } from "./arrays"; + +/** + * Gets a new object which represents the provided object, excluding some properties. + * @param a The object to strip properties of. Must be defined. + * @param props The property names to remove. + * @returns The new object without the provided properties. + */ +export function objectExcluding(a: any, props: string[]): any { + // We use a Map to avoid hammering the `delete` keyword, which is slow and painful. + const tempMap = new Map(Object.entries(a)); + for (const prop of props) { + tempMap.delete(prop); + } + + // Convert the map to an object again + return Array.from(tempMap.entries()).reduce((c, [k, v]) => { + c[k] = v; + return c; + }, {}); +} + +/** + * Gets a new object which represents the provided object, with only some properties + * included. + * @param a The object to clone properties of. Must be defined. + * @param props The property names to keep. + * @returns The new object with only the provided properties. + */ +export function objectWithOnly(a: any, props: string[]): any { + const existingProps = Object.keys(a); + const diff = arrayDiff(existingProps, props); + if (diff.removed.length === 0) { + return objectShallowClone(a); + } else { + return objectExcluding(a, diff.removed); + } +} + +/** + * Clones an object to a caller-controlled depth. When a propertyCloner is supplied, the + * object's properties will be passed through it with the return value used as the new + * object's type. This is intended to be used to deep clone a reference, but without + * having to deep clone the entire object. This function is safe to call recursively within + * the propertyCloner. + * @param a The object to clone. Must be defined. + * @param propertyCloner The function to clone the properties of the object with, optionally. + * First argument is the property key with the second being the current value. + * @returns A cloned object. + */ +export function objectShallowClone(a: any, propertyCloner?: (k: string, v: any) => any): any { + const newObj = {}; + for (const [k, v] of Object.entries(a)) { + newObj[k] = v; + if (propertyCloner) { + newObj[k] = propertyCloner(k, v); + } + } + return newObj; +} + +/** + * Determines if any keys were added, removed, or changed between two objects. + * For changes, simple triple equal comparisons are done, not in-depth + * tree checking. + * @param a The first object. Must be defined. + * @param b The second object. Must be defined. + * @returns True if there's a difference between the objects, false otherwise + */ +export function objectHasDiff(a: any, b: any): boolean { + const aKeys = Object.keys(a); + const bKeys = Object.keys(b); + if (arrayHasDiff(aKeys, bKeys)) return true; + + const possibleChanges = arrayUnion(aKeys, bKeys); + return possibleChanges.some(k => a[k] !== b[k]); +} /** * Determines the keys added, changed, and removed between two objects. diff --git a/src/verification.js b/src/verification.js index 1dccb7dc28..36fb8b0e4f 100644 --- a/src/verification.js +++ b/src/verification.js @@ -19,10 +19,11 @@ import dis from "./dispatcher/dispatcher"; import Modal from './Modal'; import * as sdk from './index'; import { _t } from './languageHandler'; -import {RIGHT_PANEL_PHASES} from "./stores/RightPanelStorePhases"; +import {RightPanelPhases} from "./stores/RightPanelStorePhases"; import {findDMForUser} from './createRoom'; import {accessSecretStorage} from './CrossSigningManager'; import {verificationMethods} from 'matrix-js-sdk/src/crypto'; +import {Action} from './dispatcher/actions'; async function enable4SIfNeeded() { const cli = MatrixClientPeg.get(); @@ -91,8 +92,8 @@ export async function verifyDevice(user, device) { verificationMethods.SAS, ); dis.dispatch({ - action: "set_right_panel_phase", - phase: RIGHT_PANEL_PHASES.EncryptionPanel, + action: Action.SetRightPanelPhase, + phase: RightPanelPhases.EncryptionPanel, refireParams: {member: user, verificationRequestPromise}, }); } else if (action === "legacy") { @@ -120,8 +121,8 @@ export async function legacyVerifyUser(user) { } const verificationRequestPromise = cli.requestVerification(user.userId); dis.dispatch({ - action: "set_right_panel_phase", - phase: RIGHT_PANEL_PHASES.EncryptionPanel, + action: Action.SetRightPanelPhase, + phase: RightPanelPhases.EncryptionPanel, refireParams: {member: user, verificationRequestPromise}, }); } @@ -132,8 +133,8 @@ export async function verifyUser(user) { } const existingRequest = pendingVerificationRequestForUser(user); dis.dispatch({ - action: "set_right_panel_phase", - phase: RIGHT_PANEL_PHASES.EncryptionPanel, + action: Action.SetRightPanelPhase, + phase: RightPanelPhases.EncryptionPanel, refireParams: { member: user, verificationRequest: existingRequest, diff --git a/test/components/views/messages/TextualBody-test.js b/test/components/views/messages/TextualBody-test.js index 1f0749aff5..07cd51edbd 100644 --- a/test/components/views/messages/TextualBody-test.js +++ b/test/components/views/messages/TextualBody-test.js @@ -205,9 +205,8 @@ describe("", () => { expect(content.html()).toBe('' + 'Hey ' + '' + - 'Member' + + 'Member' + ''); }); }); diff --git a/test/editor/model-test.js b/test/editor/model-test.js index 2a3584d508..2df9fdd573 100644 --- a/test/editor/model-test.js +++ b/test/editor/model-test.js @@ -281,5 +281,38 @@ describe('editor/model', function() { expect(model.parts[0].type).toBe("plain"); expect(model.parts[0].text).toBe("try #define"); }); + + it('insert room pill without splitting at the colon', () => { + const renderer = createRenderer(); + const pc = createPartCreator([{resourceId: "#room:server"}]); + const model = new EditorModel([], pc, renderer); + + model.update("#roo", "insertText", {offset: 4, atNodeEnd: true}); + + expect(renderer.count).toBe(1); + expect(model.parts.length).toBe(1); + expect(model.parts[0].type).toBe("pill-candidate"); + expect(model.parts[0].text).toBe("#roo"); + + model.update("#room:s", "insertText", {offset: 7, atNodeEnd: true}); + + expect(renderer.count).toBe(2); + expect(model.parts.length).toBe(1); + expect(model.parts[0].type).toBe("pill-candidate"); + expect(model.parts[0].text).toBe("#room:s"); + }); + + it('allow typing e-mail addresses without splitting at the @', () => { + const renderer = createRenderer(); + const pc = createPartCreator([{resourceId: "@alice", label: "Alice"}]); + const model = new EditorModel([], pc, renderer); + + model.update("foo@a", "insertText", {offset: 5, atNodeEnd: true}); + + expect(renderer.count).toBe(1); + expect(model.parts.length).toBe(1); + expect(model.parts[0].type).toBe("plain"); + expect(model.parts[0].text).toBe("foo@a"); + }); }); }); diff --git a/tslint.json b/tslint.json deleted file mode 100644 index fd99d9d228..0000000000 --- a/tslint.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "rules": { - "class-name": false, - "comment-format": [ - true - ], - "curly": false, - "eofline": false, - "forin": false, - "indent": [ - true, - "spaces" - ], - "label-position": true, - "max-line-length": false, - "member-access": false, - "member-ordering": [ - true, - "static-after-instance", - "variables-before-functions" - ], - "no-arg": true, - "no-bitwise": false, - "no-console": false, - "no-construct": true, - "no-debugger": true, - "no-duplicate-variable": true, - "no-empty": false, - "no-eval": true, - "no-inferrable-types": true, - "no-shadowed-variable": true, - "no-string-literal": false, - "no-switch-case-fall-through": true, - "no-trailing-whitespace": true, - "no-unused-expression": true, - "no-use-before-declare": false, - "no-var-keyword": true, - "object-literal-sort-keys": false, - "one-line": [ - true, - "check-open-brace", - "check-catch", - "check-else", - "check-whitespace" - ], - "quotemark": false, - "radix": true, - "semicolon": [ - true, - "always", - "strict-bound-class-methods" - ], - "triple-equals": [], - "typedef-whitespace": [ - true, - { - "call-signature": "nospace", - "index-signature": "nospace", - "parameter": "nospace", - "property-declaration": "nospace", - "variable-declaration": "nospace" - } - ], - "variable-name": false, - "whitespace": [ - true, - "check-branch", - "check-decl", - "check-operator", - "check-separator", - "check-type" - ] - } -} diff --git a/yarn.lock b/yarn.lock index f721d47a36..edbd8c1a2c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,16 +2,16 @@ # yarn lockfile v1 -"@babel/cli@^7.7.5": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.10.1.tgz#b6e5cd43a17b8f639442ab027976408ebe6d79a0" - integrity sha512-cVB+dXeGhMOqViIaZs3A9OUAe4pKw4SBNdMw6yHJMYR7s4TB+Cei7ThquV/84O19PdIFWuwe03vxxES0BHUm5g== +"@babel/cli@^7.10.5": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.10.5.tgz#57df2987c8cf89d0fc7d4b157ec59d7619f1b77a" + integrity sha512-j9H9qSf3kLdM0Ao3aGPbGZ73mEA9XazuupcS6cDGWuiyAcANoguhP0r2Lx32H5JGw4sSSoHG3x/mxVnHgvOoyA== dependencies: commander "^4.0.1" convert-source-map "^1.1.0" fs-readdir-recursive "^1.1.0" glob "^7.0.0" - lodash "^4.17.13" + lodash "^4.17.19" make-dir "^2.1.0" slash "^2.0.0" source-map "^0.5.0" @@ -32,16 +32,23 @@ dependencies: "@babel/highlight" "^7.10.1" -"@babel/compat-data@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.10.1.tgz#b1085ffe72cd17bf2c0ee790fc09f9626011b2db" - integrity sha512-CHvCj7So7iCkGKPRFUfryXIkU2gSBw7VSZFYLsqVhrS47269VK2Hfi9S/YcublPMW8k1u2bQBlbDruoQEm4fgw== +"@babel/code-frame@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" + integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== + dependencies: + "@babel/highlight" "^7.10.4" + +"@babel/compat-data@^7.10.4": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.10.5.tgz#d38425e67ea96b1480a3f50404d1bf85676301a6" + integrity sha512-mPVoWNzIpYJHbWje0if7Ck36bpbtTvIxOi9+6WSK9wjGEXearAqlwBoTQvVjsAY2VIwgcs8V940geY3okzRCEw== dependencies: browserslist "^4.12.0" invariant "^2.2.4" semver "^5.5.0" -"@babel/core@>=7.2.2", "@babel/core@^7.1.0", "@babel/core@^7.7.5": +"@babel/core@>=7.2.2", "@babel/core@^7.1.0": version "7.10.2" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.10.2.tgz#bd6786046668a925ac2bd2fd95b579b92a23b36a" integrity sha512-KQmV9yguEjQsXqyOUGKjS4+3K8/DlOCE2pZcq4augdQmtTy5iv5EHtmMSJ7V4c1BIPjuwtZYqYLCq9Ga+hGBRQ== @@ -63,6 +70,28 @@ semver "^5.4.1" source-map "^0.5.0" +"@babel/core@^7.10.5": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.10.5.tgz#1f15e2cca8ad9a1d78a38ddba612f5e7cdbbd330" + integrity sha512-O34LQooYVDXPl7QWCdW9p4NR+QlzOr7xShPPJz8GsuCU3/8ua/wqTr7gmnxXv+WBESiGU/G5s16i6tUvHkNb+w== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.10.5" + "@babel/helper-module-transforms" "^7.10.5" + "@babel/helpers" "^7.10.4" + "@babel/parser" "^7.10.5" + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.10.5" + "@babel/types" "^7.10.5" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.1" + json5 "^2.1.2" + lodash "^4.17.19" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + "@babel/generator@^7.10.1", "@babel/generator@^7.10.2", "@babel/generator@^7.4.0": version "7.10.2" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.10.2.tgz#0fa5b5b2389db8bfdfcc3492b551ee20f5dd69a9" @@ -73,6 +102,24 @@ lodash "^4.17.13" source-map "^0.5.0" +"@babel/generator@^7.10.4", "@babel/generator@^7.10.5": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.10.5.tgz#1b903554bc8c583ee8d25f1e8969732e6b829a69" + integrity sha512-3vXxr3FEW7E7lJZiWQ3bM4+v/Vyr9C+hpolQ8BGFr9Y8Ri2tFLWTixmwKBafDujO1WVah4fhZBeU1bieKdghig== + dependencies: + "@babel/types" "^7.10.5" + jsesc "^2.5.1" + source-map "^0.5.0" + +"@babel/generator@^7.11.0": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.11.0.tgz#4b90c78d8c12825024568cbe83ee6c9af193585c" + integrity sha512-fEm3Uzw7Mc9Xi//qU20cBKatTfs2aOtKqmvy/Vm7RkJEGFQ4xc9myCfbXxqK//ZS8MR/ciOHw6meGASJuKmDfQ== + dependencies: + "@babel/types" "^7.11.0" + jsesc "^2.5.1" + source-map "^0.5.0" + "@babel/helper-annotate-as-pure@^7.10.1": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.1.tgz#f6d08acc6f70bbd59b436262553fb2e259a1a268" @@ -80,55 +127,62 @@ dependencies: "@babel/types" "^7.10.1" -"@babel/helper-builder-binary-assignment-operator-visitor@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.1.tgz#0ec7d9be8174934532661f87783eb18d72290059" - integrity sha512-cQpVq48EkYxUU0xozpGCLla3wlkdRRqLWu1ksFMXA9CM5KQmyyRpSEsYXbao7JUkOw/tAaYKCaYyZq6HOFYtyw== +"@babel/helper-annotate-as-pure@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3" + integrity sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA== dependencies: - "@babel/helper-explode-assignable-expression" "^7.10.1" - "@babel/types" "^7.10.1" + "@babel/types" "^7.10.4" -"@babel/helper-builder-react-jsx-experimental@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx-experimental/-/helper-builder-react-jsx-experimental-7.10.1.tgz#9a7d58ad184d3ac3bafb1a452cec2bad7e4a0bc8" - integrity sha512-irQJ8kpQUV3JasXPSFQ+LCCtJSc5ceZrPFVj6TElR6XCHssi3jV8ch3odIrNtjJFRZZVbrOEfJMI79TPU/h1pQ== +"@babel/helper-builder-binary-assignment-operator-visitor@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz#bb0b75f31bf98cbf9ff143c1ae578b87274ae1a3" + integrity sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg== dependencies: - "@babel/helper-annotate-as-pure" "^7.10.1" - "@babel/helper-module-imports" "^7.10.1" - "@babel/types" "^7.10.1" + "@babel/helper-explode-assignable-expression" "^7.10.4" + "@babel/types" "^7.10.4" -"@babel/helper-builder-react-jsx@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.10.1.tgz#a327f0cf983af5554701b1215de54a019f09b532" - integrity sha512-KXzzpyWhXgzjXIlJU1ZjIXzUPdej1suE6vzqgImZ/cpAsR/CC8gUcX4EWRmDfWz/cs6HOCPMBIJ3nKoXt3BFuw== +"@babel/helper-builder-react-jsx-experimental@^7.10.4": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx-experimental/-/helper-builder-react-jsx-experimental-7.10.5.tgz#f35e956a19955ff08c1258e44a515a6d6248646b" + integrity sha512-Buewnx6M4ttG+NLkKyt7baQn7ScC/Td+e99G914fRU8fGIUivDDgVIQeDHFa5e4CRSJQt58WpNHhsAZgtzVhsg== dependencies: - "@babel/helper-annotate-as-pure" "^7.10.1" - "@babel/types" "^7.10.1" + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-module-imports" "^7.10.4" + "@babel/types" "^7.10.5" -"@babel/helper-compilation-targets@^7.10.2": - version "7.10.2" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.2.tgz#a17d9723b6e2c750299d2a14d4637c76936d8285" - integrity sha512-hYgOhF4To2UTB4LTaZepN/4Pl9LD4gfbJx8A34mqoluT8TLbof1mhUlYuNWTEebONa8+UlCC4X0TEXu7AOUyGA== +"@babel/helper-builder-react-jsx@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.10.4.tgz#8095cddbff858e6fa9c326daee54a2f2732c1d5d" + integrity sha512-5nPcIZ7+KKDxT1427oBivl9V9YTal7qk0diccnh7RrcgrT/pGFOjgGw1dgryyx1GvHEpXVfoDF6Ak3rTiWh8Rg== dependencies: - "@babel/compat-data" "^7.10.1" + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/types" "^7.10.4" + +"@babel/helper-compilation-targets@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.4.tgz#804ae8e3f04376607cc791b9d47d540276332bd2" + integrity sha512-a3rYhlsGV0UHNDvrtOXBg8/OpfV0OKTkxKPzIplS1zpx7CygDcWWxckxZeDd3gzPzC4kUT0A4nVFDK0wGMh4MQ== + dependencies: + "@babel/compat-data" "^7.10.4" browserslist "^4.12.0" invariant "^2.2.4" levenary "^1.1.1" semver "^5.5.0" -"@babel/helper-create-class-features-plugin@^7.10.1": - version "7.10.2" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.2.tgz#7474295770f217dbcf288bf7572eb213db46ee67" - integrity sha512-5C/QhkGFh1vqcziq1vAL6SI9ymzUp8BCYjFpvYVhWP4DlATIb3u5q3iUd35mvlyGs8fO7hckkW7i0tmH+5+bvQ== +"@babel/helper-create-class-features-plugin@^7.10.4", "@babel/helper-create-class-features-plugin@^7.10.5": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.5.tgz#9f61446ba80e8240b0a5c85c6fdac8459d6f259d" + integrity sha512-0nkdeijB7VlZoLT3r/mY3bUkw3T8WG/hNw+FATs/6+pG2039IJWjTYL0VTISqsNHMUTEnwbVnc89WIJX9Qed0A== dependencies: - "@babel/helper-function-name" "^7.10.1" - "@babel/helper-member-expression-to-functions" "^7.10.1" - "@babel/helper-optimise-call-expression" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" - "@babel/helper-replace-supers" "^7.10.1" - "@babel/helper-split-export-declaration" "^7.10.1" + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-member-expression-to-functions" "^7.10.5" + "@babel/helper-optimise-call-expression" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-replace-supers" "^7.10.4" + "@babel/helper-split-export-declaration" "^7.10.4" -"@babel/helper-create-regexp-features-plugin@^7.10.1", "@babel/helper-create-regexp-features-plugin@^7.8.3": +"@babel/helper-create-regexp-features-plugin@^7.10.1": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.1.tgz#1b8feeab1594cbcfbf3ab5a3bbcabac0468efdbd" integrity sha512-Rx4rHS0pVuJn5pJOqaqcZR4XSgeF9G/pO/79t+4r7380tXFJdzImFnxMU19f83wjSrmKHq6myrM10pFHTGzkUA== @@ -137,22 +191,31 @@ "@babel/helper-regex" "^7.10.1" regexpu-core "^4.7.0" -"@babel/helper-define-map@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.10.1.tgz#5e69ee8308648470dd7900d159c044c10285221d" - integrity sha512-+5odWpX+OnvkD0Zmq7panrMuAGQBu6aPUgvMzuMGo4R+jUOvealEj2hiqI6WhxgKrTpFoFj0+VdsuA8KDxHBDg== +"@babel/helper-create-regexp-features-plugin@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz#fdd60d88524659a0b6959c0579925e425714f3b8" + integrity sha512-2/hu58IEPKeoLF45DBwx3XFqsbCXmkdAay4spVr2x0jYgRxrSNp+ePwvSsy9g6YSaNDcKIQVPXk1Ov8S2edk2g== dependencies: - "@babel/helper-function-name" "^7.10.1" - "@babel/types" "^7.10.1" - lodash "^4.17.13" + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-regex" "^7.10.4" + regexpu-core "^4.7.0" -"@babel/helper-explode-assignable-expression@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.10.1.tgz#e9d76305ee1162ca467357ae25df94f179af2b7e" - integrity sha512-vcUJ3cDjLjvkKzt6rHrl767FeE7pMEYfPanq5L16GRtrXIoznc0HykNW2aEYkcnP76P0isoqJ34dDMFZwzEpJg== +"@babel/helper-define-map@^7.10.4": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz#b53c10db78a640800152692b13393147acb9bb30" + integrity sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ== dependencies: - "@babel/traverse" "^7.10.1" - "@babel/types" "^7.10.1" + "@babel/helper-function-name" "^7.10.4" + "@babel/types" "^7.10.5" + lodash "^4.17.19" + +"@babel/helper-explode-assignable-expression@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.10.4.tgz#40a1cd917bff1288f699a94a75b37a1a2dbd8c7c" + integrity sha512-4K71RyRQNPRrR85sr5QY4X3VwG4wtVoXZB9+L3r1Gp38DhELyHCtovqydRi7c1Ovb17eRGiQ/FD5s8JdU0Uy5A== + dependencies: + "@babel/traverse" "^7.10.4" + "@babel/types" "^7.10.4" "@babel/helper-function-name@^7.10.1": version "7.10.1" @@ -163,6 +226,15 @@ "@babel/template" "^7.10.1" "@babel/types" "^7.10.1" +"@babel/helper-function-name@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a" + integrity sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ== + dependencies: + "@babel/helper-get-function-arity" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/types" "^7.10.4" + "@babel/helper-get-function-arity@^7.10.1": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.1.tgz#7303390a81ba7cb59613895a192b93850e373f7d" @@ -170,12 +242,19 @@ dependencies: "@babel/types" "^7.10.1" -"@babel/helper-hoist-variables@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.1.tgz#7e77c82e5dcae1ebf123174c385aaadbf787d077" - integrity sha512-vLm5srkU8rI6X3+aQ1rQJyfjvCBLXP8cAGeuw04zeAM2ItKb1e7pmVmLyHb4sDaAYnLL13RHOZPLEtcGZ5xvjg== +"@babel/helper-get-function-arity@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2" + integrity sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A== dependencies: - "@babel/types" "^7.10.1" + "@babel/types" "^7.10.4" + +"@babel/helper-hoist-variables@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz#d49b001d1d5a68ca5e6604dda01a6297f7c9381e" + integrity sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA== + dependencies: + "@babel/types" "^7.10.4" "@babel/helper-member-expression-to-functions@^7.10.1": version "7.10.1" @@ -184,6 +263,13 @@ dependencies: "@babel/types" "^7.10.1" +"@babel/helper-member-expression-to-functions@^7.10.4", "@babel/helper-member-expression-to-functions@^7.10.5": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.5.tgz#172f56e7a63e78112f3a04055f24365af702e7ee" + integrity sha512-HiqJpYD5+WopCXIAbQDG0zye5XYVvcO9w/DHp5GsaGkRUaamLj2bEtu6i8rnGGprAhHM3qidCMgp71HF4endhA== + dependencies: + "@babel/types" "^7.10.5" + "@babel/helper-module-imports@^7.10.1": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.1.tgz#dd331bd45bccc566ce77004e9d05fe17add13876" @@ -191,6 +277,13 @@ dependencies: "@babel/types" "^7.10.1" +"@babel/helper-module-imports@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620" + integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw== + dependencies: + "@babel/types" "^7.10.4" + "@babel/helper-module-transforms@^7.10.1": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.10.1.tgz#24e2f08ee6832c60b157bb0936c86bef7210c622" @@ -204,6 +297,19 @@ "@babel/types" "^7.10.1" lodash "^4.17.13" +"@babel/helper-module-transforms@^7.10.4", "@babel/helper-module-transforms@^7.10.5": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.10.5.tgz#120c271c0b3353673fcdfd8c053db3c544a260d6" + integrity sha512-4P+CWMJ6/j1W915ITJaUkadLObmCRRSC234uctJfn/vHrsLNxsR8dwlcXv9ZhJWzl77awf+mWXSZEKt5t0OnlA== + dependencies: + "@babel/helper-module-imports" "^7.10.4" + "@babel/helper-replace-supers" "^7.10.4" + "@babel/helper-simple-access" "^7.10.4" + "@babel/helper-split-export-declaration" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/types" "^7.10.5" + lodash "^4.17.19" + "@babel/helper-optimise-call-expression@^7.10.1": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.1.tgz#b4a1f2561870ce1247ceddb02a3860fa96d72543" @@ -211,11 +317,23 @@ dependencies: "@babel/types" "^7.10.1" +"@babel/helper-optimise-call-expression@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673" + integrity sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg== + dependencies: + "@babel/types" "^7.10.4" + "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.1", "@babel/helper-plugin-utils@^7.8.0": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.1.tgz#ec5a5cf0eec925b66c60580328b122c01230a127" integrity sha512-fvoGeXt0bJc7VMWZGCAEBEMo/HAjW2mP8apF5eXK0wSqwLAVHAISCWRoLMBMUs2kqeaG77jltVqu4Hn8Egl3nA== +"@babel/helper-plugin-utils@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" + integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== + "@babel/helper-regex@^7.10.1": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.10.1.tgz#021cf1a7ba99822f993222a001cc3fec83255b96" @@ -223,16 +341,23 @@ dependencies: lodash "^4.17.13" -"@babel/helper-remap-async-to-generator@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.10.1.tgz#bad6aaa4ff39ce8d4b82ccaae0bfe0f7dbb5f432" - integrity sha512-RfX1P8HqsfgmJ6CwaXGKMAqbYdlleqglvVtht0HGPMSsy2V6MqLlOJVF/0Qyb/m2ZCi2z3q3+s6Pv7R/dQuZ6A== +"@babel/helper-regex@^7.10.4": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.10.5.tgz#32dfbb79899073c415557053a19bd055aae50ae0" + integrity sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg== dependencies: - "@babel/helper-annotate-as-pure" "^7.10.1" - "@babel/helper-wrap-function" "^7.10.1" - "@babel/template" "^7.10.1" - "@babel/traverse" "^7.10.1" - "@babel/types" "^7.10.1" + lodash "^4.17.19" + +"@babel/helper-remap-async-to-generator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.10.4.tgz#fce8bea4e9690bbe923056ded21e54b4e8b68ed5" + integrity sha512-86Lsr6NNw3qTNl+TBcF1oRZMaVzJtbWTyTko+CQL/tvNvcGYEFKbLXDPxtW0HKk3McNOk4KzY55itGWCAGK5tg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-wrap-function" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.10.4" + "@babel/types" "^7.10.4" "@babel/helper-replace-supers@^7.10.1": version "7.10.1" @@ -244,6 +369,16 @@ "@babel/traverse" "^7.10.1" "@babel/types" "^7.10.1" +"@babel/helper-replace-supers@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz#d585cd9388ea06e6031e4cd44b6713cbead9e6cf" + integrity sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.10.4" + "@babel/helper-optimise-call-expression" "^7.10.4" + "@babel/traverse" "^7.10.4" + "@babel/types" "^7.10.4" + "@babel/helper-simple-access@^7.10.1": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.1.tgz#08fb7e22ace9eb8326f7e3920a1c2052f13d851e" @@ -252,6 +387,14 @@ "@babel/template" "^7.10.1" "@babel/types" "^7.10.1" +"@babel/helper-simple-access@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz#0f5ccda2945277a2a7a2d3a821e15395edcf3461" + integrity sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw== + dependencies: + "@babel/template" "^7.10.4" + "@babel/types" "^7.10.4" + "@babel/helper-split-export-declaration@^7.10.1": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.1.tgz#c6f4be1cbc15e3a868e4c64a17d5d31d754da35f" @@ -259,20 +402,39 @@ dependencies: "@babel/types" "^7.10.1" +"@babel/helper-split-export-declaration@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.4.tgz#2c70576eaa3b5609b24cb99db2888cc3fc4251d1" + integrity sha512-pySBTeoUff56fL5CBU2hWm9TesA4r/rOkI9DyJLvvgz09MB9YtfIYe3iBriVaYNaPe+Alua0vBIOVOLs2buWhg== + dependencies: + "@babel/types" "^7.10.4" + +"@babel/helper-split-export-declaration@^7.11.0": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz#f8a491244acf6a676158ac42072911ba83ad099f" + integrity sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg== + dependencies: + "@babel/types" "^7.11.0" + "@babel/helper-validator-identifier@^7.10.1", "@babel/helper-validator-identifier@^7.10.3": version "7.10.3" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.3.tgz#60d9847f98c4cea1b279e005fdb7c28be5412d15" integrity sha512-bU8JvtlYpJSBPuj1VUmKpFGaDZuLxASky3LhaKj3bmpSTY6VWooSM8msk+Z0CZoErFye2tlABF6yDkT3FOPAXw== -"@babel/helper-wrap-function@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.10.1.tgz#956d1310d6696257a7afd47e4c42dfda5dfcedc9" - integrity sha512-C0MzRGteVDn+H32/ZgbAv5r56f2o1fZSA/rj/TYo8JEJNHg+9BdSmKBUND0shxWRztWhjlT2cvHYuynpPsVJwQ== +"@babel/helper-validator-identifier@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" + integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw== + +"@babel/helper-wrap-function@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz#8a6f701eab0ff39f765b5a1cfef409990e624b87" + integrity sha512-6py45WvEF0MhiLrdxtRjKjufwLL1/ob2qDJgg5JgNdojBAZSAKnAjkyOCNug6n+OBl4VW76XjvgSFTdaMcW0Ug== dependencies: - "@babel/helper-function-name" "^7.10.1" - "@babel/template" "^7.10.1" - "@babel/traverse" "^7.10.1" - "@babel/types" "^7.10.1" + "@babel/helper-function-name" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.10.4" + "@babel/types" "^7.10.4" "@babel/helpers@^7.10.1": version "7.10.1" @@ -283,6 +445,15 @@ "@babel/traverse" "^7.10.1" "@babel/types" "^7.10.1" +"@babel/helpers@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.10.4.tgz#2abeb0d721aff7c0a97376b9e1f6f65d7a475044" + integrity sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA== + dependencies: + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.10.4" + "@babel/types" "^7.10.4" + "@babel/highlight@^7.10.1", "@babel/highlight@^7.10.3": version "7.10.3" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.3.tgz#c633bb34adf07c5c13156692f5922c81ec53f28d" @@ -292,111 +463,138 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@babel/highlight@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143" + integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA== + dependencies: + "@babel/helper-validator-identifier" "^7.10.4" + chalk "^2.0.0" + js-tokens "^4.0.0" + "@babel/parser@^7.1.0", "@babel/parser@^7.10.1", "@babel/parser@^7.10.2", "@babel/parser@^7.4.3", "@babel/parser@^7.7.0": version "7.10.2" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.2.tgz#871807f10442b92ff97e4783b9b54f6a0ca812d0" integrity sha512-PApSXlNMJyB4JiGVhCOlzKIif+TKFTvu0aQAhnTvfP/z3vVSN6ZypH5bfUNwFXXjRQtUEBNFd2PtmCmG2Py3qQ== -"@babel/plugin-proposal-async-generator-functions@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.1.tgz#6911af5ba2e615c4ff3c497fe2f47b35bf6d7e55" - integrity sha512-vzZE12ZTdB336POZjmpblWfNNRpMSua45EYnRigE2XsZxcXcIyly2ixnTJasJE4Zq3U7t2d8rRF7XRUuzHxbOw== +"@babel/parser@^7.10.4", "@babel/parser@^7.10.5": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.5.tgz#e7c6bf5a7deff957cec9f04b551e2762909d826b" + integrity sha512-wfryxy4bE1UivvQKSQDU4/X6dr+i8bctjUjj8Zyt3DQy7NtPizJXT8M52nqpNKL+nq2PW8lxk4ZqLj0fD4B4hQ== + +"@babel/parser@^7.11.0": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.11.0.tgz#a9d7e11aead25d3b422d17b2c6502c8dddef6a5d" + integrity sha512-qvRvi4oI8xii8NllyEc4MDJjuZiNaRzyb7Y7lup1NqJV8TZHF4O27CcP+72WPn/k1zkgJ6WJfnIbk4jTsVAZHw== + +"@babel/plugin-proposal-async-generator-functions@^7.10.4": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.5.tgz#3491cabf2f7c179ab820606cec27fed15e0e8558" + integrity sha512-cNMCVezQbrRGvXJwm9fu/1sJj9bHdGAgKodZdLqOQIpfoH3raqmRPBM17+lh7CzhiKRRBrGtZL9WcjxSoGYUSg== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" - "@babel/helper-remap-async-to-generator" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-remap-async-to-generator" "^7.10.4" "@babel/plugin-syntax-async-generators" "^7.8.0" -"@babel/plugin-proposal-class-properties@^7.10.1", "@babel/plugin-proposal-class-properties@^7.7.4": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.1.tgz#046bc7f6550bb08d9bd1d4f060f5f5a4f1087e01" - integrity sha512-sqdGWgoXlnOdgMXU+9MbhzwFRgxVLeiGBqTrnuS7LC2IBU31wSsESbTUreT2O418obpfPdGUR2GbEufZF1bpqw== +"@babel/plugin-proposal-class-properties@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz#a33bf632da390a59c7a8c570045d1115cd778807" + integrity sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg== dependencies: - "@babel/helper-create-class-features-plugin" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-create-class-features-plugin" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-proposal-decorators@^7.7.4": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.10.1.tgz#9373c2d8db45345c6e30452ad77b469758e5c8f7" - integrity sha512-xBfteh352MTke2U1NpclzMDmAmCdQ2fBZjhZQQfGTjXw6qcRYMkt528sA1U8o0ThDCSeuETXIj5bOGdxN+5gkw== +"@babel/plugin-proposal-decorators@^7.10.5": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.10.5.tgz#42898bba478bc4b1ae242a703a953a7ad350ffb4" + integrity sha512-Sc5TAQSZuLzgY0664mMDn24Vw2P8g/VhyLyGPaWiHahhgLqeZvcGeyBZOrJW0oSKIK2mvQ22a1ENXBIQLhrEiQ== dependencies: - "@babel/helper-create-class-features-plugin" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" - "@babel/plugin-syntax-decorators" "^7.10.1" + "@babel/helper-create-class-features-plugin" "^7.10.5" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-decorators" "^7.10.4" -"@babel/plugin-proposal-dynamic-import@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.1.tgz#e36979dc1dc3b73f6d6816fc4951da2363488ef0" - integrity sha512-Cpc2yUVHTEGPlmiQzXj026kqwjEQAD9I4ZC16uzdbgWgitg/UHKHLffKNCQZ5+y8jpIZPJcKcwsr2HwPh+w3XA== +"@babel/plugin-proposal-dynamic-import@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.4.tgz#ba57a26cb98b37741e9d5bca1b8b0ddf8291f17e" + integrity sha512-up6oID1LeidOOASNXgv/CFbgBqTuKJ0cJjz6An5tWD+NVBNlp3VNSBxv2ZdU7SYl3NxJC7agAQDApZusV6uFwQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-dynamic-import" "^7.8.0" -"@babel/plugin-proposal-export-default-from@^7.7.4": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.10.1.tgz#59ea2a4f09dbb0358c73dab27def3d21a27bd370" - integrity sha512-Xfc1CfHapIkwZ/+AI+j4Ha3g233ol0EEdy6SmnUuQQiZX78SfQXHd8tmntc5zqCkwPnIHoiZa6l6p0OAvxYXHw== +"@babel/plugin-proposal-export-default-from@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.10.4.tgz#08f66eef0067cbf6a7bc036977dcdccecaf0c6c5" + integrity sha512-G1l00VvDZ7Yk2yRlC5D8Ybvu3gmeHS3rCHoUYdjrqGYUtdeOBoRypnvDZ5KQqxyaiiGHWnVDeSEzA5F9ozItig== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" - "@babel/plugin-syntax-export-default-from" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-export-default-from" "^7.10.4" -"@babel/plugin-proposal-json-strings@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.10.1.tgz#b1e691ee24c651b5a5e32213222b2379734aff09" - integrity sha512-m8r5BmV+ZLpWPtMY2mOKN7wre6HIO4gfIiV+eOmsnZABNenrt/kzYBwrh+KOfgumSWpnlGs5F70J8afYMSJMBg== +"@babel/plugin-proposal-json-strings@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.10.4.tgz#593e59c63528160233bd321b1aebe0820c2341db" + integrity sha512-fCL7QF0Jo83uy1K0P2YXrfX11tj3lkpN7l4dMv9Y9VkowkhkQDwFHFd8IiwyK5MZjE8UpbgokkgtcReH88Abaw== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-json-strings" "^7.8.0" -"@babel/plugin-proposal-nullish-coalescing-operator@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.1.tgz#02dca21673842ff2fe763ac253777f235e9bbf78" - integrity sha512-56cI/uHYgL2C8HVuHOuvVowihhX0sxb3nnfVRzUeVHTWmRHTZrKuAh/OBIMggGU/S1g/1D2CRCXqP+3u7vX7iA== +"@babel/plugin-proposal-nullish-coalescing-operator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.4.tgz#02a7e961fc32e6d5b2db0649e01bf80ddee7e04a" + integrity sha512-wq5n1M3ZUlHl9sqT2ok1T2/MTt6AXE0e1Lz4WzWBr95LsAZ5qDXe4KnFuauYyEyLiohvXFMdbsOTMyLZs91Zlw== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" -"@babel/plugin-proposal-numeric-separator@^7.10.1", "@babel/plugin-proposal-numeric-separator@^7.7.4": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.10.1.tgz#a9a38bc34f78bdfd981e791c27c6fdcec478c123" - integrity sha512-jjfym4N9HtCiNfyyLAVD8WqPYeHUrw4ihxuAynWj6zzp2gf9Ey2f7ImhFm6ikB3CLf5Z/zmcJDri6B4+9j9RsA== +"@babel/plugin-proposal-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.10.4.tgz#ce1590ff0a65ad12970a609d78855e9a4c1aef06" + integrity sha512-73/G7QoRoeNkLZFxsoCCvlg4ezE4eM+57PnOqgaPOozd5myfj7p0muD1mRVJvbUWbOzD+q3No2bWbaKy+DJ8DA== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" - "@babel/plugin-syntax-numeric-separator" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-proposal-object-rest-spread@^7.10.1", "@babel/plugin-proposal-object-rest-spread@^7.7.4": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.10.1.tgz#cba44908ac9f142650b4a65b8aa06bf3478d5fb6" - integrity sha512-Z+Qri55KiQkHh7Fc4BW6o+QBuTagbOp9txE+4U1i79u9oWlf2npkiDx+Rf3iK3lbcHBuNy9UOkwuR5wOMH3LIQ== +"@babel/plugin-proposal-object-rest-spread@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.10.4.tgz#50129ac216b9a6a55b3853fdd923e74bf553a4c0" + integrity sha512-6vh4SqRuLLarjgeOf4EaROJAHjvu9Gl+/346PbDH9yWbJyfnJ/ah3jmYKYtswEyCoWZiidvVHjHshd4WgjB9BA== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-object-rest-spread" "^7.8.0" - "@babel/plugin-transform-parameters" "^7.10.1" + "@babel/plugin-transform-parameters" "^7.10.4" -"@babel/plugin-proposal-optional-catch-binding@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.1.tgz#c9f86d99305f9fa531b568ff5ab8c964b8b223d2" - integrity sha512-VqExgeE62YBqI3ogkGoOJp1R6u12DFZjqwJhqtKc2o5m1YTUuUWnos7bZQFBhwkxIFpWYJ7uB75U7VAPPiKETA== +"@babel/plugin-proposal-optional-catch-binding@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.4.tgz#31c938309d24a78a49d68fdabffaa863758554dd" + integrity sha512-LflT6nPh+GK2MnFiKDyLiqSqVHkQnVf7hdoAvyTnnKj9xB3docGRsdPuxp6qqqW19ifK3xgc9U5/FwrSaCNX5g== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" -"@babel/plugin-proposal-optional-chaining@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.10.1.tgz#15f5d6d22708629451a91be28f8facc55b0e818c" - integrity sha512-dqQj475q8+/avvok72CF3AOSV/SGEcH29zT5hhohqqvvZ2+boQoOr7iGldBG5YXTO2qgCgc2B3WvVLUdbeMlGA== +"@babel/plugin-proposal-optional-chaining@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.10.4.tgz#750f1255e930a1f82d8cdde45031f81a0d0adff7" + integrity sha512-ZIhQIEeavTgouyMSdZRap4VPPHqJJ3NEs2cuHs5p0erH+iz6khB0qfgU8g7UuJkG88+fBMy23ZiU+nuHvekJeQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-optional-chaining" "^7.8.0" -"@babel/plugin-proposal-private-methods@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.1.tgz#ed85e8058ab0fe309c3f448e5e1b73ca89cdb598" - integrity sha512-RZecFFJjDiQ2z6maFprLgrdnm0OzoC23Mx89xf1CcEsxmHuzuXOdniEuI+S3v7vjQG4F5sa6YtUp+19sZuSxHg== +"@babel/plugin-proposal-private-methods@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.4.tgz#b160d972b8fdba5c7d111a145fc8c421fc2a6909" + integrity sha512-wh5GJleuI8k3emgTg5KkJK6kHNsGEr0uBTDBuQUBJwckk9xs1ez79ioheEVVxMLyPscB0LfkbVHslQqIzWV6Bw== dependencies: - "@babel/helper-create-class-features-plugin" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-create-class-features-plugin" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-proposal-unicode-property-regex@^7.10.1", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": +"@babel/plugin-proposal-unicode-property-regex@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz#4483cda53041ce3413b7fe2f00022665ddfaa75d" + integrity sha512-H+3fOgPnEXFL9zGYtKQe4IDOPKYlZdF1kqFDQRRb8PK4B8af1vAGK04tF5iQAAsui+mHNBQSAtd2/ndEDe9wuA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-proposal-unicode-property-regex@^7.4.4": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.1.tgz#dc04feb25e2dd70c12b05d680190e138fa2c0c6f" integrity sha512-JjfngYRvwmPwmnbRZyNiPFI8zxCZb8euzbCG/LxyKdeTb59tVciKo9GK9bi6JYKInk1H11Dq9j/zRqIH4KigfQ== @@ -411,19 +609,19 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.1.tgz#d5bc0645913df5b17ad7eda0fa2308330bde34c5" - integrity sha512-Gf2Yx/iRs1JREDtVZ56OrjjgFHCaldpTnuy9BHla10qyVT3YkIIGEtoDWhyop0ksu1GvNjHIoYRBqm3zoR1jyQ== +"@babel/plugin-syntax-class-properties@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.4.tgz#6644e6a0baa55a61f9e3231f6c9eeb6ee46c124c" + integrity sha512-GCSBF7iUle6rNugfURwNmCGG3Z/2+opxAMLs1nND4bhEG5PuxTIggDBoeYYSujAlLtsupzOHYJQgPS3pivwXIA== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-decorators@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.10.1.tgz#16b869c4beafc9a442565147bda7ce0967bd4f13" - integrity sha512-a9OAbQhKOwSle1Vr0NJu/ISg1sPfdEkfRKWpgPuzhnWWzForou2gIeUIIwjAMHRekhhpJ7eulZlYs0H14Cbi+g== +"@babel/plugin-syntax-decorators@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.10.4.tgz#6853085b2c429f9d322d02f5a635018cdeb2360c" + integrity sha512-2NaoC6fAk2VMdhY1eerkfHV+lVYC1u8b+jmRJISqANCJlTxYy19HGdIkkQtix2UtkcPuPu+IlDgrVseZnU03bw== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-dynamic-import@^7.8.0": version "7.8.3" @@ -432,19 +630,19 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-export-default-from@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.10.1.tgz#634f58f36b5d6320d80f75441fdc61e1c05c33b0" - integrity sha512-+rcL4S/mN1Ss4zhSCbxzv1Wsf12eauvgTjWi0krXEeX1zd6qSxYnJoniE5Ssr5w2WPt61oUCJyXIFQIqO/29zw== +"@babel/plugin-syntax-export-default-from@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.10.4.tgz#e5494f95006355c10292a0ff1ce42a5746002ec8" + integrity sha512-79V6r6Pgudz0RnuMGp5xidu6Z+bPFugh8/Q9eDHonmLp4wKFAZDwygJwYgCzuDu8lFA/sYyT+mc5y2wkd7bTXA== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-flow@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.10.1.tgz#cd4bbca62fb402babacb174f64f8734310d742f0" - integrity sha512-b3pWVncLBYoPP60UOTc7NMlbtsHQ6ITim78KQejNHK6WJ2mzV5kCcg4mIWpasAfJEgwVTibwo2e+FU7UEIKQUg== +"@babel/plugin-syntax-flow@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.10.4.tgz#53351dd7ae01995e567d04ce42af1a6e0ba846a6" + integrity sha512-yxQsX1dJixF4qEEdzVbst3SZQ58Nrooz8NV9Z9GL4byTE25BvJgl5lf0RECUf0fh28rZBb/RYTWn/eeKwCMrZQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-json-strings@^7.8.0": version "7.8.3" @@ -453,12 +651,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-jsx@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.10.1.tgz#0ae371134a42b91d5418feb3c8c8d43e1565d2da" - integrity sha512-+OxyOArpVFXQeXKLO9o+r2I4dIoVoy6+Uu0vKELrlweDM3QJADZj+Z+5ERansZqIZBcLj42vHnDI8Rz9BnRIuQ== +"@babel/plugin-syntax-jsx@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.10.4.tgz#39abaae3cbf710c4373d8429484e6ba21340166c" + integrity sha512-KCg9mio9jwiARCB7WAcQ7Y1q+qicILjoK8LP/VkPkEKaf5dkaZZK1EcTe91a3JJlZ3qy6L5s9X52boEYi8DM9g== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0": version "7.8.3" @@ -467,12 +665,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-numeric-separator@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.1.tgz#25761ee7410bc8cf97327ba741ee94e4a61b7d99" - integrity sha512-uTd0OsHrpe3tH5gRPTxG8Voh99/WCU78vIm5NMRYPAqC8lR4vajt6KkCAknCHrx24vkPdd/05yfdGSB4EIY2mg== +"@babel/plugin-syntax-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.8.0": version "7.8.3" @@ -495,80 +693,87 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-top-level-await@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.1.tgz#8b8733f8c57397b3eaa47ddba8841586dcaef362" - integrity sha512-hgA5RYkmZm8FTFT3yu2N9Bx7yVVOKYT6yEdXXo6j2JTm0wNxgqaGeQVaSHRjhfnQbX91DtjFB6McRFSlcJH3xQ== +"@babel/plugin-syntax-top-level-await@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.4.tgz#4bbeb8917b54fcf768364e0a81f560e33a3ef57d" + integrity sha512-ni1brg4lXEmWyafKr0ccFWkJG0CeMt4WV1oyeBW6EFObF4oOHclbkj5cARxAPQyAQ2UTuplJyK4nfkXIMMFvsQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-typescript@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.10.1.tgz#5e82bc27bb4202b93b949b029e699db536733810" - integrity sha512-X/d8glkrAtra7CaQGMiGs/OGa6XgUzqPcBXCIGFCpCqnfGlT0Wfbzo/B89xHhnInTaItPK8LALblVXcUOEh95Q== +"@babel/plugin-syntax-typescript@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.10.4.tgz#2f55e770d3501e83af217d782cb7517d7bb34d25" + integrity sha512-oSAEz1YkBCAKr5Yiq8/BNtvSAPwkp/IyUnwZogd8p+F0RuYQQrLeRUzIQhueQTTBy/F+a40uS7OFKxnkRvmvFQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-arrow-functions@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.1.tgz#cb5ee3a36f0863c06ead0b409b4cc43a889b295b" - integrity sha512-6AZHgFJKP3DJX0eCNJj01RpytUa3SOGawIxweHkNX2L6PYikOZmoh5B0d7hIHaIgveMjX990IAa/xK7jRTN8OA== +"@babel/plugin-transform-arrow-functions@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.4.tgz#e22960d77e697c74f41c501d44d73dbf8a6a64cd" + integrity sha512-9J/oD1jV0ZCBcgnoFWFq1vJd4msoKb/TCpGNFyyLt0zABdcvgK3aYikZ8HjzB14c26bc7E3Q1yugpwGy2aTPNA== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-async-to-generator@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.1.tgz#e5153eb1a3e028f79194ed8a7a4bf55f862b2062" - integrity sha512-XCgYjJ8TY2slj6SReBUyamJn3k2JLUIiiR5b6t1mNCMSvv7yx+jJpaewakikp0uWFQSF7ChPPoe3dHmXLpISkg== +"@babel/plugin-transform-async-to-generator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.4.tgz#41a5017e49eb6f3cda9392a51eef29405b245a37" + integrity sha512-F6nREOan7J5UXTLsDsZG3DXmZSVofr2tGNwfdrVwkDWHfQckbQXnXSPfD7iO+c/2HGqycwyLST3DnZ16n+cBJQ== dependencies: - "@babel/helper-module-imports" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" - "@babel/helper-remap-async-to-generator" "^7.10.1" + "@babel/helper-module-imports" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-remap-async-to-generator" "^7.10.4" -"@babel/plugin-transform-block-scoped-functions@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.1.tgz#146856e756d54b20fff14b819456b3e01820b85d" - integrity sha512-B7K15Xp8lv0sOJrdVAoukKlxP9N59HS48V1J3U/JGj+Ad+MHq+am6xJVs85AgXrQn4LV8vaYFOB+pr/yIuzW8Q== +"@babel/plugin-transform-block-scoped-functions@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.4.tgz#1afa595744f75e43a91af73b0d998ecfe4ebc2e8" + integrity sha512-WzXDarQXYYfjaV1szJvN3AD7rZgZzC1JtjJZ8dMHUyiK8mxPRahynp14zzNjU3VkPqPsO38CzxiWO1c9ARZ8JA== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-block-scoping@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.10.1.tgz#47092d89ca345811451cd0dc5d91605982705d5e" - integrity sha512-8bpWG6TtF5akdhIm/uWTyjHqENpy13Fx8chg7pFH875aNLwX8JxIxqm08gmAT+Whe6AOmaTeLPe7dpLbXt+xUw== +"@babel/plugin-transform-block-scoping@^7.10.4": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.10.5.tgz#b81b8aafefbfe68f0f65f7ef397b9ece68a6037d" + integrity sha512-6Ycw3hjpQti0qssQcA6AMSFDHeNJ++R6dIMnpRqUjFeBBTmTDPa8zgF90OVfTvAo11mXZTlVUViY1g8ffrURLg== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" - lodash "^4.17.13" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-classes@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.1.tgz#6e11dd6c4dfae70f540480a4702477ed766d733f" - integrity sha512-P9V0YIh+ln/B3RStPoXpEQ/CoAxQIhRSUn7aXqQ+FZJ2u8+oCtjIXR3+X0vsSD8zv+mb56K7wZW1XiDTDGiDRQ== +"@babel/plugin-transform-classes@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.4.tgz#405136af2b3e218bc4a1926228bc917ab1a0adc7" + integrity sha512-2oZ9qLjt161dn1ZE0Ms66xBncQH4In8Sqw1YWgBUZuGVJJS5c0OFZXL6dP2MRHrkU/eKhWg8CzFJhRQl50rQxA== dependencies: - "@babel/helper-annotate-as-pure" "^7.10.1" - "@babel/helper-define-map" "^7.10.1" - "@babel/helper-function-name" "^7.10.1" - "@babel/helper-optimise-call-expression" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" - "@babel/helper-replace-supers" "^7.10.1" - "@babel/helper-split-export-declaration" "^7.10.1" + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-define-map" "^7.10.4" + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-optimise-call-expression" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-replace-supers" "^7.10.4" + "@babel/helper-split-export-declaration" "^7.10.4" globals "^11.1.0" -"@babel/plugin-transform-computed-properties@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.1.tgz#59aa399064429d64dce5cf76ef9b90b7245ebd07" - integrity sha512-mqSrGjp3IefMsXIenBfGcPXxJxweQe2hEIwMQvjtiDQ9b1IBvDUjkAtV/HMXX47/vXf14qDNedXsIiNd1FmkaQ== +"@babel/plugin-transform-computed-properties@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.4.tgz#9ded83a816e82ded28d52d4b4ecbdd810cdfc0eb" + integrity sha512-JFwVDXcP/hM/TbyzGq3l/XWGut7p46Z3QvqFMXTfk6/09m7xZHJUN9xHfsv7vqqD4YnfI5ueYdSJtXqqBLyjBw== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-destructuring@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.1.tgz#abd58e51337815ca3a22a336b85f62b998e71907" - integrity sha512-V/nUc4yGWG71OhaTH705pU8ZSdM6c1KmmLP8ys59oOYbT7RpMYAR3MsVOt6OHL0WzG7BlTU076va9fjJyYzJMA== +"@babel/plugin-transform-destructuring@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.4.tgz#70ddd2b3d1bea83d01509e9bb25ddb3a74fc85e5" + integrity sha512-+WmfvyfsyF603iPa6825mq6Qrb7uLjTOsa3XOFzlYcYDHSS4QmpOWOL0NNBY5qMbvrcf3tq0Cw+v4lxswOBpgA== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-dotall-regex@^7.10.1", "@babel/plugin-transform-dotall-regex@^7.4.4": +"@babel/plugin-transform-dotall-regex@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz#469c2062105c1eb6a040eaf4fac4b488078395ee" + integrity sha512-ZEAVvUTCMlMFAbASYSVQoxIbHm2OkG2MseW6bV2JjIygOjdVv8tuxrCTzj1+Rynh7ODb8GivUy7dzEXzEhuPaA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-dotall-regex@^7.4.4": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.1.tgz#920b9fec2d78bb57ebb64a644d5c2ba67cc104ee" integrity sha512-19VIMsD1dp02RvduFUmfzj8uknaO3uiHHF0s3E1OHnVsNj8oge8EQ5RzHRbJjGSetRnkEuBYO7TG1M5kKjGLOA== @@ -576,353 +781,353 @@ "@babel/helper-create-regexp-features-plugin" "^7.10.1" "@babel/helper-plugin-utils" "^7.10.1" -"@babel/plugin-transform-duplicate-keys@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.1.tgz#c900a793beb096bc9d4d0a9d0cde19518ffc83b9" - integrity sha512-wIEpkX4QvX8Mo9W6XF3EdGttrIPZWozHfEaDTU0WJD/TDnXMvdDh30mzUl/9qWhnf7naicYartcEfUghTCSNpA== +"@babel/plugin-transform-duplicate-keys@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.4.tgz#697e50c9fee14380fe843d1f306b295617431e47" + integrity sha512-GL0/fJnmgMclHiBTTWXNlYjYsA7rDrtsazHG6mglaGSTh0KsrW04qml+Bbz9FL0LcJIRwBWL5ZqlNHKTkU3xAA== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-exponentiation-operator@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.1.tgz#279c3116756a60dd6e6f5e488ba7957db9c59eb3" - integrity sha512-lr/przdAbpEA2BUzRvjXdEDLrArGRRPwbaF9rvayuHRvdQ7lUTTkZnhZrJ4LE2jvgMRFF4f0YuPQ20vhiPYxtA== +"@babel/plugin-transform-exponentiation-operator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.4.tgz#5ae338c57f8cf4001bdb35607ae66b92d665af2e" + integrity sha512-S5HgLVgkBcRdyQAHbKj+7KyuWx8C6t5oETmUuwz1pt3WTWJhsUV0WIIXuVvfXMxl/QQyHKlSCNNtaIamG8fysw== dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-flow-comments@^7.7.4": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-comments/-/plugin-transform-flow-comments-7.10.1.tgz#1befb98f8d37245b70770a1f83c67057e41bd4a9" - integrity sha512-A1yDAD/3pU+NyCHRvm+GQE2xiyRV6mGDyhMdTKPqgs5aRcc2MR4wmnHJJIB91f8NwMNl8dxmN6nmj/7FCr6Jgw== +"@babel/plugin-transform-flow-comments@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-comments/-/plugin-transform-flow-comments-7.10.4.tgz#e0aebf9d1dbfe48fdc97e4bc31fc25985db5c07d" + integrity sha512-wiwS5fCzeWP71WLIzAoFAPTk0GLnhpUfGV4ygwX+Zib6nYiaLhUOWsjLt6+hCwCoH/bwZSg7Qzlc2AuzXg/mbg== dependencies: - "@babel/generator" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" - "@babel/plugin-syntax-flow" "^7.10.1" + "@babel/generator" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-flow" "^7.10.4" -"@babel/plugin-transform-flow-strip-types@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.10.1.tgz#59eafbff9ae85ec8932d4c16c068654be814ec5e" - integrity sha512-i4o0YwiJBIsIx7/liVCZ3Q2WkWr1/Yu39PksBOnh/khW2SwIFsGa5Ze+MSon5KbDfrEHP9NeyefAgvUSXzaEkw== +"@babel/plugin-transform-flow-strip-types@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.10.4.tgz#c497957f09e86e3df7296271e9eb642876bf7788" + integrity sha512-XTadyuqNst88UWBTdLjM+wEY7BFnY2sYtPyAidfC7M/QaZnSuIZpMvLxqGT7phAcnGyWh/XQFLKcGf04CnvxSQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" - "@babel/plugin-syntax-flow" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-flow" "^7.10.4" -"@babel/plugin-transform-for-of@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.1.tgz#ff01119784eb0ee32258e8646157ba2501fcfda5" - integrity sha512-US8KCuxfQcn0LwSCMWMma8M2R5mAjJGsmoCBVwlMygvmDUMkTCykc84IqN1M7t+agSfOmLYTInLCHJM+RUoz+w== +"@babel/plugin-transform-for-of@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.4.tgz#c08892e8819d3a5db29031b115af511dbbfebae9" + integrity sha512-ItdQfAzu9AlEqmusA/65TqJ79eRcgGmpPPFvBnGILXZH975G0LNjP1yjHvGgfuCxqrPPueXOPe+FsvxmxKiHHQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-function-name@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.1.tgz#4ed46fd6e1d8fde2a2ec7b03c66d853d2c92427d" - integrity sha512-//bsKsKFBJfGd65qSNNh1exBy5Y9gD9ZN+DvrJ8f7HXr4avE5POW6zB7Rj6VnqHV33+0vXWUwJT0wSHubiAQkw== +"@babel/plugin-transform-function-name@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.4.tgz#6a467880e0fc9638514ba369111811ddbe2644b7" + integrity sha512-OcDCq2y5+E0dVD5MagT5X+yTRbcvFjDI2ZVAottGH6tzqjx/LKpgkUepu3hp/u4tZBzxxpNGwLsAvGBvQ2mJzg== dependencies: - "@babel/helper-function-name" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-literals@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.1.tgz#5794f8da82846b22e4e6631ea1658bce708eb46a" - integrity sha512-qi0+5qgevz1NHLZroObRm5A+8JJtibb7vdcPQF1KQE12+Y/xxl8coJ+TpPW9iRq+Mhw/NKLjm+5SHtAHCC7lAw== +"@babel/plugin-transform-literals@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.4.tgz#9f42ba0841100a135f22712d0e391c462f571f3c" + integrity sha512-Xd/dFSTEVuUWnyZiMu76/InZxLTYilOSr1UlHV+p115Z/Le2Fi1KXkJUYz0b42DfndostYlPub3m8ZTQlMaiqQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-member-expression-literals@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.1.tgz#90347cba31bca6f394b3f7bd95d2bbfd9fce2f39" - integrity sha512-UmaWhDokOFT2GcgU6MkHC11i0NQcL63iqeufXWfRy6pUOGYeCGEKhvfFO6Vz70UfYJYHwveg62GS83Rvpxn+NA== +"@babel/plugin-transform-member-expression-literals@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.4.tgz#b1ec44fcf195afcb8db2c62cd8e551c881baf8b7" + integrity sha512-0bFOvPyAoTBhtcJLr9VcwZqKmSjFml1iVxvPL0ReomGU53CX53HsM4h2SzckNdkQcHox1bpAqzxBI1Y09LlBSw== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-modules-amd@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.1.tgz#65950e8e05797ebd2fe532b96e19fc5482a1d52a" - integrity sha512-31+hnWSFRI4/ACFr1qkboBbrTxoBIzj7qA69qlq8HY8p7+YCzkCT6/TvQ1a4B0z27VeWtAeJd6pr5G04dc1iHw== +"@babel/plugin-transform-modules-amd@^7.10.4": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.5.tgz#1b9cddaf05d9e88b3aad339cb3e445c4f020a9b1" + integrity sha512-elm5uruNio7CTLFItVC/rIzKLfQ17+fX7EVz5W0TMgIHFo1zY0Ozzx+lgwhL4plzl8OzVn6Qasx5DeEFyoNiRw== dependencies: - "@babel/helper-module-transforms" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-module-transforms" "^7.10.5" + "@babel/helper-plugin-utils" "^7.10.4" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-commonjs@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.1.tgz#d5ff4b4413ed97ffded99961056e1fb980fb9301" - integrity sha512-AQG4fc3KOah0vdITwt7Gi6hD9BtQP/8bhem7OjbaMoRNCH5Djx42O2vYMfau7QnAzQCa+RJnhJBmFFMGpQEzrg== +"@babel/plugin-transform-modules-commonjs@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz#66667c3eeda1ebf7896d41f1f16b17105a2fbca0" + integrity sha512-Xj7Uq5o80HDLlW64rVfDBhao6OX89HKUmb+9vWYaLXBZOma4gA6tw4Ni1O5qVDoZWUV0fxMYA0aYzOawz0l+1w== dependencies: - "@babel/helper-module-transforms" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" - "@babel/helper-simple-access" "^7.10.1" + "@babel/helper-module-transforms" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-simple-access" "^7.10.4" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-systemjs@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.1.tgz#9962e4b0ac6aaf2e20431ada3d8ec72082cbffb6" - integrity sha512-ewNKcj1TQZDL3YnO85qh9zo1YF1CHgmSTlRQgHqe63oTrMI85cthKtZjAiZSsSNjPQ5NCaYo5QkbYqEw1ZBgZA== +"@babel/plugin-transform-modules-systemjs@^7.10.4": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.5.tgz#6270099c854066681bae9e05f87e1b9cadbe8c85" + integrity sha512-f4RLO/OL14/FP1AEbcsWMzpbUz6tssRaeQg11RH1BP/XnPpRoVwgeYViMFacnkaw4k4wjRSjn3ip1Uw9TaXuMw== dependencies: - "@babel/helper-hoist-variables" "^7.10.1" - "@babel/helper-module-transforms" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-hoist-variables" "^7.10.4" + "@babel/helper-module-transforms" "^7.10.5" + "@babel/helper-plugin-utils" "^7.10.4" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-umd@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.1.tgz#ea080911ffc6eb21840a5197a39ede4ee67b1595" - integrity sha512-EIuiRNMd6GB6ulcYlETnYYfgv4AxqrswghmBRQbWLHZxN4s7mupxzglnHqk9ZiUpDI4eRWewedJJNj67PWOXKA== +"@babel/plugin-transform-modules-umd@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.4.tgz#9a8481fe81b824654b3a0b65da3df89f3d21839e" + integrity sha512-mohW5q3uAEt8T45YT7Qc5ws6mWgJAaL/8BfWD9Dodo1A3RKWli8wTS+WiQ/knF+tXlPirW/1/MqzzGfCExKECA== dependencies: - "@babel/helper-module-transforms" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-module-transforms" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-named-capturing-groups-regex@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.8.3.tgz#a2a72bffa202ac0e2d0506afd0939c5ecbc48c6c" - integrity sha512-f+tF/8UVPU86TrCb06JoPWIdDpTNSGGcAtaD9mLP0aYGA0OS0j7j7DHJR0GTFrUZPUU6loZhbsVZgTh0N+Qdnw== +"@babel/plugin-transform-named-capturing-groups-regex@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.10.4.tgz#78b4d978810b6f3bcf03f9e318f2fc0ed41aecb6" + integrity sha512-V6LuOnD31kTkxQPhKiVYzYC/Jgdq53irJC/xBSmqcNcqFGV+PER4l6rU5SH2Vl7bH9mLDHcc0+l9HUOe4RNGKA== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.8.3" + "@babel/helper-create-regexp-features-plugin" "^7.10.4" -"@babel/plugin-transform-new-target@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.1.tgz#6ee41a5e648da7632e22b6fb54012e87f612f324" - integrity sha512-MBlzPc1nJvbmO9rPr1fQwXOM2iGut+JC92ku6PbiJMMK7SnQc1rytgpopveE3Evn47gzvGYeCdgfCDbZo0ecUw== +"@babel/plugin-transform-new-target@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.4.tgz#9097d753cb7b024cb7381a3b2e52e9513a9c6888" + integrity sha512-YXwWUDAH/J6dlfwqlWsztI2Puz1NtUAubXhOPLQ5gjR/qmQ5U96DY4FQO8At33JN4XPBhrjB8I4eMmLROjjLjw== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-object-super@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.1.tgz#2e3016b0adbf262983bf0d5121d676a5ed9c4fde" - integrity sha512-WnnStUDN5GL+wGQrJylrnnVlFhFmeArINIR9gjhSeYyvroGhBrSAXYg/RHsnfzmsa+onJrTJrEClPzgNmmQ4Gw== +"@babel/plugin-transform-object-super@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.4.tgz#d7146c4d139433e7a6526f888c667e314a093894" + integrity sha512-5iTw0JkdRdJvr7sY0vHqTpnruUpTea32JHmq/atIWqsnNussbRzjEDyWep8UNztt1B5IusBYg8Irb0bLbiEBCQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" - "@babel/helper-replace-supers" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-replace-supers" "^7.10.4" -"@babel/plugin-transform-parameters@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.1.tgz#b25938a3c5fae0354144a720b07b32766f683ddd" - integrity sha512-tJ1T0n6g4dXMsL45YsSzzSDZCxiHXAQp/qHrucOq5gEHncTA3xDxnd5+sZcoQp+N1ZbieAaB8r/VUCG0gqseOg== +"@babel/plugin-transform-parameters@^7.10.4": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.5.tgz#59d339d58d0b1950435f4043e74e2510005e2c4a" + integrity sha512-xPHwUj5RdFV8l1wuYiu5S9fqWGM2DrYc24TMvUiRrPVm+SM3XeqU9BcokQX/kEUe+p2RBwy+yoiR1w/Blq6ubw== dependencies: - "@babel/helper-get-function-arity" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-get-function-arity" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-property-literals@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.1.tgz#cffc7315219230ed81dc53e4625bf86815b6050d" - integrity sha512-Kr6+mgag8auNrgEpbfIWzdXYOvqDHZOF0+Bx2xh4H2EDNwcbRb9lY6nkZg8oSjsX+DH9Ebxm9hOqtKW+gRDeNA== +"@babel/plugin-transform-property-literals@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.4.tgz#f6fe54b6590352298785b83edd815d214c42e3c0" + integrity sha512-ofsAcKiUxQ8TY4sScgsGeR2vJIsfrzqvFb9GvJ5UdXDzl+MyYCaBj/FGzXuv7qE0aJcjWMILny1epqelnFlz8g== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-react-display-name@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.10.1.tgz#e6a33f6d48dfb213dda5e007d0c7ff82b6a3d8ef" - integrity sha512-rBjKcVwjk26H3VX8pavMxGf33LNlbocMHdSeldIEswtQ/hrjyTG8fKKILW1cSkODyRovckN/uZlGb2+sAV9JUQ== +"@babel/plugin-transform-react-display-name@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.10.4.tgz#b5795f4e3e3140419c3611b7a2a3832b9aef328d" + integrity sha512-Zd4X54Mu9SBfPGnEcaGcOrVAYOtjT2on8QZkLKEq1S/tHexG39d9XXGZv19VfRrDjPJzFmPfTAqOQS1pfFOujw== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-react-jsx-development@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.10.1.tgz#1ac6300d8b28ef381ee48e6fec430cc38047b7f3" - integrity sha512-XwDy/FFoCfw9wGFtdn5Z+dHh6HXKHkC6DwKNWpN74VWinUagZfDcEJc3Y8Dn5B3WMVnAllX8Kviaw7MtC5Epwg== +"@babel/plugin-transform-react-jsx-development@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.10.4.tgz#6ec90f244394604623880e15ebc3c34c356258ba" + integrity sha512-RM3ZAd1sU1iQ7rI2dhrZRZGv0aqzNQMbkIUCS1txYpi9wHQ2ZHNjo5TwX+UD6pvFW4AbWqLVYvKy5qJSAyRGjQ== dependencies: - "@babel/helper-builder-react-jsx-experimental" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" - "@babel/plugin-syntax-jsx" "^7.10.1" + "@babel/helper-builder-react-jsx-experimental" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-jsx" "^7.10.4" -"@babel/plugin-transform-react-jsx-self@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.10.1.tgz#22143e14388d72eb88649606bb9e46f421bc3821" - integrity sha512-4p+RBw9d1qV4S749J42ZooeQaBomFPrSxa9JONLHJ1TxCBo3TzJ79vtmG2S2erUT8PDDrPdw4ZbXGr2/1+dILA== +"@babel/plugin-transform-react-jsx-self@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.10.4.tgz#cd301a5fed8988c182ed0b9d55e9bd6db0bd9369" + integrity sha512-yOvxY2pDiVJi0axdTWHSMi5T0DILN+H+SaeJeACHKjQLezEzhLx9nEF9xgpBLPtkZsks9cnb5P9iBEi21En3gg== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" - "@babel/plugin-syntax-jsx" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-jsx" "^7.10.4" -"@babel/plugin-transform-react-jsx-source@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.10.1.tgz#30db3d4ee3cdebbb26a82a9703673714777a4273" - integrity sha512-neAbaKkoiL+LXYbGDvh6PjPG+YeA67OsZlE78u50xbWh2L1/C81uHiNP5d1fw+uqUIoiNdCC8ZB+G4Zh3hShJA== +"@babel/plugin-transform-react-jsx-source@^7.10.4": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.10.5.tgz#34f1779117520a779c054f2cdd9680435b9222b4" + integrity sha512-wTeqHVkN1lfPLubRiZH3o73f4rfon42HpgxUSs86Nc+8QIcm/B9s8NNVXu/gwGcOyd7yDib9ikxoDLxJP0UiDA== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" - "@babel/plugin-syntax-jsx" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-jsx" "^7.10.4" -"@babel/plugin-transform-react-jsx@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.10.1.tgz#91f544248ba131486decb5d9806da6a6e19a2896" - integrity sha512-MBVworWiSRBap3Vs39eHt+6pJuLUAaK4oxGc8g+wY+vuSJvLiEQjW1LSTqKb8OUPtDvHCkdPhk7d6sjC19xyFw== +"@babel/plugin-transform-react-jsx@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.10.4.tgz#673c9f913948764a4421683b2bef2936968fddf2" + integrity sha512-L+MfRhWjX0eI7Js093MM6MacKU4M6dnCRa/QPDwYMxjljzSCzzlzKzj9Pk4P3OtrPcxr2N3znR419nr3Xw+65A== dependencies: - "@babel/helper-builder-react-jsx" "^7.10.1" - "@babel/helper-builder-react-jsx-experimental" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" - "@babel/plugin-syntax-jsx" "^7.10.1" + "@babel/helper-builder-react-jsx" "^7.10.4" + "@babel/helper-builder-react-jsx-experimental" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-jsx" "^7.10.4" -"@babel/plugin-transform-react-pure-annotations@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.10.1.tgz#f5e7c755d3e7614d4c926e144f501648a5277b70" - integrity sha512-mfhoiai083AkeewsBHUpaS/FM1dmUENHBMpS/tugSJ7VXqXO5dCN1Gkint2YvM1Cdv1uhmAKt1ZOuAjceKmlLA== +"@babel/plugin-transform-react-pure-annotations@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.10.4.tgz#3eefbb73db94afbc075f097523e445354a1c6501" + integrity sha512-+njZkqcOuS8RaPakrnR9KvxjoG1ASJWpoIv/doyWngId88JoFlPlISenGXjrVacZUIALGUr6eodRs1vmPnF23A== dependencies: - "@babel/helper-annotate-as-pure" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-regenerator@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.1.tgz#10e175cbe7bdb63cc9b39f9b3f823c5c7c5c5490" - integrity sha512-B3+Y2prScgJ2Bh/2l9LJxKbb8C8kRfsG4AdPT+n7ixBHIxJaIG8bi8tgjxUMege1+WqSJ+7gu1YeoMVO3gPWzw== +"@babel/plugin-transform-regenerator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz#2015e59d839074e76838de2159db421966fd8b63" + integrity sha512-3thAHwtor39A7C04XucbMg17RcZ3Qppfxr22wYzZNcVIkPHfpM9J0SO8zuCV6SZa265kxBJSrfKTvDCYqBFXGw== dependencies: regenerator-transform "^0.14.2" -"@babel/plugin-transform-reserved-words@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.1.tgz#0fc1027312b4d1c3276a57890c8ae3bcc0b64a86" - integrity sha512-qN1OMoE2nuqSPmpTqEM7OvJ1FkMEV+BjVeZZm9V9mq/x1JLKQ4pcv8riZJMNN3u2AUGl0ouOMjRr2siecvHqUQ== +"@babel/plugin-transform-reserved-words@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.4.tgz#8f2682bcdcef9ed327e1b0861585d7013f8a54dd" + integrity sha512-hGsw1O6Rew1fkFbDImZIEqA8GoidwTAilwCyWqLBM9f+e/u/sQMQu7uX6dyokfOayRuuVfKOW4O7HvaBWM+JlQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-runtime@^7.8.3": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.10.1.tgz#fd1887f749637fb2ed86dc278e79eb41df37f4b1" - integrity sha512-4w2tcglDVEwXJ5qxsY++DgWQdNJcCCsPxfT34wCUwIf2E7dI7pMpH8JczkMBbgBTNzBX62SZlNJ9H+De6Zebaw== +"@babel/plugin-transform-runtime@^7.10.5": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.10.5.tgz#3b39b7b24830e0c2d8ff7a4489fe5cf99fbace86" + integrity sha512-tV4V/FjElJ9lQtyjr5xD2IFFbgY46r7EeVu5a8CpEKT5laheHKSlFeHjpkPppW3PqzGLAuv5k2qZX5LgVZIX5w== dependencies: - "@babel/helper-module-imports" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-module-imports" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" resolve "^1.8.1" semver "^5.5.1" -"@babel/plugin-transform-shorthand-properties@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.1.tgz#e8b54f238a1ccbae482c4dce946180ae7b3143f3" - integrity sha512-AR0E/lZMfLstScFwztApGeyTHJ5u3JUKMjneqRItWeEqDdHWZwAOKycvQNCasCK/3r5YXsuNG25funcJDu7Y2g== +"@babel/plugin-transform-shorthand-properties@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.4.tgz#9fd25ec5cdd555bb7f473e5e6ee1c971eede4dd6" + integrity sha512-AC2K/t7o07KeTIxMoHneyX90v3zkm5cjHJEokrPEAGEy3UCp8sLKfnfOIGdZ194fyN4wfX/zZUWT9trJZ0qc+Q== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-spread@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.10.1.tgz#0c6d618a0c4461a274418460a28c9ccf5239a7c8" - integrity sha512-8wTPym6edIrClW8FI2IoaePB91ETOtg36dOkj3bYcNe7aDMN2FXEoUa+WrmPc4xa1u2PQK46fUX2aCb+zo9rfw== +"@babel/plugin-transform-spread@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.10.4.tgz#4e2c85ea0d6abaee1b24dcfbbae426fe8d674cff" + integrity sha512-1e/51G/Ni+7uH5gktbWv+eCED9pP8ZpRhZB3jOaI3mmzfvJTWHkuyYTv0Z5PYtyM+Tr2Ccr9kUdQxn60fI5WuQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-sticky-regex@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.1.tgz#90fc89b7526228bed9842cff3588270a7a393b00" - integrity sha512-j17ojftKjrL7ufX8ajKvwRilwqTok4q+BjkknmQw9VNHnItTyMP5anPFzxFJdCQs7clLcWpCV3ma+6qZWLnGMA== +"@babel/plugin-transform-sticky-regex@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.4.tgz#8f3889ee8657581130a29d9cc91d7c73b7c4a28d" + integrity sha512-Ddy3QZfIbEV0VYcVtFDCjeE4xwVTJWTmUtorAJkn6u/92Z/nWJNV+mILyqHKrUxXYKA2EoCilgoPePymKL4DvQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" - "@babel/helper-regex" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-regex" "^7.10.4" -"@babel/plugin-transform-template-literals@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.1.tgz#914c7b7f4752c570ea00553b4284dad8070e8628" - integrity sha512-t7B/3MQf5M1T9hPCRG28DNGZUuxAuDqLYS03rJrIk2prj/UV7Z6FOneijhQhnv/Xa039vidXeVbvjK2SK5f7Gg== +"@babel/plugin-transform-template-literals@^7.10.4": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.5.tgz#78bc5d626a6642db3312d9d0f001f5e7639fde8c" + integrity sha512-V/lnPGIb+KT12OQikDvgSuesRX14ck5FfJXt6+tXhdkJ+Vsd0lDCVtF6jcB4rNClYFzaB2jusZ+lNISDk2mMMw== dependencies: - "@babel/helper-annotate-as-pure" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-typeof-symbol@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.1.tgz#60c0239b69965d166b80a84de7315c1bc7e0bb0e" - integrity sha512-qX8KZcmbvA23zDi+lk9s6hC1FM7jgLHYIjuLgULgc8QtYnmB3tAVIYkNoKRQ75qWBeyzcoMoK8ZQmogGtC/w0g== +"@babel/plugin-transform-typeof-symbol@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.4.tgz#9509f1a7eec31c4edbffe137c16cc33ff0bc5bfc" + integrity sha512-QqNgYwuuW0y0H+kUE/GWSR45t/ccRhe14Fs/4ZRouNNQsyd4o3PG4OtHiIrepbM2WKUBDAXKCAK/Lk4VhzTaGA== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-typescript@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.10.1.tgz#2c54daea231f602468686d9faa76f182a94507a6" - integrity sha512-v+QWKlmCnsaimLeqq9vyCsVRMViZG1k2SZTlcZvB+TqyH570Zsij8nvVUZzOASCRiQFUxkLrn9Wg/kH0zgy5OQ== +"@babel/plugin-transform-typescript@^7.10.4": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.10.5.tgz#edf353944e979f40d8ff9fe4e9975d0a465037c5" + integrity sha512-YCyYsFrrRMZ3qR7wRwtSSJovPG5vGyG4ZdcSAivGwTfoasMp3VOB/AKhohu3dFtmB4cCDcsndCSxGtrdliCsZQ== dependencies: - "@babel/helper-create-class-features-plugin" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" - "@babel/plugin-syntax-typescript" "^7.10.1" + "@babel/helper-create-class-features-plugin" "^7.10.5" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-typescript" "^7.10.4" -"@babel/plugin-transform-unicode-escapes@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.1.tgz#add0f8483dab60570d9e03cecef6c023aa8c9940" - integrity sha512-zZ0Poh/yy1d4jeDWpx/mNwbKJVwUYJX73q+gyh4bwtG0/iUlzdEu0sLMda8yuDFS6LBQlT/ST1SJAR6zYwXWgw== +"@babel/plugin-transform-unicode-escapes@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.4.tgz#feae523391c7651ddac115dae0a9d06857892007" + integrity sha512-y5XJ9waMti2J+e7ij20e+aH+fho7Wb7W8rNuu72aKRwCHFqQdhkdU2lo3uZ9tQuboEJcUFayXdARhcxLQ3+6Fg== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-unicode-regex@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.10.1.tgz#6b58f2aea7b68df37ac5025d9c88752443a6b43f" - integrity sha512-Y/2a2W299k0VIUdbqYm9X2qS6fE0CUBhhiPpimK6byy7OJ/kORLlIX+J6UrjgNu5awvs62k+6RSslxhcvVw2Tw== +"@babel/plugin-transform-unicode-regex@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.10.4.tgz#e56d71f9282fac6db09c82742055576d5e6d80a8" + integrity sha512-wNfsc4s8N2qnIwpO/WP2ZiSyjfpTamT2C9V9FDH/Ljub9zw6P3SjkXcFmc0RQUt96k2fmIvtla2MMjgTwIAC+A== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" + "@babel/helper-create-regexp-features-plugin" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/preset-env@^7.7.6": - version "7.10.2" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.10.2.tgz#715930f2cf8573b0928005ee562bed52fb65fdfb" - integrity sha512-MjqhX0RZaEgK/KueRzh+3yPSk30oqDKJ5HP5tqTSB1e2gzGS3PLy7K0BIpnp78+0anFuSwOeuCf1zZO7RzRvEA== +"@babel/preset-env@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.10.4.tgz#fbf57f9a803afd97f4f32e4f798bb62e4b2bef5f" + integrity sha512-tcmuQ6vupfMZPrLrc38d0sF2OjLT3/bZ0dry5HchNCQbrokoQi4reXqclvkkAT5b+gWc23meVWpve5P/7+w/zw== dependencies: - "@babel/compat-data" "^7.10.1" - "@babel/helper-compilation-targets" "^7.10.2" - "@babel/helper-module-imports" "^7.10.1" - "@babel/helper-plugin-utils" "^7.10.1" - "@babel/plugin-proposal-async-generator-functions" "^7.10.1" - "@babel/plugin-proposal-class-properties" "^7.10.1" - "@babel/plugin-proposal-dynamic-import" "^7.10.1" - "@babel/plugin-proposal-json-strings" "^7.10.1" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.10.1" - "@babel/plugin-proposal-numeric-separator" "^7.10.1" - "@babel/plugin-proposal-object-rest-spread" "^7.10.1" - "@babel/plugin-proposal-optional-catch-binding" "^7.10.1" - "@babel/plugin-proposal-optional-chaining" "^7.10.1" - "@babel/plugin-proposal-private-methods" "^7.10.1" - "@babel/plugin-proposal-unicode-property-regex" "^7.10.1" + "@babel/compat-data" "^7.10.4" + "@babel/helper-compilation-targets" "^7.10.4" + "@babel/helper-module-imports" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-proposal-async-generator-functions" "^7.10.4" + "@babel/plugin-proposal-class-properties" "^7.10.4" + "@babel/plugin-proposal-dynamic-import" "^7.10.4" + "@babel/plugin-proposal-json-strings" "^7.10.4" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.10.4" + "@babel/plugin-proposal-numeric-separator" "^7.10.4" + "@babel/plugin-proposal-object-rest-spread" "^7.10.4" + "@babel/plugin-proposal-optional-catch-binding" "^7.10.4" + "@babel/plugin-proposal-optional-chaining" "^7.10.4" + "@babel/plugin-proposal-private-methods" "^7.10.4" + "@babel/plugin-proposal-unicode-property-regex" "^7.10.4" "@babel/plugin-syntax-async-generators" "^7.8.0" - "@babel/plugin-syntax-class-properties" "^7.10.1" + "@babel/plugin-syntax-class-properties" "^7.10.4" "@babel/plugin-syntax-dynamic-import" "^7.8.0" "@babel/plugin-syntax-json-strings" "^7.8.0" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" - "@babel/plugin-syntax-numeric-separator" "^7.10.1" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" "@babel/plugin-syntax-object-rest-spread" "^7.8.0" "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" "@babel/plugin-syntax-optional-chaining" "^7.8.0" - "@babel/plugin-syntax-top-level-await" "^7.10.1" - "@babel/plugin-transform-arrow-functions" "^7.10.1" - "@babel/plugin-transform-async-to-generator" "^7.10.1" - "@babel/plugin-transform-block-scoped-functions" "^7.10.1" - "@babel/plugin-transform-block-scoping" "^7.10.1" - "@babel/plugin-transform-classes" "^7.10.1" - "@babel/plugin-transform-computed-properties" "^7.10.1" - "@babel/plugin-transform-destructuring" "^7.10.1" - "@babel/plugin-transform-dotall-regex" "^7.10.1" - "@babel/plugin-transform-duplicate-keys" "^7.10.1" - "@babel/plugin-transform-exponentiation-operator" "^7.10.1" - "@babel/plugin-transform-for-of" "^7.10.1" - "@babel/plugin-transform-function-name" "^7.10.1" - "@babel/plugin-transform-literals" "^7.10.1" - "@babel/plugin-transform-member-expression-literals" "^7.10.1" - "@babel/plugin-transform-modules-amd" "^7.10.1" - "@babel/plugin-transform-modules-commonjs" "^7.10.1" - "@babel/plugin-transform-modules-systemjs" "^7.10.1" - "@babel/plugin-transform-modules-umd" "^7.10.1" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.8.3" - "@babel/plugin-transform-new-target" "^7.10.1" - "@babel/plugin-transform-object-super" "^7.10.1" - "@babel/plugin-transform-parameters" "^7.10.1" - "@babel/plugin-transform-property-literals" "^7.10.1" - "@babel/plugin-transform-regenerator" "^7.10.1" - "@babel/plugin-transform-reserved-words" "^7.10.1" - "@babel/plugin-transform-shorthand-properties" "^7.10.1" - "@babel/plugin-transform-spread" "^7.10.1" - "@babel/plugin-transform-sticky-regex" "^7.10.1" - "@babel/plugin-transform-template-literals" "^7.10.1" - "@babel/plugin-transform-typeof-symbol" "^7.10.1" - "@babel/plugin-transform-unicode-escapes" "^7.10.1" - "@babel/plugin-transform-unicode-regex" "^7.10.1" + "@babel/plugin-syntax-top-level-await" "^7.10.4" + "@babel/plugin-transform-arrow-functions" "^7.10.4" + "@babel/plugin-transform-async-to-generator" "^7.10.4" + "@babel/plugin-transform-block-scoped-functions" "^7.10.4" + "@babel/plugin-transform-block-scoping" "^7.10.4" + "@babel/plugin-transform-classes" "^7.10.4" + "@babel/plugin-transform-computed-properties" "^7.10.4" + "@babel/plugin-transform-destructuring" "^7.10.4" + "@babel/plugin-transform-dotall-regex" "^7.10.4" + "@babel/plugin-transform-duplicate-keys" "^7.10.4" + "@babel/plugin-transform-exponentiation-operator" "^7.10.4" + "@babel/plugin-transform-for-of" "^7.10.4" + "@babel/plugin-transform-function-name" "^7.10.4" + "@babel/plugin-transform-literals" "^7.10.4" + "@babel/plugin-transform-member-expression-literals" "^7.10.4" + "@babel/plugin-transform-modules-amd" "^7.10.4" + "@babel/plugin-transform-modules-commonjs" "^7.10.4" + "@babel/plugin-transform-modules-systemjs" "^7.10.4" + "@babel/plugin-transform-modules-umd" "^7.10.4" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.10.4" + "@babel/plugin-transform-new-target" "^7.10.4" + "@babel/plugin-transform-object-super" "^7.10.4" + "@babel/plugin-transform-parameters" "^7.10.4" + "@babel/plugin-transform-property-literals" "^7.10.4" + "@babel/plugin-transform-regenerator" "^7.10.4" + "@babel/plugin-transform-reserved-words" "^7.10.4" + "@babel/plugin-transform-shorthand-properties" "^7.10.4" + "@babel/plugin-transform-spread" "^7.10.4" + "@babel/plugin-transform-sticky-regex" "^7.10.4" + "@babel/plugin-transform-template-literals" "^7.10.4" + "@babel/plugin-transform-typeof-symbol" "^7.10.4" + "@babel/plugin-transform-unicode-escapes" "^7.10.4" + "@babel/plugin-transform-unicode-regex" "^7.10.4" "@babel/preset-modules" "^0.1.3" - "@babel/types" "^7.10.2" + "@babel/types" "^7.10.4" browserslist "^4.12.0" core-js-compat "^3.6.2" invariant "^2.2.2" levenary "^1.1.1" semver "^5.5.0" -"@babel/preset-flow@^7.7.4": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.10.1.tgz#29498ec23baf9aa6dae50c568ceba09d71692b82" - integrity sha512-FuQsibb5PaX07fF1XUO5gjjxdEZbcJv8+ugPDaeFEsBIvUTib8hCtEJow/c2F0jq9ZUjpHCQ8IQKNHRvKE1kJQ== +"@babel/preset-flow@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.10.4.tgz#e0d9c72f8cb02d1633f6a5b7b16763aa2edf659f" + integrity sha512-XI6l1CptQCOBv+ZKYwynyswhtOKwpZZp5n0LG1QKCo8erRhqjoQV6nvx61Eg30JHpysWQSBwA2AWRU3pBbSY5g== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" - "@babel/plugin-transform-flow-strip-types" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-flow-strip-types" "^7.10.4" "@babel/preset-modules@^0.1.3": version "0.1.3" @@ -935,46 +1140,38 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" -"@babel/preset-react@^7.7.4": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.10.1.tgz#e2ab8ae9a363ec307b936589f07ed753192de041" - integrity sha512-Rw0SxQ7VKhObmFjD/cUcKhPTtzpeviEFX1E6PgP+cYOhQ98icNqtINNFANlsdbQHrmeWnqdxA4Tmnl1jy5tp3Q== +"@babel/preset-react@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.10.4.tgz#92e8a66d816f9911d11d4cc935be67adfc82dbcf" + integrity sha512-BrHp4TgOIy4M19JAfO1LhycVXOPWdDbTRep7eVyatf174Hff+6Uk53sDyajqZPu8W1qXRBiYOfIamek6jA7YVw== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" - "@babel/plugin-transform-react-display-name" "^7.10.1" - "@babel/plugin-transform-react-jsx" "^7.10.1" - "@babel/plugin-transform-react-jsx-development" "^7.10.1" - "@babel/plugin-transform-react-jsx-self" "^7.10.1" - "@babel/plugin-transform-react-jsx-source" "^7.10.1" - "@babel/plugin-transform-react-pure-annotations" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-react-display-name" "^7.10.4" + "@babel/plugin-transform-react-jsx" "^7.10.4" + "@babel/plugin-transform-react-jsx-development" "^7.10.4" + "@babel/plugin-transform-react-jsx-self" "^7.10.4" + "@babel/plugin-transform-react-jsx-source" "^7.10.4" + "@babel/plugin-transform-react-pure-annotations" "^7.10.4" -"@babel/preset-typescript@^7.7.4": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.10.1.tgz#a8d8d9035f55b7d99a2461a0bdc506582914d07e" - integrity sha512-m6GV3y1ShiqxnyQj10600ZVOFrSSAa8HQ3qIUk2r+gcGtHTIRw0dJnFLt1WNXpKjtVw7yw1DAPU/6ma2ZvgJuA== +"@babel/preset-typescript@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.10.4.tgz#7d5d052e52a682480d6e2cc5aa31be61c8c25e36" + integrity sha512-SdYnvGPv+bLlwkF2VkJnaX/ni1sMNetcGI1+nThF1gyv6Ph8Qucc4ZZAjM5yZcE/AKRXIOTZz7eSRDWOEjPyRQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.1" - "@babel/plugin-transform-typescript" "^7.10.1" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-typescript" "^7.10.4" -"@babel/register@^7.7.4": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.10.1.tgz#b6567c5cb5049f44bbf8c35d6ff68ca3c43238ed" - integrity sha512-sl96+kB3IA2B9EzpwwBmYadOT14vw3KaXOknGDbJaZCOj52GDA4Tivudq9doCJcB+bEIKCEARZYwRgBBsCGXyg== +"@babel/register@^7.10.5": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.10.5.tgz#354f3574895f1307f79efe37a51525e52fd38d89" + integrity sha512-eYHdLv43nyvmPn9bfNfrcC4+iYNwdQ8Pxk1MFJuU/U5LpSYl/PH4dFMazCYZDFVi8ueG3shvO+AQfLrxpYulQw== dependencies: find-cache-dir "^2.0.0" - lodash "^4.17.13" + lodash "^4.17.19" make-dir "^2.1.0" pirates "^4.0.0" source-map-support "^0.5.16" -"@babel/runtime-corejs3@^7.8.3": - version "7.10.2" - resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.10.2.tgz#3511797ddf9a3d6f3ce46b99cc835184817eaa4e" - integrity sha512-+a2M/u7r15o3dV1NEizr9bRi+KUVnrs/qYxF0Z06DAPx/4VCWaz1WA7EcbE+uqGgt39lp5akWGmHsTseIkHkHg== - dependencies: - core-js-pure "^3.0.0" - regenerator-runtime "^0.13.4" - "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": version "7.10.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.2.tgz#d103f21f2602497d38348a32e008637d506db839" @@ -982,6 +1179,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.10.5": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.5.tgz#303d8bd440ecd5a491eae6117fd3367698674c5c" + integrity sha512-otddXKhdNn7d0ptoFRHtMLa8LqDxLYwTjB4nYgM1yy5N6gU/MUf8zqyyLltCH3yAVitBzmwK4us+DD0l/MauAg== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.10.1", "@babel/template@^7.4.0": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.1.tgz#e167154a94cb5f14b28dc58f5356d2162f539811" @@ -991,6 +1195,15 @@ "@babel/parser" "^7.10.1" "@babel/types" "^7.10.1" +"@babel/template@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" + integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/parser" "^7.10.4" + "@babel/types" "^7.10.4" + "@babel/traverse@^7.1.0", "@babel/traverse@^7.10.1", "@babel/traverse@^7.4.3", "@babel/traverse@^7.7.0": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.10.1.tgz#bbcef3031e4152a6c0b50147f4958df54ca0dd27" @@ -1006,6 +1219,36 @@ globals "^11.1.0" lodash "^4.17.13" +"@babel/traverse@^7.10.4", "@babel/traverse@^7.10.5": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.10.5.tgz#77ce464f5b258be265af618d8fddf0536f20b564" + integrity sha512-yc/fyv2gUjPqzTz0WHeRJH2pv7jA9kA7mBX2tXl/x5iOE81uaVPuGPtaYk7wmkx4b67mQ7NqI8rmT2pF47KYKQ== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.10.5" + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-split-export-declaration" "^7.10.4" + "@babel/parser" "^7.10.5" + "@babel/types" "^7.10.5" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.19" + +"@babel/traverse@^7.11.0": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.11.0.tgz#9b996ce1b98f53f7c3e4175115605d56ed07dd24" + integrity sha512-ZB2V+LskoWKNpMq6E5UUCrjtDUh5IOTAyIl0dTjIEoXum/iKWkoIEKIRDnUucO6f+2FzNkE0oD4RLKoPIufDtg== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.11.0" + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-split-export-declaration" "^7.11.0" + "@babel/parser" "^7.11.0" + "@babel/types" "^7.11.0" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.19" + "@babel/types@^7.0.0", "@babel/types@^7.10.1", "@babel/types@^7.10.2", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.7.0": version "7.10.2" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.2.tgz#30283be31cad0dbf6fb00bd40641ca0ea675172d" @@ -1015,6 +1258,24 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" +"@babel/types@^7.10.4", "@babel/types@^7.10.5": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.5.tgz#d88ae7e2fde86bfbfe851d4d81afa70a997b5d15" + integrity sha512-ixV66KWfCI6GKoA/2H9v6bQdbfXEwwpOdQ8cRvb4F+eyvhlaHxWFMQB4+3d9QFJXZsiiiqVrewNV0DFEQpyT4Q== + dependencies: + "@babel/helper-validator-identifier" "^7.10.4" + lodash "^4.17.19" + to-fast-properties "^2.0.0" + +"@babel/types@^7.11.0": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.11.0.tgz#2ae6bf1ba9ae8c3c43824e5861269871b206e90d" + integrity sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA== + dependencies: + "@babel/helper-validator-identifier" "^7.10.4" + lodash "^4.17.19" + to-fast-properties "^2.0.0" + "@cnakazawa/watch@^1.0.3": version "1.0.4" resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" @@ -1184,7 +1445,7 @@ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== -"@peculiar/asn1-schema@^2.0.1", "@peculiar/asn1-schema@^2.0.3": +"@peculiar/asn1-schema@^2.0.1": version "2.0.5" resolved "https://registry.yarnpkg.com/@peculiar/asn1-schema/-/asn1-schema-2.0.5.tgz#ba6c5a107eec16a23804d0176a3595837b53c0e9" integrity sha512-VIKJjsgMkv+yyWx3C+D4xo6/NeCg0XFBgNlavtkxELijV+aKAq53du5KkOJbeZtm1nn9CinQKny2PqL8zCfpeA== @@ -1194,6 +1455,16 @@ pvtsutils "^1.0.10" tslib "^1.11.1" +"@peculiar/asn1-schema@^2.0.8": + version "2.0.8" + resolved "https://registry.yarnpkg.com/@peculiar/asn1-schema/-/asn1-schema-2.0.8.tgz#bafb74388590f6ec3d53d1b2a4fdbe66d44224a4" + integrity sha512-D8ZqT61DdzuXfrILNvtdf7MUcTY2o9WHwmF0WgTKPEGNY5SDxNAjBY3enuwV9SXcSuCAwWac9c9v0vsswB1NIw== + dependencies: + "@types/asn1js" "^0.0.1" + asn1js "^2.0.26" + pvtsutils "^1.0.10" + tslib "^1.11.1" + "@peculiar/json-schema@^1.1.10": version "1.1.10" resolved "https://registry.yarnpkg.com/@peculiar/json-schema/-/json-schema-1.1.10.tgz#d772b4323c9a4b5352b5ad52dc821a07b0db4877" @@ -1201,16 +1472,16 @@ dependencies: tslib "^1.11.1" -"@peculiar/webcrypto@^1.0.22": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@peculiar/webcrypto/-/webcrypto-1.1.1.tgz#4c7498e4861878e299ef058bce1208a4d063d0ff" - integrity sha512-Bu2XgOvzirnLcojZYs4KQ8hOLf2ETpa0NL6btQt5NgsAwctI6yVkzgYP+EcG7Mm579RBP+V0LM5rXyMlTVx23A== +"@peculiar/webcrypto@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@peculiar/webcrypto/-/webcrypto-1.1.2.tgz#3114da877ddd9d2d0be10188371e15855aa71368" + integrity sha512-BkgD5iH2n3+Fdd/+xfhac8VbISo4MPvECPhK1kRpuYC7PnhxaJe2rpU7B4udvMeEL8lhJlvCWybo8Y7A29u/xQ== dependencies: - "@peculiar/asn1-schema" "^2.0.3" + "@peculiar/asn1-schema" "^2.0.8" "@peculiar/json-schema" "^1.1.10" pvtsutils "^1.0.10" - tslib "^1.11.2" - webcrypto-core "^1.1.0" + tslib "^2.0.0" + webcrypto-core "^1.1.2" "@sinonjs/commons@^1.7.0": version "1.8.0" @@ -1337,10 +1608,10 @@ dependencies: "@types/react" "*" -"@types/lodash@^4.14.152": - version "4.14.155" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.155.tgz#e2b4514f46a261fd11542e47519c20ebce7bc23a" - integrity sha512-vEcX7S7aPhsBCivxMwAANQburHBtfN9RdyXFk84IJmu2Z4Hkg1tOFgaslRiEqqvoLtbCBi6ika1EMspE+NZ9Lg== +"@types/lodash@^4.14.158": + version "4.14.158" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.158.tgz#b38ea8b6fe799acd076d7a8d7ab71c26ef77f785" + integrity sha512-InCEXJNTv/59yO4VSfuvNrZHt7eeNtWQEgnieIA+mIC+MOWM9arOWG2eQ8Vhk6NbOre6/BidiXhkZYeDY9U35w== "@types/minimatch@*": version "3.0.3" @@ -1357,10 +1628,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.11.tgz#61d4886e2424da73b7b25547f59fdcb534c165a3" integrity sha512-lCvvI24L21ZVeIiyIUHZ5Oflv1hhHQ5E1S25IRlKIXaRkVgmXpJMI3wUJkmym2bTbCe+WoIibQnMVAU3FguaOg== -"@types/node@^12.12.41": - version "12.12.44" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.44.tgz#0d400a1453adcb359b133acceae4dd8bb0e0a159" - integrity sha512-jM6QVv0Sm5d3nW+nUD5jSzPcO6oPqboitSNcwgBay9hifVq/Rauq1PYnROnsmuw45JMBiTnsPAno0bKu2e2xrg== +"@types/node@^12.12.51": + version "12.12.51" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.51.tgz#446a67af8c5ff98947d7cef296484c6ad47ddb16" + integrity sha512-6ILqt8iNThALrxDv2Q4LyYFQxULQz96HKNIFd4s9QRQaiHINYeUpLqeU/2IU7YMtvipG1fQVAy//vY8/fX1Y9w== "@types/prop-types@*": version "15.7.3" @@ -1463,6 +1734,18 @@ semver "^7.3.2" tsutils "^3.17.1" +"@typescript-eslint/eslint-plugin@^3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.7.0.tgz#0f91aa3c83d019591719e597fbdb73a59595a263" + integrity sha512-4OEcPON3QIx0ntsuiuFP/TkldmBGXf0uKxPQlGtS/W2F3ndYm8Vgdpj/woPJkzUc65gd3iR+qi3K8SDQP/obFg== + dependencies: + "@typescript-eslint/experimental-utils" "3.7.0" + debug "^4.1.1" + functional-red-black-tree "^1.0.1" + regexpp "^3.0.0" + semver "^7.3.2" + tsutils "^3.17.1" + "@typescript-eslint/experimental-utils@3.4.0": version "3.4.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-3.4.0.tgz#8a44dfc6fb7f1d071937b390fe27608ebda122b8" @@ -1473,13 +1756,14 @@ eslint-scope "^5.0.0" eslint-utils "^2.0.0" -"@typescript-eslint/experimental-utils@^2.5.0": - version "2.34.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz#d3524b644cdb40eebceca67f8cf3e4cc9c8f980f" - integrity sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA== +"@typescript-eslint/experimental-utils@3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-3.7.0.tgz#0ee21f6c48b2b30c63211da23827725078d5169a" + integrity sha512-xpfXXAfZqhhqs5RPQBfAFrWDHoNxD5+sVB5A46TF58Bq1hRfVROrWHcQHHUM9aCBdy9+cwATcvCbRg8aIRbaHQ== dependencies: "@types/json-schema" "^7.0.3" - "@typescript-eslint/typescript-estree" "2.34.0" + "@typescript-eslint/types" "3.7.0" + "@typescript-eslint/typescript-estree" "3.7.0" eslint-scope "^5.0.0" eslint-utils "^2.0.0" @@ -1493,18 +1777,21 @@ "@typescript-eslint/typescript-estree" "3.4.0" eslint-visitor-keys "^1.1.0" -"@typescript-eslint/typescript-estree@2.34.0": - version "2.34.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz#14aeb6353b39ef0732cc7f1b8285294937cf37d5" - integrity sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg== +"@typescript-eslint/parser@^3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-3.7.0.tgz#3e9cd9df9ea644536feb6e5acdb8279ecff96ce9" + integrity sha512-2LZauVUt7jAWkcIW7djUc3kyW+fSarNEuM3RF2JdLHR9BfX/nDEnyA4/uWz0wseoWVZbDXDF7iF9Jc342flNqQ== dependencies: - debug "^4.1.1" + "@types/eslint-visitor-keys" "^1.0.0" + "@typescript-eslint/experimental-utils" "3.7.0" + "@typescript-eslint/types" "3.7.0" + "@typescript-eslint/typescript-estree" "3.7.0" eslint-visitor-keys "^1.1.0" - glob "^7.1.6" - is-glob "^4.0.1" - lodash "^4.17.15" - semver "^7.3.2" - tsutils "^3.17.1" + +"@typescript-eslint/types@3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-3.7.0.tgz#09897fab0cb95479c01166b10b2c03c224821077" + integrity sha512-reCaK+hyKkKF+itoylAnLzFeNYAEktB0XVfSQvf0gcVgpz1l49Lt6Vo9x4MVCCxiDydA0iLAjTF/ODH0pbfnpg== "@typescript-eslint/typescript-estree@3.4.0": version "3.4.0" @@ -1519,6 +1806,27 @@ semver "^7.3.2" tsutils "^3.17.1" +"@typescript-eslint/typescript-estree@3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-3.7.0.tgz#66872e6da120caa4b64e6b4ca5c8702afc74738d" + integrity sha512-xr5oobkYRebejlACGr1TJ0Z/r0a2/HUf0SXqPvlgUMwiMqOCu/J+/Dr9U3T0IxpE5oLFSkqMx1FE/dKaZ8KsOQ== + dependencies: + "@typescript-eslint/types" "3.7.0" + "@typescript-eslint/visitor-keys" "3.7.0" + debug "^4.1.1" + glob "^7.1.6" + is-glob "^4.0.1" + lodash "^4.17.15" + semver "^7.3.2" + tsutils "^3.17.1" + +"@typescript-eslint/visitor-keys@3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-3.7.0.tgz#ac0417d382a136e4571a0b0dcfe52088cb628177" + integrity sha512-k5PiZdB4vklUpUX4NBncn5RBKty8G3ihTY+hqJsCdMuD0v4jofI5xuqwnVcWxfv6iTm2P/dfEa2wMUnsUY8ODw== + dependencies: + eslint-visitor-keys "^1.1.0" + "@webassemblyjs/ast@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" @@ -1707,7 +2015,7 @@ acorn@^6.0.1, acorn@^6.4.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== -acorn@^7.1.1, acorn@^7.2.0: +acorn@^7.1.1, acorn@^7.3.1: version "7.3.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.3.1.tgz#85010754db53c3fbaf3b9ea3e083aa5c5d147ffd" integrity sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA== @@ -2046,7 +2354,7 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.0.tgz#a17b3a8ea811060e74d47d306122400ad4497ae2" integrity sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA== -babel-eslint@^10.0.1, babel-eslint@^10.0.3, babel-eslint@^10.1.0: +babel-eslint@^10.0.1, babel-eslint@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" integrity sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg== @@ -2180,7 +2488,7 @@ bluebird@^3.5.0, bluebird@^3.5.5: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== -blueimp-canvas-to-blob@^3.5.0: +blueimp-canvas-to-blob@^3.27.0: version "3.27.0" resolved "https://registry.yarnpkg.com/blueimp-canvas-to-blob/-/blueimp-canvas-to-blob-3.27.0.tgz#a2bd5c43587b95dedf0f6998603452d1bfcc9b9e" integrity sha512-AcIj+hCw6WquxzJuzC6KzgYmqxLFeTWe88KuY2BEIsW1zbEOfoinDAGlhyvFNGt+U3JElkVSK7anA1FaSdmmfA== @@ -2572,7 +2880,7 @@ chokidar@^2.1.8: optionalDependencies: fsevents "^1.2.7" -chokidar@^3.3.1, chokidar@^3.4.0: +chokidar@^3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.0.tgz#b30611423ce376357c765b9b8f904b9fba3c0be8" integrity sha512-aXAaho2VJtisB/1fg1+3nlLJqGOuewTzQpd/Tz0yTg2R0e4IGtshYvtjowyEumcBv2z+y4+kc75Mz7j5xJskcQ== @@ -2587,6 +2895,21 @@ chokidar@^3.3.1, chokidar@^3.4.0: optionalDependencies: fsevents "~2.1.2" +chokidar@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.1.tgz#e905bdecf10eaa0a0b1db0c664481cc4cbc22ba1" + integrity sha512-TQTJyr2stihpC4Sya9hs2Xh+O2wf+igjL36Y75xx2WdHuiICcn/XJza46Jwt0eT5hVpQOzo3FpY3cj3RVYLX0g== + dependencies: + anymatch "~3.1.1" + braces "~3.0.2" + glob-parent "~5.1.0" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.4.0" + optionalDependencies: + fsevents "~2.1.2" + chownr@^1.1.1: version "1.1.4" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" @@ -2622,7 +2945,7 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -classnames@^2.1.2: +classnames@^2.2.6: version "2.2.6" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== @@ -2739,14 +3062,14 @@ commondir@^1.0.1: resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= -commonmark@^0.28.1: - version "0.28.1" - resolved "https://registry.yarnpkg.com/commonmark/-/commonmark-0.28.1.tgz#06eab8d52338b839fa1a2d75af0085eed1b1beae" - integrity sha1-Buq41SM4uDn6Gi11rwCF7tGxvq4= +commonmark@^0.29.1: + version "0.29.1" + resolved "https://registry.yarnpkg.com/commonmark/-/commonmark-0.29.1.tgz#fdbf5970ca23600f4a27487e30eed43b66b83ef5" + integrity sha512-DafPdNYFXoEhsSiR4O+dJ45UJBfDL4cBTks4B+agKiaWt7qjG0bIhg5xuCE0RqU71ikJcBIf4/sRHh9vYQVF8Q== dependencies: - entities "~ 1.1.1" - mdurl "~ 1.0.1" - minimist "~ 1.2.0" + entities "~1.1.1" + mdurl "~1.0.1" + minimist "~1.2.0" string.prototype.repeat "^0.2.0" component-emitter@^1.2.1: @@ -2769,7 +3092,7 @@ concat-stream@^1.5.0: readable-stream "^2.2.2" typedarray "^0.0.6" -concurrently@^4.0.1: +concurrently@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-4.1.2.tgz#1a683b2b5c41e9ed324c9002b9f6e4c6e1f3b6d7" integrity sha512-Kim9SFrNr2jd8/0yNYqDTFALzUX1tvimmwFWxmp/D4mRI+kbqIIwE2RkBDrxS2ic25O1UgQMI5AtBqdtX3ynYg== @@ -2836,11 +3159,6 @@ core-js-compat@^3.6.2: browserslist "^4.8.5" semver "7.0.0" -core-js-pure@^3.0.0: - version "3.6.5" - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.5.tgz#c79e75f5e38dbc85a662d91eea52b8256d53b813" - integrity sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA== - core-js@^1.0.0: version "1.2.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" @@ -2866,7 +3184,7 @@ cosmiconfig@^5.0.0: js-yaml "^3.13.1" parse-json "^4.0.0" -counterpart@^0.18.0: +counterpart@^0.18.6: version "0.18.6" resolved "https://registry.yarnpkg.com/counterpart/-/counterpart-0.18.6.tgz#cf6b60d8ef99a4b44b8bf6445fa99b4bd1b2f9dd" integrity sha512-cAIDAYbC3x8S2DDbvFEJ4TzPtPYXma25/kfAkfmprNLlkPWeX4SdUp1c2xklfphqCU3HnDaivR4R3BrAYf5OMA== @@ -2913,7 +3231,7 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: safe-buffer "^5.0.1" sha.js "^2.4.8" -create-react-class@^15.6.0: +create-react-class@^15.6.3: version "15.6.3" resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.6.3.tgz#2d73237fb3f970ae6ebe011a9e66f46dbca80036" integrity sha512-M+/3Q6E6DLO6Yx3OwrWjwHBnvfXXYA7W+dFjt/ZDBemHO1DDZhsalX/NUtnTYclN6GfnBDRh4qRHjcDHmlJBJg== @@ -2922,7 +3240,7 @@ create-react-class@^15.6.0: loose-envify "^1.3.1" object-assign "^4.1.1" -cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.5: +cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== @@ -3152,7 +3470,7 @@ detect-node@^2.0.4: resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw== -diff-dom@^4.1.3: +diff-dom@^4.1.6: version "4.1.6" resolved "https://registry.yarnpkg.com/diff-dom/-/diff-dom-4.1.6.tgz#ecd20f4b34703d777b7956790fc7e28e5ff3fece" integrity sha512-hzHojf1Ar3x1Db/1ijN/uhwYDgde+RoP8pPAPJlrmxp05Bt+Z9Hd7tmuEyPYu1mEuvcO+0pQRZAOCMKi+0I1PQ== @@ -3160,7 +3478,7 @@ diff-dom@^4.1.3: rollup-plugin-terser "^5.1.1" updates "^8.5.2" -diff-match-patch@^1.0.4: +diff-match-patch@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.5.tgz#abb584d5f10cd1196dfc55aa03701592ae3f7b37" integrity sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw== @@ -3334,9 +3652,9 @@ electron-to-chromium@^1.3.413: integrity sha512-Oo+0+CN9d2z6FToQW6Hwvi9ez09Y/usKwr0tsDsyg43a871zVJCi1nR0v03djLbRNcaCKjtrnVf2XJhTxEpPCg== elliptic@^6.0.0, elliptic@^6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.2.tgz#05c5678d7173c049d8ca433552224a495d0e3762" - integrity sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw== + version "6.5.3" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6" + integrity sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw== dependencies: bn.js "^4.4.0" brorand "^1.0.1" @@ -3366,11 +3684,6 @@ emojibase-regex@^4.0.1: resolved "https://registry.yarnpkg.com/emojibase-regex/-/emojibase-regex-4.0.1.tgz#a2cd4bbb42825422da9ec72f15e970bc2c90b46a" integrity sha512-S42UHkFfz15i4NNz+wi9iMKFo+B6Kalc6PJLpYX0BUANViXw4vSyYZMFdBGRLduSabWHuEcTLZl9xOa2YP3eJw== -emojis-list@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" - integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= - emojis-list@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" @@ -3390,15 +3703,6 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0: dependencies: once "^1.4.0" -enhanced-resolve@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f" - integrity sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng== - dependencies: - graceful-fs "^4.1.2" - memory-fs "^0.4.0" - tapable "^1.0.0" - enhanced-resolve@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz#2937e2b8066cd0fe7ce0990a98f0d71a35189f66" @@ -3408,6 +3712,15 @@ enhanced-resolve@^4.1.0: memory-fs "^0.5.0" tapable "^1.0.0" +enhanced-resolve@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz#3b806f3bfafc1ec7de69551ef93cca46c1704126" + integrity sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ== + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.5.0" + tapable "^1.0.0" + enquirer@^2.3.5: version "2.3.5" resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.5.tgz#3ab2b838df0a9d8ab9e7dff235b0e8712ef92381" @@ -3415,7 +3728,7 @@ enquirer@^2.3.5: dependencies: ansi-colors "^3.2.1" -entities@^1.1.1, "entities@~ 1.1.1", entities@~1.1.1: +entities@^1.1.1, entities@~1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== @@ -3425,7 +3738,7 @@ entities@^2.0.0: resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f" integrity sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ== -enzyme-adapter-react-16@^1.15.1: +enzyme-adapter-react-16@^1.15.2: version "1.15.2" resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.15.2.tgz#b16db2f0ea424d58a808f9df86ab6212895a4501" integrity sha512-SkvDrb8xU3lSxID8Qic9rB8pvevDbLybxPK6D/vW7PrT0s2Cl/zJYuXvsd1EBTz0q4o3iqG3FJhpYz3nUNpM2Q== @@ -3460,7 +3773,7 @@ enzyme-shallow-equal@^1.0.1: has "^1.0.3" object-is "^1.0.2" -enzyme@^3.10.0: +enzyme@^3.11.0: version "3.11.0" resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-3.11.0.tgz#71d680c580fe9349f6f5ac6c775bc3e6b7a79c28" integrity sha512-Dw8/Gs4vRjxY6/6i9wU0V+utmQO9kvh9XLnz3LIudviOnVYDEe2ec+0k+NQoMamn1VrjKgCUOWj5jG/5M5M0Qw== @@ -3595,11 +3908,6 @@ eslint-config-google@^0.14.0: resolved "https://registry.yarnpkg.com/eslint-config-google/-/eslint-config-google-0.14.0.tgz#4f5f8759ba6e11b424294a219dbfa18c508bcc1a" integrity sha512-WsbX4WbjuMvTdeVL6+J3rK1RGhCTqjsFjX7UMSMgZiyxxaNLkoJENbrGExzERFeoTpGw3F3FypTiWAP9ZXzkEw== -eslint-config-google@^0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/eslint-config-google/-/eslint-config-google-0.7.1.tgz#5598f8498e9e078420f34b80495b8d959f651fb2" - integrity sha1-VZj4SY6eB4Qg80uASVuNlZ9lH7I= - eslint-config-matrix-org@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/eslint-config-matrix-org/-/eslint-config-matrix-org-0.1.2.tgz#b5d7e193e4f3fc5041905967b53c5ddd6924c793" @@ -3664,14 +3972,14 @@ eslint-plugin-babel@^5.2.1: dependencies: eslint-rule-composer "^0.3.0" -eslint-plugin-babel@^5.3.0: +eslint-plugin-babel@^5.3.0, eslint-plugin-babel@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/eslint-plugin-babel/-/eslint-plugin-babel-5.3.1.tgz#75a2413ffbf17e7be57458301c60291f2cfbf560" integrity sha512-VsQEr6NH3dj664+EyxJwO4FCYm/00JhYb3Sk3ft8o+fpKuIfQ9TaW6uVUfvwMXHcf/lsnRIoyFPsLMyiWCSL/g== dependencies: eslint-rule-composer "^0.3.0" -eslint-plugin-flowtype@^2.30.0: +eslint-plugin-flowtype@^2.50.3: version "2.50.3" resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.50.3.tgz#61379d6dce1d010370acd6681740fd913d68175f" integrity sha512-X+AoKVOr7Re0ko/yEXyM5SSZ0tazc6ffdIOocp2fFUlWoDt7DV0Bz99mngOkAFLOAWjqRA5jPwqUCbrx13XoxQ== @@ -3697,14 +4005,7 @@ eslint-plugin-import@^2.14.0: resolve "^1.17.0" tsconfig-paths "^3.9.0" -eslint-plugin-jest@^23.0.4: - version "23.13.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-23.13.2.tgz#7b7993b4e09be708c696b02555083ddefd7e4cc7" - integrity sha512-qZit+moTXTyZFNDqSIR88/L3rdBlTU7CuW6XmyErD2FfHEkdoLgThkRbiQjzgYnX6rfgLx3Ci4eJmF4Ui5v1Cw== - dependencies: - "@typescript-eslint/experimental-utils" "^2.5.0" - -eslint-plugin-react-hooks@^2.0.1: +eslint-plugin-react-hooks@^2.5.1: version "2.5.1" resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-2.5.1.tgz#4ef5930592588ce171abeb26f400c7fbcbc23cd0" integrity sha512-Y2c4b55R+6ZzwtTppKwSmK/Kar8AdLiC2f9NADCuxbcTgPPg41Gyqa6b9GppgXSvCtkRw43ZE86CT5sejKC6/g== @@ -3721,7 +4022,7 @@ eslint-plugin-react-native@^3.8.1: dependencies: eslint-plugin-react-native-globals "^0.1.1" -eslint-plugin-react@^7.19.0: +eslint-plugin-react@^7.19.0, eslint-plugin-react@^7.20.3: version "7.20.3" resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.20.3.tgz#0590525e7eb83890ce71f73c2cf836284ad8c2f1" integrity sha512-txbo090buDeyV0ugF3YMWrzLIUqpYTsWSDZV9xLSmExE1P/Kmgg9++PD931r+KEWS66O1c9R4srLVVHmeHpoAg== @@ -3738,23 +4039,6 @@ eslint-plugin-react@^7.19.0: resolve "^1.17.0" string.prototype.matchall "^4.0.2" -eslint-plugin-react@^7.7.0: - version "7.20.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.20.0.tgz#f98712f0a5e57dfd3e5542ef0604b8739cd47be3" - integrity sha512-rqe1abd0vxMjmbPngo4NaYxTcR3Y4Hrmc/jg4T+sYz63yqlmJRknpEQfmWY+eDWPuMmix6iUIK+mv0zExjeLgA== - dependencies: - array-includes "^3.1.1" - doctrine "^2.1.0" - has "^1.0.3" - jsx-ast-utils "^2.2.3" - object.entries "^1.1.1" - object.fromentries "^2.0.2" - object.values "^1.1.1" - prop-types "^15.7.2" - resolve "^1.15.1" - string.prototype.matchall "^4.0.2" - xregexp "^4.3.0" - eslint-rule-composer@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9" @@ -3790,15 +4074,22 @@ eslint-utils@^2.0.0: dependencies: eslint-visitor-keys "^1.1.0" -eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.2.0: +eslint-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" + integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== -eslint@7.3.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.3.1.tgz#76392bd7e44468d046149ba128d1566c59acbe19" - integrity sha512-cQC/xj9bhWUcyi/RuMbRtC3I0eW8MH0jhRELSvpKYkWep3C6YZ2OkvcvJVUeO6gcunABmzptbXBuDoXsjHmfTA== +eslint@7.5.0: + version "7.5.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.5.0.tgz#9ecbfad62216d223b82ac9ffea7ef3444671d135" + integrity sha512-vlUP10xse9sWt9SGRtcr1LAC67BENcQMFeV+w5EvLEoFe3xJ8cF1Skd0msziRx/VMC+72B4DxreCE+OR12OA6Q== dependencies: "@babel/code-frame" "^7.0.0" ajv "^6.10.0" @@ -3808,9 +4099,9 @@ eslint@7.3.1: doctrine "^3.0.0" enquirer "^2.3.5" eslint-scope "^5.1.0" - eslint-utils "^2.0.0" - eslint-visitor-keys "^1.2.0" - espree "^7.1.0" + eslint-utils "^2.1.0" + eslint-visitor-keys "^1.3.0" + espree "^7.2.0" esquery "^1.2.0" esutils "^2.0.2" file-entry-cache "^5.0.1" @@ -3824,7 +4115,7 @@ eslint@7.3.1: js-yaml "^3.13.1" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" - lodash "^4.17.14" + lodash "^4.17.19" minimatch "^3.0.4" natural-compare "^1.4.0" optionator "^0.9.1" @@ -3889,14 +4180,14 @@ espree@^6.1.2: acorn-jsx "^5.2.0" eslint-visitor-keys "^1.1.0" -espree@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.1.0.tgz#a9c7f18a752056735bf1ba14cb1b70adc3a5ce1c" - integrity sha512-dcorZSyfmm4WTuTnE5Y7MEN1DyoPYy1ZR783QW1FJoenn7RailyWFsq/UL6ZAAA7uXurN9FIpYyUs3OfiIW+Qw== +espree@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.2.0.tgz#1c263d5b513dbad0ac30c4991b93ac354e948d69" + integrity sha512-H+cQ3+3JYRMEIOl87e7QdHX70ocly5iW4+dttuR8iYSPr/hXKFb+7dBsZ7+u1adC4VrnPlTkv0+OwuPnDop19g== dependencies: - acorn "^7.2.0" + acorn "^7.3.1" acorn-jsx "^5.2.0" - eslint-visitor-keys "^1.2.0" + eslint-visitor-keys "^1.3.0" esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" @@ -3927,11 +4218,6 @@ estraverse@^5.1.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.1.0.tgz#374309d39fd935ae500e7b92e8a6b4c720e59642" integrity sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw== -estree-walker@^0.5.0: - version "0.5.2" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.5.2.tgz#d3850be7529c9580d815600b53126515e146dd39" - integrity sha512-XpCnW/AE10ws/kDAs37cngSkvgIR8aN3G0MS85m7dUpuK2EREo9VJ00uvw6Dg/hXEpfsE1I1TvJOJr+Z+TL+ig== - estree-walker@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362" @@ -4192,7 +4478,7 @@ file-loader@^3.0.1: loader-utils "^1.0.2" schema-utils "^1.0.0" -file-saver@^1.3.3: +file-saver@^1.3.8: version "1.3.8" resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-1.3.8.tgz#e68a30c7cb044e2fb362b428469feb291c2e09d8" integrity sha512-spKHSBQIxxS81N/O21WmuXA2F6wppUCsutpzenOeZzOCCJ5gEfcbqJP983IrpLXzYmXnMUa6J03SubcNPdKrlg== @@ -4202,10 +4488,10 @@ file-uri-to-path@1.0.0: resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== -filesize@3.5.6: - version "3.5.6" - resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.5.6.tgz#5fd98f3eac94ec9516ef8ed5782fad84a01a0a1a" - integrity sha1-X9mPPqyU7JUW747VeC+thKAaCho= +filesize@3.6.1: + version "3.6.1" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" + integrity sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg== fill-range@^4.0.0: version "4.0.0" @@ -4255,7 +4541,7 @@ find-up@^3.0.0: dependencies: locate-path "^3.0.0" -findup-sync@3.0.0: +findup-sync@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-3.0.0.tgz#17b108f9ee512dfb7a5c7f3c8b27ea9e1a9c08d1" integrity sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg== @@ -4279,11 +4565,6 @@ flatted@^2.0.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== -flow-parser@^0.57.3: - version "0.57.3" - resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.57.3.tgz#b8d241a1b1cbae043afa7976e39f269988d8fe34" - integrity sha1-uNJBobHLrgQ6+nl2458mmYjY/jQ= - flush-write-stream@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" @@ -4301,12 +4582,12 @@ flux@2.1.1: fbjs "0.1.0-alpha.7" immutable "^3.7.4" -focus-lock@^0.6.7: - version "0.6.8" - resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-0.6.8.tgz#61985fadfa92f02f2ee1d90bc738efaf7f3c9f46" - integrity sha512-vkHTluRCoq9FcsrldC0ulQHiyBYgVJB2CX53I8r0nTC6KnEij7Of0jpBspjt3/CuNb6fyoj3aOh9J2HgQUM0og== +focus-lock@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-0.7.0.tgz#b2bfb0ca7beacc8710a1ff74275fe0dc60a1d88a" + integrity sha512-LI7v2mH02R55SekHYdv9pRHR9RajVNyIJ2N5IEkWbg7FT5ZmJ9Hw4mWxHeEUcd+dJo0QmzztHvDvWcc7prVFsw== -focus-visible@^5.0.2: +focus-visible@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/focus-visible/-/focus-visible-5.1.0.tgz#4b9d40143b865f53eafbd93ca66672b3bf9e7b6a" integrity sha512-nPer0rjtzdZ7csVIu233P2cUm/ks/4aVSI+5KUkYrYpgA7ujgC3p6J7FtFU+AIMWwnwYQOB/yeiOITxFeYIXiw== @@ -4407,7 +4688,7 @@ functions-have-names@^1.2.0: resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.1.tgz#a981ac397fa0c9964551402cdc5533d7a4d52f91" integrity sha512-j48B/ZI7VKs3sgeI2cZp7WXWmZXu7Iq5pl5/vptV5N2mq+DGFuS/ulaDjtaoLpYzuD6u8UgrUKHfgo7fDTSiBA== -fuse.js@^2.2.0: +fuse.js@^2.7.4: version "2.7.4" resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-2.7.4.tgz#96e420fde7ef011ac49c258a621314fe576536f9" integrity sha1-luQg/efvARrEnCWKYhMU/ldlNvk= @@ -4451,7 +4732,7 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" -gfm.css@^1.1.1: +gfm.css@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/gfm.css/-/gfm.css-1.1.2.tgz#94acfa600672663b9dd0fd4b6ee5d11c8dbc161e" integrity sha512-KhK3rqxMj+UTLRxWnfUA5n8XZYMWfHrrcCxtWResYR2B3hWIqBM6v9FPGZSlVuX+ScLewizOvNkjYXuPs95ThQ== @@ -4481,7 +4762,7 @@ glob-to-regexp@^0.4.1: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== -glob@^5.0.14: +glob@^5.0.15: version "5.0.15" resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E= @@ -4504,13 +4785,6 @@ glob@^7.0.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" -global-modules@2.0.0, global-modules@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" - integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== - dependencies: - global-prefix "^3.0.0" - global-modules@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" @@ -4520,6 +4794,13 @@ global-modules@^1.0.0: is-windows "^1.0.1" resolve-dir "^1.0.0" +global-modules@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" + integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== + dependencies: + global-prefix "^3.0.0" + global-prefix@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" @@ -4676,10 +4957,10 @@ hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.1" -highlight.js@^9.15.8: - version "9.18.1" - resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.18.1.tgz#ed21aa001fe6252bb10a3d76d47573c6539fe13c" - integrity sha512-OrVKYz70LHsnCgmbXctv/bfuvntIKDz177h0Co37DQ5jamGZLVmoCVMtjMtNZY3X9DrCcKfklHPNeA0uPZhSJg== +highlight.js@^10.1.2: + version "10.1.2" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.1.2.tgz#c20db951ba1c22c055010648dfffd7b2a968e00c" + integrity sha512-Q39v/Mn5mfBlMff9r+zzA+gWxRsCRKwEMvYTiisLr/XUiFI/4puWt0Ojdko3R3JCNWGdOWaA5g/Yxqa23kC5AA== hmac-drbg@^1.0.0: version "1.0.1" @@ -4730,7 +5011,7 @@ html-encoding-sniffer@^1.0.2: dependencies: whatwg-encoding "^1.0.1" -html-entities@^1.2.1: +html-entities@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.3.1.tgz#fb9a1a4b5b14c5daba82d3e34c6ae4fe701a0e44" integrity sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA== @@ -4862,7 +5143,7 @@ import-lazy@^3.1.0: resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-3.1.0.tgz#891279202c8a2280fdbd6674dbd8da1a1dfc67cc" integrity sha512-8/gvXvX2JMn0F+CDlSC4l6kOmVaLOO3XLkksI7CI3Ud95KDYJuYur2b9P/PUt/i/pDAMd/DulQsNbbbmRRsDIQ== -import-local@2.0.0, import-local@^2.0.0: +import-local@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== @@ -4951,10 +5232,10 @@ internal-slot@^1.0.2: has "^1.0.3" side-channel "^1.0.2" -interpret@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" - integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== +interpret@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" + integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== invariant@^2.2.2, invariant@^2.2.4: version "2.2.4" @@ -5888,14 +6169,6 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -jsx-ast-utils@^2.2.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.3.0.tgz#edd727794ea284d7fda575015ed1b0cde0289ab6" - integrity sha512-3HNoc7nZ1hpZIKB3hJ7BlFRkzCx2BynRtfSwbkqZdpRdvAPsGMnzclPwrvDBS7/lalHTj21NwIeaEpysHBOudg== - dependencies: - array-includes "^3.1.1" - object.assign "^4.1.0" - jsx-ast-utils@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.4.1.tgz#1114a4c1209481db06c690c2b4f488cc665f657e" @@ -5983,7 +6256,7 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -linkifyjs@^2.1.6: +linkifyjs@^2.1.9: version "2.1.9" resolved "https://registry.yarnpkg.com/linkifyjs/-/linkifyjs-2.1.9.tgz#af06e45a2866ff06c4766582590d098a4d584702" integrity sha512-74ivurkK6WHvHFozVaGtQWV38FzBwSTGNmJolEgFp7QgR2bl6ArUWlvT4GcHKbPe1z3nWYi+VUdDZk16zDOVug== @@ -6013,16 +6286,7 @@ loader-runner@^2.4.0: resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== -loader-utils@1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" - integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== - dependencies: - big.js "^5.2.2" - emojis-list "^2.0.0" - json5 "^1.0.1" - -loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3: +loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== @@ -6079,7 +6343,7 @@ lodash.sortby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= -lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.16, lodash@^4.17.4, lodash@^4.2.1: +lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.16, lodash@^4.17.19, lodash@^4.17.4, lodash@^4.2.1: version "4.17.19" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ== @@ -6207,8 +6471,8 @@ mathml-tag-names@^2.0.1: integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg== "matrix-js-sdk@github:matrix-org/matrix-js-sdk#develop": - version "7.1.0" - resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/2a688bdac828dc62916437d83c72cef1e525d5f9" + version "8.0.0" + resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/c669382e12c8cd1d7d538421dfad4f50812af44d" dependencies: "@babel/runtime" "^7.8.3" another-json "^0.2.0" @@ -6249,7 +6513,7 @@ mdast-util-compact@^1.0.0: dependencies: unist-util-visit "^1.1.0" -"mdurl@~ 1.0.1": +mdurl@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= @@ -6268,7 +6532,7 @@ memoize-one@^3.0.1: resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-3.1.1.tgz#ef609811e3bc28970eac2884eece64d167830d17" integrity sha512-YqVh744GsMlZu6xkhGslPSqSurOv6P+kLN2J3ysBZfagLcL5FdRK/0UpgLoL8hwjjEvvAVkjJZyFP+1T6p1vgA== -memory-fs@^0.4.0, memory-fs@^0.4.1: +memory-fs@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= @@ -6383,7 +6647,7 @@ minimist@1.2.0: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= -minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5, "minimist@~ 1.2.0": +minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5, minimist@~1.2.0: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== @@ -6773,7 +7037,7 @@ os-browserify@^0.3.0: resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= -os-locale@^3.0.0, os-locale@^3.1.0: +os-locale@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== @@ -6859,7 +7123,7 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== -pako@^1.0.5, pako@~1.0.5: +pako@^1.0.11, pako@~1.0.5: version "1.0.11" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== @@ -7397,7 +7661,7 @@ qrcode@^1.4.4: pngjs "^3.3.0" yargs "^13.2.4" -qs@^6.5.2, qs@^6.6.0: +qs@^6.5.2, qs@^6.9.4: version "6.9.4" resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687" integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ== @@ -7472,10 +7736,10 @@ rc@1.2.8, rc@^1.2.8: minimist "^1.2.0" strip-json-comments "~2.0.1" -re-resizable@^6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.5.2.tgz#7eb1928c673285d4dcf654211e47acb9a3801c3e" - integrity sha512-Pjo3ydkr/meTr6j3YZqyv+9fRS5UNOj5SaAI06gHFQ35BnpsZKmwNvupCnbo11gjQ1I62Uy+UzlHLO9xPQEuWQ== +re-resizable@^6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.5.4.tgz#909a1e37f9d1a3afd356893a5779a030167be641" + integrity sha512-7T3L1lexB2zkZIDmzRJbwdq+xGFuRkrEVQIf5hBPnh7JuS9kG9Yc8XgIaxTWic1kU7jVlDgqzfId/gvmpBCjpA== dependencies: fast-memoize "^2.5.1" @@ -7502,7 +7766,7 @@ react-clientside-effect@^1.2.2: dependencies: "@babel/runtime" "^7.0.0" -react-dom@^16.9.0: +react-dom@^16.13.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.13.1.tgz#c1bd37331a0486c078ee54c4740720993b2e0e7f" integrity sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag== @@ -7512,13 +7776,13 @@ react-dom@^16.9.0: prop-types "^15.6.2" scheduler "^0.19.1" -react-focus-lock@^2.2.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-2.3.1.tgz#9d5d85899773609c7eefa4fc54fff6a0f5f2fc47" - integrity sha512-j15cWLPzH0gOmRrUg01C09Peu8qbcdVqr6Bjyfxj80cNZmH+idk/bNBYEDSmkAtwkXI+xEYWSmHYqtaQhZ8iUQ== +react-focus-lock@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-2.4.1.tgz#e842cc93da736b5c5d331799012544295cbcee4f" + integrity sha512-c5ZP56KSpj9EAxzScTqQO7bQQNPltf/W1ZEBDqNDOV1XOIwvAyHX0O7db9ekiAtxyKgnqZjQlLppVg94fUeL9w== dependencies: "@babel/runtime" "^7.0.0" - focus-lock "^0.6.7" + focus-lock "^0.7.0" prop-types "^15.6.2" react-clientside-effect "^1.2.2" use-callback-ref "^1.2.1" @@ -7556,7 +7820,7 @@ react-redux@^5.0.6: react-is "^16.6.0" react-lifecycles-compat "^3.0.0" -react-test-renderer@^16.0.0-0, react-test-renderer@^16.9.0: +react-test-renderer@^16.0.0-0, react-test-renderer@^16.13.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.13.1.tgz#de25ea358d9012606de51e012d9742e7f0deabc1" integrity sha512-Sn2VRyOK2YJJldOqoh8Tn/lWQ+ZiKhyZTPtaO0Q6yNj+QDbmRkVFap6pZPy3YQk8DScRDfyqm/KxKYP9gCMRiQ== @@ -7576,7 +7840,7 @@ react-transition-group@^4.4.1: loose-envify "^1.4.0" prop-types "^15.6.2" -react@^16.9.0: +react@^16.13.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e" integrity sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w== @@ -7929,7 +8193,7 @@ reselect@^3.0.1: resolved "https://registry.yarnpkg.com/reselect/-/reselect-3.0.1.tgz#efdaa98ea7451324d092b2b2163a6a1d7a9a2147" integrity sha1-79qpjqdFEyTQkrKyFjpqHXqaIUc= -resize-observer-polyfill@^1.5.0: +resize-observer-polyfill@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== @@ -7969,7 +8233,7 @@ resolve@1.1.7: resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= -resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.15.1, resolve@^1.17.0, resolve@^1.3.2, resolve@^1.8.1: +resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.3.2, resolve@^1.8.1: version "1.17.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== @@ -8001,7 +8265,7 @@ rimraf@2.6.3: dependencies: glob "^7.1.3" -rimraf@^2.4.3, rimraf@^2.5.4, rimraf@^2.6.3: +rimraf@^2.5.4, rimraf@^2.6.3, rimraf@^2.7.1: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== @@ -8110,17 +8374,15 @@ sane@^4.0.3: minimist "^1.1.1" walker "~1.0.5" -sanitize-html@^1.18.4: - version "1.26.0" - resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-1.26.0.tgz#ab38d671526b9b7c08aa7af7f9ad5a73fcc1bbe4" - integrity sha512-xriDBT2FbfN0ZKCcX6H6svkh1bZpO2e5ny05RQGZY6vFOMAU13La2L5YYf3XpcjXSksCYXzPj7YPvyGp5wbaUA== +sanitize-html@^1.27.1: + version "1.27.1" + resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-1.27.1.tgz#ce147951aa3defba13448e2ca8a4e18d8f2e2cd7" + integrity sha512-C+N7E+7ikYaLHdb9lEkQaFOgmj+9ddZ311Ixs/QsBsoLD411/vdLweiFyGqrswUVgLqagOS5NCDxcEPH7trObQ== dependencies: - chalk "^2.4.1" htmlparser2 "^4.1.0" lodash "^4.17.15" postcss "^7.0.27" srcset "^2.0.1" - xtend "^4.0.1" sax@^1.2.4: version "1.2.4" @@ -8321,7 +8583,7 @@ source-list-map@^2.0.0: resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== -source-map-loader@^0.2.3: +source-map-loader@^0.2.4: version "0.2.4" resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-0.2.4.tgz#c18b0dc6e23bf66f6792437557c569a11e072271" integrity sha512-OU6UJUty+i2JDpTItnizPrlpOIBLmQbWMuBg9q5bVtnHACqw1tn9nNwqJLbv0/00JjnJb/Ee5g5WS5vrRv7zIQ== @@ -8702,17 +8964,17 @@ stylelint-config-recommended@^2.2.0: resolved "https://registry.yarnpkg.com/stylelint-config-recommended/-/stylelint-config-recommended-2.2.0.tgz#46ab139db4a0e7151fd5f94af155512886c96d3f" integrity sha512-bZ+d4RiNEfmoR74KZtCKmsABdBJr4iXRiCso+6LtMJPw5rd/KnxUWTxht7TbafrTJK1YRjNgnN0iVZaJfc3xJA== -stylelint-config-standard@^18.2.0: +stylelint-config-standard@^18.3.0: version "18.3.0" resolved "https://registry.yarnpkg.com/stylelint-config-standard/-/stylelint-config-standard-18.3.0.tgz#a2a1b788d2cf876c013feaff8ae276117a1befa7" integrity sha512-Tdc/TFeddjjy64LvjPau9SsfVRexmTFqUhnMBrzz07J4p2dVQtmpncRF/o8yZn8ugA3Ut43E6o1GtjX80TFytw== dependencies: stylelint-config-recommended "^2.2.0" -stylelint-scss@^3.9.0: - version "3.17.2" - resolved "https://registry.yarnpkg.com/stylelint-scss/-/stylelint-scss-3.17.2.tgz#4d849a153f9241834396f5880db2c3c964def4e3" - integrity sha512-e0dmxqsofy/HZj4urcGSJw4S6yHDJxiQdT20/1ciCsd5lomisa7YM4+Qtt1EG4hsqEG1dbEeF855tec1UyqcSA== +stylelint-scss@^3.18.0: + version "3.18.0" + resolved "https://registry.yarnpkg.com/stylelint-scss/-/stylelint-scss-3.18.0.tgz#8f06371c223909bf3f62e839548af1badeed31e9" + integrity sha512-LD7+hv/6/ApNGt7+nR/50ft7cezKP2HM5rI8avIdGaUWre3xlHfV4jKO/DRZhscfuN+Ewy9FMhcTq0CcS0C/SA== dependencies: lodash "^4.17.15" postcss-media-query-parser "^0.2.3" @@ -8780,13 +9042,6 @@ sugarss@^2.0.0: dependencies: postcss "^7.0.2" -supports-color@6.1.0, supports-color@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" - integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== - dependencies: - has-flag "^3.0.0" - supports-color@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b" @@ -8801,6 +9056,13 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" +supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + supports-color@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" @@ -8872,7 +9134,7 @@ test-exclude@^5.2.3: read-pkg-up "^4.0.0" require-main-filename "^2.0.0" -text-encoding-utf-8@^1.0.1: +text-encoding-utf-8@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz#585b62197b0ae437e3c7b5d0af27ac1021e10d13" integrity sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg== @@ -9021,6 +9283,11 @@ tslib@^1.10.0, tslib@^1.11.1, tslib@^1.11.2, tslib@^1.8.1, tslib@^1.9.0, tslib@^ resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q== +tslib@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.0.tgz#18d13fc2dce04051e20f074cc8387fd8089ce4f3" + integrity sha512-lTqkx847PI7xEDYJntxZH89L2/aXInsyF2luSafe/+0fHOMjlBNXdH6th7f70qxLDhul7KZK0zC8V5ZIyHl0/g== + tsutils@^3.17.1: version "3.17.1" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" @@ -9079,12 +9346,7 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@^3.7.3: - version "3.9.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36" - integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ== - -typescript@^3.9.5: +typescript@^3.9.5, typescript@^3.9.7: version "3.9.7" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw== @@ -9319,12 +9581,7 @@ uuid@^3.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -v8-compile-cache@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe" - integrity sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w== - -v8-compile-cache@^2.0.3: +v8-compile-cache@^2.0.3, v8-compile-cache@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745" integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ== @@ -9393,7 +9650,7 @@ w3c-hr-time@^1.0.1: dependencies: browser-process-hrtime "^1.0.0" -walk@^2.3.9: +walk@^2.3.14: version "2.3.14" resolved "https://registry.yarnpkg.com/walk/-/walk-2.3.14.tgz#60ec8631cfd23276ae1e7363ce11d626452e1ef3" integrity sha512-5skcWAUmySj6hkBdH6B6+3ddMjVQYH5Qy9QGbPmN8kVmLteXk+yVXg+yfk1nbX30EYakahLrr8iPcCxJQSCBeg== @@ -9425,10 +9682,10 @@ watchpack@^1.6.1: chokidar "^3.4.0" watchpack-chokidar2 "^2.0.0" -webcrypto-core@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/webcrypto-core/-/webcrypto-core-1.1.1.tgz#c9cd26f8dea696d7b5f5c1b0598ff16e6bdcab7c" - integrity sha512-xK61sFRUyZdSAJG7+bJox36+Tnhxw1PaMbmrLLp30HNTJ4mffqsY2jUMlmGq6OOoej3WO/SsH5serzlzBMZ+jg== +webcrypto-core@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/webcrypto-core/-/webcrypto-core-1.1.2.tgz#c522a9e5596688f2b6bb19e2d336f68efa8bdd57" + integrity sha512-LxM/dTcXr/ZnwwKLox0tGEOIqvP7KIJ4Hk/fFPX20tr1EgqTmpEFZinmu4FzoGVbs6e4jI1priQKCDrOBD3L6w== dependencies: "@peculiar/asn1-schema" "^2.0.1" "@peculiar/json-schema" "^1.1.10" @@ -9441,22 +9698,22 @@ webidl-conversions@^4.0.2: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== -webpack-cli@^3.1.1: - version "3.3.11" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.11.tgz#3bf21889bf597b5d82c38f215135a411edfdc631" - integrity sha512-dXlfuml7xvAFwYUPsrtQAA9e4DOe58gnzSxhgrO/ZM/gyXTBowrsYeubyN4mqGhYdpXMFNyQ6emjJS9M7OBd4g== +webpack-cli@^3.3.12: + version "3.3.12" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.12.tgz#94e9ada081453cd0aa609c99e500012fd3ad2d4a" + integrity sha512-NVWBaz9k839ZH/sinurM+HcDvJOTXwSjYp1ku+5XKeOC03z8v5QitnK/x+lAxGXFyhdayoIf/GOpv85z3/xPag== dependencies: - chalk "2.4.2" - cross-spawn "6.0.5" - enhanced-resolve "4.1.0" - findup-sync "3.0.0" - global-modules "2.0.0" - import-local "2.0.0" - interpret "1.2.0" - loader-utils "1.2.3" - supports-color "6.1.0" - v8-compile-cache "2.0.3" - yargs "13.2.4" + chalk "^2.4.2" + cross-spawn "^6.0.5" + enhanced-resolve "^4.1.1" + findup-sync "^3.0.0" + global-modules "^2.0.0" + import-local "^2.0.0" + interpret "^1.4.0" + loader-utils "^1.4.0" + supports-color "^6.1.0" + v8-compile-cache "^2.1.1" + yargs "^13.3.2" webpack-sources@^1.4.0, webpack-sources@^1.4.1: version "1.4.3" @@ -9466,7 +9723,7 @@ webpack-sources@^1.4.0, webpack-sources@^1.4.1: source-list-map "^2.0.0" source-map "~0.6.1" -webpack@^4.20.2: +webpack@^4.43.0: version "4.43.0" resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.43.0.tgz#c48547b11d563224c561dad1172c8aa0b8a678e6" integrity sha512-GW1LjnPipFW2Y78OOab8NJlCflB7EFskMih2AHdvjbpKMeDJqEgSx24cXXXiPS65+WSwVyxtDsJH6jGX2czy+g== @@ -9495,7 +9752,7 @@ webpack@^4.20.2: watchpack "^1.6.1" webpack-sources "^1.4.1" -what-input@^5.2.6: +what-input@^5.2.10: version "5.2.10" resolved "https://registry.yarnpkg.com/what-input/-/what-input-5.2.10.tgz#f79f5b65cf95d75e55e6d580bb0a6b98174cad4e" integrity sha512-7AQoIMGq7uU8esmKniOtZG3A+pzlwgeyFpkS3f/yzRbxknSL68tvn5gjE6bZ4OMFxCPjpaBd2udUTqlZ0HwrXQ== @@ -9647,13 +9904,6 @@ xml-name-validator@^3.0.0: resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== -xregexp@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.3.0.tgz#7e92e73d9174a99a59743f67a4ce879a04b5ae50" - integrity sha512-7jXDIFXh5yJ/orPn4SXjuVrWWoi4Cr8jfV1eHv9CixKSbU+jY4mxfrBwAuDvupPNKpMUY+FeIqsVw/JLT9+B8g== - dependencies: - "@babel/runtime-corejs3" "^7.8.3" - xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" @@ -9684,7 +9934,7 @@ yargs-parser@^11.1.1: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^13.1.0, yargs-parser@^13.1.2: +yargs-parser@^13.1.2: version "13.1.2" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== @@ -9692,23 +9942,6 @@ yargs-parser@^13.1.0, yargs-parser@^13.1.2: camelcase "^5.0.0" decamelize "^1.2.0" -yargs@13.2.4: - version "13.2.4" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.4.tgz#0b562b794016eb9651b98bd37acf364aa5d6dc83" - integrity sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg== - dependencies: - cliui "^5.0.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" - os-locale "^3.1.0" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^13.1.0" - yargs@^12.0.5: version "12.0.5" resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" @@ -9727,7 +9960,7 @@ yargs@^12.0.5: y18n "^3.2.1 || ^4.0.0" yargs-parser "^11.1.1" -yargs@^13.2.4, yargs@^13.3.0: +yargs@^13.2.4, yargs@^13.3.0, yargs@^13.3.2: version "13.3.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==