Merge branch 'develop' into germain-gg/notifications-labs

pull/28788/head^2
RMidhunSuresh 2023-09-14 12:14:08 +05:30
commit 1ba419fe11
No known key found for this signature in database
155 changed files with 17952 additions and 15335 deletions
cypress
e2e
plugins/dendritedocker
src
async-components/views/dialogs/security
effects

View File

@ -118,8 +118,8 @@ jobs:
strategy:
fail-fast: false
matrix:
# Naive segmentation of tests
segment: ["a-i", "j-p", "q-s", "t-z"]
# Run 4 instances in Parallel
runner: [1, 2, 3, 4]
steps:
- uses: browser-actions/setup-chrome@c485fa3bab6be59dce18dbc18ef6ab7cbc8ff5f1
- run: echo "BROWSER_PATH=$(which chrome)" >> $GITHUB_ENV
@ -163,7 +163,7 @@ jobs:
echo "CYPRESS_RUST_CRYPTO=1" >> "$GITHUB_ENV"
- name: Run Cypress tests
uses: cypress-io/github-action@fa88e4afe551e64c8827a4b9e379afc63d8f691a
uses: cypress-io/github-action@2558ee6af05072a19de2ce92cb68b38616132726
with:
working-directory: matrix-react-sdk
# The built-in Electron runner seems to grind to a halt trying to run the tests, so use chrome.
@ -172,11 +172,10 @@ jobs:
start: npx serve -p 8080 -L ../webapp
wait-on: "http://localhost:8080"
record: true
parallel: false
parallel: true
command-prefix: "yarn percy exec --parallel --"
config: '{"reporter":"cypress-multi-reporters", "reporterOptions": { "configFile": "cypress-ci-reporter-config.json" } }'
ci-build-id: ${{ needs.prepare.outputs.uuid }}
spec: cypress/e2e/[${{ matrix.segment }}]*/**
env:
# pass the Dashboard record key as an environment variable
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}

View File

@ -12,7 +12,7 @@ jobs:
- name: "Get modified files"
id: changed_files
if: github.event_name == 'pull_request' && github.event.pull_request.user.login != 'RiotTranslateBot' && github.event.pull_request.user.login != 't3chguy'
uses: tj-actions/changed-files@1c26215f3fbd51eba03bc199e5cbabdfc3584ce3 # v38
uses: tj-actions/changed-files@48566bbcc22ceb7c5809ebdd27377309f2c3de8c # v39
with:
files: |
src/i18n/strings/*

View File

@ -41,7 +41,7 @@ jobs:
- name: ☁️ Deploy to Netlify
id: netlify
uses: nwtgck/actions-netlify@5da65c9f74c7961c5501a3ba329b8d0912f39c03 # v2.0
uses: nwtgck/actions-netlify@7a92f00dde8c92a5a9e8385ec2919775f7647352 # v2.1
with:
publish-dir: webapp
deploy-message: "Deploy from GitHub Actions"

View File

@ -12,7 +12,7 @@ jobs:
if: github.repository == 'matrix-org/matrix-react-sdk'
steps:
- name: Notify element-web repo that a new SDK build is on develop
uses: peter-evans/repository-dispatch@26b39ed245ab8f31526069329e112ab2fb224588 # v2
uses: peter-evans/repository-dispatch@bf47d102fdb849e755b0b0023ea3e81a44b6f570 # v2
with:
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
repository: vector-im/element-web

View File

@ -1,3 +1,39 @@
Changes in [3.80.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.80.1) (2023-09-13)
=====================================================================================================
## 🐛 Bug Fixes
* Update Compound to fix Firefox-specific avatar regression ([\#11604](https://github.com/matrix-org/matrix-react-sdk/pull/11604))
Changes in [3.80.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.80.0) (2023-09-12)
=====================================================================================================
## ✨ Features
* Allow creating public knock rooms ([\#11481](https://github.com/matrix-org/matrix-react-sdk/pull/11481)). Contributed by @charlynguyen.
* Render custom images in reactions according to MSC4027 ([\#11087](https://github.com/matrix-org/matrix-react-sdk/pull/11087)). Contributed by @sumnerevans.
* Introduce room knocks bar ([\#11475](https://github.com/matrix-org/matrix-react-sdk/pull/11475)). Contributed by @charlynguyen.
* Room header UI updates ([\#11507](https://github.com/matrix-org/matrix-react-sdk/pull/11507)). Fixes vector-im/element-web#25892.
* Remove green "verified" bar for encrypted events ([\#11496](https://github.com/matrix-org/matrix-react-sdk/pull/11496)).
* Update member count on room summary update ([\#11488](https://github.com/matrix-org/matrix-react-sdk/pull/11488)).
* Support for E2EE in Element Call ([\#11492](https://github.com/matrix-org/matrix-react-sdk/pull/11492)).
* Allow requesting to join knock rooms via spotlight ([\#11482](https://github.com/matrix-org/matrix-react-sdk/pull/11482)). Contributed by @charlynguyen.
* Lock out the first tab if Element is opened in a second tab. ([\#11425](https://github.com/matrix-org/matrix-react-sdk/pull/11425)). Fixes vector-im/element-web#25157.
* Change avatar to use Compound implementation ([\#11448](https://github.com/matrix-org/matrix-react-sdk/pull/11448)).
## 🐛 Bug Fixes
* Fix vertical alignment of default avatar font ([\#11582](https://github.com/matrix-org/matrix-react-sdk/pull/11582)). Fixes vector-im/element-web#26081.
* Fix avatars in public room & space search being flex shrunk ([\#11580](https://github.com/matrix-org/matrix-react-sdk/pull/11580)). Fixes vector-im/element-web#26133.
* Fix EventTile avatars being rendered with a size of 0 instead of hidden ([\#11558](https://github.com/matrix-org/matrix-react-sdk/pull/11558)). Fixes vector-im/element-web#26075.
* Use RoomStateEvent.Update for knocks ([\#11516](https://github.com/matrix-org/matrix-react-sdk/pull/11516)). Contributed by @charlynguyen.
* Prevent event propagation when clicking icon buttons ([\#11515](https://github.com/matrix-org/matrix-react-sdk/pull/11515)).
* Only display RoomKnocksBar when feature flag is enabled ([\#11513](https://github.com/matrix-org/matrix-react-sdk/pull/11513)). Contributed by @andybalaam.
* Fix avatars of knock members for people tab of room settings ([\#11506](https://github.com/matrix-org/matrix-react-sdk/pull/11506)). Fixes vector-im/element-web#26083. Contributed by @charlynguyen.
* Fixes read receipt avatar offset ([\#11483](https://github.com/matrix-org/matrix-react-sdk/pull/11483)). Fixes vector-im/element-web#26067, vector-im/element-web#26064 vector-im/element-web#26059 and vector-im/element-web#26061.
* Fix avatar defects ([\#11473](https://github.com/matrix-org/matrix-react-sdk/pull/11473)). Fixes vector-im/element-web#26051 and vector-im/element-web#26046.
* Fix consistent avatar output for Percy ([\#11472](https://github.com/matrix-org/matrix-react-sdk/pull/11472)). Fixes vector-im/element-web#26049 and vector-im/element-web#26052.
* Fix colour of avatar and colour matching with username ([\#11470](https://github.com/matrix-org/matrix-react-sdk/pull/11470)). Fixes vector-im/element-web#26042.
* Fix incompatibility of Soft Logout with Element-R ([\#11468](https://github.com/matrix-org/matrix-react-sdk/pull/11468)).
* Fix instances of double translation and guard translation calls using typescript ([\#11443](https://github.com/matrix-org/matrix-react-sdk/pull/11443)).
Changes in [3.79.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.79.0) (2023-08-29)
=====================================================================================================

View File

@ -15,9 +15,10 @@ limitations under the License.
*/
import { defineConfig } from "cypress";
import * as fs from "node:fs";
export default defineConfig({
videoUploadOnPasses: false,
video: true,
projectId: "ppvnzg",
experimentalInteractiveRunEvents: true,
experimentalMemoryManagement: true,
@ -25,6 +26,18 @@ export default defineConfig({
chromeWebSecurity: false,
e2e: {
setupNodeEvents(on, config) {
// Delete videos of passing tests
on("after:spec", (spec, results) => {
if (results && results.video) {
const failures = results.tests.some((test) =>
test.attempts.some((attempt) => attempt.state === "failed"),
);
if (!failures) {
fs.unlinkSync(results.video);
}
}
});
return require("./cypress/plugins/index.ts").default(on, config);
},
baseUrl: "http://localhost:8080",

View File

@ -103,6 +103,29 @@ describe("Read receipts", () => {
});
}
function backToThreadsList() {
cy.log("Back to threads list");
cy.get(".mx_RightPanel").findByTitle("Threads").click();
}
/**
* Find and display a message.
*
* @param room the name of the room to look inside
* @param message the content of the message to fine
* @param includeThreads look for messages inside threads, not just the main timeline
*/
function jumpTo(room: string, message: string, includeThreads = false) {
cy.log("Jump to message", room, message, includeThreads);
cy.getClient().then((cli) => {
findRoomByName(room).then(async ({ roomId }) => {
const roomObject = cli.getRoom(roomId);
const foundMessage = await getMessage(roomObject, message, includeThreads);
cy.visit(`/#/room/${roomId}/${foundMessage.getId()}`);
});
});
}
function openThread(rootMessage: string) {
cy.log("Open thread", rootMessage);
cy.get(".mx_RoomView_body", { log: false }).within(() => {
@ -246,6 +269,26 @@ describe("Read receipts", () => {
})();
}
/**
* Generate MessageContentSpecs to send multiple threaded responses into a room.
*
* @param rootMessage - the body of the thread root message to send a response to
* @param newMessages - the contents of the messages
*/
function manyThreadedOff(rootMessage: string, newMessages: Array<string>): Array<MessageContentSpec> {
return newMessages.map((body) => threadedOff(rootMessage, body));
}
/**
* Generate strings with the supplied prefix, suffixed with numbers.
*
* @param prefix the prefix of each string
* @param howMany the number of strings to generate
*/
function many(prefix: string, howMany: number): Array<string> {
return Array.from(Array(howMany).keys()).map((i) => prefix + i.toFixed());
}
/**
* BotActionSpec to send a reaction to an existing event into a room
* @param targetMessage - the body of the message to send a reaction to
@ -311,6 +354,16 @@ describe("Read receipts", () => {
});
}
/**
* Assert that this room remains read, when it was previously read.
* (In practice, this just waits a short while to allow any unread marker to
* appear, and then asserts that the room is read.)
*/
function assertStillRead(room: string) {
cy.wait(200);
assertRead(room);
}
/**
* Assert a given room is marked as unread (via the room list tile)
* @param room - the name of the room to check
@ -327,8 +380,24 @@ describe("Read receipts", () => {
});
}
/**
* Assert a given room is marked as unread, and the number of unread
* messages is less than the supplied count.
*
* @param room - the name of the room to check
* @param lessThan - the number of unread messages that is too many
*/
function assertUnreadLessThan(room: string, lessThan: number) {
cy.log("Assert room some unread", room);
return getRoomListTile(room).within(() => {
cy.get(".mx_NotificationBadge_count").should(($count) =>
expect(parseInt($count.get(0).textContent, 10)).to.be.lessThan(lessThan),
);
});
}
function openThreadList() {
cy.log("Open thread list");
cy.log("Open threads list");
cy.findByTestId("threadsButton", { log: false }).then(($button) => {
if ($button?.attr("aria-current") !== "true") {
cy.findByTestId("threadsButton", { log: false }).click();
@ -405,7 +474,19 @@ describe("Read receipts", () => {
// Then the room becomes read
assertRead(room2);
});
it.skip("Reading an older message leaves the room unread", () => {});
// XXX: fails (sometimes!) because the unread count stays high
it.skip("Reading an older message leaves the room unread", () => {
// Given there are lots of messages in a room
goTo(room1);
receiveMessages(room2, many("Msg", 30));
assertUnread(room2, 30);
// When I jump to one of the older messages
jumpTo(room2, "Msg1");
// Then the room is still unread, but some messages were read
assertUnreadLessThan(room2, 30);
});
it("Marking a room as read makes it read", () => {
// Given I have some unread messages
goTo(room1);
@ -447,7 +528,21 @@ describe("Read receipts", () => {
// Then I still have an unread message
assertUnread(room2, 1);
});
it.skip("A room where all messages are read is still read after restart", () => {});
it("A room where all messages are read is still read after restart", () => {
// Given I have read all messages
goTo(room1);
assertRead(room2);
receiveMessages(room2, ["Msg1"]);
assertUnread(room2, 1);
goTo(room2);
assertRead(room2);
// When I restart
saveAndReload();
// Then all messages are still read
assertRead(room2);
});
it("A room that was marked as read is still read after restart", () => {
// Given I have marked all messages as read
goTo(room1);
@ -525,7 +620,25 @@ describe("Read receipts", () => {
assertReadThread("Msg1");
assertRead(room2);
});
it.skip("Reading an older thread message (via permalink) leaves the thread unread", () => {});
it("Reading an older thread message leaves the thread unread", () => {
// Given there are many messages in a thread
goTo(room1);
receiveMessages(room2, ["ThreadRoot", ...manyThreadedOff("ThreadRoot", many("InThread", 20))]);
assertUnread(room2, 21);
// When I read an older message in the thread
jumpTo(room2, "InThread1", true);
assertUnreadLessThan(room2, 21);
// TODO: for some reason, we can't find the first message
// "InThread0", so I am using the second here. Also, they appear
// out of order, with "InThread2" before "InThread1". Might be a
// clue to the sporadic reports we have had of messages going
// missing in threads?
// Then the thread is still marked as unread
backToThreadsList();
assertUnreadThread("ThreadRoot");
});
it("Reading only one thread's message does not make the room read", () => {
// Given two threads are unread
goTo(room1);
@ -668,23 +781,56 @@ describe("Read receipts", () => {
assertUnread(room2, 1);
assertUnreadThread("Msg1");
});
it.skip("Reading a thread root within the thread view marks it as read in the main timeline", () => {});
it("Creating a new thread based on a reply makes the room unread", () => {
// XXX: fails because we jump to the wrong place in the timeline
it.skip("Reading a thread root within the thread view marks it as read in the main timeline", () => {
// Given lots of messages are on the main timeline, and one has a thread off it
goTo(room1);
receiveMessages(room2, ["Msg1", replyTo("Msg1", "Reply1"), threadedOff("Reply1", "Resp1")]);
assertUnread(room2, 3);
receiveMessages(room2, [
...many("beforeThread", 30),
"ThreadRoot",
threadedOff("ThreadRoot", "InThread"),
...many("afterThread", 30),
]);
assertUnread(room2, 62); // Sanity
// When I jump to an old message and read the thread
jumpTo(room2, "beforeThread0");
openThread("ThreadRoot");
// Then the thread root is marked as read in the main timeline,
// so there are only 30 left - the ones after the thread root.
assertUnread(room2, 30);
});
it("Creating a new thread based on a reply makes the room unread", () => {
// Given a message and reply exist and are read
goTo(room1);
receiveMessages(room2, ["Msg1", replyTo("Msg1", "Reply1")]);
goTo(room2);
assertRead(room2);
goTo(room1);
assertRead(room2);
// When I receive a thread message created on the reply
receiveMessages(room2, [threadedOff("Reply1", "Resp1")]);
// Then the room is unread
assertUnread(room2, 1);
});
it("Reading a thread whose root is a reply makes the room read", () => {
// Given an unread thread off a reply exists
goTo(room1);
receiveMessages(room2, ["Msg1", replyTo("Msg1", "Reply1"), threadedOff("Reply1", "Resp1")]);
assertUnread(room2, 3);
goTo(room2);
assertUnread(room2, 1);
assertUnreadThread("Reply1");
// When I read the thread
openThread("Reply1");
// Then the room and thread are read
assertRead(room2);
assertReadThread("Reply1");
});
});
});
@ -692,15 +838,16 @@ describe("Read receipts", () => {
describe("editing messages", () => {
describe("in the main timeline", () => {
// TODO: this passes but we think this should fail, because we think edits should not cause unreads.
// XXX: fails because on CI we get a dot, but locally we get a count. Must be a timing issue.
// XXX: fails because we see a dot instead of an unread number - probably the server and client disagree
it.skip("Editing a message makes a room unread", () => {
// Given I am not looking at the room
goTo(room1);
receiveMessages(room2, ["Msg1"]);
assertUnread(room2, 1);
markAsRead(room2);
goTo(room2);
assertRead(room2);
goTo(room1);
// When an edit appears in the room
receiveMessages(room2, [editOf("Msg1", "Msg1 Edit1")]);
@ -708,7 +855,7 @@ describe("Read receipts", () => {
// Then it becomes unread
assertUnread(room2, 1);
});
// XXX: fails because on CI we get a dot, but locally we get a count. Must be a timing issue.
// XXX: fails because we see a dot instead of an unread number - probably the server and client disagree
it.skip("Reading an edit makes the room read", () => {
// Given an edit is making the room unread
goTo(room1);
@ -730,14 +877,12 @@ describe("Read receipts", () => {
goTo(room1);
assertRead(room2);
});
// XXX: fails because on CI we get a dot, but locally we get a count. Must be a timing issue.
it.skip("Marking a room as read after an edit makes it read", () => {
// Given an edit is makng a room unread
goTo(room1);
it("Marking a room as read after an edit makes it read", () => {
// Given an edit is making a room unread
goTo(room2);
receiveMessages(room2, ["Msg1"]);
assertUnread(room2, 1);
markAsRead(room2);
assertRead(room2);
goTo(room1);
receiveMessages(room2, [editOf("Msg1", "Msg1 Edit1")]);
assertUnread(room2, 1);
@ -747,7 +892,7 @@ describe("Read receipts", () => {
// Then the room becomes read
assertRead(room2);
});
// XXX: fails because on CI we get a dot, but locally we get a count. Must be a timing issue.
// XXX: fails because we see a dot instead of an unread number - probably the server and client disagree
it.skip("Editing a message after marking as read makes the room unread", () => {
// Given the room is marked as read
goTo(room1);
@ -762,7 +907,7 @@ describe("Read receipts", () => {
// Then the room becomes unread
assertUnread(room2, 1);
});
// XXX: fails because on CI we get a dot, but locally we get a count. Must be a timing issue.
// XXX: fails because we see a dot instead of an unread number - probably the server and client disagree
it.skip("Editing a reply after reading it makes the room unread", () => {
// Given the room is all read
goTo(room1);
@ -780,7 +925,7 @@ describe("Read receipts", () => {
// Then it becomes unread
assertUnread(room2, 1);
});
// XXX: fails because on CI we get a dot, but locally we get a count. Must be a timing issue.
// XXX: fails because we see a dot instead of an unread number - probably the server and client disagree
it.skip("Editing a reply after marking as read makes the room unread", () => {
// Given a reply is marked as read
goTo(room1);
@ -795,14 +940,13 @@ describe("Read receipts", () => {
// Then the room becomes unread
assertUnread(room2, 1);
});
// XXX: fails because on CI we get a dot, but locally we get a count. Must be a timing issue.
// XXX: fails because we see a dot instead of an unread number - probably the server and client disagree
it.skip("A room with an edit is still unread after restart", () => {
// Given a message is marked as read
goTo(room1);
goTo(room2);
receiveMessages(room2, ["Msg1"]);
assertUnread(room2, 1);
markAsRead(room2);
assertRead(room2);
goTo(room1);
// When an edit appears in the room
receiveMessages(room2, [editOf("Msg1", "Msg1 Edit1")]);
@ -814,13 +958,22 @@ describe("Read receipts", () => {
saveAndReload();
assertUnread(room2, 1);
});
// XXX: fails because on CI we get a dot, but locally we get a count. Must be a timing issue.
it.skip("A room where all edits are read is still read after restart", () => {
// Given an edit made the room unread
goTo(room1);
it("An edited message becomes read if it happens while I am looking", () => {
// Given a message is marked as read
goTo(room2);
receiveMessages(room2, ["Msg1"]);
assertRead(room2);
// When I see an edit appear in the room I am looking at
receiveMessages(room2, [editOf("Msg1", "Msg1 Edit1")]);
// Then it becomes read
assertRead(room2);
});
it("A room where all edits are read is still read after restart", () => {
// Given an edit made the room unread
goTo(room2);
receiveMessages(room2, ["Msg1"]);
assertUnread(room2, 1);
markAsRead(room2);
assertRead(room2);
receiveMessages(room2, [editOf("Msg1", "Msg1 Edit1")]);
assertUnread(room2, 1);
@ -838,40 +991,50 @@ describe("Read receipts", () => {
});
describe("in threads", () => {
// XXX: fails because on CI we get a dot, but locally we get a count. Must be a timing issue.
// XXX: fails because we see a dot instead of an unread number - probably the server and client disagree
it.skip("An edit of a threaded message makes the room unread", () => {
// Given we have read the thread
goTo(room1);
receiveMessages(room2, ["Msg1", threadedOff("Msg1", "Resp1")]);
assertUnread(room2, 2);
goTo(room2);
openThread("Msg1");
assertRead(room2);
backToThreadsList();
goTo(room1);
// When a message inside it is edited
receiveMessages(room2, [editOf("Resp1", "Edit1")]);
// Then the room and thread are unread
assertUnread(room2, 1);
goTo(room2);
assertUnreadThread("Msg1");
});
// XXX: fails because on CI we get a dot, but locally we get a count. Must be a timing issue.
// XXX: fails because we see a dot instead of an unread number - probably the server and client disagree
it.skip("Reading an edit of a threaded message makes the room read", () => {
// Given an edited thread message is making the room unread
goTo(room1);
receiveMessages(room2, ["Msg1", threadedOff("Msg1", "Resp1")]);
assertUnread(room2, 2);
goTo(room2);
openThread("Msg1");
assertRead(room2);
goTo(room1);
receiveMessages(room2, [editOf("Resp1", "Edit1")]);
assertUnread(room2, 1);
// When I read it
goTo(room2);
openThread("Msg1");
// Then the room and thread are read
assertRead(room2);
assertReadThread("Msg1");
});
// XXX: fails because the room is still "bold" even though the notification counts all disappear
it.skip("Marking a room as read after an edit in a thread makes it read", () => {
// Given an edit in a thread is making the room unread
goTo(room1);
receiveMessages(room2, ["Msg1", threadedOff("Msg1", "Resp1"), editOf("Resp1", "Edit1")]);
assertUnread(room2, 3); // TODO: the edit counts as a message!
@ -882,7 +1045,7 @@ describe("Read receipts", () => {
// Then it is read
assertRead(room2);
});
// XXX: fails because the room is still "bold" even though the notification counts all disappear
// XXX: fails because the unread dot remains after marking as read
it.skip("Editing a thread message after marking as read makes the room unread", () => {
// Given a room is marked as read
goTo(room1);
@ -897,49 +1060,76 @@ describe("Read receipts", () => {
// Then the room becomes unread
assertUnread(room2, 1); // TODO: should this edit make us unread?
});
// XXX: fails because on CI the count is 2 instead of 3. Must be a timing issue.
// XXX: fails because we see a dot instead of an unread number - probably the server and client disagree
it.skip("A room with an edited threaded message is still unread after restart", () => {
// Given an edit in a thread is making a room unread
goTo(room1);
receiveMessages(room2, ["Msg1", threadedOff("Msg1", "Resp1"), editOf("Resp1", "Edit1")]);
assertUnread(room2, 3);
saveAndReload();
assertUnread(room2, 3);
});
// XXX: fails because on CI the count is 2 instead of 3. Must be a timing issue.
it.skip("A room where all threaded edits are read is still read after restart", () => {
goTo(room1);
receiveMessages(room2, ["Msg1", threadedOff("Msg1", "Resp1"), editOf("Resp1", "Edit1")]);
assertUnread(room2, 3);
receiveMessages(room2, ["Msg1", threadedOff("Msg1", "Resp1")]);
markAsRead(room2);
receiveMessages(room2, [editOf("Resp1", "Edit1")]);
assertUnread(room2, 1);
// When I restart
saveAndReload();
// Then is it still unread
assertUnread(room2, 1);
});
it("A room where all threaded edits are read is still read after restart", () => {
goTo(room2);
receiveMessages(room2, ["Msg1", threadedOff("Msg1", "Resp1"), editOf("Resp1", "Edit1")]);
assertUnread(room2, 2);
openThread("Msg1");
assertRead(room2);
goTo(room1); // Make sure we are looking at room1 after reload
assertRead(room2);
saveAndReload();
assertRead(room2);
});
// XXX: fails because we see a dot instead of an unread number - probably the server and client disagree
it.skip("A room where all threaded edits are marked as read is still read after restart", () => {
goTo(room1);
receiveMessages(room2, ["Msg1", threadedOff("Msg1", "Resp1"), editOf("Resp1", "Edit1")]);
assertUnread(room2, 3);
markAsRead(room2);
assertRead(room2);
// When I restart
saveAndReload();
// It is still read
assertRead(room2);
});
});
describe("thread roots", () => {
// XXX: fails because on CI we get a dot, but locally we get a count. Must be a timing issue.
// XXX: fails because we see a dot instead of an unread number - probably the server and client disagree
it.skip("An edit of a thread root makes the room unread", () => {
// Given I have read a thread
goTo(room1);
receiveMessages(room2, ["Msg1", threadedOff("Msg1", "Resp1")]);
assertUnread(room2, 2);
goTo(room2);
openThread("Msg1");
assertRead(room2);
goTo(room1);
// When the thread root is edited
receiveMessages(room2, [editOf("Msg1", "Edit1")]);
// Then the room is unread but not the thread
assertUnread(room2, 1);
goTo(room2);
assertRead(room2);
assertReadThread("Msg1");
});
it.skip("Reading an edit of a thread root makes the room read", () => {
it("Reading an edit of a thread root makes the room read", () => {
// Given a fully-read thread exists
goTo(room2);
receiveMessages(room2, ["Msg1", threadedOff("Msg1", "Resp1")]);
openThread("Msg1");
assertRead(room2);
goTo(room1);
assertRead(room2);
@ -954,10 +1144,77 @@ describe("Read receipts", () => {
goTo(room1);
assertRead(room2);
});
it.skip("Marking a room as read after an edit of a thread root makes it read", () => {});
it.skip("Editing a thread root after marking as read makes the room unread", () => {});
it.skip("Marking a room as read after an edit of a thread root that is a reply makes it read", () => {});
it.skip("Editing a thread root that is a reply after marking as read makes the room unread but not the thread", () => {});
// XXX: fails because it shows a dot instead of unread count
it.skip("Editing a thread root after reading makes the room unread", () => {
// Given a fully-read thread exists
goTo(room2);
receiveMessages(room2, ["Msg1", threadedOff("Msg1", "Resp1")]);
openThread("Msg1");
assertRead(room2);
goTo(room1);
// When the thread root is edited
receiveMessages(room2, [editOf("Msg1", "Msg1 Edit1")]);
// Then the room becomes unread
assertUnread(room2, 1);
});
// XXX: fails because the room has an unread dot after I marked it as read
it.skip("Marking a room as read after an edit of a thread root makes it read", () => {
// Given a fully-read thread exists
goTo(room2);
receiveMessages(room2, ["Msg1", threadedOff("Msg1", "Resp1")]);
openThread("Msg1");
assertRead(room2);
goTo(room1);
assertRead(room2);
// When the thread root is edited
receiveMessages(room2, [editOf("Msg1", "Msg1 Edit1")]);
// And I mark the room as read
markAsRead(room2);
// Then the room becomes read and stays read
assertRead(room2);
goTo(room1);
assertRead(room2);
});
// XXX: fails because the room has an unread dot after I marked it as read
it.skip("Editing a thread root that is a reply after marking as read makes the room unread but not the thread", () => {
// Given a thread based on a reply exists and is read because it is marked as read
goTo(room1);
receiveMessages(room2, ["Msg", replyTo("Msg", "Reply"), threadedOff("Reply", "InThread")]);
assertUnread(room2, 3);
markAsRead(room2);
assertRead(room2);
// When I edit the thread root
receiveMessages(room1, [editOf("Reply", "Edited Reply")]);
// Then the room is unread
assertUnread(room2, 1);
goTo(room2);
// But the thread is still read (because the root is not part of the thread)
assertReadThread("EditedReply");
});
// XXX: fails because the room has an unread dot after I marked it as read
it.skip("Marking a room as read after an edit of a thread root that is a reply makes it read", () => {
// Given a thread based on a reply exists and the reply has been edited
goTo(room1);
receiveMessages(room2, ["Msg", replyTo("Msg", "Reply"), threadedOff("Reply", "InThread")]);
receiveMessages(room2, [editOf("Reply", "Edited Reply")]);
assertUnread(room2, 3);
// When I mark the room as read
markAsRead(room2);
// Then the room and thread are read
assertRead(room2);
goTo(room2);
assertReadThread("Edited Reply");
});
});
});
@ -1042,57 +1299,318 @@ describe("Read receipts", () => {
describe("thread roots", () => {
it("A reaction to a thread root does not make the room unread", () => {
// Given a read thread root exists
goTo(room1);
assertRead(room2);
receiveMessages(room2, ["Msg1", threadedOff("Msg1", "Reply1")]);
assertUnread(room2, 2);
goTo(room2);
openThread("Msg1");
assertRead(room2);
// When someone reacts to it
goTo(room1);
receiveMessages(room2, [reactionTo("Msg1", "🪿")]);
cy.wait(200);
// Then the room is still read
assertRead(room2);
});
it("Reading a reaction to a thread root leaves the room read", () => {
// Given a read thread root exists
goTo(room1);
assertRead(room2);
receiveMessages(room2, ["Msg1", threadedOff("Msg1", "Reply1")]);
assertUnread(room2, 2);
goTo(room2);
openThread("Msg1");
assertRead(room2);
// And the reaction to it does not make us unread
goTo(room1);
receiveMessages(room2, [reactionTo("Msg1", "🪿")]);
assertRead(room2);
// When we read the reaction and go away again
goTo(room2);
openThread("Msg1");
assertRead(room2);
goTo(room1);
cy.wait(200);
// Then the room is still read
assertRead(room2);
});
// XXX: fails because the room is still "bold" even though the notification counts all disappear
it.skip("Reacting to a thread root after marking as read makes the room unread but not the thread", () => {
// Given a thread root exists
goTo(room1);
assertRead(room2);
receiveMessages(room2, ["Msg1", threadedOff("Msg1", "Reply1")]);
assertUnread(room2, 2);
goTo(room2);
openThread("Msg1");
// And we have marked the room as read
markAsRead(room2);
assertRead(room2);
goTo(room1);
// When someone reacts to it
receiveMessages(room2, [reactionTo("Msg1", "🪿")]);
cy.wait(200);
// Then the room is still read
assertRead(room2);
});
it.skip("Reading a reaction to a thread root makes the room read", () => {});
it.skip("Marking a room as read after a reaction to a thread root makes it read", () => {});
it.skip("Reacting to a thread root after marking as read makes the room unread but not the thread", () => {});
});
});
describe("redactions", () => {
describe("in the main timeline", () => {
it("Redacting the message pointed to by my receipt leaves the room read", () => {
// Given I have read the messages in a room
goTo(room1);
receiveMessages(room2, ["Msg1", "Msg2"]);
assertUnread(room2, 2);
goTo(room2);
assertRead(room2);
goTo(room1);
// When the latest message is redacted
receiveMessages(room2, [redactionOf("Msg2")]);
// Then the room remains read
assertStillRead(room2);
});
it("Reading an unread room after a redaction of the latest message makes it read", () => {
// Given an unread room
goTo(room1);
receiveMessages(room2, ["Msg1", "Msg2"]);
assertUnread(room2, 2);
// When I read the main timeline
// And the latest message has been redacted
receiveMessages(room2, [redactionOf("Msg2")]);
// When I read the room
goTo(room2);
assertRead(room2);
goTo(room1);
// Then it becomes read
assertStillRead(room2);
});
it("Reading an unread room after a redaction of an older message makes it read", () => {
// Given an unread room with an earlier redaction
goTo(room1);
receiveMessages(room2, ["Msg1", "Msg2"]);
assertUnread(room2, 2);
receiveMessages(room2, [redactionOf("Msg1")]);
// When I read the room
goTo(room2);
assertRead(room2);
goTo(room1);
// Then it becomes read
assertStillRead(room2);
});
it("Marking an unread room as read after a redaction makes it read", () => {
// Given an unread room where latest message is redacted
goTo(room1);
receiveMessages(room2, ["Msg1", "Msg2"]);
assertUnread(room2, 2);
receiveMessages(room2, [redactionOf("Msg2")]);
assertUnread(room2, 1);
// When I mark it as read
markAsRead(room2);
// Then it becomes read
assertRead(room2);
});
it("Sending and redacting a message after marking the room as read makes it read", () => {
// Given a room that is marked as read
goTo(room1);
receiveMessages(room2, ["Msg1", "Msg2"]);
assertUnread(room2, 2);
markAsRead(room2);
assertRead(room2);
// When a message is sent and then redacted
receiveMessages(room2, ["Msg3"]);
assertUnread(room2, 1);
receiveMessages(room2, [redactionOf("Msg3")]);
// Then the room is read
assertRead(room2);
});
it("Redacting a message after marking the room as read leaves it read", () => {
// Given a room that is marked as read
goTo(room1);
receiveMessages(room2, ["Msg1", "Msg2", "Msg3"]);
assertUnread(room2, 3);
markAsRead(room2);
assertRead(room2);
// When we redact some messages
receiveMessages(room2, [redactionOf("Msg3")]);
receiveMessages(room2, [redactionOf("Msg1")]);
// Then it is still read
assertStillRead(room2);
});
it("Redacting one of the unread messages reduces the unread count", () => {
// Given an unread room
goTo(room1);
receiveMessages(room2, ["Msg1", "Msg2", "Msg3"]);
assertUnread(room2, 3);
// When I redact a non-latest message
receiveMessages(room2, [redactionOf("Msg2")]);
// Then the unread count goes down
assertUnread(room2, 2);
// And when I redact the latest message
receiveMessages(room2, [redactionOf("Msg3")]);
// Then the unread count goes down again
assertUnread(room2, 1);
});
it("Redacting one of the unread messages reduces the unread count after restart", () => {
// Given unread count was reduced by redacting messages
goTo(room1);
receiveMessages(room2, ["Msg1", "Msg2", "Msg3"]);
assertUnread(room2, 3);
receiveMessages(room2, [redactionOf("Msg2")]);
assertUnread(room2, 2);
receiveMessages(room2, [redactionOf("Msg3")]);
assertUnread(room2, 1);
// When I restart
saveAndReload();
// Then the unread count is still reduced
assertUnread(room2, 1);
});
it("Redacting all unread messages makes the room read", () => {
// Given an unread room
goTo(room1);
receiveMessages(room2, ["Msg1", "Msg2"]);
assertUnread(room2, 2);
// When I redact all the unread messages
receiveMessages(room2, [redactionOf("Msg2")]);
receiveMessages(room2, [redactionOf("Msg1")]);
// Then the room is back to being read
assertRead(room2);
});
it("Redacting all unread messages makes the room read after restart", () => {
// Given all unread messages were redacted
goTo(room1);
receiveMessages(room2, ["Msg1", "Msg2"]);
assertUnread(room2, 2);
receiveMessages(room2, [redactionOf("Msg2")]);
receiveMessages(room2, [redactionOf("Msg1")]);
assertRead(room2);
// When I restart
saveAndReload();
// Then the room is still read
assertRead(room2);
});
// TODO: Doesn't work because the test setup can't (yet) find the ID of a redacted message
it.skip("Reacting to a redacted message leaves the room read", () => {
// Given a redacted message exists
goTo(room1);
receiveMessages(room2, ["Msg1", "Msg2"]);
receiveMessages(room2, [redactionOf("Msg2")]);
assertUnread(room2, 1);
// And the room is read
goTo(room2);
assertRead(room2);
cy.wait(200);
goTo(room1);
// When I react to the redacted message
// TODO: doesn't work yet because we need to be able to look up
// the ID of Msg2 even though it has now disappeared from the
// timeline.
receiveMessages(room2, [reactionTo("Msg2", "🪿")]);
// Then the room is still read
assertStillRead(room2);
});
// TODO: Doesn't work because the test setup can't (yet) find the ID of a redacted message
it.skip("Editing a redacted message leaves the room read", () => {
// Given a redacted message exists
goTo(room1);
receiveMessages(room2, ["Msg1", "Msg2"]);
receiveMessages(room2, [redactionOf("Msg2")]);
assertUnread(room2, 1);
// And the room is read
goTo(room2);
assertRead(room2);
goTo(room1);
// When I attempt to edit the redacted message
// TODO: doesn't work yet because we need to be able to look up
// the ID of Msg2 even though it has now disappeared from the
// timeline.
receiveMessages(room2, [editOf("Msg2", "Msg2 is BACK")]);
// Then the room is still read
assertStillRead(room2);
});
// TODO: Doesn't work because the test setup can't (yet) find the ID of a redacted message
it.skip("A reply to a redacted message makes the room unread", () => {
// Given a message was redacted
goTo(room1);
receiveMessages(room2, ["Msg1", "Msg2"]);
receiveMessages(room2, [redactionOf("Msg2")]);
assertUnread(room2, 1);
// And the room is read
goTo(room2);
assertRead(room2);
goTo(room1);
// When I receive a reply to the redacted message
// TODO: doesn't work yet because we need to be able to look up
// the ID of Msg2 even though it has now disappeared from the
// timeline.
receiveMessages(room2, [replyTo("Msg2", "Reply to Msg2")]);
// Then the room is unread
assertUnread(room2, 1);
});
// TODO: Doesn't work because the test setup can't (yet) find the ID of a redacted message
it.skip("Reading a reply to a redacted message marks the room as read", () => {
// Given someone replied to a redacted message
goTo(room1);
receiveMessages(room2, ["Msg1", "Msg2"]);
receiveMessages(room2, [redactionOf("Msg2")]);
assertUnread(room2, 1);
goTo(room2);
assertRead(room2);
goTo(room1);
// TODO: doesn't work yet because we need to be able to look up
// the ID of Msg2 even though it has now disappeared from the
// timeline.
receiveMessages(room2, [replyTo("Msg2", "Reply to Msg2")]);
assertUnread(room2, 1);
// When I read the reply
goTo(room2);
assertRead(room2);
// Then the room is unread
goTo(room1);
receiveMessages(room2, [redactionOf("Msg2")]);
assertRead(room2);
assertStillRead(room2);
});
it.skip("Reading an unread room after a redaction of the latest message makes it read", () => {});
it.skip("Reading an unread room after a redaction of an older message makes it read", () => {});
it.skip("Marking an unread room as read after a redaction makes it read", () => {});
it.skip("Sending and redacting a message after marking the room as read makes it unread", () => {});
it.skip("?? Redacting a message after marking the room as read makes it unread", () => {});
it.skip("Reacting to a redacted message leaves the room read", () => {});
it.skip("Editing a redacted message leaves the room read", () => {});
it.skip("?? Reading a reaction to a redacted message marks the room as read", () => {});
it.skip("?? Reading an edit of a redacted message marks the room as read", () => {});
it.skip("Reading a reply to a redacted message marks the room as read", () => {});
it.skip("A room with an unread redaction is still unread after restart", () => {});
it.skip("A room with a read redaction is still read after restart", () => {});
});
describe("in threads", () => {

View File

@ -226,8 +226,8 @@ describe("Spotlight", () => {
cy.get(".mx_SpotlightDialog_filter").should("contain", "Public spaces");
cy.spotlightSearch().type("{backspace}");
cy.get(".mx_SpotlightDialog_filter").should("not.exist");
cy.wait(200); // Again, wait to settle so keypresses arrive correctly
cy.spotlightSearch().type("{downArrow}");
cy.spotlightSearch().type("{downArrow}");
cy.get("#mx_SpotlightDialog_button_explorePublicRooms").should("have.attr", "aria-selected", "true");
cy.spotlightSearch().type("{enter}");
@ -240,6 +240,7 @@ describe("Spotlight", () => {
it("should find joined rooms", () => {
cy.openSpotlightDialog()
.within(() => {
cy.wait(500); // Wait for dialog to settle
cy.spotlightSearch().clear().type(room1Name);
cy.spotlightResults().should("have.length", 1);
cy.spotlightResults().eq(0).should("contain", room1Name);
@ -254,6 +255,7 @@ describe("Spotlight", () => {
it("should find known public rooms", () => {
cy.openSpotlightDialog()
.within(() => {
cy.wait(500); // Wait for dialog to settle
cy.spotlightFilter(Filter.PublicRooms);
cy.spotlightSearch().clear().type(room1Name);
cy.spotlightResults().should("have.length", 1);
@ -270,6 +272,7 @@ describe("Spotlight", () => {
it("should find unknown public rooms", () => {
cy.openSpotlightDialog()
.within(() => {
cy.wait(500); // Wait for dialog to settle
cy.spotlightFilter(Filter.PublicRooms);
cy.spotlightSearch().clear().type(room2Name);
cy.spotlightResults().should("have.length", 1);
@ -287,6 +290,7 @@ describe("Spotlight", () => {
it("should find unknown public world readable rooms", () => {
cy.openSpotlightDialog()
.within(() => {
cy.wait(500); // Wait for dialog to settle
cy.spotlightFilter(Filter.PublicRooms);
cy.spotlightSearch().clear().type(room3Name);
cy.spotlightResults().should("have.length", 1);
@ -306,6 +310,7 @@ describe("Spotlight", () => {
it.skip("should find unknown public rooms on other homeservers", () => {
cy.openSpotlightDialog()
.within(() => {
cy.wait(500); // Wait for dialog to settle
cy.spotlightFilter(Filter.PublicRooms);
cy.spotlightSearch().clear().type(room3Name);
cy.get("[aria-haspopup=true][role=button]").click();
@ -318,6 +323,7 @@ describe("Spotlight", () => {
})
.then(() =>
cy.spotlightDialog().within(() => {
cy.wait(500); // Wait for dialog to settle
cy.spotlightResults().should("have.length", 1);
cy.spotlightResults().eq(0).should("contain", room3Name);
cy.spotlightResults().eq(0).should("contain", room3Id);
@ -328,6 +334,7 @@ describe("Spotlight", () => {
it("should find known people", () => {
cy.openSpotlightDialog()
.within(() => {
cy.wait(500); // Wait for dialog to settle
cy.spotlightFilter(Filter.People);
cy.spotlightSearch().clear().type(bot1Name);
cy.spotlightResults().should("have.length", 1);
@ -342,6 +349,7 @@ describe("Spotlight", () => {
it("should find unknown people", () => {
cy.openSpotlightDialog()
.within(() => {
cy.wait(500); // Wait for dialog to settle
cy.spotlightFilter(Filter.People);
cy.spotlightSearch().clear().type(bot2Name);
cy.spotlightResults().should("have.length", 1);
@ -359,6 +367,7 @@ describe("Spotlight", () => {
// Starting a DM with ByteBot (will be turned into a group dm later)
cy.openSpotlightDialog().within(() => {
cy.wait(500); // Wait for dialog to settle
cy.spotlightFilter(Filter.People);
cy.spotlightSearch().clear().type(bot2Name);
cy.spotlightResults().should("have.length", 1);
@ -414,6 +423,7 @@ describe("Spotlight", () => {
// Test against https://github.com/vector-im/element-web/issues/22851
it("should show each person result only once", () => {
cy.openSpotlightDialog().within(() => {
cy.wait(500); // Wait for dialog to settle
cy.spotlightFilter(Filter.People);
// 2 rounds of search to simulate the bug conditions. Specifically, the first search
@ -434,6 +444,7 @@ describe("Spotlight", () => {
it("should allow opening group chat dialog", () => {
cy.openSpotlightDialog()
.within(() => {
cy.wait(500); // Wait for dialog to settle
cy.spotlightFilter(Filter.People);
cy.spotlightSearch().clear().type(bot2Name);
cy.wait(3000); // wait for the dialog code to settle
@ -457,6 +468,7 @@ describe("Spotlight", () => {
cy.visit("/#/home");
cy.openSpotlightDialog().within(() => {
cy.wait(500); // Wait for dialog to settle
cy.spotlightFilter(Filter.People);
cy.spotlightSearch().clear().type(bot1Name);
cy.wait(3000); // wait for the dialog code to settle
@ -467,6 +479,7 @@ describe("Spotlight", () => {
it("should be able to navigate results via keyboard", () => {
cy.openSpotlightDialog().within(() => {
cy.wait(500); // Wait for dialog to settle
cy.spotlightFilter(Filter.People);
cy.spotlightSearch().clear().type("b");
// our debouncing logic only starts the search after a short timeout,
@ -475,6 +488,7 @@ describe("Spotlight", () => {
cy.get(".mx_Spinner")
.should("not.exist")
.then(() => {
cy.wait(500); // Wait to settle again
cy.spotlightResults()
.should("have.length", 2)
.then(() => {

View File

@ -96,7 +96,7 @@ async function dendritePineconeStart(template: string): Promise<HomeserverInstan
async function containerStart(template: string, usePinecone: boolean): Promise<HomeserverInstance> {
let dendriteImage = "matrixdotorg/dendrite-monolith:main";
let dendriteEntrypoint = "/usr/bin/dendrite-monolith-server";
let dendriteEntrypoint = "/usr/bin/dendrite";
if (usePinecone) {
dendriteImage = "matrixdotorg/dendrite-demo-pinecone:main";
dendriteEntrypoint = "/usr/bin/dendrite-demo-pinecone";

View File

@ -24,11 +24,15 @@ need to have Docker installed and working in order to run the Cypress tests.
There are a few different ways to run the tests yourself. The simplest is to run:
```
docker pull matrixdotorg/synapse:develop
yarn run test:cypress
```
This will run the Cypress tests once, non-interactively.
Note: you don't need to run the `docker pull` command every time, but you should
do it regularly to ensure you are running against an up-to-date Synapse.
You can also run individual tests this way too, as you'd expect:
```
@ -45,7 +49,7 @@ yarn run test:cypress:open
### Matching the CI environment
In our Continuous Integration environment, we run the Cypress tests in the
Chrome browser.
Chrome browser, and with the latest Synapse image from Docker Hub.
In some rare cases, tests behave differently between different browsers, so if
you see CI failures for the Cypress tests, but those tests work OK on your local
@ -64,6 +68,17 @@ Note that you will need to have Chrome installed on your system to run the tests
inside those browsers, whereas the default is to use Electron, which is included
within the Cypress dependency.
Another cause of inconsistency between local and CI is the Synapse version. The
first time you run the tests, they automatically fetch the latest Docker image
of Synapse, but this won't update again unless you do it explicitly. To update
the Synapse you are using, run:
```
docker pull matrixdotorg/synapse:develop
```
and then run the tests as normal.
### Running with Rust cryptography
`matrix-js-sdk` is currently in the

View File

@ -1,6 +1,6 @@
{
"name": "matrix-react-sdk",
"version": "3.79.0",
"version": "3.80.1",
"description": "SDK for matrix.org using React",
"author": "matrix.org",
"repository": {
@ -69,7 +69,7 @@
"@sentry/tracing": "^7.0.0",
"@testing-library/react-hooks": "^8.0.1",
"@vector-im/compound-design-tokens": "^0.0.5",
"@vector-im/compound-web": "^0.2.3",
"@vector-im/compound-web": "^0.4.0",
"await-lock": "^2.1.0",
"blurhash": "^1.1.3",
"classnames": "^2.2.6",
@ -80,7 +80,7 @@
"emojibase-regex": "15.0.0",
"escape-html": "^1.0.3",
"file-saver": "^2.0.5",
"filesize": "10.0.7",
"filesize": "10.0.12",
"focus-visible": "^5.2.0",
"gfm.css": "^1.1.2",
"glob-to-regexp": "^0.4.1",
@ -106,7 +106,7 @@
"opus-recorder": "^8.0.3",
"pako": "^2.0.3",
"png-chunks-extract": "^1.0.0",
"posthog-js": "1.73.1",
"posthog-js": "1.77.2",
"proposal-temporal": "^0.9.0",
"qrcode": "1.5.3",
"re-resizable": "^6.9.0",
@ -159,7 +159,7 @@
"@types/fs-extra": "^11.0.0",
"@types/geojson": "^7946.0.8",
"@types/glob-to-regexp": "^0.4.1",
"@types/jest": "29.5.3",
"@types/jest": "29.5.4",
"@types/katex": "^0.16.0",
"@types/lodash": "^4.14.168",
"@types/modernizr": "^3.5.3",
@ -181,23 +181,23 @@
"@typescript-eslint/eslint-plugin": "^5.35.1",
"@typescript-eslint/parser": "^5.6.0",
"allchange": "^1.1.0",
"axe-core": "4.7.2",
"axe-core": "4.8.0",
"babel-jest": "^29.0.0",
"blob-polyfill": "^7.0.0",
"chokidar": "^3.5.1",
"cypress": "^12.0.0",
"cypress": "^13.0.0",
"cypress-axe": "^1.0.0",
"cypress-multi-reporters": "^1.6.1",
"cypress-real-events": "^1.7.1",
"cypress-terminal-report": "^5.3.2",
"eslint": "8.45.0",
"eslint": "8.48.0",
"eslint-config-google": "^0.14.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-deprecate": "^0.7.0",
"eslint-plugin-deprecate": "0.7.0",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-jest": "^27.2.1",
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-matrix-org": "1.2.0",
"eslint-plugin-matrix-org": "1.2.1",
"eslint-plugin-react": "^7.28.0",
"eslint-plugin-react-hooks": "^4.3.0",
"eslint-plugin-unicorn": "^48.0.0",

View File

@ -18,7 +18,7 @@ limitations under the License.
text-align: center;
.mx_Icon {
mask-border: $spacing-16;
margin-bottom: $spacing-16;
}
.mx_Dialog_header {

View File

@ -24,8 +24,9 @@ limitations under the License.
}
button.mx_BaseAvatar {
/* The user agent stylesheet overrides the font-size in this scenario
And that breaks the alignment, emojis, and all sorts of things
/* <button> is a form element and by default it uses the user agent (browser) styling.
We want it to inherit the font-family and line-height from its parent.
*/
font-size: inherit;
font-family: inherit;
line-height: inherit;
}

View File

@ -277,6 +277,7 @@ limitations under the License.
margin-right: $spacing-8;
width: 24px;
height: 24px;
flex-shrink: 0;
.mx_BaseAvatar {
width: inherit;

View File

@ -99,6 +99,11 @@ limitations under the License.
margin: 0 auto;
transition: 0.5s;
.mx_BaseAvatar {
/* Override the calculated font-size so that the letter isn't tiny */
font-size: 4rem;
}
.mx_BaseAvatar,
.mx_BaseAvatar img {
width: 100%;
@ -250,6 +255,11 @@ limitations under the License.
max-width: 72px;
margin: 0 auto;
}
.mx_BaseAvatar {
/* Override the calculated font-size so that the letter isn't tiny */
font-size: 2rem;
}
}
}
}

View File

@ -74,3 +74,8 @@ limitations under the License.
}
}
}
.mx_JoinRuleSettings_labelledCheckbox {
font: var(--cpd-font-body-md-regular);
margin-top: var(--cpd-space-2x);
}

View File

@ -220,7 +220,7 @@ export default class AddThreepid {
body: _t(
"Confirm adding this email address by using Single Sign On to prove your identity.",
),
continueText: _t("Single Sign On"),
continueText: _t("auth|sso"),
continueKind: "primary",
},
[SSOAuthEntry.PHASE_POSTAUTH]: {
@ -323,7 +323,7 @@ export default class AddThreepid {
[SSOAuthEntry.PHASE_PREAUTH]: {
title: _t("Use Single Sign On to continue"),
body: _t("Confirm adding this phone number by using Single Sign On to prove your identity."),
continueText: _t("Single Sign On"),
continueText: _t("auth|sso"),
continueKind: "primary",
},
[SSOAuthEntry.PHASE_POSTAUTH]: {

View File

@ -624,7 +624,7 @@ export const Commands = [
!isCurrentLocalRoom(cli),
runFn: function (cli, roomId, threadId, widgetUrl) {
if (!widgetUrl) {
return reject(new UserFriendlyError("Please supply a widget URL or embed code"));
return reject(new UserFriendlyError("slash_command|addwidget_missing_url"));
}
// Try and parse out a widget URL from iframes
@ -635,7 +635,7 @@ export const Commands = [
if (iframe?.tagName.toLowerCase() === "iframe") {
logger.log("Pulling URL out of iframe (embed code)");
if (!iframe.hasAttribute("src")) {
return reject(new UserFriendlyError("iframe has no src attribute"));
return reject(new UserFriendlyError("slash_command|addwidget_iframe_missing_src"));
}
widgetUrl = iframe.getAttribute("src")!;
}
@ -643,7 +643,7 @@ export const Commands = [
}
if (!widgetUrl.startsWith("https://") && !widgetUrl.startsWith("http://")) {
return reject(new UserFriendlyError("Please supply a https:// or http:// widget URL"));
return reject(new UserFriendlyError("slash_command|addwidget_invalid_protocol"));
}
if (WidgetUtils.canUserModifyWidgets(cli, roomId)) {
const userId = cli.getUserId();
@ -665,7 +665,7 @@ export const Commands = [
return success(WidgetUtils.setRoomWidget(cli, roomId, widgetId, type, widgetUrl, name, data));
} else {
return reject(new UserFriendlyError("You cannot modify widgets in this room."));
return reject(new UserFriendlyError("slash_command|addwidget_no_permissions"));
}
},
category: CommandCategories.admin,
@ -749,7 +749,7 @@ export const Commands = [
}),
new Command({
command: "discardsession",
description: _td("Forces the current outbound group session in an encrypted room to be discarded"),
description: _td("slash_command|discardsession"),
isEnabled: (cli) => !isCurrentLocalRoom(cli),
runFn: function (cli, roomId) {
try {
@ -764,7 +764,7 @@ export const Commands = [
}),
new Command({
command: "remakeolm",
description: _td("Developer command: Discards the current outbound group session and sets up new Olm sessions"),
description: _td("slash_command|remakeolm"),
isEnabled: (cli) => {
return SettingsStore.getValue("developerMode") && !isCurrentLocalRoom(cli);
},
@ -856,7 +856,7 @@ export const Commands = [
}),
new Command({
command: "tovirtual",
description: _td("Switches to this room's virtual room, if it has one"),
description: _td("slash_command|tovirtual"),
category: CommandCategories.advanced,
isEnabled(cli): boolean {
return !!LegacyCallHandler.instance.getSupportsVirtualRooms() && !isCurrentLocalRoom(cli);
@ -865,7 +865,7 @@ export const Commands = [
return success(
(async (): Promise<void> => {
const room = await VoipUserMapper.sharedInstance().getVirtualRoomForRoom(roomId);
if (!room) throw new UserFriendlyError("No virtual room for this room");
if (!room) throw new UserFriendlyError("slash_command|tovirtual_not_found");
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: room.roomId,
@ -878,7 +878,7 @@ export const Commands = [
}),
new Command({
command: "query",
description: _td("Opens chat with the given user"),
description: _td("slash_command|query"),
args: "<user-id>",
runFn: function (cli, roomId, threadId, userId) {
// easter-egg for now: look up phone numbers through the thirdparty API
@ -893,7 +893,7 @@ export const Commands = [
if (isPhoneNumber) {
const results = await LegacyCallHandler.instance.pstnLookup(userId);
if (!results || results.length === 0 || !results[0].userid) {
throw new UserFriendlyError("Unable to find Matrix ID for phone number");
throw new UserFriendlyError("slash_command|query_not_found_phone_number");
}
userId = results[0].userid;
}
@ -949,13 +949,13 @@ export const Commands = [
}),
new Command({
command: "holdcall",
description: _td("Places the call in the current room on hold"),
description: _td("slash_command|holdcall"),
category: CommandCategories.other,
isEnabled: (cli) => !isCurrentLocalRoom(cli),
runFn: function (cli, roomId, threadId, args) {
const call = LegacyCallHandler.instance.getCallForRoom(roomId);
if (!call) {
return reject(new UserFriendlyError("No active call in this room"));
return reject(new UserFriendlyError("slash_command|no_active_call"));
}
call.setRemoteOnHold(true);
return success();
@ -964,13 +964,13 @@ export const Commands = [
}),
new Command({
command: "unholdcall",
description: _td("Takes the call in the current room off hold"),
description: _td("slash_command|unholdcall"),
category: CommandCategories.other,
isEnabled: (cli) => !isCurrentLocalRoom(cli),
runFn: function (cli, roomId, threadId, args) {
const call = LegacyCallHandler.instance.getCallForRoom(roomId);
if (!call) {
return reject(new UserFriendlyError("No active call in this room"));
return reject(new UserFriendlyError("slash_command|no_active_call"));
}
call.setRemoteOnHold(false);
return success();
@ -979,24 +979,24 @@ export const Commands = [
}),
new Command({
command: "converttodm",
description: _td("Converts the room to a DM"),
description: _td("slash_command|converttodm"),
category: CommandCategories.other,
isEnabled: (cli) => !isCurrentLocalRoom(cli),
runFn: function (cli, roomId, threadId, args) {
const room = cli.getRoom(roomId);
if (!room) return reject(new UserFriendlyError("Could not find room"));
if (!room) return reject(new UserFriendlyError("slash_command|could_not_find_room"));
return success(guessAndSetDMRoom(room, true));
},
renderingTypes: [TimelineRenderingType.Room],
}),
new Command({
command: "converttoroom",
description: _td("Converts the DM to a room"),
description: _td("slash_command|converttoroom"),
category: CommandCategories.other,
isEnabled: (cli) => !isCurrentLocalRoom(cli),
runFn: function (cli, roomId, threadId, args) {
const room = cli.getRoom(roomId);
if (!room) return reject(new UserFriendlyError("Could not find room"));
if (!room) return reject(new UserFriendlyError("slash_command|could_not_find_room"));
return success(guessAndSetDMRoom(room, false));
},
renderingTypes: [TimelineRenderingType.Room],
@ -1007,7 +1007,7 @@ export const Commands = [
new Command({
command: "me",
args: "<message>",
description: _td("Displays action"),
description: _td("slash_command|me"),
category: CommandCategories.messages,
hideCompletionAfterSpace: true,
}),

View File

@ -423,7 +423,7 @@ function textForCanonicalAliasEvent(ev: MatrixEvent): (() => string) | null {
} else if (newAlias === oldAlias) {
if (addedAltAliases.length && !removedAltAliases.length) {
return () =>
_t("%(senderName)s added the alternative addresses %(addresses)s for this room.", {
_t("timeline|m.room.canonical_alias|alt_added", {
senderName,
addresses: addedAltAliases.join(", "),
count: addedAltAliases.length,
@ -431,7 +431,7 @@ function textForCanonicalAliasEvent(ev: MatrixEvent): (() => string) | null {
}
if (removedAltAliases.length && !addedAltAliases.length) {
return () =>
_t("%(senderName)s removed the alternative addresses %(addresses)s for this room.", {
_t("timeline|m.room.canonical_alias|alt_removed", {
senderName,
addresses: removedAltAliases.join(", "),
count: removedAltAliases.length,
@ -547,11 +547,11 @@ function textForPowerEvent(event: MatrixEvent, client: MatrixClient): (() => str
// XXX: This is also surely broken for i18n
return () =>
_t("%(senderName)s changed the power level of %(powerLevelDiffText)s.", {
_t("timeline|m.room.power_levels|changed", {
senderName,
powerLevelDiffText: diffs
.map((diff) =>
_t("%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s", {
_t("timeline|m.room.power_levels|user_from_to", {
userId: diff.name,
fromPowerLevel: Roles.textualPowerLevel(diff.from, previousUserDefault),
toPowerLevel: Roles.textualPowerLevel(diff.to, currentUserDefault),
@ -711,45 +711,43 @@ function textForMjolnirEvent(event: MatrixEvent): (() => string) | null {
// Rule removed
if (!entity) {
if (USER_RULE_TYPES.includes(event.getType())) {
return () =>
_t("%(senderName)s removed the rule banning users matching %(glob)s", { senderName, glob: prevEntity });
return () => _t("timeline|mjolnir|removed_rule_users", { senderName, glob: prevEntity });
} else if (ROOM_RULE_TYPES.includes(event.getType())) {
return () =>
_t("%(senderName)s removed the rule banning rooms matching %(glob)s", { senderName, glob: prevEntity });
return () => _t("timeline|mjolnir|removed_rule_rooms", { senderName, glob: prevEntity });
} else if (SERVER_RULE_TYPES.includes(event.getType())) {
return () =>
_t("%(senderName)s removed the rule banning servers matching %(glob)s", {
_t("timeline|mjolnir|removed_rule_servers", {
senderName,
glob: prevEntity,
});
}
// Unknown type. We'll say something, but we shouldn't end up here.
return () => _t("%(senderName)s removed a ban rule matching %(glob)s", { senderName, glob: prevEntity });
return () => _t("timeline|mjolnir|removed_rule", { senderName, glob: prevEntity });
}
// Invalid rule
if (!recommendation || !reason) return () => _t(`%(senderName)s updated an invalid ban rule`, { senderName });
if (!recommendation || !reason) return () => _t("timeline|mjolnir|updated_invalid_rule", { senderName });
// Rule updated
if (entity === prevEntity) {
if (USER_RULE_TYPES.includes(event.getType())) {
return () =>
_t("%(senderName)s updated the rule banning users matching %(glob)s for %(reason)s", {
_t("timeline|mjolnir|updated_rule_users", {
senderName,
glob: entity,
reason,
});
} else if (ROOM_RULE_TYPES.includes(event.getType())) {
return () =>
_t("%(senderName)s updated the rule banning rooms matching %(glob)s for %(reason)s", {
_t("timeline|mjolnir|updated_rule_rooms", {
senderName,
glob: entity,
reason,
});
} else if (SERVER_RULE_TYPES.includes(event.getType())) {
return () =>
_t("%(senderName)s updated the rule banning servers matching %(glob)s for %(reason)s", {
_t("timeline|mjolnir|updated_rule_servers", {
senderName,
glob: entity,
reason,
@ -758,7 +756,7 @@ function textForMjolnirEvent(event: MatrixEvent): (() => string) | null {
// Unknown type. We'll say something but we shouldn't end up here.
return () =>
_t("%(senderName)s updated a ban rule matching %(glob)s for %(reason)s", {
_t("timeline|mjolnir|updated_rule", {
senderName,
glob: entity,
reason,
@ -769,21 +767,21 @@ function textForMjolnirEvent(event: MatrixEvent): (() => string) | null {
if (!prevEntity) {
if (USER_RULE_TYPES.includes(event.getType())) {
return () =>
_t("%(senderName)s created a rule banning users matching %(glob)s for %(reason)s", {
_t("timeline|mjolnir|created_rule_users", {
senderName,
glob: entity,
reason,
});
} else if (ROOM_RULE_TYPES.includes(event.getType())) {
return () =>
_t("%(senderName)s created a rule banning rooms matching %(glob)s for %(reason)s", {
_t("timeline|mjolnir|created_rule_rooms", {
senderName,
glob: entity,
reason,
});
} else if (SERVER_RULE_TYPES.includes(event.getType())) {
return () =>
_t("%(senderName)s created a rule banning servers matching %(glob)s for %(reason)s", {
_t("timeline|mjolnir|created_rule_servers", {
senderName,
glob: entity,
reason,
@ -792,7 +790,7 @@ function textForMjolnirEvent(event: MatrixEvent): (() => string) | null {
// Unknown type. We'll say something but we shouldn't end up here.
return () =>
_t("%(senderName)s created a ban rule matching %(glob)s for %(reason)s", {
_t("timeline|mjolnir|created_rule", {
senderName,
glob: entity,
reason,
@ -802,27 +800,18 @@ function textForMjolnirEvent(event: MatrixEvent): (() => string) | null {
// else the entity !== prevEntity - count as a removal & add
if (USER_RULE_TYPES.includes(event.getType())) {
return () =>
_t(
"%(senderName)s changed a rule that was banning users matching %(oldGlob)s to matching %(newGlob)s for %(reason)s",
{ senderName, oldGlob: prevEntity, newGlob: entity, reason },
);
_t("timeline|mjolnir|changed_rule_users", { senderName, oldGlob: prevEntity, newGlob: entity, reason });
} else if (ROOM_RULE_TYPES.includes(event.getType())) {
return () =>
_t(
"%(senderName)s changed a rule that was banning rooms matching %(oldGlob)s to matching %(newGlob)s for %(reason)s",
{ senderName, oldGlob: prevEntity, newGlob: entity, reason },
);
_t("timeline|mjolnir|changed_rule_rooms", { senderName, oldGlob: prevEntity, newGlob: entity, reason });
} else if (SERVER_RULE_TYPES.includes(event.getType())) {
return () =>
_t(
"%(senderName)s changed a rule that was banning servers matching %(oldGlob)s to matching %(newGlob)s for %(reason)s",
{ senderName, oldGlob: prevEntity, newGlob: entity, reason },
);
_t("timeline|mjolnir|changed_rule_servers", { senderName, oldGlob: prevEntity, newGlob: entity, reason });
}
// Unknown type. We'll say something but we shouldn't end up here.
return () =>
_t("%(senderName)s updated a ban rule that was matching %(oldGlob)s to matching %(newGlob)s for %(reason)s", {
_t("timeline|mjolnir|changed_rule_glob", {
senderName,
oldGlob: prevEntity,
newGlob: entity,

View File

@ -50,7 +50,7 @@ const getUIOnlyShortcuts = (): IKeyboardShortcuts => {
key: Key.ENTER,
shiftKey: !ctrlEnterToSend,
},
displayName: _td("New line"),
displayName: _td("keyboard|composer_new_line"),
},
[KeyBindingAction.CompleteAutocomplete]: {
default: {
@ -62,14 +62,14 @@ const getUIOnlyShortcuts = (): IKeyboardShortcuts => {
default: {
key: Key.TAB,
},
displayName: _td("Force complete"),
displayName: _td("keyboard|autocomplete_force"),
},
[KeyBindingAction.SearchInRoom]: {
default: {
ctrlOrCmdKey: true,
key: Key.F,
},
displayName: _td("Search (must be enabled)"),
displayName: _td("keyboard|search"),
},
};
@ -82,7 +82,7 @@ const getUIOnlyShortcuts = (): IKeyboardShortcuts => {
ctrlOrCmdKey: true,
key: DIGITS,
},
displayName: _td("Switch to space by number"),
displayName: _td("keyboard|switch_to_space"),
};
}

View File

@ -229,7 +229,7 @@ export const CATEGORIES: Record<CategoryName, ICategory> = {
],
},
[CategoryName.CALLS]: {
categoryLabel: _td("Calls"),
categoryLabel: _td("keyboard|category_calls"),
settingNames: [KeyBindingAction.ToggleMicInCall, KeyBindingAction.ToggleWebcamInCall],
},
[CategoryName.ROOM]: {
@ -246,7 +246,7 @@ export const CATEGORIES: Record<CategoryName, ICategory> = {
],
},
[CategoryName.ROOM_LIST]: {
categoryLabel: _td("Room List"),
categoryLabel: _td("keyboard|category_room_list"),
settingNames: [
KeyBindingAction.SelectRoomInRoomList,
KeyBindingAction.ClearRoomFilter,
@ -274,7 +274,7 @@ export const CATEGORIES: Record<CategoryName, ICategory> = {
],
},
[CategoryName.NAVIGATION]: {
categoryLabel: _td("Navigation"),
categoryLabel: _td("keyboard|category_navigation"),
settingNames: [
KeyBindingAction.ToggleUserMenu,
KeyBindingAction.ToggleRoomSidePanel,
@ -293,7 +293,7 @@ export const CATEGORIES: Record<CategoryName, ICategory> = {
],
},
[CategoryName.AUTOCOMPLETE]: {
categoryLabel: _td("Autocomplete"),
categoryLabel: _td("keyboard|category_autocomplete"),
settingNames: [
KeyBindingAction.CancelAutocomplete,
KeyBindingAction.NextSelectionInAutocomplete,
@ -327,14 +327,14 @@ export const KEYBOARD_SHORTCUTS: IKeyboardShortcuts = {
ctrlOrCmdKey: true,
key: Key.B,
},
displayName: _td("Toggle Bold"),
displayName: _td("keyboard|composer_toggle_bold"),
},
[KeyBindingAction.FormatItalics]: {
default: {
ctrlOrCmdKey: true,
key: Key.I,
},
displayName: _td("Toggle Italics"),
displayName: _td("keyboard|composer_toggle_italics"),
},
[KeyBindingAction.FormatQuote]: {
default: {
@ -342,14 +342,14 @@ export const KEYBOARD_SHORTCUTS: IKeyboardShortcuts = {
shiftKey: true,
key: Key.GREATER_THAN,
},
displayName: _td("Toggle Quote"),
displayName: _td("keyboard|composer_toggle_quote"),
},
[KeyBindingAction.FormatCode]: {
default: {
ctrlOrCmdKey: true,
key: Key.E,
},
displayName: _td("Toggle Code Block"),
displayName: _td("keyboard|composer_toggle_code_block"),
},
[KeyBindingAction.FormatLink]: {
default: {
@ -357,39 +357,39 @@ export const KEYBOARD_SHORTCUTS: IKeyboardShortcuts = {
shiftKey: true,
key: Key.L,
},
displayName: _td("Toggle Link"),
displayName: _td("keyboard|composer_toggle_link"),
},
[KeyBindingAction.CancelReplyOrEdit]: {
default: {
key: Key.ESCAPE,
},
displayName: _td("Cancel replying to a message"),
displayName: _td("keyboard|cancel_reply"),
},
[KeyBindingAction.EditNextMessage]: {
default: {
key: Key.ARROW_DOWN,
},
displayName: _td("Navigate to next message to edit"),
displayName: _td("keyboard|navigate_next_message_edit"),
},
[KeyBindingAction.EditPrevMessage]: {
default: {
key: Key.ARROW_UP,
},
displayName: _td("Navigate to previous message to edit"),
displayName: _td("keyboard|navigate_prev_message_edit"),
},
[KeyBindingAction.MoveCursorToStart]: {
default: {
ctrlOrCmdKey: true,
key: Key.HOME,
},
displayName: _td("Jump to start of the composer"),
displayName: _td("keyboard|composer_jump_start"),
},
[KeyBindingAction.MoveCursorToEnd]: {
default: {
ctrlOrCmdKey: true,
key: Key.END,
},
displayName: _td("Jump to end of the composer"),
displayName: _td("keyboard|composer_jump_end"),
},
[KeyBindingAction.SelectNextSendHistory]: {
default: {
@ -397,7 +397,7 @@ export const KEYBOARD_SHORTCUTS: IKeyboardShortcuts = {
ctrlKey: true,
key: Key.ARROW_DOWN,
},
displayName: _td("Navigate to next message in composer history"),
displayName: _td("keyboard|composer_navigate_next_history"),
},
[KeyBindingAction.SelectPrevSendHistory]: {
default: {
@ -405,41 +405,41 @@ export const KEYBOARD_SHORTCUTS: IKeyboardShortcuts = {
ctrlKey: true,
key: Key.ARROW_UP,
},
displayName: _td("Navigate to previous message in composer history"),
displayName: _td("keyboard|composer_navigate_prev_history"),
},
[KeyBindingAction.ShowStickerPicker]: {
default: {
ctrlOrCmdKey: true,
key: Key.SEMICOLON,
},
displayName: _td("Send a sticker"),
displayName: _td("keyboard|send_sticker"),
},
[KeyBindingAction.ToggleMicInCall]: {
default: {
ctrlOrCmdKey: true,
key: Key.D,
},
displayName: _td("Toggle microphone mute"),
displayName: _td("keyboard|toggle_microphone_mute"),
},
[KeyBindingAction.ToggleWebcamInCall]: {
default: {
ctrlOrCmdKey: true,
key: Key.E,
},
displayName: _td("Toggle webcam on/off"),
displayName: _td("keyboard|toggle_webcam_mute"),
},
[KeyBindingAction.DismissReadMarker]: {
default: {
key: Key.ESCAPE,
},
displayName: _td("Dismiss read marker and jump to bottom"),
displayName: _td("keyboard|dismiss_read_marker_and_jump_bottom"),
},
[KeyBindingAction.JumpToOldestUnread]: {
default: {
shiftKey: true,
key: Key.PAGE_UP,
},
displayName: _td("Jump to oldest unread message"),
displayName: _td("keyboard|jump_to_read_marker"),
},
[KeyBindingAction.UploadFile]: {
default: {
@ -447,77 +447,77 @@ export const KEYBOARD_SHORTCUTS: IKeyboardShortcuts = {
shiftKey: true,
key: Key.U,
},
displayName: _td("Upload a file"),
displayName: _td("keyboard|upload_file"),
},
[KeyBindingAction.ScrollUp]: {
default: {
key: Key.PAGE_UP,
},
displayName: _td("Scroll up in the timeline"),
displayName: _td("keyboard|scroll_up_timeline"),
},
[KeyBindingAction.ScrollDown]: {
default: {
key: Key.PAGE_DOWN,
},
displayName: _td("Scroll down in the timeline"),
displayName: _td("keyboard|scroll_down_timeline"),
},
[KeyBindingAction.FilterRooms]: {
default: {
ctrlOrCmdKey: true,
key: Key.K,
},
displayName: _td("Jump to room search"),
displayName: _td("keyboard|jump_room_search"),
},
[KeyBindingAction.SelectRoomInRoomList]: {
default: {
key: Key.ENTER,
},
displayName: _td("Select room from the room list"),
displayName: _td("keyboard|room_list_select_room"),
},
[KeyBindingAction.CollapseRoomListSection]: {
default: {
key: Key.ARROW_LEFT,
},
displayName: _td("Collapse room list section"),
displayName: _td("keyboard|room_list_collapse_section"),
},
[KeyBindingAction.ExpandRoomListSection]: {
default: {
key: Key.ARROW_RIGHT,
},
displayName: _td("Expand room list section"),
displayName: _td("keyboard|room_list_expand_section"),
},
[KeyBindingAction.NextRoom]: {
default: {
key: Key.ARROW_DOWN,
},
displayName: _td("Navigate down in the room list"),
displayName: _td("keyboard|room_list_navigate_down"),
},
[KeyBindingAction.PrevRoom]: {
default: {
key: Key.ARROW_UP,
},
displayName: _td("Navigate up in the room list"),
displayName: _td("keyboard|room_list_navigate_up"),
},
[KeyBindingAction.ToggleUserMenu]: {
default: {
ctrlOrCmdKey: true,
key: Key.BACKTICK,
},
displayName: _td("Toggle the top left menu"),
displayName: _td("keyboard|toggle_top_left_menu"),
},
[KeyBindingAction.ToggleRoomSidePanel]: {
default: {
ctrlOrCmdKey: true,
key: Key.PERIOD,
},
displayName: _td("Toggle right panel"),
displayName: _td("keyboard|toggle_right_panel"),
},
[KeyBindingAction.ShowKeyboardSettings]: {
default: {
ctrlOrCmdKey: true,
key: Key.SLASH,
},
displayName: _td("Open this settings tab"),
displayName: _td("keyboard|keyboard_shortcuts_tab"),
},
[KeyBindingAction.GoToHome]: {
default: {
@ -526,7 +526,7 @@ export const KEYBOARD_SHORTCUTS: IKeyboardShortcuts = {
shiftKey: IS_MAC,
key: Key.H,
},
displayName: _td("Go to Home View"),
displayName: _td("keyboard|go_home_view"),
},
[KeyBindingAction.SelectNextUnreadRoom]: {
default: {
@ -534,7 +534,7 @@ export const KEYBOARD_SHORTCUTS: IKeyboardShortcuts = {
altKey: true,
key: Key.ARROW_DOWN,
},
displayName: _td("Next unread room or DM"),
displayName: _td("keyboard|next_unread_room"),
},
[KeyBindingAction.SelectPrevUnreadRoom]: {
default: {
@ -542,39 +542,39 @@ export const KEYBOARD_SHORTCUTS: IKeyboardShortcuts = {
altKey: true,
key: Key.ARROW_UP,
},
displayName: _td("Previous unread room or DM"),
displayName: _td("keyboard|prev_unread_room"),
},
[KeyBindingAction.SelectNextRoom]: {
default: {
altKey: true,
key: Key.ARROW_DOWN,
},
displayName: _td("Next room or DM"),
displayName: _td("keyboard|next_room"),
},
[KeyBindingAction.SelectPrevRoom]: {
default: {
altKey: true,
key: Key.ARROW_UP,
},
displayName: _td("Previous room or DM"),
displayName: _td("keyboard|prev_room"),
},
[KeyBindingAction.CancelAutocomplete]: {
default: {
key: Key.ESCAPE,
},
displayName: _td("Cancel autocomplete"),
displayName: _td("keyboard|autocomplete_cancel"),
},
[KeyBindingAction.NextSelectionInAutocomplete]: {
default: {
key: Key.ARROW_DOWN,
},
displayName: _td("Next autocomplete suggestion"),
displayName: _td("keyboard|autocomplete_navigate_next"),
},
[KeyBindingAction.PrevSelectionInAutocomplete]: {
default: {
key: Key.ARROW_UP,
},
displayName: _td("Previous autocomplete suggestion"),
displayName: _td("keyboard|autocomplete_navigate_prev"),
},
[KeyBindingAction.ToggleSpacePanel]: {
default: {
@ -582,7 +582,7 @@ export const KEYBOARD_SHORTCUTS: IKeyboardShortcuts = {
shiftKey: true,
key: Key.D,
},
displayName: _td("Toggle space panel"),
displayName: _td("keyboard|toggle_space_panel"),
},
[KeyBindingAction.ToggleHiddenEventVisibility]: {
default: {
@ -590,28 +590,28 @@ export const KEYBOARD_SHORTCUTS: IKeyboardShortcuts = {
shiftKey: true,
key: Key.H,
},
displayName: _td("Toggle hidden event visibility"),
displayName: _td("keyboard|toggle_hidden_events"),
},
[KeyBindingAction.JumpToFirstMessage]: {
default: {
key: Key.HOME,
ctrlKey: true,
},
displayName: _td("Jump to first message"),
displayName: _td("keyboard|jump_first_message"),
},
[KeyBindingAction.JumpToLatestMessage]: {
default: {
key: Key.END,
ctrlKey: true,
},
displayName: _td("Jump to last message"),
displayName: _td("keyboard|jump_last_message"),
},
[KeyBindingAction.EditUndo]: {
default: {
key: Key.Z,
ctrlOrCmdKey: true,
},
displayName: _td("Undo edit"),
displayName: _td("keyboard|composer_undo"),
},
[KeyBindingAction.EditRedo]: {
default: {
@ -619,7 +619,7 @@ export const KEYBOARD_SHORTCUTS: IKeyboardShortcuts = {
ctrlOrCmdKey: true,
shiftKey: IS_MAC,
},
displayName: _td("Redo edit"),
displayName: _td("keyboard|composer_redo"),
},
[KeyBindingAction.PreviousVisitedRoomOrSpace]: {
default: {
@ -627,7 +627,7 @@ export const KEYBOARD_SHORTCUTS: IKeyboardShortcuts = {
altKey: !IS_MAC,
key: IS_MAC ? Key.SQUARE_BRACKET_LEFT : Key.ARROW_LEFT,
},
displayName: _td("Previous recently visited room or space"),
displayName: _td("keyboard|navigate_prev_history"),
},
[KeyBindingAction.NextVisitedRoomOrSpace]: {
default: {
@ -635,33 +635,33 @@ export const KEYBOARD_SHORTCUTS: IKeyboardShortcuts = {
altKey: !IS_MAC,
key: IS_MAC ? Key.SQUARE_BRACKET_RIGHT : Key.ARROW_RIGHT,
},
displayName: _td("Next recently visited room or space"),
displayName: _td("keyboard|navigate_next_history"),
},
[KeyBindingAction.SwitchToSpaceByNumber]: {
default: {
ctrlOrCmdKey: true,
key: DIGITS,
},
displayName: _td("Switch to space by number"),
displayName: _td("keyboard|switch_to_space"),
},
[KeyBindingAction.OpenUserSettings]: {
default: {
metaKey: true,
key: Key.COMMA,
},
displayName: _td("Open user settings"),
displayName: _td("keyboard|open_user_settings"),
},
[KeyBindingAction.Escape]: {
default: {
key: Key.ESCAPE,
},
displayName: _td("Close dialog or context menu"),
displayName: _td("keyboard|close_dialog_menu"),
},
[KeyBindingAction.Enter]: {
default: {
key: Key.ENTER,
},
displayName: _td("Activate selected button"),
displayName: _td("keyboard|activate_button"),
},
[KeyBindingAction.Space]: {
default: {

View File

@ -303,7 +303,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
[SSOAuthEntry.PHASE_PREAUTH]: {
title: _t("Use Single Sign On to continue"),
body: _t("To continue, use Single Sign On to prove your identity."),
continueText: _t("Single Sign On"),
continueText: _t("auth|sso"),
continueKind: "primary",
},
[SSOAuthEntry.PHASE_POSTAUTH]: {

View File

@ -74,8 +74,8 @@ const UserWelcomeTop: React.FC = () => {
<div>
<MiniAvatarUploader
hasAvatar={!!ownProfile.avatarUrl}
hasAvatarLabel={_tDom("Great, that'll help people know it's you")}
noAvatarLabel={_tDom("Add a photo so people know it's you.")}
hasAvatarLabel={_tDom("onboarding|has_avatar_label")}
noAvatarLabel={_tDom("onboarding|no_avatar_label")}
setAvatarUrl={(url) => cli.setAvatarUrl(url)}
isUserAvatar
onClick={(ev) => PosthogTrackers.trackInteraction("WebHomeMiniAvatarUploadButton", ev)}
@ -88,8 +88,8 @@ const UserWelcomeTop: React.FC = () => {
/>
</MiniAvatarUploader>
<h1>{_tDom("Welcome %(name)s", { name: ownProfile.displayName })}</h1>
<h2>{_tDom("Now, let's help you get started")}</h2>
<h1>{_tDom("onboarding|welcome_user", { name: ownProfile.displayName })}</h1>
<h2>{_tDom("onboarding|welcome_detail")}</h2>
</div>
);
};
@ -113,8 +113,8 @@ const HomePage: React.FC<IProps> = ({ justRegistered = false }) => {
introSection = (
<React.Fragment>
<img src={logoUrl} alt={config.brand} />
<h1>{_tDom("Welcome to %(appName)s", { appName: config.brand })}</h1>
<h2>{_tDom("Own your conversations.")}</h2>
<h1>{_tDom("onboarding|intro_welcome", { appName: config.brand })}</h1>
<h2>{_tDom("onboarding|intro_byline")}</h2>
</React.Fragment>
);
}
@ -125,13 +125,13 @@ const HomePage: React.FC<IProps> = ({ justRegistered = false }) => {
{introSection}
<div className="mx_HomePage_default_buttons">
<AccessibleButton onClick={onClickSendDm} className="mx_HomePage_button_sendDm">
{_tDom("Send a Direct Message")}
{_tDom("onboarding|send_dm")}
</AccessibleButton>
<AccessibleButton onClick={onClickExplore} className="mx_HomePage_button_explore">
{_tDom("Explore Public Rooms")}
{_tDom("onboarding|explore_rooms")}
</AccessibleButton>
<AccessibleButton onClick={onClickNewRoom} className="mx_HomePage_button_createGroup">
{_tDom("Create a Group Chat")}
{_tDom("onboarding|create_room")}
</AccessibleButton>
</div>
</div>

View File

@ -245,7 +245,6 @@ export interface IRoomState {
canAskToJoin: boolean;
promptAskToJoin: boolean;
knocked: boolean;
}
interface LocalRoomViewProps {
@ -458,7 +457,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
msc3946ProcessDynamicPredecessor: SettingsStore.getValue("feature_dynamic_room_predecessors"),
canAskToJoin: this.askToJoinEnabled,
promptAskToJoin: false,
knocked: false,
};
this.dispatcherRef = dis.register(this.onAction);
@ -664,7 +662,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
: false,
activeCall: roomId ? CallStore.instance.getActiveCall(roomId) : null,
promptAskToJoin: this.context.roomViewStore.promptAskToJoin(),
knocked: this.context.roomViewStore.knocked(),
};
if (
@ -2118,7 +2115,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
signUrl={this.props.threepidInvite?.signUrl}
roomId={this.state.roomId}
promptAskToJoin={this.state.promptAskToJoin}
knocked={this.state.knocked}
onSubmitAskToJoin={this.onSubmitAskToJoin}
onCancelAskToJoin={this.onCancelAskToJoin}
/>
@ -2202,9 +2198,10 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
<RoomPreviewBar
room={this.state.room}
promptAskToJoin={myMembership === "leave" || this.state.promptAskToJoin}
knocked={myMembership === "knock" || this.state.knocked}
knocked={myMembership === "knock"}
onSubmitAskToJoin={this.onSubmitAskToJoin}
onCancelAskToJoin={this.onCancelAskToJoin}
onForgetClick={this.onForgetClick}
/>
</ErrorBoundary>
</div>

View File

@ -384,12 +384,12 @@ export default class ForgotPassword extends React.Component<Props, State> {
public renderSetPassword(): JSX.Element {
const submitButtonChild =
this.state.phase === Phase.ResettingPassword ? <Spinner w={16} h={16} /> : _t("Reset password");
this.state.phase === Phase.ResettingPassword ? <Spinner w={16} h={16} /> : _t("auth|reset_password_action");
return (
<>
<LockIcon className="mx_AuthBody_lockIcon" />
<h1>{_t("Reset your password")}</h1>
<h1>{_t("auth|reset_password_title")}</h1>
<form onSubmit={this.onSubmitForm}>
<fieldset disabled={this.state.phase === Phase.ResettingPassword}>
<div className="mx_AuthBody_fieldRow">

View File

@ -523,7 +523,7 @@ export default class Registration extends React.Component<IProps, IState> {
// i18n: ssoButtons is a placeholder to help translators understand context
continueWithSection = (
<h2 className="mx_AuthBody_centered">
{_t("Continue with %(ssoButtons)s", { ssoButtons: "" }).trim()}
{_t("auth|continue_with_sso", { ssoButtons: "" }).trim()}
</h2>
);
}
@ -540,7 +540,7 @@ export default class Registration extends React.Component<IProps, IState> {
action={SSOAction.REGISTER}
/>
<h2 className="mx_AuthBody_centered">
{_t("%(ssoButtons)s Or %(usernamePassword)s", {
{_t("auth|sso_or_username_password", {
ssoButtons: "",
usernamePassword: "",
}).trim()}
@ -591,7 +591,7 @@ export default class Registration extends React.Component<IProps, IState> {
const signIn = (
<span className="mx_AuthBody_changeFlow">
{_t(
"Already have an account? <a>Sign in here</a>",
"auth|sign_in_instead",
{},
{
a: (sub) => (
@ -621,13 +621,10 @@ export default class Registration extends React.Component<IProps, IState> {
regDoneText = (
<div>
<p>
{_t(
"Your new account (%(newAccountId)s) is registered, but you're already logged into a different account (%(loggedInUserId)s).",
{
newAccountId: this.state.registeredUsername,
loggedInUserId: this.state.differentLoggedInUserId,
},
)}
{_t("auth|account_clash", {
newAccountId: this.state.registeredUsername,
loggedInUserId: this.state.differentLoggedInUserId,
})}
</p>
<p>
<AccessibleButton
@ -639,7 +636,7 @@ export default class Registration extends React.Component<IProps, IState> {
}
}}
>
{_t("Continue with previous account")}
{_t("auth|account_clash_previous_account")}
</AccessibleButton>
</p>
</div>
@ -650,7 +647,7 @@ export default class Registration extends React.Component<IProps, IState> {
regDoneText = (
<h2>
{_t(
"<a>Log in</a> to your new account.",
"auth|log_in_new_account",
{},
{
a: (sub) => (
@ -673,7 +670,7 @@ export default class Registration extends React.Component<IProps, IState> {
}
body = (
<div>
<h1>{_t("Registration Successful")}</h1>
<h1>{_t("auth|registration_successful")}</h1>
{regDoneText}
</div>
);
@ -685,8 +682,8 @@ export default class Registration extends React.Component<IProps, IState> {
title={_t("Create account")}
serverPicker={
<ServerPicker
title={_t("Host account on")}
dialogTitle={_t("Decide where your account is hosted")}
title={_t("auth|server_picker_title")}
dialogTitle={_t("auth|server_picker_dialog_title")}
serverConfig={this.props.serverConfig}
onServerConfigChange={
this.state.doingUIAuth ? undefined : this.props.onServerConfigChange

View File

@ -287,7 +287,7 @@ export default class SoftLogout extends React.Component<IProps, IState> {
<p>{_t("Sign in and regain access to your account.")}</p>
{this.renderSsoForm(null)}
<h2 className="mx_AuthBody_centered">
{_t("%(ssoButtons)s Or %(usernamePassword)s", {
{_t("auth|sso_or_username_password", {
ssoButtons: "",
usernamePassword: "",
}).trim()}

View File

@ -874,7 +874,7 @@ export class SSOAuthEntry extends React.Component<ISSOAuthEntryProps, ISSOAuthEn
if (this.state.phase === SSOAuthEntry.PHASE_PREAUTH) {
continueButton = (
<AccessibleButton onClick={this.onStartAuthClick} kind={this.props.continueKind || "primary"}>
{this.props.continueText || _t("Single Sign On")}
{this.props.continueText || _t("auth|sso")}
</AccessibleButton>
);
} else {

View File

@ -66,7 +66,7 @@ const LiveTimeRemaining: React.FC<{ beacon: Beacon }> = ({ beacon }) => {
const msRemaining = useMsRemaining(beacon);
const timeRemaining = formatDuration(msRemaining);
const liveTimeRemaining = _t(`%(timeRemaining)s left`, { timeRemaining });
const liveTimeRemaining = _t("time|left", { timeRemaining });
return (
<span data-testid="room-live-share-expiry" className="mx_LiveTimeRemaining">

View File

@ -45,8 +45,8 @@ interface IBetaPillProps {
export const BetaPill: React.FC<IBetaPillProps> = ({
onClick,
tooltipTitle = _t("This is a beta feature"),
tooltipCaption = _t("Click for more info"),
tooltipTitle = _t("labs|beta_feature"),
tooltipCaption = _t("labs|click_for_info"),
}) => {
if (onClick) {
return (
@ -94,18 +94,16 @@ const BetaCard: React.FC<IProps> = ({ title: titleOverride, featureId }) => {
let refreshWarning: string | undefined;
if (requiresRefresh) {
const brand = SdkConfig.get().brand;
refreshWarning = value
? _t("Leaving the beta will reload %(brand)s.", { brand })
: _t("Joining the beta will reload %(brand)s.", { brand });
refreshWarning = value ? _t("labs|leave_beta_reload", { brand }) : _t("labs|join_beta_reload", { brand });
}
let content: ReactNode;
if (busy) {
content = <InlineSpinner />;
} else if (value) {
content = _t("Leave the beta");
content = _t("labs|leave_beta");
} else {
content = _t("Join the beta");
content = _t("labs|join_beta");
}
return (

View File

@ -51,7 +51,7 @@ export const AnalyticsLearnMoreDialog: React.FC<IProps> = ({
const privacyPolicyLink = privacyPolicyUrl ? (
<span>
{_t(
"You can read all our terms <PrivacyPolicyUrl>here</PrivacyPolicyUrl>",
"analytics|privacy_policy",
{},
{
PrivacyPolicyUrl: (sub) => {
@ -71,33 +71,18 @@ export const AnalyticsLearnMoreDialog: React.FC<IProps> = ({
<BaseDialog
className="mx_AnalyticsLearnMoreDialog"
contentId="mx_AnalyticsLearnMore"
title={_t("Help improve %(analyticsOwner)s", { analyticsOwner })}
title={_t("analytics|enable_prompt", { analyticsOwner })}
onFinished={onFinished}
>
<div className="mx_Dialog_content">
<div className="mx_AnalyticsLearnMore_image_holder" />
<div className="mx_AnalyticsLearnMore_copy">
{_t(
"Help us identify issues and improve %(analyticsOwner)s by sharing anonymous usage data. To understand how people use multiple devices, we'll generate a random identifier, shared by your devices.",
{ analyticsOwner },
)}
{_t("analytics|pseudonymous_usage_data", { analyticsOwner })}
</div>
<ul className="mx_AnalyticsLearnMore_bullets">
<li>
{_t(
"We <Bold>don't</Bold> record or profile any account data",
{},
{ Bold: (sub) => <b>{sub}</b> },
)}
</li>
<li>
{_t(
"We <Bold>don't</Bold> share information with third parties",
{},
{ Bold: (sub) => <b>{sub}</b> },
)}
</li>
<li>{_t("You can turn this off anytime in settings")}</li>
<li>{_t("analytics|bullet_1", {}, { Bold: (sub) => <b>{sub}</b> })}</li>
<li>{_t("analytics|bullet_2", {}, { Bold: (sub) => <b>{sub}</b> })}</li>
<li>{_t("analytics|disable_prompt")}</li>
</ul>
{privacyPolicyLink}
</div>

View File

@ -47,14 +47,14 @@ export const AppDownloadDialog: FC<Props> = ({ onFinished }) => {
return (
<BaseDialog
title={_t("Download %(brand)s", { brand })}
title={_t("onboarding|download_brand", { brand })}
className="mx_AppDownloadDialog"
fixedWidth
onFinished={onFinished}
>
{desktopBuilds?.get("available") && (
<div className="mx_AppDownloadDialog_desktop">
<Heading size="3">{_t("Download %(brand)s Desktop", { brand })}</Heading>
<Heading size="3">{_t("onboarding|download_brand_desktop", { brand })}</Heading>
<AccessibleButton
kind="primary"
element="a"
@ -62,7 +62,7 @@ export const AppDownloadDialog: FC<Props> = ({ onFinished }) => {
target="_blank"
onClick={() => {}}
>
{_t("Download %(brand)s Desktop", { brand })}
{_t("onboarding|download_brand_desktop", { brand })}
</AccessibleButton>
</div>
)}
@ -71,7 +71,7 @@ export const AppDownloadDialog: FC<Props> = ({ onFinished }) => {
<Heading size="3">{_t("common|ios")}</Heading>
<QRCode data={urlAppStore} margin={0} width={172} />
<div className="mx_AppDownloadDialog_info">
{_t("%(qrCode)s or %(appLinks)s", {
{_t("onboarding|qr_or_app_links", {
appLinks: "",
qrCode: "",
})}
@ -81,7 +81,7 @@ export const AppDownloadDialog: FC<Props> = ({ onFinished }) => {
element="a"
href={urlAppStore}
target="_blank"
aria-label={_t("Download on the App Store")}
aria-label={_t("onboarding|download_app_store")}
onClick={() => {}}
>
<IOSBadge />
@ -92,7 +92,7 @@ export const AppDownloadDialog: FC<Props> = ({ onFinished }) => {
<Heading size="3">{_t("common|android")}</Heading>
<QRCode data={urlAndroid} margin={0} width={172} />
<div className="mx_AppDownloadDialog_info">
{_t("%(qrCode)s or %(appLinks)s", {
{_t("onboarding|qr_or_app_links", {
appLinks: "",
qrCode: "",
})}
@ -102,7 +102,7 @@ export const AppDownloadDialog: FC<Props> = ({ onFinished }) => {
element="a"
href={urlGooglePlay}
target="_blank"
aria-label={_t("Get it on Google Play")}
aria-label={_t("onboarding|download_google_play")}
onClick={() => {}}
>
<GooglePlayBadge />
@ -111,7 +111,7 @@ export const AppDownloadDialog: FC<Props> = ({ onFinished }) => {
element="a"
href={urlFDroid}
target="_blank"
aria-label={_t("Get it on F-Droid")}
aria-label={_t("onboarding|download_f_droid")}
onClick={() => {}}
>
<FDroidBadge />
@ -120,8 +120,8 @@ export const AppDownloadDialog: FC<Props> = ({ onFinished }) => {
</div>
</div>
<div className="mx_AppDownloadDialog_legal">
<p>{_t("App Store® and the Apple logo® are trademarks of Apple Inc.")}</p>
<p>{_t("Google Play and the Google Play logo are trademarks of Google LLC.")}</p>
<p>{_t("onboarding|apple_trademarks")}</p>
<p>{_t("onboarding|google_trademarks")}</p>
</div>
</BaseDialog>
);

View File

@ -74,7 +74,7 @@ export default class DeactivateAccountDialog extends React.Component<IProps, ISt
const dialogAesthetics = {
[SSOAuthEntry.PHASE_PREAUTH]: {
body: _t("Confirm your account deactivation by using Single Sign On to prove your identity."),
continueText: _t("Single Sign On"),
continueText: _t("auth|sso"),
continueKind: "danger",
},
[SSOAuthEntry.PHASE_POSTAUTH]: {

View File

@ -106,7 +106,7 @@ const ExportDialog: React.FC<IProps> = ({ room, onFinished }) => {
const [isExporting, setExporting] = useState(false);
const sizeLimitRef = useRef<Field>(null);
const messageCountRef = useRef<Field>(null);
const [exportProgressText, setExportProgressText] = useState(_t("Processing…"));
const [exportProgressText, setExportProgressText] = useState(_t("export_chat|processing"));
const [displayCancel, setCancelWarning] = useState(false);
const [exportCancelled, setExportCancelled] = useState(false);
const [exportSuccessful, setExportSuccessful] = useState(false);
@ -173,7 +173,7 @@ const ExportDialog: React.FC<IProps> = ({ room, onFinished }) => {
invalid: () => {
const min = 1;
const max = 2000;
return _t("Enter a number between %(min)s and %(max)s", {
return _t("export_chat|enter_number_between_min_max", {
min,
max,
});
@ -188,7 +188,7 @@ const ExportDialog: React.FC<IProps> = ({ room, onFinished }) => {
invalid: () => {
const min = 1;
const max = 2000;
return _t("Size can only be a number between %(min)s MB and %(max)s MB", { min, max });
return _t("export_chat|size_limit_min_max", { min, max });
},
},
],
@ -209,7 +209,7 @@ const ExportDialog: React.FC<IProps> = ({ room, onFinished }) => {
invalid: () => {
const min = 1;
const max = 10 ** 8;
return _t("Enter a number between %(min)s and %(max)s", {
return _t("export_chat|enter_number_between_min_max", {
min,
max,
});
@ -224,7 +224,7 @@ const ExportDialog: React.FC<IProps> = ({ room, onFinished }) => {
invalid: () => {
const min = 1;
const max = 10 ** 8;
return _t("Number of messages can only be a number between %(min)s and %(max)s", { min, max });
return _t("export_chat|num_messages_min_max", { min, max });
},
},
],
@ -270,7 +270,7 @@ const ExportDialog: React.FC<IProps> = ({ room, onFinished }) => {
value={numberOfMessages.toString()}
ref={messageCountRef}
onValidate={onValidateNumberOfMessages}
label={_t("Number of messages")}
label={_t("export_chat|num_messages")}
onChange={(e) => {
setNumberOfMessages(parseInt(e.target.value));
}}
@ -284,8 +284,8 @@ const ExportDialog: React.FC<IProps> = ({ room, onFinished }) => {
// Display successful cancellation message
return (
<InfoDialog
title={_t("Export Cancelled")}
description={_t("The export was cancelled successfully")}
title={_t("export_chat|cancelled")}
description={_t("export_chat|cancelled_detail")}
hasCloseButton={true}
onFinished={onFinished}
/>
@ -294,8 +294,8 @@ const ExportDialog: React.FC<IProps> = ({ room, onFinished }) => {
// Display successful export message
return (
<InfoDialog
title={_t("Export Successful")}
description={_t("Your export was successful. Find it in your Downloads folder.")}
title={_t("export_chat|successful")}
description={_t("export_chat|successful_detail")}
hasCloseButton={true}
onFinished={onFinished}
/>
@ -310,7 +310,7 @@ const ExportDialog: React.FC<IProps> = ({ room, onFinished }) => {
onFinished={onFinished}
fixedWidth={true}
>
<p>{_t("Are you sure you want to stop exporting your data? If you do, you'll need to start over.")}</p>
<p>{_t("export_chat|confirm_stop")}</p>
<DialogButtons
primaryButton={_t("action|stop")}
primaryButtonClass="danger"
@ -325,19 +325,19 @@ const ExportDialog: React.FC<IProps> = ({ room, onFinished }) => {
// Display export settings
return (
<BaseDialog
title={isExporting ? _t("Exporting your data") : _t("Export Chat")}
title={isExporting ? _t("export_chat|exporting_your_data") : _t("export_chat|title")}
className={`mx_ExportDialog ${isExporting && "mx_ExportDialog_Exporting"}`}
contentId="mx_Dialog_content"
hasCancel={true}
onFinished={onFinished}
fixedWidth={true}
>
{!isExporting ? <p>{_t("Select from the options below to export chats from your timeline")}</p> : null}
{!isExporting ? <p>{_t("export_chat|select_option")}</p> : null}
<div className="mx_ExportDialog_options">
{!!setExportFormat && (
<>
<span className="mx_ExportDialog_subheading">{_t("Format")}</span>
<span className="mx_ExportDialog_subheading">{_t("export_chat|format")}</span>
<StyledRadioGroup
name="exportFormat"
@ -350,7 +350,7 @@ const ExportDialog: React.FC<IProps> = ({ room, onFinished }) => {
{!!setExportType && (
<>
<span className="mx_ExportDialog_subheading">{_t("Messages")}</span>
<span className="mx_ExportDialog_subheading">{_t("export_chat|messages")}</span>
<Field
id="export-type"
@ -368,7 +368,7 @@ const ExportDialog: React.FC<IProps> = ({ room, onFinished }) => {
{setSizeLimit && (
<>
<span className="mx_ExportDialog_subheading">{_t("Size Limit")}</span>
<span className="mx_ExportDialog_subheading">{_t("export_chat|size_limit")}</span>
<Field
id="size-limit"
@ -392,7 +392,7 @@ const ExportDialog: React.FC<IProps> = ({ room, onFinished }) => {
checked={includeAttachments}
onChange={(e) => setAttachments((e.target as HTMLInputElement).checked)}
>
{_t("Include Attachments")}
{_t("export_chat|include_attachments")}
</StyledCheckbox>
</>
)}

View File

@ -99,7 +99,7 @@ export default class InteractiveAuthDialog<T> extends React.Component<Interactiv
[SSOAuthEntry.PHASE_PREAUTH]: {
title: _t("Use Single Sign On to continue"),
body: _t("To continue, use Single Sign On to prove your identity."),
continueText: _t("Single Sign On"),
continueText: _t("auth|sso"),
continueKind: "primary",
},
[SSOAuthEntry.PHASE_POSTAUTH]: {

View File

@ -216,7 +216,7 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
((this.state.nature == Nature.Other || this.state.nature == NonStandardValue.Admin) && !reason)
) {
this.setState({
err: _t("Please fill why you're reporting."),
err: _t("report_content|missing_reason"),
});
return;
}
@ -225,7 +225,7 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
// We need a `reason`.
if (!reason) {
this.setState({
err: _t("Please fill why you're reporting."),
err: _t("report_content|missing_reason"),
});
return;
}
@ -295,8 +295,8 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
const ignoreUserCheckbox = (
<LabelledCheckbox
value={this.state.ignoreUserToo}
label={_t("Ignore user")}
byline={_t("Check if you want to hide all current and future messages from this user.")}
label={_t("report_content|ignore_user")}
byline={_t("report_content|hide_messages_from_user")}
onChange={this.onIgnoreUserTooChanged}
disabled={this.state.busy}
/>
@ -317,7 +317,7 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
let subtitle: string;
switch (this.state.nature) {
case Nature.Disagreement:
subtitle = _t("What this user is writing is wrong.\nThis will be reported to the room moderators.");
subtitle = _t("report_content|nature_disagreement");
break;
case Nature.Toxic:
subtitle = _t(
@ -353,7 +353,7 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
);
break;
default:
subtitle = _t("Please pick a nature and describe what makes this message abusive.");
subtitle = _t("report_content|nature");
break;
}
@ -371,7 +371,7 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
checked={this.state.nature == Nature.Disagreement}
onChange={this.onNatureChosen}
>
{_t("Disagree")}
{_t("report_content|disagree")}
</StyledRadioButton>
<StyledRadioButton
name="nature"
@ -379,7 +379,7 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
checked={this.state.nature == Nature.Toxic}
onChange={this.onNatureChosen}
>
{_t("Toxic Behaviour")}
{_t("report_content|toxic_behaviour")}
</StyledRadioButton>
<StyledRadioButton
name="nature"
@ -387,7 +387,7 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
checked={this.state.nature == Nature.Illegal}
onChange={this.onNatureChosen}
>
{_t("Illegal Content")}
{_t("report_content|illegal_content")}
</StyledRadioButton>
<StyledRadioButton
name="nature"
@ -395,7 +395,7 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
checked={this.state.nature == Nature.Spam}
onChange={this.onNatureChosen}
>
{_t("Spam or propaganda")}
{_t("report_content|spam_or_propaganda")}
</StyledRadioButton>
<StyledRadioButton
name="nature"
@ -403,7 +403,7 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
checked={this.state.nature == NonStandardValue.Admin}
onChange={this.onNatureChosen}
>
{_t("Report the entire room")}
{_t("report_content|report_entire_room")}
</StyledRadioButton>
<StyledRadioButton
name="nature"
@ -443,7 +443,7 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
<BaseDialog
className="mx_ReportEventDialog"
onFinished={this.props.onFinished}
title={_t("Report Content to Your Homeserver Administrator")}
title={_t("report_content|report_content_to_homeserver")}
contentId="mx_ReportEventDialog"
>
<div className="mx_ReportEventDialog" id="mx_ReportEventDialog">

View File

@ -67,7 +67,7 @@ export default class SessionRestoreErrorDialog extends React.Component<IProps> {
if (SdkConfig.get().bug_report_endpoint_url) {
dialogButtons = (
<DialogButtons
primaryButton={_t("Send Logs")}
primaryButton={_t("bug_reporting|send_logs")}
onPrimaryButtonClick={this.sendBugReport}
focus={true}
hasCancel={false}

View File

@ -92,14 +92,14 @@ export default class TermsDialog extends React.PureComponent<ITermsDialogProps,
case SERVICE_TYPES.IS:
return (
<div>
{_t("Identity server")}
{_t("common|identity_server")}
<br />({host})
</div>
);
case SERVICE_TYPES.IM:
return (
<div>
{_t("Integration manager")}
{_t("common|integration_manager")}
<br />({host})
</div>
);

View File

@ -51,7 +51,7 @@ export default class UploadFailureDialog extends React.Component<IProps> {
message = _t(
"This file is <b>too large</b> to upload. The file size limit is %(limit)s but this file is %(sizeOfThisFile)s.",
{
limit: fileSize(this.props.contentMessages.getUploadLimit()),
limit: fileSize(this.props.contentMessages.getUploadLimit()!),
sizeOfThisFile: fileSize(this.props.badFiles[0].size),
},
{
@ -70,7 +70,7 @@ export default class UploadFailureDialog extends React.Component<IProps> {
message = _t(
"These files are <b>too large</b> to upload. The file size limit is %(limit)s.",
{
limit: fileSize(this.props.contentMessages.getUploadLimit()),
limit: fileSize(this.props.contentMessages.getUploadLimit()!),
},
{
b: (sub) => <b>{sub}</b>,
@ -88,7 +88,7 @@ export default class UploadFailureDialog extends React.Component<IProps> {
message = _t(
"Some files are <b>too large</b> to be uploaded. The file size limit is %(limit)s.",
{
limit: fileSize(this.props.contentMessages.getUploadLimit()),
limit: fileSize(this.props.contentMessages.getUploadLimit()!),
},
{
b: (sub) => <b>{sub}</b>,

View File

@ -189,7 +189,7 @@ export default class UserSettingsDialog extends React.Component<IProps, IState>
tabs.push(
new Tab(
UserTab.Help,
_td("Help & About"),
_td("setting|help_about|title"),
"mx_UserSettingsDialog_helpIcon",
<HelpUserSettingsTab closeSettingsFn={() => this.props.onFinished()} />,
"UserSettingsHelpAbout",

View File

@ -114,7 +114,7 @@ export default class CreateCrossSigningDialog extends React.PureComponent<IProps
[SSOAuthEntry.PHASE_PREAUTH]: {
title: _t("Use Single Sign On to continue"),
body: _t("To continue, use Single Sign On to prove your identity."),
continueText: _t("Single Sign On"),
continueText: _t("auth|sso"),
continueKind: "primary",
},
[SSOAuthEntry.PHASE_POSTAUTH]: {

View File

@ -106,7 +106,7 @@ export function RoomResultContextMenus({ room }: Props): JSX.Element {
const target = ev.target as HTMLElement;
setNotificationMenuPosition(target.getBoundingClientRect());
}}
title={_t("Notification options")}
title={_t("room_list|notification_options")}
isExpanded={notificationMenuPosition !== null}
/>
)}

View File

@ -263,15 +263,15 @@ const findVisibleRoomMembers = (visibleRooms: Room[], cli: MatrixClient, filterD
const roomAriaUnreadLabel = (room: Room, notification: RoomNotificationState): string | undefined => {
if (notification.hasMentions) {
return _t("%(count)s unread messages including mentions.", {
return _t("a11y|n_unread_messages_mentions", {
count: notification.count,
});
} else if (notification.hasUnreadCount) {
return _t("%(count)s unread messages.", {
return _t("a11y|n_unread_messages", {
count: notification.count,
});
} else if (notification.isUnread) {
return _t("Unread messages.");
return _t("a11y|unread_messages");
} else {
return undefined;
}
@ -563,7 +563,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
};
let otherSearchesSection: JSX.Element | undefined;
if (trimmedQuery || filter !== Filter.PublicRooms) {
if (trimmedQuery || (filter !== Filter.PublicRooms && filter !== Filter.PublicSpaces)) {
otherSearchesSection = (
<div
className="mx_SpotlightDialog_section mx_SpotlightDialog_otherSearches"

View File

@ -85,7 +85,7 @@ export default class ErrorBoundary extends React.PureComponent<Props, IState> {
<React.Fragment>
<p>
{_t(
"Please <newIssueLink>create a new issue</newIssueLink> on GitHub so that we can investigate this bug.",
"bug_reporting|create_new_issue",
{},
{
newIssueLink: (sub) => {
@ -115,7 +115,7 @@ export default class ErrorBoundary extends React.PureComponent<Props, IState> {
if (MatrixClientPeg.get()) {
clearCacheButton = (
<AccessibleButton onClick={this.onClearCacheAndReload} kind="danger">
{_t("Clear cache and reload")}
{_t("setting|help_about|clear_cache_reload")}
</AccessibleButton>
);
}

View File

@ -133,7 +133,7 @@ export default class EventListSummary extends React.Component<
const desc = formatCommaSeparatedList(descs);
return _t("%(nameList)s %(transitionList)s", { nameList, transitionList: desc });
return _t("timeline|summary|format", { nameList, transitionList: desc });
});
if (!summaries) {
@ -250,101 +250,101 @@ export default class EventListSummary extends React.Component<
case TransitionType.Joined:
res =
userCount > 1
? _t("%(severalUsers)sjoined %(count)s times", { severalUsers: "", count })
: _t("%(oneUser)sjoined %(count)s times", { oneUser: "", count });
? _t("timeline|summary|joined_multiple", { severalUsers: "", count })
: _t("timeline|summary|joined", { oneUser: "", count });
break;
case TransitionType.Left:
res =
userCount > 1
? _t("%(severalUsers)sleft %(count)s times", { severalUsers: "", count })
: _t("%(oneUser)sleft %(count)s times", { oneUser: "", count });
? _t("timeline|summary|left_multiple", { severalUsers: "", count })
: _t("timeline|summary|left", { oneUser: "", count });
break;
case TransitionType.JoinedAndLeft:
res =
userCount > 1
? _t("%(severalUsers)sjoined and left %(count)s times", { severalUsers: "", count })
: _t("%(oneUser)sjoined and left %(count)s times", { oneUser: "", count });
? _t("timeline|summary|joined_and_left_multiple", { severalUsers: "", count })
: _t("timeline|summary|joined_and_left", { oneUser: "", count });
break;
case TransitionType.LeftAndJoined:
res =
userCount > 1
? _t("%(severalUsers)sleft and rejoined %(count)s times", { severalUsers: "", count })
: _t("%(oneUser)sleft and rejoined %(count)s times", { oneUser: "", count });
? _t("timeline|summary|rejoined_multiple", { severalUsers: "", count })
: _t("timeline|summary|rejoined", { oneUser: "", count });
break;
case TransitionType.InviteReject:
res =
userCount > 1
? _t("%(severalUsers)srejected their invitations %(count)s times", {
? _t("timeline|summary|rejected_invite_multiple", {
severalUsers: "",
count,
})
: _t("%(oneUser)srejected their invitation %(count)s times", { oneUser: "", count });
: _t("timeline|summary|rejected_invite", { oneUser: "", count });
break;
case TransitionType.InviteWithdrawal:
res =
userCount > 1
? _t("%(severalUsers)shad their invitations withdrawn %(count)s times", {
? _t("timeline|summary|invite_withdrawn_multiple", {
severalUsers: "",
count,
})
: _t("%(oneUser)shad their invitation withdrawn %(count)s times", { oneUser: "", count });
: _t("timeline|summary|invite_withdrawn", { oneUser: "", count });
break;
case TransitionType.Invited:
res =
userCount > 1
? _t("were invited %(count)s times", { count })
: _t("was invited %(count)s times", { count });
? _t("timeline|summary|invited_multiple", { count })
: _t("timeline|summary|invited", { count });
break;
case TransitionType.Banned:
res =
userCount > 1
? _t("were banned %(count)s times", { count })
: _t("was banned %(count)s times", { count });
? _t("timeline|summary|banned_multiple", { count })
: _t("timeline|summary|banned", { count });
break;
case TransitionType.Unbanned:
res =
userCount > 1
? _t("were unbanned %(count)s times", { count })
: _t("was unbanned %(count)s times", { count });
? _t("timeline|summary|unbanned_multiple", { count })
: _t("timeline|summary|unbanned", { count });
break;
case TransitionType.Kicked:
res =
userCount > 1
? _t("were removed %(count)s times", { count })
: _t("was removed %(count)s times", { count });
? _t("timeline|summary|kicked_multiple", { count })
: _t("timeline|summary|kicked", { count });
break;
case TransitionType.ChangedName:
res =
userCount > 1
? _t("%(severalUsers)schanged their name %(count)s times", { severalUsers: "", count })
: _t("%(oneUser)schanged their name %(count)s times", { oneUser: "", count });
? _t("timeline|summary|changed_name_multiple", { severalUsers: "", count })
: _t("timeline|summary|changed_name", { oneUser: "", count });
break;
case TransitionType.ChangedAvatar:
res =
userCount > 1
? _t("%(severalUsers)schanged their profile picture %(count)s times", {
? _t("timeline|summary|changed_avatar_multiple", {
severalUsers: "",
count,
})
: _t("%(oneUser)schanged their profile picture %(count)s times", { oneUser: "", count });
: _t("timeline|summary|changed_avatar", { oneUser: "", count });
break;
case TransitionType.NoChange:
res =
userCount > 1
? _t("%(severalUsers)smade no changes %(count)s times", { severalUsers: "", count })
: _t("%(oneUser)smade no changes %(count)s times", { oneUser: "", count });
? _t("timeline|summary|no_change_multiple", { severalUsers: "", count })
: _t("timeline|summary|no_change", { oneUser: "", count });
break;
case TransitionType.ServerAcl:
res =
userCount > 1
? _t("%(severalUsers)schanged the server ACLs %(count)s times", { severalUsers: "", count })
: _t("%(oneUser)schanged the server ACLs %(count)s times", { oneUser: "", count });
? _t("timeline|summary|server_acls_multiple", { severalUsers: "", count })
: _t("timeline|summary|server_acls", { oneUser: "", count });
break;
case TransitionType.ChangedPins:
res =
userCount > 1
? _t(
"%(severalUsers)schanged the <a>pinned messages</a> for the room %(count)s times",
"timeline|summary|pinned_events_multiple",
{ severalUsers: "", count },
{
a: (sub) => (
@ -355,7 +355,7 @@ export default class EventListSummary extends React.Component<
},
)
: _t(
"%(oneUser)schanged the <a>pinned messages</a> for the room %(count)s times",
"timeline|summary|pinned_events",
{ oneUser: "", count },
{
a: (sub) => (
@ -369,14 +369,14 @@ export default class EventListSummary extends React.Component<
case TransitionType.MessageRemoved:
res =
userCount > 1
? _t("%(severalUsers)sremoved a message %(count)s times", { severalUsers: "", count })
: _t("%(oneUser)sremoved a message %(count)s times", { oneUser: "", count });
? _t("timeline|summary|redacted_multiple", { severalUsers: "", count })
: _t("timeline|summary|redacted", { oneUser: "", count });
break;
case TransitionType.HiddenEvent:
res =
userCount > 1
? _t("%(severalUsers)ssent %(count)s hidden messages", { severalUsers: "", count })
: _t("%(oneUser)ssent %(count)s hidden messages", { oneUser: "", count });
? _t("timeline|summary|hidden_event_multiple", { severalUsers: "", count })
: _t("timeline|summary|hidden_event", { oneUser: "", count });
break;
}

View File

@ -50,7 +50,7 @@ const QRCode: React.FC<IProps> = ({ data, className, ...options }) => {
return (
<div className={classNames("mx_QRCode", className)}>
{dataUri ? <img src={dataUri} className="mx_VerificationQRCode" alt={_t("QR Code")} /> : <Spinner />}
{dataUri ? <img src={dataUri} className="mx_VerificationQRCode" alt={_t("common|qr_code")} /> : <Spinner />}
</div>
);
};

View File

@ -92,11 +92,11 @@ const SSOButton: React.FC<ISSOButtonProps> = ({
}) => {
let label: string;
if (idp) {
label = _t("Continue with %(provider)s", { provider: idp.name });
label = _t("auth|continue_with_idp", { provider: idp.name });
} else if (DELEGATED_OIDC_COMPATIBILITY.findIn<boolean>(flow)) {
label = _t("action|continue");
} else {
label = _t("Sign in with single sign-on");
label = _t("auth|sign_in_with_sso");
}
const onClick = (): void => {

View File

@ -87,63 +87,63 @@ class EmojiPicker extends React.Component<IProps, IState> {
this.categories = [
{
id: "recent",
name: _t("Frequently Used"),
name: _t("emoji|category_frequently_used"),
enabled: this.recentlyUsed.length > 0,
visible: this.recentlyUsed.length > 0,
ref: React.createRef(),
},
{
id: "people",
name: _t("Smileys & People"),
name: _t("emoji|category_smileys_people"),
enabled: true,
visible: true,
ref: React.createRef(),
},
{
id: "nature",
name: _t("Animals & Nature"),
name: _t("emoji|category_animals_nature"),
enabled: true,
visible: false,
ref: React.createRef(),
},
{
id: "foods",
name: _t("Food & Drink"),
name: _t("emoji|category_food_drink"),
enabled: true,
visible: false,
ref: React.createRef(),
},
{
id: "activity",
name: _t("Activities"),
name: _t("emoji|category_activities"),
enabled: true,
visible: false,
ref: React.createRef(),
},
{
id: "places",
name: _t("Travel & Places"),
name: _t("emoji|category_travel_places"),
enabled: true,
visible: false,
ref: React.createRef(),
},
{
id: "objects",
name: _t("Objects"),
name: _t("emoji|category_objects"),
enabled: true,
visible: false,
ref: React.createRef(),
},
{
id: "symbols",
name: _t("Symbols"),
name: _t("emoji|category_symbols"),
enabled: true,
visible: false,
ref: React.createRef(),
},
{
id: "flags",
name: _t("Flags"),
name: _t("emoji|category_flags"),
enabled: true,
visible: false,
ref: React.createRef(),

View File

@ -95,7 +95,7 @@ class Header extends React.PureComponent<IProps> {
<nav
className="mx_EmojiPicker_header"
role="tablist"
aria-label={_t("Categories")}
aria-label={_t("emoji|categories")}
onKeyDown={this.onKeyDown}
>
{this.props.categories.map((category) => {

View File

@ -64,7 +64,7 @@ class QuickReactions extends React.Component<IProps, IState> {
<section className="mx_EmojiPicker_footer mx_EmojiPicker_quick mx_EmojiPicker_category">
<h2 className="mx_EmojiPicker_quick_header mx_EmojiPicker_category_label">
{!this.state.hover ? (
_t("Quick Reactions")
_t("emoji|quick_reactions")
) : (
<React.Fragment>
<span className="mx_EmojiPicker_name">{this.state.hover.label}</span>
@ -72,7 +72,7 @@ class QuickReactions extends React.Component<IProps, IState> {
</React.Fragment>
)}
</h2>
<Toolbar className="mx_EmojiPicker_list" aria-label={_t("Quick Reactions")}>
<Toolbar className="mx_EmojiPicker_list" aria-label={_t("emoji|quick_reactions")}>
{QUICK_REACTIONS.map((emoji) => (
<Emoji
key={emoji.hexcode}

View File

@ -117,7 +117,7 @@ const EncryptionInfo: React.FC<IProps> = ({
"For extra security, verify this user by checking a one-time code on both of your devices.",
)}
</p>
<p>{_t("To be secure, do this in person or use a trusted way to communicate.")}</p>
<p>{_t("encryption|verification|in_person")}</p>
{content}
</div>
</div>

View File

@ -90,14 +90,7 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
const brand = SdkConfig.get().brand;
const noCommonMethodError: JSX.Element | null =
!showSAS && !showQR ? (
<p>
{_t(
"The device 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.",
{ brand },
)}
</p>
) : null;
!showSAS && !showQR ? <p>{_t("encryption|verification|no_support_qr_emoji", { brand })}</p> : null;
if (this.props.layout === "dialog") {
// HACK: This is a terrible idea.
@ -106,7 +99,7 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
if (showQR) {
qrBlockDialog = (
<div className="mx_VerificationPanel_QRPhase_startOption">
<p>{_t("Scan this unique code")}</p>
<p>{_t("encryption|verification|qr_prompt")}</p>
<VerificationQRCode qrCodeBytes={this.state.qrCodeBytes} />
</div>
);
@ -114,9 +107,9 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
if (showSAS) {
sasBlockDialog = (
<div className="mx_VerificationPanel_QRPhase_startOption">
<p>{_t("Compare unique emoji")}</p>
<p>{_t("encryption|verification|sas_prompt")}</p>
<span className="mx_VerificationPanel_QRPhase_helpText">
{_t("Compare a unique set of emoji if you don't have a camera on either device")}
{_t("encryption|verification|sas_description")}
</span>
<AccessibleButton
disabled={this.state.emojiButtonClicked}
@ -131,7 +124,7 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
const or =
qrBlockDialog && sasBlockDialog ? (
<div className="mx_VerificationPanel_QRPhase_betweenText">
{_t("%(qrCode)s or %(emojiCompare)s", {
{_t("encryption|verification|qr_or_sas", {
emojiCompare: "",
qrCode: "",
})}
@ -139,7 +132,7 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
) : null;
return (
<div>
{_t("Verify this device by completing one of the following:")}
{_t("encryption|verification|qr_or_sas_header")}
<div className="mx_VerificationPanel_QRPhase_startOptions">
{qrBlockDialog}
{or}

View File

@ -457,7 +457,7 @@ export default class AliasSettings extends React.Component<IProps, IState> {
>
<details onToggle={this.onLocalAliasesToggled} open={this.state.detailsOpen}>
<summary className="mx_AliasSettings_localAddresses">
{this.state.detailsOpen ? _t("Show less") : _t("Show more")}
{this.state.detailsOpen ? _t("room_list|show_less") : _t("Show more")}
</summary>
{localAliasesList}
</details>

View File

@ -112,7 +112,7 @@ export const RoomKnocksBar: VFC<{ room: Room }> = ({ room }) => {
</>
);
names = `${knockMembers[0].name} (${knockMembers[0].userId})`;
link = (
link = knockMembers[0].events.member?.getContent().reason && (
<AccessibleButton
className="mx_RoomKnocksBar_link"
element="a"

View File

@ -157,11 +157,7 @@ const DmAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex, dispatcher = default
showSpaceInvite(activeSpace);
}}
disabled={!canInvite}
tooltip={
canInvite
? undefined
: _t("You do not have permissions to invite people to this space")
}
tooltip={canInvite ? undefined : _t("spaces|error_no_permission_invite")}
/>
)}
</IconizedContextMenuOptionList>
@ -253,11 +249,7 @@ const UntaggedAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex }) => {
PosthogTrackers.trackInteraction("WebRoomListRoomsSublistPlusMenuCreateRoomItem", e);
}}
disabled={!canAddRooms}
tooltip={
canAddRooms
? undefined
: _t("You do not have permissions to create new rooms in this space")
}
tooltip={canAddRooms ? undefined : _t("spaces|error_no_permission_create_room")}
/>
{videoRoomsEnabled && (
<IconizedContextMenuOption
@ -273,11 +265,7 @@ const UntaggedAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex }) => {
);
}}
disabled={!canAddRooms}
tooltip={
canAddRooms
? undefined
: _t("You do not have permissions to create new rooms in this space")
}
tooltip={canAddRooms ? undefined : _t("spaces|error_no_permission_create_room")}
>
<BetaPill />
</IconizedContextMenuOption>
@ -292,9 +280,7 @@ const UntaggedAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex }) => {
showAddExistingRooms(activeSpace);
}}
disabled={!canAddRooms}
tooltip={
canAddRooms ? undefined : _t("You do not have permissions to add rooms to this space")
}
tooltip={canAddRooms ? undefined : _t("spaces|error_no_permission_add_room")}
/>
</>
) : null}

View File

@ -267,9 +267,7 @@ const RoomListHeader: React.FC<IProps> = ({ onVisibilityChange }) => {
closePlusMenu();
}}
disabled={!canAddSubRooms}
tooltip={
!canAddSubRooms ? _t("You do not have permissions to add rooms to this space") : undefined
}
tooltip={!canAddSubRooms ? _t("spaces|error_no_permission_add_room") : undefined}
/>
{canCreateSpaces && (
<IconizedContextMenuOption
@ -282,11 +280,7 @@ const RoomListHeader: React.FC<IProps> = ({ onVisibilityChange }) => {
closePlusMenu();
}}
disabled={!canAddSubSpaces}
tooltip={
!canAddSubSpaces
? _t("You do not have permissions to add spaces to this space")
: undefined
}
tooltip={!canAddSubSpaces ? _t("spaces|error_no_permission_add_space") : undefined}
>
<BetaPill />
</IconizedContextMenuOption>

View File

@ -62,6 +62,7 @@ enum MessageCase {
OtherError = "OtherError",
PromptAskToJoin = "PromptAskToJoin",
Knocked = "Knocked",
RequestDenied = "requestDenied",
}
interface IProps {
@ -188,7 +189,11 @@ export default class RoomPreviewBar extends React.Component<IProps, IState> {
const myMember = this.getMyMember();
if (myMember) {
const previousMembership = myMember.events.member?.getPrevContent().membership;
if (myMember.isKicked()) {
if (previousMembership === "knock") {
return MessageCase.RequestDenied;
}
return MessageCase.Kicked;
} else if (myMember.membership === "ban") {
return MessageCase.Banned;
@ -397,6 +402,21 @@ export default class RoomPreviewBar extends React.Component<IProps, IState> {
}
break;
}
case MessageCase.RequestDenied: {
title = _t("You have been denied access");
subTitle = _t(
"As you have been denied access, you cannot rejoin unless you are invited by the admin or moderator of the group.",
);
if (isSpace) {
primaryActionLabel = _t("Forget this space");
} else {
primaryActionLabel = _t("Forget this room");
}
primaryActionHandler = this.props.onForgetClick;
break;
}
case MessageCase.Banned: {
const { memberName, reason } = this.getKickOrBanInfo();
if (roomName) {

View File

@ -584,14 +584,14 @@ export default class RoomSublist extends React.Component<IProps, IState> {
onChange={this.onUnreadFirstChanged}
checked={isUnreadFirst}
>
{_t("Show rooms with unread messages first")}
{_t("room_list|sort_unread_first")}
</StyledMenuItemCheckbox>
<StyledMenuItemCheckbox
onClose={this.onCloseMenu}
onChange={this.onMessagePreviewChanged}
checked={this.layout.showPreviews}
>
{_t("Show previews of messages")}
{_t("room_list|show_previews")}
</StyledMenuItemCheckbox>
</fieldset>
</React.Fragment>
@ -607,14 +607,14 @@ export default class RoomSublist extends React.Component<IProps, IState> {
>
<div className="mx_RoomSublist_contextMenu">
<fieldset>
<legend className="mx_RoomSublist_contextMenu_title">{_t("Sort by")}</legend>
<legend className="mx_RoomSublist_contextMenu_title">{_t("room_list|sort_by")}</legend>
<StyledMenuItemRadio
onClose={this.onCloseMenu}
onChange={() => this.onTagSortChanged(SortAlgorithm.Recent)}
checked={!isAlphabetical}
name={`mx_${this.props.tagId}_sortBy`}
>
{_t("Activity")}
{_t("room_list|sort_by_activity")}
</StyledMenuItemRadio>
<StyledMenuItemRadio
onClose={this.onCloseMenu}
@ -622,7 +622,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
checked={isAlphabetical}
name={`mx_${this.props.tagId}_sortBy`}
>
{_t("A-Z")}
{_t("room_list|sort_by_alphabet")}
</StyledMenuItemRadio>
</fieldset>
{otherSections}
@ -636,7 +636,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
<ContextMenuTooltipButton
className="mx_RoomSublist_menuButton"
onClick={this.onOpenMenuClick}
title={_t("List options")}
title={_t("room_list|sublist_options")}
isExpanded={!!this.state.contextMenuPosition}
/>
{contextMenu}
@ -788,7 +788,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
if (this.slidingSyncMode) {
numMissing = RoomListStore.instance.getCount(this.props.tagId) - amountFullyShown;
}
const label = _t("Show %(count)s more", { count: numMissing });
const label = _t("room_list|show_n_more", { count: numMissing });
let showMoreText: ReactNode = <span className="mx_RoomSublist_showNButtonText">{label}</span>;
if (this.props.isMinimized) showMoreText = null;
showNButton = (
@ -806,7 +806,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
);
} else if (this.numTiles > this.layout.defaultVisibleTiles) {
// we have all tiles visible - add a button to show less
const label = _t("Show less");
const label = _t("room_list|show_less");
let showLessText: ReactNode = <span className="mx_RoomSublist_showNButtonText">{label}</span>;
if (this.props.isMinimized) showLessText = null;
showNButton = (

View File

@ -313,7 +313,7 @@ export class RoomTile extends React.PureComponent<ClassProps, State> {
<ContextMenuTooltipButton
className={classes}
onClick={this.onNotificationsMenuOpenClick}
title={_t("Notification options")}
title={_t("room_list|notification_options")}
isExpanded={!!this.state.notificationsMenuPosition}
tabIndex={isActive ? 0 : -1}
/>
@ -433,17 +433,17 @@ export class RoomTile extends React.PureComponent<ClassProps, State> {
} else if (this.notificationState.hasMentions) {
ariaLabel +=
" " +
_t("%(count)s unread messages including mentions.", {
_t("a11y|n_unread_messages_mentions", {
count: this.notificationState.count,
});
} else if (this.notificationState.hasUnreadCount) {
ariaLabel +=
" " +
_t("%(count)s unread messages.", {
_t("a11y|n_unread_messages", {
count: this.notificationState.count,
});
} else if (this.notificationState.isUnread) {
ariaLabel += " " + _t("Unread messages.");
ariaLabel += " " + _t("a11y|unread_messages");
}
let ariaDescribedBy: string;

View File

@ -106,7 +106,11 @@ export default class FontScalingPanel extends React.Component<IProps, IState> {
public render(): React.ReactNode {
return (
<SettingsSubsection heading={_t("Font size")} stretchContent data-testid="mx_FontScalingPanel">
<SettingsSubsection
heading={_t("settings|appearance|font_size")}
stretchContent
data-testid="mx_FontScalingPanel"
>
<EventTilePreview
className="mx_FontScalingPanel_preview"
message={this.MESSAGE_PREVIEW_TEXT}
@ -125,7 +129,7 @@ export default class FontScalingPanel extends React.Component<IProps, IState> {
onChange={this.onFontSizeChanged}
displayFunc={(_) => ""}
disabled={this.state.useCustomFontSize}
label={_t("Font size")}
label={_t("settings|appearance|font_size")}
/>
<div className="mx_FontScalingPanel_fontSlider_largeText">Aa</div>
</div>
@ -148,7 +152,7 @@ export default class FontScalingPanel extends React.Component<IProps, IState> {
<Field
type="number"
label={_t("Font size")}
label={_t("settings|appearance|font_size")}
autoComplete="off"
placeholder={this.state.fontSize.toString()}
value={this.state.fontSize.toString()}

View File

@ -50,7 +50,7 @@ export default class ImageSizePanel extends React.Component<IProps, IState> {
public render(): React.ReactNode {
return (
<SettingsSubsection heading={_t("Image size in the timeline")}>
<SettingsSubsection heading={_t("settings|appearance|timeline_image_size")}>
<div className="mx_ImageSizePanel_radios">
<label>
<div className="mx_ImageSizePanel_size mx_ImageSizePanel_sizeDefault" />

View File

@ -104,6 +104,6 @@ export default class IntegrationManager extends React.Component<IProps, IState>
);
}
return <iframe title={_t("Integration manager")} src={this.props.url} onError={this.onError} />;
return <iframe title={_t("common|integration_manager")} src={this.props.url} onError={this.onError} />;
}
}

View File

@ -14,8 +14,15 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { ReactNode } from "react";
import { IJoinRuleEventContent, JoinRule, RestrictedAllowType, Room, EventType } from "matrix-js-sdk/src/matrix";
import React, { ReactNode, useEffect, useState } from "react";
import {
IJoinRuleEventContent,
JoinRule,
RestrictedAllowType,
Room,
EventType,
Visibility,
} from "matrix-js-sdk/src/matrix";
import StyledRadioGroup, { IDefinition } from "../elements/StyledRadioGroup";
import { _t } from "../../../languageHandler";
@ -34,6 +41,7 @@ import { Action } from "../../../dispatcher/actions";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { doesRoomVersionSupport, PreferredRoomVersions } from "../../../utils/PreferredRoomVersions";
import SettingsStore from "../../../settings/SettingsStore";
import LabelledCheckbox from "../elements/LabelledCheckbox";
export interface JoinRuleSettingsProps {
room: Room;
@ -76,6 +84,22 @@ const JoinRuleSettings: React.FC<JoinRuleSettingsProps> = ({
? content?.allow?.filter((o) => o.type === RestrictedAllowType.RoomMembership).map((o) => o.room_id)
: undefined;
const [isPublicKnockRoom, setIsPublicKnockRoom] = useState(false);
useEffect(() => {
if (joinRule === JoinRule.Knock) {
cli.getRoomDirectoryVisibility(room.roomId)
.then(({ visibility }) => setIsPublicKnockRoom(visibility === Visibility.Public))
.catch(onError);
}
}, [cli, joinRule, onError, room.roomId]);
const onIsPublicKnockRoomChange = (checked: boolean): void => {
cli.setRoomDirectoryVisibility(room.roomId, checked ? Visibility.Public : Visibility.Private)
.then(() => setIsPublicKnockRoom(checked))
.catch(onError);
};
const editRestrictedRoomIds = async (): Promise<string[] | undefined> => {
let selected = restrictedAllowRoomIds;
if (!selected?.length && SpaceStore.instance.activeSpaceRoom) {
@ -297,7 +321,22 @@ const JoinRuleSettings: React.FC<JoinRuleSettingsProps> = ({
{preferredKnockVersion && upgradeRequiredPill}
</>
),
description: _t("People cannot join unless access is granted."),
description: (
<>
{_t("People cannot join unless access is granted.")}
<LabelledCheckbox
className="mx_JoinRuleSettings_labelledCheckbox"
disabled={joinRule !== JoinRule.Knock}
label={
room.isSpaceRoom()
? _t("Make this space visible in the public room directory.")
: _t("Make this room visible in the public room directory.")
}
onChange={onIsPublicKnockRoomChange}
value={isPublicKnockRoom}
/>
</>
),
});
}

View File

@ -85,7 +85,7 @@ export default class LayoutSwitcher extends React.Component<IProps, IState> {
checked={this.state.layout === Layout.IRC}
onChange={this.onLayoutChange}
>
{_t("IRC (Experimental)")}
{_t("settings|appearance|layout_irc")}
</StyledRadioButton>
</label>
<label className={groupClasses}>
@ -121,7 +121,7 @@ export default class LayoutSwitcher extends React.Component<IProps, IState> {
checked={this.state.layout == Layout.Bubble}
onChange={this.onLayoutChange}
>
{_t("Message bubbles")}
{_t("settings|appearance|layout_bubbles")}
</StyledRadioButton>
</label>
</div>

View File

@ -381,7 +381,7 @@ export default class Notifications extends React.PureComponent<IProps, IState> {
if (category === KEYWORD_RULE_CATEGORY) {
preparedNewState.vectorPushRules[category]!.push({
ruleId: KEYWORD_RULE_ID,
description: _t("Messages containing keywords"),
description: _t("settings|notifications|messages_containing_keywords"),
vectorState: preparedNewState.vectorKeywordRuleInfo.vectorState,
});
}
@ -400,8 +400,8 @@ export default class Notifications extends React.PureComponent<IProps, IState> {
private showSaveError(): void {
Modal.createDialog(ErrorDialog, {
title: _t("Error saving notification preferences"),
description: _t("An error occurred whilst saving your notification preferences."),
title: _t("settings|notifications|error_saving"),
description: _t("settings|notifications|error_saving_detail"),
});
}
@ -661,8 +661,8 @@ export default class Notifications extends React.PureComponent<IProps, IState> {
<LabelledToggleSwitch
data-testid="notif-master-switch"
value={!this.isInhibited}
label={_t("Enable notifications for this account")}
caption={_t("Turn off to disable notifications on all your devices and sessions")}
label={_t("settings|notifications|enable_notifications_account")}
caption={_t("settings|notifications|enable_notifications_account_detail")}
onChange={this.onMasterRuleChanged}
disabled={this.state.phase === Phase.Persisting}
/>
@ -680,7 +680,7 @@ export default class Notifications extends React.PureComponent<IProps, IState> {
data-testid="notif-email-switch"
key={e.address}
value={!!this.state.pushers?.some((p) => p.kind === "email" && p.pushkey === e.address)}
label={_t("Enable email notifications for %(email)s", { email: e.address })}
label={_t("settings|notifications|enable_email_notifications", { email: e.address })}
onChange={this.onEmailNotificationsChanged.bind(this, e.address)}
disabled={this.state.phase === Phase.Persisting}
/>
@ -693,7 +693,7 @@ export default class Notifications extends React.PureComponent<IProps, IState> {
<LabelledToggleSwitch
data-testid="notif-device-switch"
value={this.state.deviceNotificationsEnabled}
label={_t("Enable notifications for this device")}
label={_t("settings|notifications|enable_notifications_device")}
onChange={(checked) => this.updateDeviceNotifications(checked)}
disabled={this.state.phase === Phase.Persisting}
/>
@ -704,21 +704,21 @@ export default class Notifications extends React.PureComponent<IProps, IState> {
data-testid="notif-setting-notificationsEnabled"
value={this.state.desktopNotifications}
onChange={this.onDesktopNotificationsChanged}
label={_t("Enable desktop notifications for this session")}
label={_t("settings|notifications|enable_desktop_notifications_session")}
disabled={this.state.phase === Phase.Persisting}
/>
<LabelledToggleSwitch
data-testid="notif-setting-notificationBodyEnabled"
value={this.state.desktopShowBody}
onChange={this.onDesktopShowBodyChanged}
label={_t("Show message in desktop notification")}
label={_t("settings|notifications|show_message_desktop_notification")}
disabled={this.state.phase === Phase.Persisting}
/>
<LabelledToggleSwitch
data-testid="notif-setting-audioNotificationsEnabled"
value={this.state.audioNotifications}
onChange={this.onAudioNotificationsChanged}
label={_t("Enable audible notifications for this session")}
label={_t("settings|notifications|enable_audible_notifications_session")}
disabled={this.state.phase === Phase.Persisting}
/>
</>

View File

@ -396,7 +396,7 @@ export default class SetIdServer extends React.Component<IProps, IState> {
);
}
} else {
sectionTitle = _t("Identity server");
sectionTitle = _t("common|identity_server");
bodyText = _t(
"You are not currently using an identity server. To discover and be discoverable by existing contacts you know, add one below.",
);

View File

@ -141,18 +141,25 @@ export default class ThemeChoicePanel extends React.Component<IProps, IState> {
// XXX: need some schema for this
const themeInfo = await r.json();
if (!themeInfo || typeof themeInfo["name"] !== "string" || typeof themeInfo["colors"] !== "object") {
this.setState({ customThemeMessage: { text: _t("Invalid theme schema."), isError: true } });
this.setState({
customThemeMessage: { text: _t("settings|appearance|custom_theme_invalid"), isError: true },
});
return;
}
currentThemes.push(themeInfo);
} catch (e) {
logger.error(e);
this.setState({ customThemeMessage: { text: _t("Error downloading theme information."), isError: true } });
this.setState({
customThemeMessage: { text: _t("settings|appearance|custom_theme_error_downloading"), isError: true },
});
return; // Don't continue on error
}
await SettingsStore.setValue("custom_themes", null, SettingLevel.ACCOUNT, currentThemes);
this.setState({ customThemeUrl: "", customThemeMessage: { text: _t("Theme added!"), isError: false } });
this.setState({
customThemeUrl: "",
customThemeMessage: { text: _t("settings|appearance|custom_theme_success"), isError: false },
});
this.themeTimer = window.setTimeout(() => {
this.setState({ customThemeMessage: { text: "", isError: false } });
@ -174,7 +181,7 @@ export default class ThemeChoicePanel extends React.Component<IProps, IState> {
checked={isHighContrastTheme(this.state.theme)}
onChange={(e) => this.highContrastThemeChanged(e.target.checked)}
>
{_t("Use high contrast")}
{_t("settings|appearance|use_high_contrast")}
</StyledCheckbox>
</div>
);
@ -223,7 +230,7 @@ export default class ThemeChoicePanel extends React.Component<IProps, IState> {
<div className="mx_SettingsTab_section">
<form onSubmit={this.onAddCustomTheme}>
<Field
label={_t("Custom theme URL")}
label={_t("settings|appearance|custom_theme_url")}
type="text"
id="mx_GeneralUserSettingsTab_customThemeInput"
autoComplete="off"
@ -236,7 +243,7 @@ export default class ThemeChoicePanel extends React.Component<IProps, IState> {
kind="primary_sm"
disabled={!this.state.customThemeUrl.trim()}
>
{_t("Add theme")}
{_t("settings|appearance|custom_theme_add_button")}
</AccessibleButton>
{messageElement}
</form>

View File

@ -56,7 +56,7 @@ export const deleteDevicesWithInteractiveAuth = async (
body: _t("Confirm logging out these devices by using Single Sign On to prove your identity.", {
count: numDevices,
}),
continueText: _t("Single Sign On"),
continueText: _t("auth|sso"),
continueKind: "primary",
},
[SSOAuthEntry.PHASE_POSTAUTH]: {

View File

@ -122,7 +122,7 @@ export default function NotificationSettings2(): JSX.Element {
<SettingsSection heading={_t("Notifications")}>
<div className="mx_SettingsSubsection_content mx_NotificationSettings2_flags">
<LabelledToggleSwitch
label={_t("Enable notifications for this account")}
label={_t("settings|notifications|enable_notifications_account")}
value={!settings.globalMute}
disabled={disabled}
onChange={(value) => {
@ -133,7 +133,7 @@ export default function NotificationSettings2(): JSX.Element {
}}
/>
<LabelledToggleSwitch
label={_t("Enable desktop notifications for this session")}
label={_t("settings|notifications|enable_desktop_notifications_session")}
value={desktopNotifications}
onChange={(value) =>
SettingsStore.setValue("notificationsEnabled", null, SettingLevel.DEVICE, value)
@ -147,7 +147,7 @@ export default function NotificationSettings2(): JSX.Element {
}
/>
<LabelledToggleSwitch
label={_t("Enable audible notifications for this session")}
label={_t("settings|notifications|enable_audible_notifications_session")}
value={audioNotifications}
onChange={(value) =>
SettingsStore.setValue("audioNotificationsEnabled", null, SettingLevel.DEVICE, value)

View File

@ -106,10 +106,7 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
let advanced: React.ReactNode;
if (this.state.showAdvanced) {
const tooltipContent = _t(
"Set the name of a font installed on your system & %(brand)s will attempt to use it.",
{ brand },
);
const tooltipContent = _t("settings|appearance|custom_font_description", { brand });
advanced = (
<>
<SettingsFlag name="useCompactLayout" level={SettingLevel.DEVICE} useCheckbox={true} />
@ -151,10 +148,8 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
return (
<SettingsTab data-testid="mx_AppearanceUserSettingsTab">
<SettingsSection heading={_t("Customise your appearance")}>
<SettingsSubsectionText>
{_t("Appearance Settings only affect this %(brand)s session.", { brand })}
</SettingsSubsectionText>
<SettingsSection heading={_t("settings|appearance|heading")}>
<SettingsSubsectionText>{_t("settings|appearance|subheading", { brand })}</SettingsSubsectionText>
<ThemeChoicePanel />
<LayoutSwitcher
userId={this.state.userId}

View File

@ -78,8 +78,8 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
: "<not-enabled>";
return {
appVersion: `${_t("%(brand)s version:", { brand })} ${appVersion}`,
olmVersion: `${_t("Olm version:")} ${olmVersion}`,
appVersion: `${_t("setting|help_about|brand_version", { brand })} ${appVersion}`,
olmVersion: `${_t("setting|help_about|olm_version")} ${olmVersion}`,
};
}
@ -228,7 +228,7 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
const brand = SdkConfig.get().brand;
let faqText = _t(
"For help with using %(brand)s, click <a>here</a>.",
"setting|help_about|help_link",
{
brand,
},
@ -240,7 +240,7 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
faqText = (
<div>
{_t(
"For help with using %(brand)s, click <a>here</a> or start a chat with our bot using the button below.",
"setting|help_about|help_link_chat_bot",
{
brand,
},
@ -258,7 +258,7 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
)}
<div>
<AccessibleButton onClick={this.onStartBotChat} kind="primary">
{_t("Chat with %(brand)s Bot", { brand })}
{_t("setting|help_about|chat_bot", { brand })}
</AccessibleButton>
</div>
</div>
@ -306,10 +306,10 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
return (
<SettingsTab>
<SettingsSection heading={_t("Help & About")}>
<SettingsSection heading={_t("setting|help_about|title")}>
{bugReportingSection}
<SettingsSubsection heading={_t("common|faq")} description={faqText} />
<SettingsSubsection heading={_t("Versions")}>
<SettingsSubsection heading={_t("setting|help_about|versions")}>
<SettingsSubsectionText>
<CopyableText getTextToCopy={this.getVersionTextToCopy}>
{appVersion}
@ -325,7 +325,7 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
<SettingsSubsection heading={_t("Advanced")}>
<SettingsSubsectionText>
{_t(
"Homeserver is <code>%(homeserverUrl)s</code>",
"setting|help_about|homeserver",
{
homeserverUrl: this.context.getHomeserverUrl(),
},
@ -337,7 +337,7 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
{this.context.getIdentityServerUrl() && (
<SettingsSubsectionText>
{_t(
"Identity server is <code>%(identityServerUrl)s</code>",
"setting|help_about|identity_server",
{
identityServerUrl: this.context.getIdentityServerUrl(),
},
@ -350,18 +350,14 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
<SettingsSubsectionText>
<details>
<summary>{_t("common|access_token")}</summary>
<b>
{_t(
"Your access token gives full access to your account. Do not share it with anyone.",
)}
</b>
<b>{_t("setting|help_about|access_token_detail")}</b>
<CopyableText getTextToCopy={() => this.context.getAccessToken()}>
{this.context.getAccessToken()}
</CopyableText>
</details>
</SettingsSubsectionText>
<AccessibleButton onClick={this.onClearCacheAndReload} kind="danger">
{_t("Clear cache and reload")}
{_t("setting|help_about|clear_cache_reload")}
</AccessibleButton>
</SettingsSubsection>
</SettingsSection>

View File

@ -27,7 +27,7 @@ export default class VerificationCancelled extends React.Component<IProps> {
public render(): React.ReactNode {
return (
<div>
<p>{_t("The other party cancelled the verification.")}</p>
<p>{_t("encryption|verification|other_party_cancelled")}</p>
<DialogButtons
primaryButton={_t("action|ok")}
hasCancel={false}

View File

@ -27,8 +27,8 @@ export default class VerificationComplete extends React.Component<IProps> {
public render(): React.ReactNode {
return (
<div>
<h2>{_t("Verified!")}</h2>
<p>{_t("You've successfully verified this user.")}</p>
<h2>{_t("encryption|verification|complete_title")}</h2>
<p>{_t("encryption|verification|complete_description")}</p>
<p>
{_t(
"Secure messages with this user are end-to-end encrypted and not able to be read by third parties.",

View File

@ -180,10 +180,10 @@ export default class VerificationShowSas extends React.Component<IProps, IState>
confirm = (
<div className="mx_VerificationShowSas_buttonRow">
<AccessibleButton onClick={this.onDontMatchClick} kind="danger">
{_t("They don't match")}
{_t("encryption|verification|sas_no_match")}
</AccessibleButton>
<AccessibleButton onClick={this.onMatchClick} kind="primary">
{_t("They match")}
{_t("encryption|verification|sas_match")}
</AccessibleButton>
</div>
);
@ -193,11 +193,7 @@ export default class VerificationShowSas extends React.Component<IProps, IState>
<div className="mx_VerificationShowSas">
<p>{sasCaption}</p>
{sasDisplay}
<p>
{this.props.isSelf
? ""
: _t("To be secure, do this in person or use a trusted way to communicate.")}
</p>
<p>{this.props.isSelf ? "" : _t("encryption|verification|in_person")}</p>
{confirm}
</div>
);

View File

@ -73,7 +73,6 @@ const RoomContext = createContext<
msc3946ProcessDynamicPredecessor: false,
canAskToJoin: false,
promptAskToJoin: false,
knocked: false,
});
RoomContext.displayName = "RoomContext";
export default RoomContext;

View File

@ -31,8 +31,8 @@ export const CHAT_EFFECTS: Array<Effect<{ [key: string]: any }>> = [
emojis: ["🎊", "🎉"],
msgType: "nic.custom.confetti",
command: "confetti",
description: () => _td("Sends the given message with confetti"),
fallbackMessage: () => _t("sends confetti") + " 🎉",
description: () => _td("chat_effects|confetti_description"),
fallbackMessage: () => _t("chat_effects|confetti_message") + " 🎉",
options: {
maxCount: 150,
speed: 3,
@ -45,8 +45,8 @@ export const CHAT_EFFECTS: Array<Effect<{ [key: string]: any }>> = [
emojis: ["🎆"],
msgType: "nic.custom.fireworks",
command: "fireworks",
description: () => _td("Sends the given message with fireworks"),
fallbackMessage: () => _t("sends fireworks") + " 🎆",
description: () => _td("chat_effects|fireworks_description"),
fallbackMessage: () => _t("chat_effects|fireworks_message") + " 🎆",
options: {
maxCount: 500,
gravity: 0.05,
@ -56,8 +56,8 @@ export const CHAT_EFFECTS: Array<Effect<{ [key: string]: any }>> = [
emojis: ["🌧️", "⛈️", "🌦️"],
msgType: "io.element.effect.rainfall",
command: "rainfall",
description: () => _td("Sends the given message with rainfall"),
fallbackMessage: () => _t("sends rainfall") + " 🌧️",
description: () => _td("chat_effects|rainfall_description"),
fallbackMessage: () => _t("chat_effects|rainfall_message") + " 🌧️",
options: {
maxCount: 600,
speed: 10,
@ -67,8 +67,8 @@ export const CHAT_EFFECTS: Array<Effect<{ [key: string]: any }>> = [
emojis: ["❄", "🌨"],
msgType: "io.element.effect.snowfall",
command: "snowfall",
description: () => _td("Sends the given message with snowfall"),
fallbackMessage: () => _t("sends snowfall") + " ❄",
description: () => _td("chat_effects|snowfall_description"),
fallbackMessage: () => _t("chat_effects|snowfall_message") + " ❄",
options: {
maxCount: 200,
gravity: 0.05,
@ -79,8 +79,8 @@ export const CHAT_EFFECTS: Array<Effect<{ [key: string]: any }>> = [
emojis: ["👾", "🌌"],
msgType: "io.element.effects.space_invaders",
command: "spaceinvaders",
description: () => _td("Sends the given message with a space themed effect"),
fallbackMessage: () => _t("sends space invaders") + " 👾",
description: () => _td("chat_effects|spaceinvaders_description"),
fallbackMessage: () => _t("chat_effects|spaceinvaders_message") + " 👾",
options: {
maxCount: 50,
gravity: 0.01,
@ -90,8 +90,8 @@ export const CHAT_EFFECTS: Array<Effect<{ [key: string]: any }>> = [
emojis: ["💝"],
msgType: "io.element.effect.hearts",
command: "hearts",
description: () => _td("Sends the given message with hearts"),
fallbackMessage: () => _t("sends hearts") + " 💝",
description: () => _td("chat_effects|hearts_description"),
fallbackMessage: () => _t("chat_effects|hearts_message") + " 💝",
options: {
maxCount: 120,
gravity: 3.2,

View File

@ -18,7 +18,6 @@
"powered by Matrix": "مشغل بواسطة Matrix",
"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": "أضِف بريدًا إلكترونيًا",
@ -107,44 +106,14 @@
"Define the power level of a user": "قم بتعريف مستوى الطاقة للمستخدم",
"Could not find user in room": "لم يستطع ايجاد مستخدم في غرفة",
"Deops user with given id": "يُلغي إدارية المستخدم حسب المعرّف المعطى",
"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": "يتحقق من العناصر: المستخدم والجلسة والمفتاح العام",
"Session already verified!": "تم التحقق من الجلسة بالفعل!",
"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": "يفرض تجاهل جلسة المجموعة الصادرة الحالية في غرفة مشفرة",
"Logs sent": "تم ارسال سجل الاحداث",
"Opens chat with the given user": "يفتح دردشة من المستخدم المعطى",
"Displays action": "يعرض إجراءً",
"Reason": "السبب",
"%(senderName)s added the alternative addresses %(addresses)s for this room.": {
"other": "قام %(senderName)s بإضافة العناوين البديلة %(addresses)s لهذه الغرفة.",
"one": "قام %(senderName)s بإضافة العنوان البديل %(addresses)s لهذه الغرفة."
},
"%(senderName)s removed the alternative addresses %(addresses)s for this room.": {
"other": "قام %(senderName)s بإزالة العناوين البديلة %(addresses)s لهذه الغرفة.",
"one": "قام %(senderName)s بإزالة العنوان البديل %(addresses)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.",
"You cannot place a call with yourself.": "لا يمكنك الاتصال بنفسك.",
"%(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 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",
"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 تم تسجيل الدخول لجلسة جديدة من غير التحقق منها:",
@ -163,7 +132,6 @@
"Rotate Left": "أدر لليسار",
"expand": "توسيع",
"collapse": "تضييق",
"Please <newIssueLink>create a new issue</newIssueLink> on GitHub so that we can investigate this bug.": "الرجاء <newIssueLink> إنشاء إشكال جديد</newIssueLink> على GitHub حتى نتمكن من التحقيق في هذا الخطأ.",
"This version of %(brand)s does not support searching encrypted messages": "لا يدعم هذا الإصدار من %(brand)s البحث في الرسائل المشفرة",
"This version of %(brand)s does not support viewing some encrypted files": "لا يدعم هذا الإصدار من %(brand)s s عرض بعض الملفات المشفرة",
"Use the <a>Desktop app</a> to search encrypted messages": "استخدم <a> تطبيق سطح المكتب </a> للبحث في الرسائل المشفرة",
@ -181,17 +149,6 @@
"Your display name": "اسمك الظاهر",
"Any of the following data may be shared:": "يمكن أن تُشارَك أي من البيانات التالية:",
"Cancel search": "إلغاء البحث",
"Quick Reactions": "ردود الفعل السريعة",
"Categories": "التصنيفات",
"Flags": "الأعلام",
"Symbols": "الرموز",
"Objects": "الأشياء",
"Travel & Places": "السفر والأماكن",
"Activities": "الأنشطة",
"Food & Drink": "الطعام والشراب",
"Animals & Nature": "الحيوانات والطبيعة",
"Smileys & People": "الوجوه الضاحكة والأشخاص",
"Frequently Used": "كثيرة الاستعمال",
"Can't load this message": "تعذر تحميل هذه الرسالة",
"Submit logs": "إرسال السجلات",
"edited": "عُدل",
@ -294,33 +251,13 @@
"This room is running room version <roomVersion />, which this homeserver has marked as <i>unstable</i>.": "هذه الغرفة تشغل إصدار الغرفة <roomVersion /> ، والذي عده الخادم الوسيط هذا بأنه<i> غير مستقر </i>.",
"This room has already been upgraded.": "سبق وأن تمت ترقية هذه الغرفة.",
"Upgrading this room will shut down the current instance of the room and create an upgraded room with the same name.": "ستؤدي ترقية هذه الغرفة إلى إغلاق النسخة الحالية للغرفة وإنشاء غرفة تمت ترقيتها بنفس الاسم.",
"Unread messages.": "رسائل غير المقروءة.",
"%(count)s unread messages.": {
"one": "رسالة واحدة غير مقروءة.",
"other": "%(count)s من الرسائل غير مقروءة."
},
"%(count)s unread messages including mentions.": {
"one": "إشارة واحدة غير مقروءة.",
"other": "%(count)s من الرسائل والإشارات غير المقروءة."
},
"Room options": "خيارات الغرفة",
"Low Priority": "أولوية منخفضة",
"Favourite": "تفضيل",
"Favourited": "فُضلت",
"Forget Room": "انسَ الغرفة",
"Notification options": "خيارات الإشعارات",
"Show %(count)s more": {
"one": "أظهر %(count)s زيادة",
"other": "أظهر %(count)s زيادة"
},
"Jump to first invite.": "الانتقال لأول دعوة.",
"Jump to first unread room.": "الانتقال لأول غرفة لم تقرأ.",
"List options": "خيارات القائمة",
"A-Z": "ألفبائي",
"Activity": "النشاط",
"Sort by": "ترتيب حسب",
"Show previews of messages": "إظهار معاينات للرسائل",
"Show rooms with unread messages first": "اعرض الغرف ذات الرسائل غير المقروءة أولاً",
"%(roomName)s is not accessible at this time.": "لا يمكن الوصول إلى %(roomName)s في الوقت الحالي.",
"%(roomName)s does not exist.": "الغرفة %(roomName)s ليست موجودة.",
"%(roomName)s can't be previewed. Do you want to join it?": "لا يمكن معاينة %(roomName)s. هل تريد الانضمام إليها؟",
@ -416,14 +353,7 @@
"Something went wrong. Please try again or view your console for hints.": "هناك خطأ ما. يرجى المحاولة مرة أخرى أو عرض وحدة التحكم (console) للتلميحات.",
"Error adding ignored user/server": "تعذر إضافة مستخدم/خادم مُتجاهَل",
"Ignored/Blocked": "المُتجاهل/المحظور",
"Clear cache and reload": "محو مخزن الجيب وإعادة التحميل",
"%(brand)s version:": "إصدار %(brand)s:",
"Versions": "الإصدارات",
"Help & About": "المساعدة وعن البرنامج",
"To report a Matrix-related security issue, please read the Matrix.org <a>Security Disclosure Policy</a>.": "للإبلاغ عن مشكلة أمنية متعلقة بMatrix ، يرجى قراءة <a>سياسة الإفصاح الأمني</a> في Matrix.org.",
"Chat with %(brand)s Bot": "تخاطب مع الروبوت الخاص ب%(brand)s",
"For help with using %(brand)s, click <a>here</a> or start a chat with our bot using the button below.": "للمساعدة في استخدام %(brand)s ، انقر <a> هنا </a> أو ابدأ محادثة مع برنامج الروبوت الخاص بنا باستخدام الزر أدناه.",
"For help with using %(brand)s, click <a>here</a>.": "للمساعدة في استخدام %(brand)s انقر <a>هنا</a>.",
"General": "عام",
"Discovery": "الاكتشاف",
"Deactivate account": "تعطيل الحساب",
@ -434,14 +364,6 @@
"Account": "الحساب",
"Phone numbers": "أرقام الهواتف",
"Email addresses": "عنوان البريد الإلكتروني",
"Appearance Settings only affect this %(brand)s session.": "إنما تؤثر إعدادات المظهر في %(brand)s وعلى هذا الاتصال فقط.",
"Customise your appearance": "تخصيص مظهرك",
"Set the name of a font installed on your system & %(brand)s will attempt to use it.": "قم بتعيين اسم الخط المثبت على نظامك وسيحاول %(brand)s استخدامه.",
"Add theme": "إضافة مظهر",
"Custom theme URL": "رابط المظهر المخصص",
"Theme added!": "أُضيفَ المظهر!",
"Error downloading theme information.": "تعذر تحميل معلومات المظهر.",
"Invalid theme schema.": "ملف وصف المظهر غير صالح.",
"Use between %(min)s pt and %(max)s pt": "استعمل ما بين %(min)spt و %(max)sps",
"Custom font size can only be between %(min)s pt and %(max)s pt": "الحجم المخصص للخط يجب أن ينحصر بين %(min)spt و %(max)spt",
"Size must be a number": "الحجم يجب أن يكون رقمًا",
@ -503,9 +425,6 @@
"Noisy": "مزعج",
"On": "مشتغل",
"Off": "مطفأ",
"Enable audible notifications for this session": "تمكين الإشعارات الصوتية لهذا الاتصال",
"Show message in desktop notification": "إظهار الرسالة في إشعارات سطح المكتب",
"Enable desktop notifications for this session": "تمكين إشعارات سطح المكتب لهذا الاتصال",
"Notification targets": "أهداف الإشعار",
"You've successfully verified your device!": "لقد نجحت في التحقق من جهازك!",
"Verify all users in a room to ensure it's secure.": "تحقق من جميع المستخدمين في الغرفة للتأكد من أنها آمنة.",
@ -617,27 +536,17 @@
"New passwords don't match": "كلمات المرور الجديدة لا تتطابق",
"No display name": "لا اسم ظاهر",
"Show more": "أظهر أكثر",
"Show less": "أظهر أقل",
"This bridge is managed by <user />.": "هذا الجسر يديره <user />.",
"Accept <policyLink /> to continue:": "قبول <policyLink /> للمتابعة:",
"Your server isn't responding to some <a>requests</a>.": "خادمك لا يتجاوب مع بعض <a>الطلبات</a>.",
"Dog": "كلب",
"To be secure, do this in person or use a trusted way to communicate.": "لتكون آمنًا ، افعل ذلك شخصيًا أو استخدم طريقة موثوقة للتواصل.",
"They don't match": "لم يتطابقوا",
"They match": "تطابقوا",
"Cancelling…": "جارٍ الإلغاء…",
"Waiting for %(displayName)s to verify…": "بانتظار %(displayName)s للتحقق…",
"Unable to find a supported verification method.": "تعذر العثور على أحد طرق التحقق الممكنة.",
"Verify this user by confirming the following number appears on their screen.": "تحقق من هذا المستخدم من خلال التأكد من ظهور الرقم التالي على شاشته.",
"Verify this user by confirming the following emoji appear on their screen.": "تحقق من هذا المستخدم من خلال التأكيد من ظهور الرموز التعبيرية التالية على شاشته.",
"Compare a unique set of emoji if you don't have a camera on either device": "قارن مجموعة فريدة من الرموز التعبيرية إذا لم يكن لديك كاميرا على أي من الجهازين",
"Compare unique emoji": "قارن رمزاً تعبيريًّا فريداً",
"Scan this unique code": "امسح هذا الرمز الفريد",
"Got It": "فهمت",
"Secure messages with this user are end-to-end encrypted and not able to be read by third parties.": "الرسائل الآمنة مع هذا المستخدم مشفرة من طرفك إلى طرفه ولا يمكن قراءتها من قبل جهات خارجية.",
"You've successfully verified this user.": "لقد نجحت في التحقق من هذا المستخدم.",
"Verified!": "تم التحقق!",
"The other party cancelled the verification.": "ألغى الطرف الآخر التحقق.",
"This is your list of users/servers you have blocked - don't leave the room!": "هذه قائمتك للمستخدمين / الخوادم التي حظرت - لا تغادر الغرفة!",
"My Ban List": "قائمة الحظر",
"IRC display name width": "عرض الاسم الظاهر لIRC",
@ -650,12 +559,8 @@
"Never send encrypted messages to unverified sessions in this room from this session": "لا ترسل أبدًا رسائل مشفرة إلى اتصالات التي لم يتم التحقق منها في هذه الغرفة من هذا الاتصال",
"Never send encrypted messages to unverified sessions from this session": "لا ترسل أبدًا رسائل مشفرة إلى اتصالات لم يتم التحقق منها من هذا الاتصال",
"Send analytics data": "إرسال بيانات التحليلات",
"System font name": "اسم خط النظام",
"Use a system font": "استخدام خط النظام",
"Match system theme": "مطابقة ألوان النظام",
"Mirror local video feed": "محاكاة تغذية الفيديو المحلية",
"Use custom size": "استخدام حجم مخصص",
"Font size": "حجم الخط",
"Change notification settings": "تغيير إعدادات الإشعار",
"Please contact your homeserver administrator.": "يُرجى تواصلك مع مدير خادمك.",
"New version of %(brand)s is available": "يتوفر إصدار جديد من %(brand)s",
@ -864,11 +769,6 @@
"Send stickers into this room": "أرسل ملصقات إلى هذه الغرفة",
"Remain on your screen while running": "ابقَ على شاشتك أثناء إجراء",
"Remain on your screen when viewing another room, when running": "ابقَ على شاشتك عند مشاهدة غرفة أخرى أثناء إجراء",
"%(senderName)s created a rule banning users 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 the rule banning rooms matching %(glob)s for %(reason)s": "%(senderName)s حدَّث قاعدة حظر الغرفة المطابقة %(glob)s بسبب %(reason)s",
"Takes the call in the current room off hold": "يوقف المكالمة في الغرفة الحالية",
"Places the call in the current room on hold": "يضع المكالمة في الغرفة الحالية قيد الانتظار",
"Cuba": "كوبا",
"Croatia": "كرواتيا",
"Costa Rica": "كوستا ريكا",
@ -932,20 +832,13 @@
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "يتلقى مديرو التكامل بيانات الضبط، ويمكنهم تعديل عناصر واجهة المستخدم، وإرسال دعوات الغرف، وتعيين مستويات القوة نيابة عنك.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "استخدم مدير التكامل لإدارة البوتات وعناصر الواجهة وحزم الملصقات.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "استخدم مدير التكامل <b>(%(serverName)s)</b> لإدارة البوتات وعناصر الواجهة وحزم الملصقات.",
"Identity server": "خادوم الهوية",
"Identity server (%(server)s)": "خادوم الهوية (%(server)s)",
"Could not connect to identity server": "تعذر الاتصال بخادوم الهوية",
"Not a valid identity server (status code %(code)s)": "ليس خادوم هوية صالح (رمز الحالة %(code)s)",
"Identity server URL must be HTTPS": "يجب أن يستعمل رابط (URL) خادوم الهوية ميفاق HTTPS",
"Paraguay": "باراغواي",
"Netherlands": "هولندا",
"Dismiss read marker and jump to bottom": "تجاهل علامة القراءة وانتقل إلى الأسفل",
"Toggle microphone mute": "تبديل كتم صوت الميكروفون",
"Cancel replying to a message": "إلغاء الرد على رسالة",
"New line": "سطر جديد",
"Greece": "اليونان",
"Converts the DM to a room": "تحويل المحادثة المباشرة إلى غرفة",
"Converts the room to a DM": "تحويل الغرفة إلى محادثة مباشرة",
"Some invites couldn't be sent": "تعذر إرسال بعض الدعوات",
"We sent the others, but the below people couldn't be invited to <RoomName/>": "أرسلنا الآخرين، ولكن لم تتم دعوة الأشخاص أدناه إلى <RoomName/>",
"Zimbabwe": "زمبابوي",
@ -1096,7 +989,8 @@
"stickerpack": "حزمة الملصقات",
"system_alerts": "تنبيهات النظام",
"secure_backup": "تأمين النسخ الاحتياطي",
"cross_signing": "التوقيع المتبادل"
"cross_signing": "التوقيع المتبادل",
"identity_server": "خادوم الهوية"
},
"action": {
"continue": "واصِل",
@ -1157,10 +1051,19 @@
"state_counters": "إظهار عدّادات بسيطة في رأس الغرفة",
"custom_themes": "دعم إضافة ألوان مخصصة",
"dehydration": "الرسائل المشفرة في وضع عدم الاتصال باستخدام أجهزة مجففة",
"bridge_state": "إظهار المعلومات حول الجسور في إعدادات الغرفة"
"bridge_state": "إظهار المعلومات حول الجسور في إعدادات الغرفة",
"group_profile": "الملف الشخصي",
"group_widgets": "عناصر الواجهة",
"group_rooms": "الغرف",
"group_voip": "الصوت والفيديو",
"group_encryption": "تشفير"
},
"keyboard": {
"number": "[رقم]"
"number": "[رقم]",
"cancel_reply": "إلغاء الرد على رسالة",
"toggle_microphone_mute": "تبديل كتم صوت الميكروفون",
"dismiss_read_marker_and_jump_bottom": "تجاهل علامة القراءة وانتقل إلى الأسفل",
"composer_new_line": "سطر جديد"
},
"composer": {
"format_bold": "ثخين",
@ -1188,7 +1091,8 @@
"collecting_information": "تجميع المعلومات حول نسخة التطبيق",
"collecting_logs": "تجميع السجلات",
"uploading_logs": "رفع السجلات",
"downloading_logs": "تحميل السجلات"
"downloading_logs": "تحميل السجلات",
"create_new_issue": "الرجاء <newIssueLink> إنشاء إشكال جديد</newIssueLink> على GitHub حتى نتمكن من التحقيق في هذا الخطأ."
},
"time": {
"date_at_time": "%(date)s في %(time)s"
@ -1221,7 +1125,25 @@
"rule_call": "دعوة لمحادثة",
"rule_suppress_notices": "رسائل أرسلها آلي (Bot)",
"rule_tombstone": "عند ترقية الغرف",
"rule_encrypted_room_one_to_one": "رسائل مشفرة في المحادثات المباشرة"
"rule_encrypted_room_one_to_one": "رسائل مشفرة في المحادثات المباشرة",
"enable_desktop_notifications_session": "تمكين إشعارات سطح المكتب لهذا الاتصال",
"show_message_desktop_notification": "إظهار الرسالة في إشعارات سطح المكتب",
"enable_audible_notifications_session": "تمكين الإشعارات الصوتية لهذا الاتصال"
},
"appearance": {
"heading": "تخصيص مظهرك",
"subheading": "إنما تؤثر إعدادات المظهر في %(brand)s وعلى هذا الاتصال فقط.",
"match_system_theme": "مطابقة ألوان النظام",
"custom_font": "استخدام خط النظام",
"custom_font_name": "اسم خط النظام",
"custom_theme_invalid": "ملف وصف المظهر غير صالح.",
"custom_theme_error_downloading": "تعذر تحميل معلومات المظهر.",
"custom_theme_success": "أُضيفَ المظهر!",
"custom_theme_url": "رابط المظهر المخصص",
"custom_theme_add_button": "إضافة مظهر",
"font_size": "حجم الخط",
"custom_font_description": "قم بتعيين اسم الخط المثبت على نظامك وسيحاول %(brand)s استخدامه.",
"timeline_image_size_default": "المبدئي"
}
},
"devtools": {
@ -1279,7 +1201,15 @@
"removed": "قام %(senderName)s بإزالة العنوان الرئيسي لهذه الغرفة.",
"changed_alternative": "قام %(senderName)s بتعديل العناوين البديلة لهذه الغرفة.",
"changed_main_and_alternative": "قام %(senderName)s بتعديل العناوين الرئيسية و البديلة لهذه الغرفة.",
"changed": "قام %(senderName)s بتعديل عناوين هذه الغرفة."
"changed": "قام %(senderName)s بتعديل عناوين هذه الغرفة.",
"alt_added": {
"other": "قام %(senderName)s بإضافة العناوين البديلة %(addresses)s لهذه الغرفة.",
"one": "قام %(senderName)s بإضافة العنوان البديل %(addresses)s لهذه الغرفة."
},
"alt_removed": {
"other": "قام %(senderName)s بإزالة العناوين البديلة %(addresses)s لهذه الغرفة.",
"one": "قام %(senderName)s بإزالة العنوان البديل %(addresses)s لهذه الغرفة."
}
},
"m.room.third_party_invite": {
"revoked": "قام %(senderName)s بسحب الدعوة الى %(targetDisplayName)s بالانضمام الى الغرفة.",
@ -1312,6 +1242,29 @@
},
"m.call.hangup": {
"dm": "انتهت المكالمة"
},
"m.room.power_levels": {
"changed": "غير %(senderName)s مستوى الطاقة الخاصة ب %(powerLevelDiffText)s.",
"user_from_to": "%(userId)s من %(fromPowerLevel)s الى %(toPowerLevel)s"
},
"mjolnir": {
"removed_rule_users": "أزال %(senderName)s القاعدة الناصَّة على منع المستخدمين المطابقين %(glob)s",
"removed_rule_rooms": "أزال %(senderName)s القاعدة الناصَّة على منع الغرف المطابقة %(glob)s",
"removed_rule_servers": "أزال %(senderName)s القاعدة الناصَّة على منع الخوادم المطابقة %(glob)s",
"removed_rule": "أزال %(senderName)s قاعدة المنع المطابقة %(glob)s",
"updated_invalid_rule": "حدَّث %(senderName)s قاعدة منع غير صالحة",
"updated_rule_users": "حدَّث %(senderName)s قاعدة منع المستخدمين المطابقين %(glob)s بسبب %(reason)s",
"updated_rule_rooms": "%(senderName)s حدَّث قاعدة حظر الغرفة المطابقة %(glob)s بسبب %(reason)s",
"updated_rule_servers": "%(senderName)s حدَّث قاعدة حظر الخوادم المطابقة %(glob)s بسبب %(reason)s",
"updated_rule": "حدَّث %(senderName)s قاعدة منع تطابق %(glob)s بسبب %(reason)s",
"created_rule_users": "%(senderName)s حدَّث قاعدة حظر المستخدمين المطابقة %(glob)s بسبب %(reason)s",
"created_rule_rooms": "أنشأ %(senderName)s قاعدة منع غرف تطابق %(glob)s بسبب %(reason)s",
"created_rule_servers": "%(senderName)s قاعدة حظر سيرفرات مظابقة منشأة %(glob)s من أجل %(reason)s",
"created_rule": "%(senderName)s قاعدة حظر مطابق منشأة %(glob)s من أجل %(reason)s",
"changed_rule_users": "%(senderName)s قاعدة متغيرة التي تحظر المستخدمين المطابقين %(oldGlob)s من أجل تطابق %(newGlob)s من أجل %(reason)s",
"changed_rule_rooms": "%(senderName)s قاعدة متغيرة التي تحظر الغرف المطابقة %(oldGlob)s من أجل مطابقة %(newGlob)s من أجل %(reason)s",
"changed_rule_servers": "%(senderName)s قاعدة متغيرة التي تحظر سيرفرات مطابقة %(oldGlob)s من أجل مطابقة %(newGlob)s من أجل %(reason)s",
"changed_rule_glob": "%(senderName)s قاعدة حظر محدثة التي طابقت %(oldGlob)s لتطابق %(newGlob)s من أجل %(reason)s"
}
},
"slash_command": {
@ -1345,7 +1298,17 @@
"category_actions": "الإجراءات",
"category_admin": "مدير",
"category_advanced": "متقدم",
"category_other": "أخرى"
"category_other": "أخرى",
"addwidget_missing_url": "رجاء قم بتحديد Widget URL او قم بتضمين كود",
"addwidget_invalid_protocol": "يرجى ادخال a https:// او http:// widget URL",
"addwidget_no_permissions": "لا يمكنك تعديل الحاجيات في هذه الغرفة.",
"converttodm": "تحويل الغرفة إلى محادثة مباشرة",
"converttoroom": "تحويل المحادثة المباشرة إلى غرفة",
"discardsession": "يفرض تجاهل جلسة المجموعة الصادرة الحالية في غرفة مشفرة",
"query": "يفتح دردشة من المستخدم المعطى",
"holdcall": "يضع المكالمة في الغرفة الحالية قيد الانتظار",
"unholdcall": "يوقف المكالمة في الغرفة الحالية",
"me": "يعرض إجراءً"
},
"presence": {
"online_for": "متصل منذ %(duration)s",
@ -1393,7 +1356,6 @@
"unsupported": "المكالمات غير مدعومة",
"unsupported_browser": "لا يمكنك إجراء المكالمات في هذا المتصفّح."
},
"Messages": "الرسائل",
"Other": "أخرى",
"Advanced": "متقدم",
"room_settings": {
@ -1415,5 +1377,73 @@
"redact": "حذف رسائل الآخرين",
"notifications.room": "إشعار الجميع"
}
},
"encryption": {
"verification": {
"sas_no_match": "لم يتطابقوا",
"sas_match": "تطابقوا",
"in_person": "لتكون آمنًا ، افعل ذلك شخصيًا أو استخدم طريقة موثوقة للتواصل.",
"other_party_cancelled": "ألغى الطرف الآخر التحقق.",
"complete_title": "تم التحقق!",
"complete_description": "لقد نجحت في التحقق من هذا المستخدم.",
"qr_prompt": "امسح هذا الرمز الفريد",
"sas_prompt": "قارن رمزاً تعبيريًّا فريداً",
"sas_description": "قارن مجموعة فريدة من الرموز التعبيرية إذا لم يكن لديك كاميرا على أي من الجهازين"
}
},
"emoji": {
"category_frequently_used": "كثيرة الاستعمال",
"category_smileys_people": "الوجوه الضاحكة والأشخاص",
"category_animals_nature": "الحيوانات والطبيعة",
"category_food_drink": "الطعام والشراب",
"category_activities": "الأنشطة",
"category_travel_places": "السفر والأماكن",
"category_objects": "الأشياء",
"category_symbols": "الرموز",
"category_flags": "الأعلام",
"categories": "التصنيفات",
"quick_reactions": "ردود الفعل السريعة"
},
"auth": {
"sso": "الولوج الموحّد"
},
"export_chat": {
"messages": "الرسائل"
},
"room_list": {
"sort_unread_first": "اعرض الغرف ذات الرسائل غير المقروءة أولاً",
"show_previews": "إظهار معاينات للرسائل",
"sort_by": "ترتيب حسب",
"sort_by_activity": "النشاط",
"sort_by_alphabet": "ألفبائي",
"sublist_options": "خيارات القائمة",
"show_n_more": {
"one": "أظهر %(count)s زيادة",
"other": "أظهر %(count)s زيادة"
},
"show_less": "أظهر أقل",
"notification_options": "خيارات الإشعارات"
},
"a11y": {
"n_unread_messages_mentions": {
"one": "إشارة واحدة غير مقروءة.",
"other": "%(count)s من الرسائل والإشارات غير المقروءة."
},
"n_unread_messages": {
"one": "رسالة واحدة غير مقروءة.",
"other": "%(count)s من الرسائل غير مقروءة."
},
"unread_messages": "رسائل غير المقروءة."
},
"setting": {
"help_about": {
"brand_version": "إصدار %(brand)s:",
"help_link": "للمساعدة في استخدام %(brand)s انقر <a>هنا</a>.",
"help_link_chat_bot": "للمساعدة في استخدام %(brand)s ، انقر <a> هنا </a> أو ابدأ محادثة مع برنامج الروبوت الخاص بنا باستخدام الزر أدناه.",
"chat_bot": "تخاطب مع الروبوت الخاص ب%(brand)s",
"title": "المساعدة وعن البرنامج",
"versions": "الإصدارات",
"clear_cache_reload": "محو مخزن الجيب وإعادة التحميل"
}
}
}

View File

@ -42,10 +42,7 @@
"Unignored user": "İstifadəçi blokun siyahısından götürülmüşdür",
"You are no longer ignoring %(userId)s": "Siz %(userId)s blokdan çıxardınız",
"Deops user with given id": "Verilmiş ID-lə istifadəçidən operatorun səlahiyyətlərini çıxardır",
"Displays action": "Hərəkətlərin nümayişi",
"Reason": "Səbəb",
"%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s üçün %(fromPowerLevel)s-dan %(toPowerLevel)s-lə",
"%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s hüquqların səviyyələrini dəyişdirdi %(powerLevelDiffText)s.",
"Incorrect verification code": "Təsdiq etmənin səhv kodu",
"Phone": "Telefon",
"New passwords don't match": "Yeni şifrlər uyğun gəlmir",
@ -147,7 +144,6 @@
"You are not in this room.": "Sən bu otaqda deyilsən.",
"You do not have permission to do that in this room.": "Bu otaqda bunu etməyə icazəniz yoxdur.",
"Define the power level of a user": "Bir istifadəçinin güc səviyyəsini müəyyənləşdirin",
"You cannot modify widgets in this room.": "Bu otaqda vidjetləri dəyişdirə bilməzsiniz.",
"Verified key": "Təsdiqlənmiş açar",
"Add Email Address": "Emal ünvan əlavə etmək",
"Add Phone Number": "Telefon nömrəsi əlavə etmək",
@ -165,12 +161,9 @@
"Use an identity server": "Şəxsiyyət serverindən istifadə edin",
"Use an identity server to invite by email. Click continue to use the default identity server (%(defaultIdentityServerName)s) or manage in Settings.": "E-poçtla dəvət etmək üçün şəxsiyyət serverindən istifadə edin. Defolt şəxsiyyət serverini (%(defaultIdentityServerName)s) istifadə etməyə və ya Parametrlərdə idarə etməyə davam edin.",
"Use an identity server to invite by email. Manage in Settings.": "E-poçtla dəvət etmək üçün şəxsiyyət serverindən istifadə edin. Parametrlərdə idarə edin.",
"Please supply a https:// or http:// widget URL": "Zəhmət olmasa https:// və ya http:// widget URL təmin edin",
"Forces the current outbound group session in an encrypted room to be discarded": "Şifrəli bir otaqda mövcud qrup sessiyasını ləğv etməyə məcbur edir",
"powered by Matrix": "Matrix tərəfindən təchiz edilmişdir",
"Create Account": "Hesab Aç",
"Explore rooms": "Otaqları kəşf edin",
"Identity server": "Eyniləşdirmənin serveri",
"common": {
"analytics": "Analitik",
"error": "Səhv",
@ -183,7 +176,8 @@
"favourites": "Seçilmişlər",
"attachment": "Əlavə",
"emoji": "Smaylar",
"unnamed_room": "Adııqlanmayan otaq"
"unnamed_room": "Adııqlanmayan otaq",
"identity_server": "Eyniləşdirmənin serveri"
},
"action": {
"continue": "Davam etmək",
@ -221,6 +215,9 @@
"rule_invite_for_me": "Nə vaxt ki, məni otağa dəvət edirlər",
"rule_call": "Dəvət zəngi",
"rule_suppress_notices": "Botla göndərilmiş mesajlar"
},
"appearance": {
"timeline_image_size_default": "Varsayılan olaraq"
}
},
"timeline": {
@ -246,6 +243,10 @@
"shared": "%(senderName)s iştirakçılar üçün danışıqların tarixini açdı.",
"world_readable": "%(senderName)s hamı üçün danışıqların tarixini açdı.",
"unknown": "%(senderName)s naməlum rejimdə otağın tarixini açdı (%(visibility)s)."
},
"m.room.power_levels": {
"changed": "%(senderName)s hüquqların səviyyələrini dəyişdirdi %(powerLevelDiffText)s.",
"user_from_to": "%(userId)s üçün %(fromPowerLevel)s-dan %(toPowerLevel)s-lə"
}
},
"slash_command": {
@ -274,7 +275,11 @@
"category_actions": "Tədbirlər",
"category_admin": "Administrator",
"category_advanced": "Təfərrüatlar",
"category_other": "Digər"
"category_other": "Digər",
"addwidget_invalid_protocol": "Zəhmət olmasa https:// və ya http:// widget URL təmin edin",
"addwidget_no_permissions": "Bu otaqda vidjetləri dəyişdirə bilməzsiniz.",
"discardsession": "Şifrəli bir otaqda mövcud qrup sessiyasını ləğv etməyə məcbur edir",
"me": "Hərəkətlərin nümayişi"
},
"bug_reporting": {
"collecting_information": "Proqramın versiyası haqqında məlumatın yığılması",
@ -286,10 +291,15 @@
"video_call": "Video çağırış",
"call_failed": "Uğursuz zəng"
},
"Messages": "Mesajlar",
"devtools": {
"category_other": "Digər"
},
"Other": "Digər",
"Advanced": "Təfərrüatlar"
"Advanced": "Təfərrüatlar",
"labs": {
"group_profile": "Profil"
},
"export_chat": {
"messages": "Mesajlar"
}
}

View File

@ -67,8 +67,6 @@
"You are no longer ignoring %(userId)s": "Вече не игнорирате %(userId)s",
"Verified key": "Потвърден ключ",
"Reason": "Причина",
"%(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.",
"Failure to create room": "Неуспешно създаване на стая",
"Server may be unavailable, overloaded, or you hit a bug.": "Сървърът може би е претоварен, недостъпен или се натъкнахте на проблем.",
"Your browser does not support the required cryptography extensions": "Вашият браузър не поддържа необходимите разширения за шифроване",
@ -173,87 +171,6 @@
"Delete widget": "Изтрий приспособлението",
"Create new room": "Създай нова стая",
"Home": "Начална страница",
"%(nameList)s %(transitionList)s": "%(nameList)s %(transitionList)s",
"%(severalUsers)sjoined %(count)s times": {
"other": "%(severalUsers)sсе присъединиха %(count)s пъти",
"one": "%(severalUsers)sсе присъединиха"
},
"%(oneUser)sjoined %(count)s times": {
"other": "%(oneUser)sсе присъедини %(count)s пъти",
"one": "%(oneUser)sсе присъедини"
},
"%(severalUsers)sleft %(count)s times": {
"other": "%(severalUsers)sнапуснаха %(count)s пъти",
"one": "%(severalUsers)sнапуснаха"
},
"%(oneUser)sleft %(count)s times": {
"other": "%(oneUser)sнапусна %(count)s пъти",
"one": "%(oneUser)sнапусна"
},
"%(severalUsers)sjoined and left %(count)s times": {
"other": "%(severalUsers)sсе присъединиха и напуснаха %(count)s пъти",
"one": "%(severalUsers)sсе присъединиха и напуснаха"
},
"%(oneUser)sjoined and left %(count)s times": {
"other": "%(oneUser)sсе присъедини и напусна %(count)s пъти",
"one": "%(oneUser)sсе присъедини и напусна"
},
"%(severalUsers)sleft and rejoined %(count)s times": {
"other": "%(severalUsers)sнапуснаха и се присъединиха отново %(count)s пъти",
"one": "%(severalUsers)sнапуснаха и се присъединиха отново"
},
"%(oneUser)sleft and rejoined %(count)s times": {
"other": "%(oneUser)sнапусна и се присъедини отново %(count)s пъти",
"one": "%(oneUser)sнапусна и се присъедини отново"
},
"%(severalUsers)srejected their invitations %(count)s times": {
"other": "%(severalUsers)sотхвърлиха своите покани %(count)s пъти",
"one": "%(severalUsers)sотхвърлиха своите покани"
},
"%(oneUser)srejected their invitation %(count)s times": {
"other": "%(oneUser)sотхвърли своята покана %(count)s пъти",
"one": "%(oneUser)sотхвърли своята покана"
},
"%(severalUsers)shad their invitations withdrawn %(count)s times": {
"other": "%(severalUsers)sоттеглиха своите покани %(count)s пъти",
"one": "%(severalUsers)sоттеглиха своите покани"
},
"%(oneUser)shad their invitation withdrawn %(count)s times": {
"other": "%(oneUser)sоттегли своята покана %(count)s пъти",
"one": "%(oneUser)sоттегли своята покана"
},
"were invited %(count)s times": {
"other": "бяха поканени %(count)s пъти",
"one": "бяха поканени"
},
"was invited %(count)s times": {
"other": "беше поканен %(count)s пъти",
"one": "беше поканен"
},
"were banned %(count)s times": {
"other": "бяха блокирани %(count)s пъти",
"one": "бяха блокирани"
},
"was banned %(count)s times": {
"other": "беше блокиран %(count)s пъти",
"one": "беше блокиран"
},
"were unbanned %(count)s times": {
"other": "бяха отблокирани %(count)s пъти",
"one": "бяха отблокирани"
},
"was unbanned %(count)s times": {
"other": "беше отблокиран %(count)s пъти",
"one": "беше отблокиран"
},
"%(severalUsers)schanged their name %(count)s times": {
"other": "%(severalUsers)sсмениха своето име %(count)s пъти",
"one": "%(severalUsers)sсмениха своето име"
},
"%(oneUser)schanged their name %(count)s times": {
"other": "%(oneUser)sсмени своето име %(count)s пъти",
"one": "%(oneUser)sсмени своето име"
},
"%(items)s and %(count)s others": {
"other": "%(items)s и %(count)s други",
"one": "%(items)s и още един"
@ -319,7 +236,6 @@
"Email": "Имейл",
"Profile": "Профил",
"Account": "Акаунт",
"%(brand)s version:": "Версия на %(brand)s:",
"The email address linked to your account must be entered.": "Имейл адресът, свързан с профила Ви, трябва да бъде въведен.",
"A new password must be entered.": "Трябва да бъде въведена нова парола.",
"New passwords must match each other.": "Новите пароли трябва да съвпадат една с друга.",
@ -328,7 +244,6 @@
"Please note you are logging into the %(hs)s server, not matrix.org.": "Моля, обърнете внимание, че влизате в %(hs)s сървър, а не в matrix.org.",
"Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or <a>enable unsafe scripts</a>.": "Не е възможно свързване към Home сървъра чрез HTTP, когато има HTTPS адрес в лентата на браузъра Ви. Или използвайте HTTPS или <a>включете функция небезопасни скриптове</a>.",
"This server does not support authentication with a phone number.": "Този сървър не поддържа автентикация с телефонен номер.",
"Displays action": "Показва действие",
"Define the power level of a user": "Променя нивото на достъп на потребителя",
"Deops user with given id": "Отнема правата на потребител с даден идентификатор",
"Commands": "Команди",
@ -378,7 +293,6 @@
"You cannot delete this message. (%(code)s)": "Това съобщение не може да бъде изтрито. (%(code)s)",
"Thursday": "Четвъртък",
"Logs sent": "Логовете са изпратени",
"Show message in desktop notification": "Показване на съдържание в известията на работния плот",
"Yesterday": "Вчера",
"Error encountered (%(errorDetail)s).": "Възникна грешка (%(errorDetail)s).",
"Low Priority": "Нисък приоритет",
@ -436,7 +350,6 @@
"Failed to upgrade room": "Неуспешно обновяване на стаята",
"The room upgrade could not be completed": "Обновяването на тази стая не можа да бъде завършено",
"Upgrade this room to version %(version)s": "Обновете тази стая до версия %(version)s",
"Forces the current outbound group session in an encrypted room to be discarded": "Принудително прекратява текущата изходяща групова сесия в шифрована стая",
"Before submitting logs, you must <a>create a GitHub issue</a> to describe your problem.": "Преди да изпратите логове, трябва да <a>отворите доклад за проблем в Github</a>.",
"%(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 вече използва 3-5 пъти по-малко памет, като зарежда информация за потребители само когато е нужна. Моля, изчакайте докато ресинхронизираме със сървъра!",
"Updating %(brand)s": "Обновяване на %(brand)s",
@ -489,7 +402,6 @@
"Invalid identity server discovery response": "Невалиден отговор по време на откриването на конфигурацията за сървъра за самоличност",
"General failure": "Обща грешка",
"Failed to perform homeserver discovery": "Неуспешно откриване на конфигурацията за сървъра",
"Sign in with single sign-on": "Влезте посредством single-sign-on",
"That matches!": "Това съвпада!",
"That doesn't match.": "Това не съвпада.",
"Go back to set it again.": "Върнете се за да настройте нова.",
@ -506,9 +418,6 @@
"Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?": "Не бяга открити профили за изброените по-долу Matrix идентификатори. Желаете ли да ги поканите въпреки това?",
"Invite anyway and never warn me again": "Покани въпреки това и не питай отново",
"Invite anyway": "Покани въпреки това",
"The other party cancelled the verification.": "Другата страна прекрати потвърждението.",
"Verified!": "Потвърдено!",
"You've successfully verified this user.": "Успешно потвърдихте този потребител.",
"Secure messages with this user are end-to-end encrypted and not able to be read by third parties.": "Защитените съобщения с този потребител са шифровани от край-до-край и не могат да бъдат прочетени от други.",
"Got It": "Разбрах",
"Verify this user by confirming the following number appears on their screen.": "Потвърдете този потребител като се уверите, че следното число се вижда на екрана му.",
@ -529,11 +438,6 @@
"Phone numbers": "Телефонни номера",
"Language and region": "Език и регион",
"Account management": "Управление на акаунта",
"For help with using %(brand)s, click <a>here</a>.": "За помощ при използването на %(brand)s, кликнете <a>тук</a>.",
"For help with using %(brand)s, click <a>here</a> or start a chat with our bot using the button below.": "За помощ при използването на %(brand)s, кликнете <a>тук</a> или започнете чат с бота ни използвайки бутона по-долу.",
"Chat with %(brand)s Bot": "Чати с %(brand)s Bot",
"Help & About": "Помощ и относно",
"Versions": "Версии",
"Composer": "Въвеждане на съобщения",
"Room list": "Списък със стаи",
"Autocomplete delay (ms)": "Забавяне преди подсказки (милисекунди)",
@ -654,8 +558,6 @@
"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. <a>Learn more about encryption.</a>": "Веднъж включено, шифроването за стаята не може да бъде изключено. Съобщенията изпратени в шифрована стая не могат да бъдат прочетени от сървърът, а само от участниците в стаята. Включването на шифроване може да попречи на много ботове или мостове към други мрежи да работят правилно. <a>Научете повече за шифроването.</a>",
"Power level": "Ниво на достъп",
"The file '%(fileName)s' failed to upload.": "Файлът '%(fileName)s' не можа да бъде качен.",
"Please supply a https:// or http:// widget URL": "Моля, укажете https:// или http:// адрес на приспособление",
"You cannot modify widgets in this room.": "Не можете да модифицирате приспособления в тази стая.",
"Upgrade this room to the recommended room version": "Обнови тази стая до препоръчаната версия на стаята",
"This room is running room version <roomVersion />, which this homeserver has marked as <i>unstable</i>.": "Тази стая използва версия на стая <roomVersion />, която сървърът счита за <i>нестабилна</i>.",
"Upgrading this room will shut down the current instance of the room and create an upgraded room with the same name.": "Обновяването на тази стая ще изключи текущата стая и ще създаде обновена стая със същото име.",
@ -744,22 +646,10 @@
"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.": "Може да влезете в профила си, но някои функции няма да са достъпни докато сървъра за самоличност е офлайн. Ако продължавате да виждате това предупреждение, проверете конфигурацията или се свържете с администратора на сървъра.",
"Unexpected error resolving identity server configuration": "Неочаквана грешка при откриване на конфигурацията на сървъра за самоличност",
"Use lowercase letters, numbers, dashes and underscores only": "Използвайте само малки букви, цифри, тирета и подчерта",
"<a>Log in</a> to your new account.": "<a>Влезте</a> в новия си профил.",
"Registration Successful": "Успешна регистрация",
"Upload all": "Качи всички",
"Your new account (%(newAccountId)s) is registered, but you're already logged into a different account (%(loggedInUserId)s).": "Новият ви профил (%(newAccountId)s) е регистриран, но вече сте влезли с друг профил (%(loggedInUserId)s).",
"Continue with previous account": "Продължи с предишния профил",
"Edited at %(date)s. Click to view edits.": "Редактирано на %(date)s. Кликнете за да видите редакциите.",
"Message edits": "Редакции на съобщение",
"Upgrading this room requires closing down the current instance of the room and creating a new room in its place. To give room members the best possible experience, we will:": "Обновяването на тази стая изисква затварянето на текущата и създаване на нова на нейно място. За да е най-удобно за членовете на стаята, ще:",
"%(severalUsers)smade no changes %(count)s times": {
"other": "%(severalUsers)sне направиха промени %(count)s пъти",
"one": "%(severalUsers)sне направиха промени"
},
"%(oneUser)smade no changes %(count)s times": {
"other": "%(oneUser)sне направи промени %(count)s пъти",
"one": "%(oneUser)sне направи промени"
},
"Please tell us what went wrong or, better, create a GitHub issue that describes the problem.": "Моля, кажете ни какво се обърка, или още по-добре - създайте проблем в GitHub обясняващ ситуацията.",
"Removing…": "Премахване…",
"Clear all data": "Изчисти всички данни",
@ -844,9 +734,6 @@
},
"Remove recent messages": "Премахни скорошни съобщения",
"Italics": "Наклонено",
"Please fill why you're reporting.": "Въведете защо докладвате.",
"Report Content to Your Homeserver Administrator": "Докладвай съдържание до администратора на сървъра",
"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.": "Докладването на съобщението ще изпрати уникалният номер на събитието (event ID) до администратора на сървъра. Ако съобщенията в стаята са шифровани, администратора няма да може да прочете текста им или да види снимките или файловете.",
"Explore rooms": "Открий стаи",
"Verify the link in your inbox": "Потвърдете линка във вашата пощенска кутия",
"Read Marker lifetime (ms)": "Живот на маркера за прочитане (мсек)",
@ -865,36 +752,15 @@
"check your browser plugins for anything that might block the identity server (such as Privacy Badger)": "проверите браузър добавките за всичко, което може да блокира връзката със сървъра за самоличност (например Privacy Badger)",
"contact the administrators of identity server <idserver />": "се свържете с администратора на сървъра за самоличност <idserver />",
"wait and try again later": "изчакате и опитате пак",
"Clear cache and reload": "Изчисти кеша и презареди",
"Your email address hasn't been verified yet": "Имейл адресът ви все още не е потвърден",
"Click the link in the email you received to verify and then click continue again.": "Кликнете на връзката получена по имейл за да потвърдите, а след това натиснете продължи отново.",
"Room %(name)s": "Стая %(name)s",
"%(count)s unread messages including mentions.": {
"other": "%(count)s непрочетени съобщения, включително споменавания.",
"one": "1 непрочетено споменаване."
},
"%(count)s unread messages.": {
"other": "%(count)s непрочетени съобщения.",
"one": "1 непрочетено съобщение."
},
"Unread messages.": "Непрочетени съобщения.",
"Failed to deactivate user": "Неуспешно деактивиране на потребител",
"This client does not support end-to-end encryption.": "Този клиент не поддържа шифроване от край до край.",
"Messages in this room are not end-to-end encrypted.": "Съобщенията в тази стая не са шифровани от край до край.",
"Message Actions": "Действия със съобщението",
"Show image": "Покажи снимката",
"Frequently Used": "Често използвани",
"Smileys & People": "Усмивки и хора",
"Animals & Nature": "Животни и природа",
"Food & Drink": "Храна и напитки",
"Activities": "Действия",
"Travel & Places": "Пътуване и места",
"Objects": "Обекти",
"Symbols": "Символи",
"Flags": "Знамена",
"Quick Reactions": "Бързи реакции",
"Cancel search": "Отмени търсенето",
"Please <newIssueLink>create a new issue</newIssueLink> on GitHub so that we can investigate this bug.": "Моля, <newIssueLink>отворете нов проблем</newIssueLink> в GitHub за да проучим проблема.",
"To continue you need to accept the terms of this service.": "За да продължите, трябва да приемете условията за ползване.",
"Document": "Документ",
"Missing captcha public key in homeserver configuration. Please report this to your homeserver administrator.": "Липсва публичния ключ за catcha в конфигурацията на сървъра. Съобщете това на администратора на сървъра.",
@ -916,30 +782,12 @@
"%(name)s cancelled": "%(name)s отказа",
"%(name)s wants to verify": "%(name)s иска да извърши потвърждение",
"You sent a verification request": "Изпратихте заявка за потвърждение",
"Match system theme": "Напасване със системната тема",
"My Ban List": "Моя списък с блокирания",
"This is your list of users/servers you have blocked - don't leave the room!": "Това е списък с хора/сървъри, които сте блокирали - не напускайте стаята!",
"Cannot connect to integration manager": "Неуспешна връзка с мениджъра на интеграции",
"The integration manager is offline or it cannot reach your homeserver.": "Мениджъра на интеграции е офлайн или не може да се свърже със сървъра ви.",
"Error upgrading room": "Грешка при обновяване на стаята",
"Double check that your server supports the room version chosen and try again.": "Проверете дали сървъра поддържа тази версия на стаята и опитайте пак.",
"%(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",
"%(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",
"Cross-signing public keys:": "Публични ключове за кръстосано-подписване:",
"not found": "не са намерени",
"Cross-signing private keys:": "Private ключове за кръстосано подписване:",
@ -1017,7 +865,6 @@
"The following users might not exist or are invalid, and cannot be invited: %(csvNames)s": "Следните потребители не съществуват или са невалидни и не могат да бъдат поканени: %(csvNames)s",
"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",
"Confirm adding email": "Потвърдете добавянето на имейл",
"Click the button below to confirm adding this email address.": "Кликнете бутона по-долу за да потвърдите добавянето на имейл адреса.",
"Confirm adding this phone number by using Single Sign On to prove your identity.": "Потвърдете добавянето на този телефонен номер като докажете идентичността си чрез използване на Single Sign On.",
@ -1034,14 +881,6 @@
"Session already verified!": "Сесията вече е потвърдена!",
"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. Сесията е маркирана като потвърдена.",
"%(senderName)s added the alternative addresses %(addresses)s for this room.": {
"other": "%(senderName)s добави алтернативните адреси %(addresses)s към стаята.",
"one": "%(senderName)s добави алтернативният адрес %(addresses)s към стаята."
},
"%(senderName)s removed the alternative addresses %(addresses)s for this room.": {
"other": "%(senderName)s премахна алтернативните адреси %(addresses)s от стаята.",
"one": "%(senderName)s премахна алтернативният адрес %(addresses)s от стаята."
},
"Not Trusted": "Недоверено",
"%(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.": "Поискайте от този потребител да потвърди сесията си, или я потвърдете ръчно по-долу.",
@ -1053,20 +892,12 @@
"New login. Was this you?": "Нов вход. Вие ли бяхте това?",
"%(name)s is requesting verification": "%(name)s изпрати запитване за верификация",
"Could not find user in room": "Неуспешно намиране на потребител в стаята",
"Please supply a widget URL or embed code": "Укажете URL адрес на приспособление или код за вграждане",
"Scan this unique code": "Сканирайте този уникален код",
"Compare unique emoji": "Сравнете уникални емоджи",
"Compare a unique set of emoji if you don't have a camera on either device": "Сравнете уникални емоджи, ако нямате камера на някое от устройствата",
"Waiting for %(displayName)s to verify…": "Изчакване на %(displayName)s да потвърди…",
"Cancelling…": "Отказване…",
"They match": "Съвпадат",
"They don't match": "Не съвпадат",
"To be secure, do this in person or use a trusted way to communicate.": "За да е по-сигурно, направете го на живо или използвайте доверен начин за комуникация.",
"Lock": "Заключи",
"Later": "По-късно",
"Other users may not trust it": "Други потребители може да не се доверят",
"This bridge was provisioned by <user />.": "Мостът е настроен от <user />.",
"Show less": "Покажи по-малко",
"Your homeserver does not support cross-signing.": "Сървърът ви не поддържа кръстосано-подписване.",
"Your account has a cross-signing identity in secret storage, but it is not yet trusted by this session.": "Профилът ви има самоличност за кръстосано подписване в секретно складиране, но все още не е доверено от тази сесия.",
"well formed": "коректен",
@ -1086,13 +917,6 @@
"Connect this session to Key Backup": "Свържи тази сесия с резервно копие на ключовете",
"This backup is trusted because it has been restored on this session": "Това резервно копие е доверено, защото е било възстановено в текущата сесия",
"Your keys are <b>not being backed up from this session</b>.": "На ключовете ви <b>не се прави резервно копие от тази сесия</b>.",
"Enable desktop notifications for this session": "Включи уведомления на работния плот за тази сесия",
"Enable audible notifications for this session": "Включи звукови уведомления за тази сесия",
"Invalid theme schema.": "Невалиден формат на темата.",
"Error downloading theme information.": "Неуспешно изтегляне на информацията за темата.",
"Theme added!": "Темата беше добавена!",
"Custom theme URL": "Собствен URL адрес на тема",
"Add theme": "Добави тема",
"To report a Matrix-related security issue, please read the Matrix.org <a>Security Disclosure Policy</a>.": "За да съобщените за проблем със сигурността свързан с Matrix, прочетете <a>Политиката за споделяне на проблеми със сигурността</a> на Matrix.org.",
"Session ID:": "Сесиен идентификатор:",
"Session key:": "Сесиен ключ:",
@ -1190,14 +1014,11 @@
"Something went wrong trying to invite the users.": "Нещо се обърка при опита да бъдат поканени потребителите.",
"We couldn't invite those users. Please check the users you want to invite and try again.": "Не можахме да поканим тези потребители. Проверете потребителите, които искате да поканите и опитайте пак.",
"Recently Direct Messaged": "Скорошни директни чатове",
"Opens chat with the given user": "Отваря чат с дадения потребител",
"Font size": "Размер на шрифта",
"IRC display name width": "Ширина на IRC името",
"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",
"You've successfully verified your device!": "Успешно потвърдихте устройството си!",
"QR Code": "QR код",
"To continue, use Single Sign On to prove your identity.": "За да продължите, използвайте Single Sign On за да потвърдите самоличността си.",
"Confirm to continue": "Потвърдете за да продължите",
"Click the button below to confirm your identity.": "Кликнете бутона по-долу за да потвърдите самоличността си.",
@ -1228,7 +1049,6 @@
"You don't have permission to delete the address.": "Нямате права да изтриете адреса.",
"There was an error removing that address. It may no longer exist or a temporary error occurred.": "Възникна грешка при премахването на този адрес. Или не съществува вече или е временен проблем.",
"Error removing address": "Грешка при премахването на адреса",
"Categories": "Категории",
"Room address": "Адрес на стаята",
"This address is available to use": "Адресът е наличен за ползване",
"This address is already in use": "Адресът вече се използва",
@ -1239,10 +1059,6 @@
"Successfully restored %(sessionCount)s keys": "Успешно бяха възстановени %(sessionCount)s ключа",
"Confirm your identity by entering your account password below.": "Потвърдете самоличността си чрез въвеждане на паролата за профила по-долу.",
"Sign in with SSO": "Влезте със SSO",
"Welcome to %(appName)s": "Добре дошли в %(appName)s",
"Send a Direct Message": "Изпрати директно съобщение",
"Explore Public Rooms": "Разгледай публичните стаи",
"Create a Group Chat": "Създай групов чат",
"Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.": "Администраторът на сървъра е изключил шифроване от край-до-край по подразбиране за лични стаи и за директни съобщения.",
"Switch to light mode": "Смени на светъл режим",
"Switch to dark mode": "Смени на тъмен режим",
@ -1271,45 +1087,11 @@
"Indexed rooms:": "Индексирани стаи:",
"%(doneRooms)s out of %(totalRooms)s": "%(doneRooms)s от %(totalRooms)s",
"Message downloading sleep time(ms)": "Период на пауза между свалянията на съобщения (ms)",
"Navigation": "Навигация",
"Calls": "Обаждания",
"Room List": "Списък със стаи",
"Autocomplete": "Подсказване",
"Toggle Bold": "Превключи удебеляването",
"Toggle Italics": "Превключи накланянето",
"Toggle Quote": "Превключи цитирането",
"New line": "Нов ред",
"Cancel replying to a message": "Отказване на отговарянето на съобщение",
"Toggle microphone mute": "Превключване на заглушаването на микрофона",
"Dismiss read marker and jump to bottom": "Игнориране на маркера за прочитане и отиване най-долу",
"Jump to oldest unread message": "Прескачане до най-старото непрочетено съобщение",
"Upload a file": "Качване на файл",
"Jump to room search": "Търсене на стаи",
"Select room from the room list": "Избор на стая от списъка",
"Collapse room list section": "Свиване на раздел със стаи",
"Expand room list section": "Разширение на раздел със стаи",
"Toggle the top left menu": "Превключва основното меню (горе в ляво)",
"Close dialog or context menu": "Затваряне на прозорец или контекстно меню",
"Activate selected button": "Активиране на избрания бутон",
"Toggle right panel": "Превключване на десния панел",
"Cancel autocomplete": "Отказване на подсказките",
"No recently visited rooms": "Няма наскоро-посетени стаи",
"Sort by": "Подреди по",
"Activity": "Активност",
"A-Z": "Азбучен ред",
"Show %(count)s more": {
"other": "Покажи още %(count)s",
"one": "Покажи още %(count)s"
},
"Use custom size": "Използвай собствен размер",
"Use a system font": "Използвай системния шрифт",
"System font name": "Име на системния шрифт",
"Hey you. You're the best!": "Хей, ти. Върхът си!",
"Customise your appearance": "Настройте изгледа",
"Appearance Settings only affect this %(brand)s session.": "Настройките на изгледа влияят само на тази %(brand)s сесия.",
"The authenticity of this encrypted message can't be guaranteed on this device.": "Автентичността на това шифровано съобщение не може да бъде гарантирана на това устройство.",
"Message preview": "Преглед на съобщението",
"List options": "Опции на списъка",
"Room options": "Настройки на стаята",
"Safeguard against losing access to encrypted messages & data": "Защитете се срещу загуба на достъп до криптирани съобшения и информация",
"Set up Secure Backup": "Конфигуриране на Защитен Архив",
@ -1385,13 +1167,9 @@
},
"Favourited": "В любими",
"Forget Room": "Забрави стаята",
"Notification options": "Настройки за уведомление",
"Show previews of messages": "Показвай преглед на съобщенията",
"Show rooms with unread messages first": "Показвай стаи с непрочетени съобщения първи",
"Explore public rooms": "Прегледай публични стаи",
"Show Widgets": "Покажи приспособленията",
"Hide Widgets": "Скрий приспособленията",
"Set the name of a font installed on your system & %(brand)s will attempt to use it.": "Настройте името на шрифт инсталиран в системата и %(brand)s ще се опита да го използва.",
"not ready": "не е готово",
"ready": "готово",
"Secret storage:": "Секретно складиране:",
@ -1420,31 +1198,18 @@
"Enter a Security Phrase": "Въведете фраза за сигурност",
"Generate a Security Key": "Генерирай ключ за сигурност",
"Safeguard against losing access to encrypted messages & data by backing up encryption keys on your server.": "Предпазете се от загуба на достъп до шифрованите съобщения и данни като направите резервно копие на ключовете за шифроване върху сървъра.",
"Now, let's help you get started": "Нека ви помогнем да започнете",
"Welcome %(name)s": "Добре дошли, %(name)s",
"Add a photo so people know it's you.": "Добавете снимка, за да може другите хора да знаят, че сте вие.",
"Great, that'll help people know it's you": "Чудесно, това ще позволи на хората да знаят, че сте вие",
"Attach files from chat or just drag and drop them anywhere in a room.": "Прикачете файлове от чата или ги издърпайте и пуснете в стаята.",
"No files visible in this room": "Няма видими файлове в тази стая",
"Search (must be enabled)": "Търсене (трябва да е включено)",
"Go to Home View": "Отиване на начален изглед",
"%(creator)s created this DM.": "%(creator)s създаде този директен чат.",
"You have no visible notifications.": "Нямате видими уведомления.",
"Got an account? <a>Sign in</a>": "Имате профил? <a>Влезте от тук</a>",
"New here? <a>Create an account</a>": "Вие сте нов тук? <a>Създайте профил</a>",
"There was a problem communicating with the homeserver, please try again later.": "Възникна проблем при комуникацията със Home сървъра, моля опитайте отново по-късно.",
"New? <a>Create account</a>": "Вие сте нов? <a>Създайте профил</a>",
"Continue with %(ssoButtons)s": "Продължаване с %(ssoButtons)s",
"%(ssoButtons)s Or %(usernamePassword)s": "%(ssoButtons)s Или %(usernamePassword)s",
"Already have an account? <a>Sign in here</a>": "Вече имате профил? <a>Влезте от тук</a>",
"This session has detected that your Security Phrase and key for Secure Messages have been removed.": "Тази сесия откри, че вашата фраза за сигурност и ключ за защитени съобщения бяха премахнати.",
"A new Security Phrase and key for Secure Messages have been detected.": "Новa фраза за сигурност и ключ за защитени съобщения бяха открити.",
"Great! This Security Phrase looks strong enough.": "Чудесно! Тази фраза за сигурност изглежда достатъчно силна.",
"Confirm your Security Phrase": "Потвърдете вашата фраза за сигурност",
"Converts the DM to a room": "Превръща директния чат в стая",
"Converts the room to a DM": "Превръща стаята в директен чат",
"Takes the call in the current room off hold": "Възстановява повикването в текущата стая",
"Places the call in the current room on hold": "Задържа повикването в текущата стая",
"We couldn't log you in": "Не можахме да ви впишем",
"You've reached the maximum number of simultaneous calls.": "Достигнахте максималният брой едновременни повиквания.",
"Anguilla": "Ангила",
@ -1715,12 +1480,6 @@
"Your private space": "Вашето лично пространство",
"You can change these anytime.": "Можете да ги промените по всяко време.",
"unknown person": "",
"sends snowfall": "изпраща снеговалеж",
"Sends the given message with snowfall": "Изпраща даденото съобщение със снеговалеж",
"Sends the given message with fireworks": "Изпраща даденото съобщение с фойерверки",
"sends fireworks": "изпраща фойерверки",
"sends confetti": "изпраща конфети",
"Sends the given message with confetti": "Изпраща даденото съобщение с конфети",
"Spaces": "Пространства",
"%(deviceId)s from %(ip)s": "%(deviceId)s от %(ip)s",
"Use app for a better experience": "Използвайте приложението за по-добра работа",
@ -1730,13 +1489,11 @@
"Invite to %(spaceName)s": "Покани в %(spaceName)s",
"We asked the browser to remember which homeserver you use to let you sign in, but unfortunately your browser has forgotten it. Go to the sign in page and try again.": "Помолихме браузъра да запомни кой Home сървър използвате за влизане, но за съжаление браузърът ви го е забравил. Отидете на страницата за влизане и опитайте отново.",
"Too Many Calls": "Твърде много повиквания",
"Integration manager": "Мениджър на интеграции",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.": "Вашият %(brand)s не позволява да използвате мениджъра на интеграции за да направите това. Свържете се с администратор.",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "Използването на това приспособление може да сподели данни <helpIcon /> с %(widgetDomain)s и с мениджъра на интеграции.",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Мениджърът на интеграции получава конфигурационни данни, може да модифицира приспособления, да изпраща покани за стаи и да настройва нива на достъп от ваше име.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "Използвай мениджър на интеграции за управление на ботове, приспособления и стикери.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Използвай мениджър на интеграции <b>%(serverName)s</b> за управление на ботове, приспособления и стикери.",
"Identity server": "Сървър за самоличност",
"Identity server (%(server)s)": "Сървър за самоличност (%(server)s)",
"Could not connect to identity server": "Неуспешна връзка със сървъра за самоличност",
"Not a valid identity server (status code %(code)s)": "Невалиден сървър за самоличност (статус код %(code)s)",
@ -1821,7 +1578,10 @@
"stickerpack": "Пакет със стикери",
"system_alerts": "Системни уведомления",
"secure_backup": "Защитено резервно копие",
"cross_signing": "Кръстосано-подписване"
"cross_signing": "Кръстосано-подписване",
"identity_server": "Сървър за самоличност",
"integration_manager": "Мениджър на интеграции",
"qr_code": "QR код"
},
"action": {
"continue": "Продължи",
@ -1902,14 +1662,29 @@
"send_report": "Изпрати доклад"
},
"a11y": {
"user_menu": "Потребителско меню"
"user_menu": "Потребителско меню",
"n_unread_messages_mentions": {
"other": "%(count)s непрочетени съобщения, включително споменавания.",
"one": "1 непрочетено споменаване."
},
"n_unread_messages": {
"other": "%(count)s непрочетени съобщения.",
"one": "1 непрочетено съобщение."
},
"unread_messages": "Непрочетени съобщения."
},
"labs": {
"pinning": "Функция за закачане на съобщения",
"state_counters": "Визуализирай прости броячи в заглавието на стаята",
"custom_themes": "Включи поддръжка за добавяне на собствени теми",
"dehydration": "Офлайн шифровани съобщения чрез използването на дехидратирани устройства",
"bridge_state": "Показвай информация за връзки с други мрежи в настройките на стаята"
"bridge_state": "Показвай информация за връзки с други мрежи в настройките на стаята",
"group_profile": "Профил",
"group_spaces": "Пространства",
"group_widgets": "Приспособления",
"group_rooms": "Стаи",
"group_voip": "Глас и видео",
"group_encryption": "Шифроване"
},
"keyboard": {
"home": "Начална страница",
@ -1921,7 +1696,31 @@
"end": "End",
"alt": "Alt",
"control": "Ctrl",
"shift": "Shift"
"shift": "Shift",
"category_calls": "Обаждания",
"category_room_list": "Списък със стаи",
"category_navigation": "Навигация",
"category_autocomplete": "Подсказване",
"composer_toggle_bold": "Превключи удебеляването",
"composer_toggle_italics": "Превключи накланянето",
"composer_toggle_quote": "Превключи цитирането",
"cancel_reply": "Отказване на отговарянето на съобщение",
"toggle_microphone_mute": "Превключване на заглушаването на микрофона",
"dismiss_read_marker_and_jump_bottom": "Игнориране на маркера за прочитане и отиване най-долу",
"jump_to_read_marker": "Прескачане до най-старото непрочетено съобщение",
"upload_file": "Качване на файл",
"jump_room_search": "Търсене на стаи",
"room_list_select_room": "Избор на стая от списъка",
"room_list_collapse_section": "Свиване на раздел със стаи",
"room_list_expand_section": "Разширение на раздел със стаи",
"toggle_top_left_menu": "Превключва основното меню (горе в ляво)",
"toggle_right_panel": "Превключване на десния панел",
"go_home_view": "Отиване на начален изглед",
"autocomplete_cancel": "Отказване на подсказките",
"close_dialog_menu": "Затваряне на прозорец или контекстно меню",
"activate_button": "Активиране на избрания бутон",
"composer_new_line": "Нов ред",
"search": "Търсене (трябва да е включено)"
},
"composer": {
"format_bold": "Удебелено",
@ -1955,7 +1754,8 @@
"collecting_information": "Събиране на информация за версията на приложението",
"collecting_logs": "Събиране на логове",
"uploading_logs": "Качване на логове",
"downloading_logs": "Изтегляне на логове"
"downloading_logs": "Изтегляне на логове",
"create_new_issue": "Моля, <newIssueLink>отворете нов проблем</newIssueLink> в GitHub за да проучим проблема."
},
"time": {
"date_at_time": "%(date)s в %(time)s",
@ -2009,7 +1809,25 @@
"rule_call": "Покана за разговор",
"rule_suppress_notices": "Съобщения изпратени от бот",
"rule_tombstone": "Когато стаите се актуализират",
"rule_encrypted_room_one_to_one": "Шифровани съобщения в 1-на-1 чатове"
"rule_encrypted_room_one_to_one": "Шифровани съобщения в 1-на-1 чатове",
"enable_desktop_notifications_session": "Включи уведомления на работния плот за тази сесия",
"show_message_desktop_notification": "Показване на съдържание в известията на работния плот",
"enable_audible_notifications_session": "Включи звукови уведомления за тази сесия"
},
"appearance": {
"heading": "Настройте изгледа",
"subheading": "Настройките на изгледа влияят само на тази %(brand)s сесия.",
"match_system_theme": "Напасване със системната тема",
"custom_font": "Използвай системния шрифт",
"custom_font_name": "Име на системния шрифт",
"custom_theme_invalid": "Невалиден формат на темата.",
"custom_theme_error_downloading": "Неуспешно изтегляне на информацията за темата.",
"custom_theme_success": "Темата беше добавена!",
"custom_theme_url": "Собствен URL адрес на тема",
"custom_theme_add_button": "Добави тема",
"font_size": "Размер на шрифта",
"custom_font_description": "Настройте името на шрифт инсталиран в системата и %(brand)s ще се опита да го използва.",
"timeline_image_size_default": "По подразбиране"
}
},
"devtools": {
@ -2061,7 +1879,15 @@
"removed": "%(senderName)s премахна основния адрес на тази стая.",
"changed_alternative": "%(senderName)s промени алтернативните адреси на стаята.",
"changed_main_and_alternative": "%(senderName)s промени основният и алтернативните адреси на стаята.",
"changed": "%(senderName)s промени адресите на стаята."
"changed": "%(senderName)s промени адресите на стаята.",
"alt_added": {
"other": "%(senderName)s добави алтернативните адреси %(addresses)s към стаята.",
"one": "%(senderName)s добави алтернативният адрес %(addresses)s към стаята."
},
"alt_removed": {
"other": "%(senderName)s премахна алтернативните адреси %(addresses)s от стаята.",
"one": "%(senderName)s премахна алтернативният адрес %(addresses)s от стаята."
}
},
"m.room.third_party_invite": {
"revoked": "%(senderName)s премахна покана към %(targetDisplayName)s за присъединяване в стаята.",
@ -2094,6 +1920,120 @@
},
"m.call.hangup": {
"dm": "Разговора приключи"
},
"summary": {
"format": "%(nameList)s %(transitionList)s",
"joined_multiple": {
"other": "%(severalUsers)sсе присъединиха %(count)s пъти",
"one": "%(severalUsers)sсе присъединиха"
},
"joined": {
"other": "%(oneUser)sсе присъедини %(count)s пъти",
"one": "%(oneUser)sсе присъедини"
},
"left_multiple": {
"other": "%(severalUsers)sнапуснаха %(count)s пъти",
"one": "%(severalUsers)sнапуснаха"
},
"left": {
"other": "%(oneUser)sнапусна %(count)s пъти",
"one": "%(oneUser)sнапусна"
},
"joined_and_left_multiple": {
"other": "%(severalUsers)sсе присъединиха и напуснаха %(count)s пъти",
"one": "%(severalUsers)sсе присъединиха и напуснаха"
},
"joined_and_left": {
"other": "%(oneUser)sсе присъедини и напусна %(count)s пъти",
"one": "%(oneUser)sсе присъедини и напусна"
},
"rejoined_multiple": {
"other": "%(severalUsers)sнапуснаха и се присъединиха отново %(count)s пъти",
"one": "%(severalUsers)sнапуснаха и се присъединиха отново"
},
"rejoined": {
"other": "%(oneUser)sнапусна и се присъедини отново %(count)s пъти",
"one": "%(oneUser)sнапусна и се присъедини отново"
},
"rejected_invite_multiple": {
"other": "%(severalUsers)sотхвърлиха своите покани %(count)s пъти",
"one": "%(severalUsers)sотхвърлиха своите покани"
},
"rejected_invite": {
"other": "%(oneUser)sотхвърли своята покана %(count)s пъти",
"one": "%(oneUser)sотхвърли своята покана"
},
"invite_withdrawn_multiple": {
"other": "%(severalUsers)sоттеглиха своите покани %(count)s пъти",
"one": "%(severalUsers)sоттеглиха своите покани"
},
"invite_withdrawn": {
"other": "%(oneUser)sоттегли своята покана %(count)s пъти",
"one": "%(oneUser)sоттегли своята покана"
},
"invited_multiple": {
"other": "бяха поканени %(count)s пъти",
"one": "бяха поканени"
},
"invited": {
"other": "беше поканен %(count)s пъти",
"one": "беше поканен"
},
"banned_multiple": {
"other": "бяха блокирани %(count)s пъти",
"one": "бяха блокирани"
},
"banned": {
"other": "беше блокиран %(count)s пъти",
"one": "беше блокиран"
},
"unbanned_multiple": {
"other": "бяха отблокирани %(count)s пъти",
"one": "бяха отблокирани"
},
"unbanned": {
"other": "беше отблокиран %(count)s пъти",
"one": "беше отблокиран"
},
"changed_name_multiple": {
"other": "%(severalUsers)sсмениха своето име %(count)s пъти",
"one": "%(severalUsers)sсмениха своето име"
},
"changed_name": {
"other": "%(oneUser)sсмени своето име %(count)s пъти",
"one": "%(oneUser)sсмени своето име"
},
"no_change_multiple": {
"other": "%(severalUsers)sне направиха промени %(count)s пъти",
"one": "%(severalUsers)sне направиха промени"
},
"no_change": {
"other": "%(oneUser)sне направи промени %(count)s пъти",
"one": "%(oneUser)sне направи промени"
}
},
"m.room.power_levels": {
"changed": "%(senderName)s смени нивото на достъп на %(powerLevelDiffText)s.",
"user_from_to": "%(userId)s от %(fromPowerLevel)s на %(toPowerLevel)s"
},
"mjolnir": {
"removed_rule_users": "%(senderName)s премахна правилото блокиращо достъпа на потребители отговарящи на %(glob)s",
"removed_rule_rooms": "%(senderName)s премахна правилото блокиращо достъпа до стаи отговарящи на %(glob)s",
"removed_rule_servers": "%(senderName)s премахна правилото блокиращо достъпа до сървъри отговарящи на %(glob)s",
"removed_rule": "%(senderName)s премахна правилото блокиращо достъпа неща отговарящи на %(glob)s",
"updated_invalid_rule": "%(senderName)s промени невалидно правило за блокиране",
"updated_rule_users": "%(senderName)s промени правилото блокиращо достъпа на потребители отговарящи на %(glob)s поради %(reason)s",
"updated_rule_rooms": "%(senderName)s промени правилото блокиращо достъпа до стаи отговарящи на %(glob)s поради %(reason)s",
"updated_rule_servers": "%(senderName)s промени правилото блокиращо достъпа до сървъри отговарящи на %(glob)s поради %(reason)s",
"updated_rule": "%(senderName)s промени правило блокиращо достъпа неща отговарящи на %(glob)s поради %(reason)s",
"created_rule_users": "%(senderName)s създаде правило блокиращо достъпа на потребители отговарящи на %(glob)s поради %(reason)s",
"created_rule_rooms": "%(senderName)s създаде правило блокиращо достъпа до стаи отговарящи на %(glob)s поради %(reason)s",
"created_rule_servers": "%(senderName)s създаде правило блокиращо достъпа до сървъри отговарящи на %(glob)s поради %(reason)s",
"created_rule": "%(senderName)s създаде правило блокиращо достъпа до неща отговарящи на %(glob)s поради %(reason)s",
"changed_rule_users": "%(senderName)s промени правило блокиращо достъпа на потребители отговарящи на %(oldGlob)s към отговарящи на %(newGlob)s поради %(reason)s",
"changed_rule_rooms": "%(senderName)s промени правило блокиращо достъпа до стаи отговарящи на %(oldGlob)s към отговарящи на %(newGlob)s поради %(reason)s",
"changed_rule_servers": "%(senderName)s промени правило блокиращо достъпа до сървъри отговарящи на %(oldGlob)s към отговарящи на %(newGlob)s поради %(reason)s",
"changed_rule_glob": "%(senderName)s промени правило блокиращо достъпа до неща отговарящи на %(oldGlob)s към отговарящи на %(newGlob)s поради %(reason)s"
}
},
"slash_command": {
@ -2131,7 +2071,17 @@
"category_admin": "Администратор",
"category_advanced": "Разширени",
"category_effects": "Ефекти",
"category_other": "Други"
"category_other": "Други",
"addwidget_missing_url": "Укажете URL адрес на приспособление или код за вграждане",
"addwidget_invalid_protocol": "Моля, укажете https:// или http:// адрес на приспособление",
"addwidget_no_permissions": "Не можете да модифицирате приспособления в тази стая.",
"converttodm": "Превръща стаята в директен чат",
"converttoroom": "Превръща директния чат в стая",
"discardsession": "Принудително прекратява текущата изходяща групова сесия в шифрована стая",
"query": "Отваря чат с дадения потребител",
"holdcall": "Задържа повикването в текущата стая",
"unholdcall": "Възстановява повикването в текущата стая",
"me": "Показва действие"
},
"presence": {
"online_for": "Онлайн от %(duration)s",
@ -2183,7 +2133,6 @@
"unsupported": "Обажданията не се поддържат",
"unsupported_browser": "Не можете да провеждате обаждания в този браузър."
},
"Messages": "Съобщения",
"Other": "Други",
"Advanced": "Разширени",
"room_settings": {
@ -2205,5 +2154,93 @@
"redact": "Премахвай съобщения изпратени от други",
"notifications.room": "Уведомяване на всички"
}
},
"encryption": {
"verification": {
"sas_no_match": "Не съвпадат",
"sas_match": "Съвпадат",
"in_person": "За да е по-сигурно, направете го на живо или използвайте доверен начин за комуникация.",
"other_party_cancelled": "Другата страна прекрати потвърждението.",
"complete_title": "Потвърдено!",
"complete_description": "Успешно потвърдихте този потребител.",
"qr_prompt": "Сканирайте този уникален код",
"sas_prompt": "Сравнете уникални емоджи",
"sas_description": "Сравнете уникални емоджи, ако нямате камера на някое от устройствата"
}
},
"emoji": {
"category_frequently_used": "Често използвани",
"category_smileys_people": "Усмивки и хора",
"category_animals_nature": "Животни и природа",
"category_food_drink": "Храна и напитки",
"category_activities": "Действия",
"category_travel_places": "Пътуване и места",
"category_objects": "Обекти",
"category_symbols": "Символи",
"category_flags": "Знамена",
"categories": "Категории",
"quick_reactions": "Бързи реакции"
},
"chat_effects": {
"confetti_description": "Изпраща даденото съобщение с конфети",
"confetti_message": "изпраща конфети",
"fireworks_description": "Изпраща даденото съобщение с фойерверки",
"fireworks_message": "изпраща фойерверки",
"snowfall_description": "Изпраща даденото съобщение със снеговалеж",
"snowfall_message": "изпраща снеговалеж"
},
"auth": {
"sign_in_with_sso": "Влезте посредством single-sign-on",
"sso": "Single Sign On",
"continue_with_sso": "Продължаване с %(ssoButtons)s",
"sso_or_username_password": "%(ssoButtons)s Или %(usernamePassword)s",
"sign_in_instead": "Вече имате профил? <a>Влезте от тук</a>",
"account_clash": "Новият ви профил (%(newAccountId)s) е регистриран, но вече сте влезли с друг профил (%(loggedInUserId)s).",
"account_clash_previous_account": "Продължи с предишния профил",
"log_in_new_account": "<a>Влезте</a> в новия си профил.",
"registration_successful": "Успешна регистрация"
},
"export_chat": {
"messages": "Съобщения"
},
"room_list": {
"sort_unread_first": "Показвай стаи с непрочетени съобщения първи",
"show_previews": "Показвай преглед на съобщенията",
"sort_by": "Подреди по",
"sort_by_activity": "Активност",
"sort_by_alphabet": "Азбучен ред",
"sublist_options": "Опции на списъка",
"show_n_more": {
"other": "Покажи още %(count)s",
"one": "Покажи още %(count)s"
},
"show_less": "Покажи по-малко",
"notification_options": "Настройки за уведомление"
},
"report_content": {
"missing_reason": "Въведете защо докладвате.",
"report_content_to_homeserver": "Докладвай съдържание до администратора на сървъра",
"description": "Докладването на съобщението ще изпрати уникалният номер на събитието (event ID) до администратора на сървъра. Ако съобщенията в стаята са шифровани, администратора няма да може да прочете текста им или да види снимките или файловете."
},
"onboarding": {
"has_avatar_label": "Чудесно, това ще позволи на хората да знаят, че сте вие",
"no_avatar_label": "Добавете снимка, за да може другите хора да знаят, че сте вие.",
"welcome_user": "Добре дошли, %(name)s",
"welcome_detail": "Нека ви помогнем да започнете",
"intro_welcome": "Добре дошли в %(appName)s",
"send_dm": "Изпрати директно съобщение",
"explore_rooms": "Разгледай публичните стаи",
"create_room": "Създай групов чат"
},
"setting": {
"help_about": {
"brand_version": "Версия на %(brand)s:",
"help_link": "За помощ при използването на %(brand)s, кликнете <a>тук</a>.",
"help_link_chat_bot": "За помощ при използването на %(brand)s, кликнете <a>тук</a> или започнете чат с бота ни използвайки бутона по-долу.",
"chat_bot": "Чати с %(brand)s Bot",
"title": "Помощ и относно",
"versions": "Версии",
"clear_cache_reload": "Изчисти кеша и презареди"
}
}
}

View File

@ -1,4 +1,6 @@
{
"Integration manager": "ইন্টিগ্রেশন ম্যানেজার",
"Identity server": "পরিচয় সার্ভার"
"common": {
"identity_server": "পরিচয় সার্ভার",
"integration_manager": "ইন্টিগ্রেশন ম্যানেজার"
}
}

View File

@ -1,4 +1,6 @@
{
"Integration manager": "ইন্টিগ্রেশন ম্যানেজার",
"Identity server": "পরিচয় সার্ভার"
"common": {
"identity_server": "পরিচয় সার্ভার",
"integration_manager": "ইন্টিগ্রেশন ম্যানেজার"
}
}

View File

@ -1,9 +1,11 @@
{
"Create Account": "Otvori račun",
"Explore rooms": "Istražite sobe",
"Identity server": "Identifikacioni Server",
"action": {
"dismiss": "Odbaci",
"sign_in": "Prijavite se"
},
"common": {
"identity_server": "Identifikacioni Server"
}
}

View File

@ -67,8 +67,6 @@
"You are no longer ignoring %(userId)s": "Ja no estàs ignorant l'usuari %(userId)s",
"Verified key": "Claus verificades",
"Reason": "Raó",
"%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s de %(fromPowerLevel)s a %(toPowerLevel)s",
"%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s ha canviat el nivell d'autoritat de %(powerLevelDiffText)s.",
"Failure to create room": "No s'ha pogut crear la sala",
"Server may be unavailable, overloaded, or you hit a bug.": "És possible que el servidor no estigui disponible, sobrecarregat o que hagi topat amb un error.",
"Send": "Envia",
@ -176,87 +174,6 @@
"Deleting a widget removes it for all users in this room. Are you sure you want to delete this widget?": "La supressió d'un giny l'elimina per a tots els usuaris d'aquesta sala. Esteu segur que voleu eliminar aquest giny?",
"Delete widget": "Suprimeix el giny",
"Home": "Inici",
"%(nameList)s %(transitionList)s": "%(nameList)s %(transitionList)s",
"%(severalUsers)sjoined %(count)s times": {
"one": "%(severalUsers)s s'hi han unit",
"other": "%(severalUsers)s han entrat %(count)s vegades"
},
"%(oneUser)sjoined %(count)s times": {
"one": "%(oneUser)ss'ha unit",
"other": "%(oneUser)sha entrat %(count)s vegades"
},
"%(severalUsers)sleft %(count)s times": {
"one": "%(severalUsers)s han sortit",
"other": "%(severalUsers)s han sortit %(count)s vegades"
},
"%(oneUser)sleft %(count)s times": {
"one": "%(oneUser)sha sortit",
"other": "%(oneUser)sha sortit %(count)s vegades"
},
"%(severalUsers)sjoined and left %(count)s times": {
"other": "%(severalUsers)s s'hi han unit i han sortit %(count)s vegades",
"one": "%(severalUsers)s s'hi han unit i han sortit"
},
"%(oneUser)sjoined and left %(count)s times": {
"other": "%(oneUser)sha entrat i ha sortit %(count)s vegades",
"one": "%(oneUser)sha entrat i ha sortit"
},
"%(severalUsers)sleft and rejoined %(count)s times": {
"other": "%(severalUsers)s han sortit i han tornat a entrar %(count)s vegades",
"one": "%(severalUsers)s han sortit i han tornat a entrar"
},
"%(oneUser)sleft and rejoined %(count)s times": {
"other": "%(oneUser)sha sortit i ha tornat a entrar %(count)s vegades",
"one": "%(oneUser)sha sortit i ha tornat a entrar"
},
"%(severalUsers)srejected their invitations %(count)s times": {
"other": "%(severalUsers)s han rebutjat les seves invitacions %(count)s vegades",
"one": "%(severalUsers)s han rebutjat les seves invitacions"
},
"%(oneUser)srejected their invitation %(count)s times": {
"other": "%(oneUser)sha rebutjat la seva invitació %(count)s vegades",
"one": "%(oneUser)sha rebutjat la seva invitació"
},
"%(severalUsers)shad their invitations withdrawn %(count)s times": {
"other": "S'han retirat les invitacions de %(severalUsers)s %(count)s vegades",
"one": "S'han retirat les invitacions de %(severalUsers)s"
},
"%(oneUser)shad their invitation withdrawn %(count)s times": {
"other": "S'ha retirat la invitació de %(oneUser)s %(count)s vegades",
"one": "S'ha retirat la invitació de %(oneUser)s"
},
"were invited %(count)s times": {
"other": "a sigut invitat %(count)s vegades",
"one": "han sigut convidats"
},
"was invited %(count)s times": {
"other": "ha sigut convidat %(count)s vegades",
"one": "ha sigut convidat"
},
"were banned %(count)s times": {
"other": "han sigut expulsats %(count)s vegades",
"one": "ha sigut expulsat"
},
"was banned %(count)s times": {
"other": "ha sigut expulsat %(count)s vegades",
"one": "ha sigut expulsat"
},
"were unbanned %(count)s times": {
"other": "han sigut readmesos %(count)s vegades",
"one": "han sigut readmesos"
},
"was unbanned %(count)s times": {
"other": "ha sigut readmès %(count)s vegades",
"one": "ha sigut readmès"
},
"%(severalUsers)schanged their name %(count)s times": {
"other": "%(severalUsers)s han canviat el seu nom %(count)s vegades",
"one": "%(severalUsers)s han canviat el seu nom"
},
"%(oneUser)schanged their name %(count)s times": {
"other": "%(oneUser)sha canviat el seu nom %(count)s vegades",
"one": "%(oneUser)s ha canviat el seu nom"
},
"%(items)s and %(count)s others": {
"other": "%(items)s i %(count)s altres",
"one": "%(items)s i un altre"
@ -310,7 +227,6 @@
"Uploading %(filename)s": "Pujant %(filename)s",
"Import E2E room keys": "Importar claus E2E de sala",
"Cryptography": "Criptografia",
"%(brand)s version:": "Versió de %(brand)s:",
"Incorrect username and/or password.": "Usuari i/o contrasenya incorrectes.",
"Session ID": "ID de la sessió",
"Export room keys": "Exporta les claus de la sala",
@ -346,7 +262,6 @@
"You cannot delete this message. (%(code)s)": "No podeu eliminar aquest missatge. (%(code)s)",
"Thursday": "Dijous",
"Logs sent": "Logs enviats",
"Show message in desktop notification": "Mostra els missatges amb notificacions d'escriptori",
"Yesterday": "Ahir",
"Error encountered (%(errorDetail)s).": "S'ha trobat un error (%(errorDetail)s).",
"Low Priority": "Baixa prioritat",
@ -359,7 +274,6 @@
"Missing roomId.": "Falta l'ID de sala.",
"Define the power level of a user": "Defineix el nivell d'autoritat d'un usuari",
"Deops user with given id": "Degrada l'usuari amb l'id donat",
"Displays action": "Mostra l'acció",
"The file '%(fileName)s' exceeds this homeserver's size limit for uploads": "El fitxer %(fileName)s supera la mida màxima permesa per a pujades d'aquest servidor",
"You do not have permission to invite people to this room.": "No teniu permís per convidar gent a aquesta sala.",
"Use a few words, avoid common phrases": "Feu servir unes quantes paraules, eviteu frases comunes",
@ -419,7 +333,6 @@
"Error removing ignored user/server": "Error eliminant usuari/servidor ignorat",
"Error subscribing to list": "Error subscrivint-se a la llista",
"Error adding ignored user/server": "Error afegint usuari/servidor ignorat",
"Error downloading theme information.": "Error baixant informació de tema.",
"Unexpected server error trying to leave the room": "Error de servidor inesperat intentant sortir de la sala",
"Error leaving room": "Error sortint de la sala",
"Unexpected error resolving identity server configuration": "Error inesperat resolent la configuració del servidor d'identitat",
@ -460,7 +373,6 @@
"Confirm this user's session by comparing the following with their User Settings:": "Confirma aquesta sessió d'usuari comparant amb la seva configuració d'usuari, el següent:",
"Confirm by comparing the following with the User Settings in your other session:": "Confirma comparant el següent amb la configuració d'usuari de la teva altra sessió:",
"Room settings": "Configuració de sala",
"Appearance Settings only affect this %(brand)s session.": "La configuració d'aspecte només afecta aquesta sessió %(brand)s.",
"Change notification settings": "Canvia la configuració de notificacions",
"⚠ These settings are meant for advanced users.": "⚠ Aquesta configuració està pensada per usuaris avançats.",
"Link this email with your account in Settings to receive invites directly in %(brand)s.": "Per rebre invitacions directament a %(brand)s, enllaça aquest correu electrònic amb el teu compte a Configuració.",
@ -478,21 +390,13 @@
"Confirm your account deactivation by using Single Sign On to prove your identity.": "Confirma la desactivació del teu compte mitjançant la inscripció única SSO (per demostrar la teva identitat).",
"Confirm adding this phone number by using Single Sign On to prove your identity.": "Confirma l'addició d'aquest número de telèfon mitjançant la inscripció única SSO (per demostrar la teva identitat).",
"Confirm adding this email address by using Single Sign On to prove your identity.": "Confirma l'addició d'aquest correu electrònic mitjançant la inscripció única SSO (per demostrar la teva identitat).",
"Sign in with single sign-on": "Inicia sessió mitjançant la inscripció única (SSO)",
"Single Sign On": "Inscripció única (SSO)",
"Use Single Sign On to continue": "Utilitza la inscripció única (SSO) per a continuar",
"Click the button below to confirm adding this phone number.": "Fes clic al botó de sota per confirmar l'addició d'aquest número de telèfon.",
"Confirm adding phone number": "Confirma l'addició del número de telèfon",
"Add Email Address": "Afegeix una adreça de correu electrònic",
"Click the button below to confirm adding this email address.": "Fes clic al botó de sota per confirmar l'addició d'aquesta adreça de correu electrònic.",
"Explore rooms": "Explora sales",
"%(oneUser)smade no changes %(count)s times": {
"one": "%(oneUser)sno ha fet canvis",
"other": "%(oneUser)sno ha fet canvis %(count)s cops"
},
"Integration manager": "Gestor d'integracions",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Els gestors d'integracions reben dades de configuració i poden modificar ginys, enviar invitacions a sales i establir nivells d'autoritat en nom teu.",
"Identity server": "Servidor d'identitat",
"Could not connect to identity server": "No s'ha pogut connectar amb el servidor d'identitat",
"common": {
"analytics": "Analítiques",
@ -517,7 +421,9 @@
"camera": "Càmera",
"microphone": "Micròfon",
"someone": "Algú",
"unnamed_room": "Sala sense nom"
"unnamed_room": "Sala sense nom",
"identity_server": "Servidor d'identitat",
"integration_manager": "Gestor d'integracions"
},
"action": {
"continue": "Continua",
@ -562,7 +468,8 @@
},
"labs": {
"pinning": "Fixació de missatges",
"bridge_state": "Mostra informació d'enllaços a la configuració de sala"
"bridge_state": "Mostra informació d'enllaços a la configuració de sala",
"group_rooms": "Sales"
},
"keyboard": {
"home": "Inici"
@ -597,7 +504,13 @@
"rule_message": "Missatges en xats de grup",
"rule_invite_for_me": "Quan sóc convidat a una sala",
"rule_call": "Invitació de trucada",
"rule_suppress_notices": "Missatges enviats pel bot"
"rule_suppress_notices": "Missatges enviats pel bot",
"show_message_desktop_notification": "Mostra els missatges amb notificacions d'escriptori"
},
"appearance": {
"subheading": "La configuració d'aspecte només afecta aquesta sessió %(brand)s.",
"custom_theme_error_downloading": "Error baixant informació de tema.",
"timeline_image_size_default": "Predeterminat"
}
},
"devtools": {
@ -657,6 +570,97 @@
"other": "%(names)s i %(count)s més estan escrivint…",
"one": "%(names)s i una altra persona estan escrivint…"
}
},
"summary": {
"format": "%(nameList)s %(transitionList)s",
"joined_multiple": {
"one": "%(severalUsers)s s'hi han unit",
"other": "%(severalUsers)s han entrat %(count)s vegades"
},
"joined": {
"one": "%(oneUser)ss'ha unit",
"other": "%(oneUser)sha entrat %(count)s vegades"
},
"left_multiple": {
"one": "%(severalUsers)s han sortit",
"other": "%(severalUsers)s han sortit %(count)s vegades"
},
"left": {
"one": "%(oneUser)sha sortit",
"other": "%(oneUser)sha sortit %(count)s vegades"
},
"joined_and_left_multiple": {
"other": "%(severalUsers)s s'hi han unit i han sortit %(count)s vegades",
"one": "%(severalUsers)s s'hi han unit i han sortit"
},
"joined_and_left": {
"other": "%(oneUser)sha entrat i ha sortit %(count)s vegades",
"one": "%(oneUser)sha entrat i ha sortit"
},
"rejoined_multiple": {
"other": "%(severalUsers)s han sortit i han tornat a entrar %(count)s vegades",
"one": "%(severalUsers)s han sortit i han tornat a entrar"
},
"rejoined": {
"other": "%(oneUser)sha sortit i ha tornat a entrar %(count)s vegades",
"one": "%(oneUser)sha sortit i ha tornat a entrar"
},
"rejected_invite_multiple": {
"other": "%(severalUsers)s han rebutjat les seves invitacions %(count)s vegades",
"one": "%(severalUsers)s han rebutjat les seves invitacions"
},
"rejected_invite": {
"other": "%(oneUser)sha rebutjat la seva invitació %(count)s vegades",
"one": "%(oneUser)sha rebutjat la seva invitació"
},
"invite_withdrawn_multiple": {
"other": "S'han retirat les invitacions de %(severalUsers)s %(count)s vegades",
"one": "S'han retirat les invitacions de %(severalUsers)s"
},
"invite_withdrawn": {
"other": "S'ha retirat la invitació de %(oneUser)s %(count)s vegades",
"one": "S'ha retirat la invitació de %(oneUser)s"
},
"invited_multiple": {
"other": "a sigut invitat %(count)s vegades",
"one": "han sigut convidats"
},
"invited": {
"other": "ha sigut convidat %(count)s vegades",
"one": "ha sigut convidat"
},
"banned_multiple": {
"other": "han sigut expulsats %(count)s vegades",
"one": "ha sigut expulsat"
},
"banned": {
"other": "ha sigut expulsat %(count)s vegades",
"one": "ha sigut expulsat"
},
"unbanned_multiple": {
"other": "han sigut readmesos %(count)s vegades",
"one": "han sigut readmesos"
},
"unbanned": {
"other": "ha sigut readmès %(count)s vegades",
"one": "ha sigut readmès"
},
"changed_name_multiple": {
"other": "%(severalUsers)s han canviat el seu nom %(count)s vegades",
"one": "%(severalUsers)s han canviat el seu nom"
},
"changed_name": {
"other": "%(oneUser)sha canviat el seu nom %(count)s vegades",
"one": "%(oneUser)s ha canviat el seu nom"
},
"no_change": {
"one": "%(oneUser)sno ha fet canvis",
"other": "%(oneUser)sno ha fet canvis %(count)s cops"
}
},
"m.room.power_levels": {
"changed": "%(senderName)s ha canviat el nivell d'autoritat de %(powerLevelDiffText)s.",
"user_from_to": "%(userId)s de %(fromPowerLevel)s a %(toPowerLevel)s"
}
},
"slash_command": {
@ -683,7 +687,8 @@
"category_actions": "Accions",
"category_admin": "Administrador",
"category_advanced": "Avançat",
"category_other": "Altres"
"category_other": "Altres",
"me": "Mostra l'acció"
},
"presence": {
"online_for": "En línia durant %(duration)s",
@ -704,7 +709,6 @@
"unable_to_access_microphone": "No s'ha pogut accedir al micròfon",
"unable_to_access_media": "No s'ha pogut accedir a la càmera web / micròfon"
},
"Messages": "Missatges",
"Other": "Altres",
"Advanced": "Avançat",
"composer": {
@ -715,5 +719,17 @@
"permissions": {
"state_default": "Canvia la configuració"
}
},
"auth": {
"sign_in_with_sso": "Inicia sessió mitjançant la inscripció única (SSO)",
"sso": "Inscripció única (SSO)"
},
"export_chat": {
"messages": "Missatges"
},
"setting": {
"help_about": {
"brand_version": "Versió de %(brand)s:"
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -6,9 +6,11 @@
"Add Phone Number": "Ychwanegu Rhif Ffôn",
"Create Account": "Creu Cyfrif",
"Explore rooms": "Archwilio Ystafelloedd",
"Identity server": "Gweinydd Adnabod",
"action": {
"dismiss": "Wfftio",
"sign_in": "Mewngofnodi"
},
"common": {
"identity_server": "Gweinydd Adnabod"
}
}

View File

@ -7,7 +7,6 @@
"A new password must be entered.": "Der skal indtastes en ny adgangskode.",
"The email address linked to your account must be entered.": "Den emailadresse, der tilhører til din adgang, skal indtastes.",
"Session ID": "Sessions ID",
"Displays action": "Viser handling",
"Deops user with given id": "Fjerner OP af bruger med givet id",
"Commands": "Kommandoer",
"Warning!": "Advarsel!",
@ -108,7 +107,6 @@
"All Rooms": "Alle rum",
"You cannot delete this message. (%(code)s)": "Du kan ikke slette denne besked. (%(code)s)",
"Thursday": "Torsdag",
"Show message in desktop notification": "Vis besked i skrivebordsnotifikation",
"Yesterday": "I går",
"Error encountered (%(errorDetail)s).": "En fejl er opstået (%(errorDetail)s).",
"Low Priority": "Lav prioritet",
@ -134,11 +132,6 @@
"Use an identity server to invite by email. Click continue to use the default identity server (%(defaultIdentityServerName)s) or manage in Settings.": "Brug en identitetsserver for at invitere pr. mail. Tryk på Fortsæt for at bruge den almindelige identitetsserver (%(defaultIdentityServerName)s) eller indtast en anden under Indstillinger.",
"Use an identity server to invite by email. Manage in Settings.": "Brug en identitetsserver for at invitere pr. mail. Administrer dette under Indstillinger.",
"Define the power level of a user": "Indstil rettighedsniveau for en bruger",
"Please supply a https:// or http:// widget URL": "Oplys venligst en https:// eller http:// widget URL",
"You cannot modify widgets in this room.": "Du kan ikke ændre widgets i dette rum.",
"Forces the current outbound group session in an encrypted room to be discarded": "Tvinger den nuværende udgående gruppe-session i et krypteret rum til at blive kasseret",
"%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s fra %(fromPowerLevel)s til %(toPowerLevel)s",
"%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s ændrede rettighedsniveau af %(powerLevelDiffText)s.",
"Cannot reach homeserver": "Homeserveren kan ikke kontaktes",
"Ensure you have a stable internet connection, or get in touch with the server admin": "Vær sikker at du har en stabil internetforbindelse, eller kontakt serveradministratoren",
"Your %(brand)s is misconfigured": "Din %(brand)s er konfigureret forkert",
@ -197,7 +190,6 @@
"Add Phone Number": "Tilføj telefonnummer",
"Use Single Sign On to continue": "Brug engangs login for at fortsætte",
"Confirm adding this email address by using Single Sign On to prove your identity.": "Bekræft tilføjelsen af denne email adresse ved at bruge Single Sign On til at bevise din identitet.",
"Single Sign On": "Engangs login",
"Confirm adding email": "Bekræft tilføjelse af email",
"Click the button below to confirm adding this email address.": "Klik på knappen herunder for at bekræfte tilføjelsen af denne email adresse.",
"Confirm adding this phone number by using Single Sign On to prove your identity.": "Bekræft tilføjelsen af dette telefonnummer ved at bruge Single Sign On til at bevise din identitet.",
@ -222,49 +214,25 @@
"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!": "ADVARSEL: NØGLEVERIFIKATIONEN FEJLEDE! Underskriftsnøglen for %(userId)s og session %(deviceId)s er %(fprint)s som ikke matcher den supplerede nøgle \"%(fingerprint)s\". Dette kunne betyde at jeres kommunikation er infiltreret!",
"Session already verified!": "Sessionen er allerede verificeret!",
"The signing key you provided matches the signing key you received from %(userId)s's session %(deviceId)s. Session marked as verified.": "Underskriftsnøglen du supplerede matcher den underskriftsnøgle du modtog fra %(userId)s's session %(deviceId)s. Sessionen er markeret som verificeret.",
"%(senderName)s added the alternative addresses %(addresses)s for this room.": {
"other": "%(senderName)s tilføjede de alternative adresser %(addresses)s til dette rum.",
"one": "%(senderName)s tilføjede alternative adresser %(addresses)s til dette rum."
},
"%(senderName)s removed the alternative addresses %(addresses)s for this room.": {
"other": "%(senderName)s fjernede de alternative adresser %(addresses)s til dette rum.",
"one": "%(senderName)s fjernede alternative adresser %(addresses)s til dette rum."
},
"%(senderName)s removed the rule banning users matching %(glob)s": "%(senderName)s fjernede den regel der bannede brugere der matcher %(glob)s",
"%(senderName)s removed the rule banning rooms matching %(glob)s": "%(senderName)s fjernede den regel der bannede brugere der matcher %(glob)s",
"%(senderName)s removed the rule banning servers matching %(glob)s": "%(senderName)s fjernede den regel der bannede servere som matcher %(glob)s",
"%(senderName)s removed a ban rule matching %(glob)s": "%(senderName)s fjernede en ban-regel der matcher %(glob)s",
"%(senderName)s updated an invalid ban rule": "%(senderName)s opdaterede en ugyldig ban-regel",
"%(senderName)s updated the rule banning users matching %(glob)s for %(reason)s": "%(senderName)s opdaterede den regel der banner brugere som matcher %(glob)s på grund af %(reason)s",
"%(senderName)s updated the rule banning rooms matching %(glob)s for %(reason)s": "%(senderName)s opdaterede den regel der banner rum som matcher %(glob)s på grund af %(reason)s",
"%(senderName)s updated the rule banning servers matching %(glob)s for %(reason)s": "%(senderName)s opdaterede den regel der banner servere der matcher %(glob)s på grund af %(reason)s",
"%(senderName)s updated a ban rule matching %(glob)s for %(reason)s": "%(senderName)s opdaterede en ban-regel der matcher %(glob)s på grund af %(reason)s",
"Explore rooms": "Udforsk rum",
"Verification code": "Verifikationskode",
"Once enabled, encryption cannot be disabled.": "Efter aktivering er det ikke muligt at slå kryptering fra.",
"Security & Privacy": "Sikkerhed & Privatliv",
"Who can read history?": "Hvem kan læse historikken?",
"Enable encryption?": "Aktiver kryptering?",
"Create a Group Chat": "Opret en gruppechat",
"Explore Public Rooms": "Udforsk offentlige rum",
"Send a Direct Message": "Send en Direkte Besked",
"Permissions": "Tilladelser",
"Headphones": "Hovedtelefoner",
"Show more": "Vis mere",
"Show less": "Vis mindre",
"Passwords don't match": "Adgangskoderne matcher ikke",
"Confirm password": "Bekræft adgangskode",
"Enter password": "Indtast adgangskode",
"Add a new server": "Tilføj en ny server",
"Change notification settings": "Skift notifikations indstillinger",
"Verified!": "Bekræftet!",
"Profile picture": "Profil billede",
"Categories": "Kategorier",
"Checking server": "Tjekker server",
"You're signed out": "Du er logget ud",
"Change Password": "Skift adgangskode",
"Current password": "Nuværende adgangskode",
"Theme added!": "Tema tilføjet!",
"Comment": "Kommentar",
"Please enter a name for the room": "Indtast et navn for rummet",
"Profile": "Profil",
@ -608,7 +576,9 @@
},
"labs": {
"pinning": "Fastgørelse af beskeder",
"state_counters": "Vis simple tællere i rumhovedet"
"state_counters": "Vis simple tællere i rumhovedet",
"group_profile": "Profil",
"group_rooms": "Rum"
},
"power_level": {
"default": "Standard",
@ -635,7 +605,12 @@
"rule_message": "Beskeder i gruppechats",
"rule_invite_for_me": "Når jeg bliver inviteret til et rum",
"rule_call": "Opkalds invitation",
"rule_suppress_notices": "Beskeder sendt af en bot"
"rule_suppress_notices": "Beskeder sendt af en bot",
"show_message_desktop_notification": "Vis besked i skrivebordsnotifikation"
},
"appearance": {
"custom_theme_success": "Tema tilføjet!",
"timeline_image_size_default": "Standard"
}
},
"devtools": {
@ -677,7 +652,15 @@
"removed": "%(senderName)s fjernede hovedadressen for dette rum.",
"changed_alternative": "%(senderName)s ændrede de alternative adresser til dette rum.",
"changed_main_and_alternative": "%(senderName)s ændrede hoved- og alternative adresser til dette rum.",
"changed": "%(senderName)s ændrede adresserne til dette rum."
"changed": "%(senderName)s ændrede adresserne til dette rum.",
"alt_added": {
"other": "%(senderName)s tilføjede de alternative adresser %(addresses)s til dette rum.",
"one": "%(senderName)s tilføjede alternative adresser %(addresses)s til dette rum."
},
"alt_removed": {
"other": "%(senderName)s fjernede de alternative adresser %(addresses)s til dette rum.",
"one": "%(senderName)s fjernede alternative adresser %(addresses)s til dette rum."
}
},
"m.room.third_party_invite": {
"revoked": "%(senderName)s tilbagetrak invitationen til %(targetDisplayName)s om at deltage i rummet.",
@ -707,6 +690,21 @@
"other": "%(names)s og %(count)s andre skriver …",
"one": "%(names)s og en anden skriver …"
}
},
"m.room.power_levels": {
"changed": "%(senderName)s ændrede rettighedsniveau af %(powerLevelDiffText)s.",
"user_from_to": "%(userId)s fra %(fromPowerLevel)s til %(toPowerLevel)s"
},
"mjolnir": {
"removed_rule_users": "%(senderName)s fjernede den regel der bannede brugere der matcher %(glob)s",
"removed_rule_rooms": "%(senderName)s fjernede den regel der bannede brugere der matcher %(glob)s",
"removed_rule_servers": "%(senderName)s fjernede den regel der bannede servere som matcher %(glob)s",
"removed_rule": "%(senderName)s fjernede en ban-regel der matcher %(glob)s",
"updated_invalid_rule": "%(senderName)s opdaterede en ugyldig ban-regel",
"updated_rule_users": "%(senderName)s opdaterede den regel der banner brugere som matcher %(glob)s på grund af %(reason)s",
"updated_rule_rooms": "%(senderName)s opdaterede den regel der banner rum som matcher %(glob)s på grund af %(reason)s",
"updated_rule_servers": "%(senderName)s opdaterede den regel der banner servere der matcher %(glob)s på grund af %(reason)s",
"updated_rule": "%(senderName)s opdaterede en ban-regel der matcher %(glob)s på grund af %(reason)s"
}
},
"slash_command": {
@ -739,7 +737,11 @@
"category_admin": "Administrator",
"category_advanced": "Avanceret",
"category_effects": "Effekter",
"category_other": "Andre"
"category_other": "Andre",
"addwidget_invalid_protocol": "Oplys venligst en https:// eller http:// widget URL",
"addwidget_no_permissions": "Du kan ikke ændre widgets i dette rum.",
"discardsession": "Tvinger den nuværende udgående gruppe-session i et krypteret rum til at blive kasseret",
"me": "Viser handling"
},
"presence": {
"online": "Online"
@ -755,7 +757,6 @@
"m.text": "%(senderName)s: %(message)s",
"m.sticker": "%(senderName)s: %(stickerName)s"
},
"Messages": "Beskeder",
"Other": "Andre",
"Advanced": "Avanceret",
"composer": {
@ -776,5 +777,27 @@
"already_in_call_person": "Du har allerede i et opkald med denne person.",
"unsupported": "Opkald er ikke understøttet",
"unsupported_browser": "Du kan ikke lave opkald i denne browser."
},
"encryption": {
"verification": {
"complete_title": "Bekræftet!"
}
},
"emoji": {
"categories": "Kategorier"
},
"auth": {
"sso": "Engangs login"
},
"export_chat": {
"messages": "Beskeder"
},
"room_list": {
"show_less": "Vis mindre"
},
"onboarding": {
"send_dm": "Send en Direkte Besked",
"explore_rooms": "Udforsk offentlige rum",
"create_room": "Opret en gruppechat"
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,6 @@
"Banned users": "Banned users",
"Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or <a>enable unsafe scripts</a>.": "Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or <a>enable unsafe scripts</a>.",
"Change Password": "Change Password",
"%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s changed the power level of %(powerLevelDiffText)s.",
"Command error": "Command error",
"Commands": "Commands",
"Confirm password": "Confirm password",
@ -34,7 +33,6 @@
"Deops user with given id": "Deops user with given id",
"Default": "Default",
"Delete widget": "Delete widget",
"Displays action": "Displays action",
"Download %(text)s": "Download %(text)s",
"Email": "Email",
"Email address": "Email address",
@ -57,7 +55,6 @@
"Filter room members": "Filter room members",
"Forget room": "Forget room",
"For security, this session has been signed out. Please sign in again.": "For security, this session has been signed out. Please sign in again.",
"%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s",
"Historical": "Historical",
"Import E2E room keys": "Import E2E room keys",
"Incorrect username and/or password.": "Incorrect username and/or password.",
@ -98,7 +95,6 @@
"Return to login screen": "Return to login screen",
"%(brand)s does not have permission to send you notifications - please check your browser settings": "%(brand)s does not have permission to send you notifications - please check your browser settings",
"%(brand)s was not given permission to send notifications - please try again": "%(brand)s was not given permission to send notifications - please try again",
"%(brand)s version:": "%(brand)s version:",
"Room %(roomId)s not visible": "Room %(roomId)s not visible",
"Rooms": "Rooms",
"Search failed": "Search failed",
@ -264,7 +260,6 @@
"%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s",
"Restricted": "Restricted",
"Missing roomId.": "Missing roomId.",
"Forces the current outbound group session in an encrypted room to be discarded": "Forces the current outbound group session in an encrypted room to be discarded",
"Spanner": "Wrench",
"Aeroplane": "Airplane",
"Cat": "Cat",
@ -273,8 +268,6 @@
"The file '%(fileName)s' exceeds this homeserver's size limit for uploads": "The file '%(fileName)s' exceeds this homeserver's size limit for uploads",
"The server does not support the room version specified.": "The server does not support the room version specified.",
"Unable to load! Check your network connectivity and try again.": "Unable to load! Check your network connectivity and try again.",
"Please supply a https:// or http:// widget URL": "Please supply an https:// or http:// widget URL",
"You cannot modify widgets in this room.": "You cannot modify widgets in this room.",
"Your %(brand)s is misconfigured": "Your %(brand)s is misconfigured",
"Call failed due to misconfigured server": "Call failed due to misconfigured server",
"Please ask the administrator of your homeserver (<code>%(homeserverDomain)s</code>) to configure a TURN server in order for calls to work reliably.": "Please ask the administrator of your homeserver (<code>%(homeserverDomain)s</code>) to configure a TURN server in order for calls to work reliably.",
@ -299,11 +292,9 @@
"Explore rooms": "Explore rooms",
"Click the button below to confirm adding this email address.": "Click the button below to confirm adding this email address.",
"Confirm adding email": "Confirm adding email",
"Single Sign On": "Single Sign On",
"Confirm adding this email address by using Single Sign On to prove your identity.": "Confirm adding this email address by using Single Sign On to prove your identity.",
"Use Single Sign On to continue": "Use Single Sign On to continue",
"%(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 now uses 3-5x less memory, by only loading information about other users when needed. Please wait while we resynchronize with the server!",
"Customise your appearance": "Customize your appearance",
"Unrecognised command: %(commandText)s": "Unrecognized command: %(commandText)s",
"Add some details to help people recognise it.": "Add some details to help people recognize it.",
"A private space to organise your rooms": "A private space to organize your rooms",
@ -406,6 +397,10 @@
"rule_invite_for_me": "When I'm invited to a room",
"rule_call": "Call invitation",
"rule_suppress_notices": "Messages sent by bot"
},
"appearance": {
"heading": "Customize your appearance",
"timeline_image_size_default": "Default"
}
},
"timeline": {
@ -454,6 +449,10 @@
"more_users": {
"other": "%(names)s and %(count)s others are typing …"
}
},
"m.room.power_levels": {
"changed": "%(senderName)s changed the power level of %(powerLevelDiffText)s.",
"user_from_to": "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s"
}
},
"slash_command": {
@ -482,7 +481,11 @@
"category_actions": "Actions",
"category_admin": "Admin",
"category_advanced": "Advanced",
"category_other": "Other"
"category_other": "Other",
"addwidget_invalid_protocol": "Please supply an https:// or http:// widget URL",
"addwidget_no_permissions": "You cannot modify widgets in this room.",
"discardsession": "Forces the current outbound group session in an encrypted room to be discarded",
"me": "Displays action"
},
"presence": {
"online": "Online",
@ -504,7 +507,21 @@
"category_room": "Room",
"category_other": "Other"
},
"Messages": "Messages",
"Other": "Other",
"Advanced": "Advanced"
"Advanced": "Advanced",
"labs": {
"group_profile": "Profile",
"group_rooms": "Rooms"
},
"auth": {
"sso": "Single Sign On"
},
"export_chat": {
"messages": "Messages"
},
"setting": {
"help_about": {
"brand_version": "%(brand)s version:"
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -65,7 +65,6 @@
"Deactivate Account": "Itxi kontua",
"Decrypt %(text)s": "Deszifratu %(text)s",
"Default": "Lehenetsia",
"Displays action": "Ekintza bistaratzen du",
"%(items)s and %(lastItem)s": "%(items)s eta %(lastItem)s",
"Download %(text)s": "Deskargatu %(text)s",
"Error decrypting attachment": "Errorea eranskina deszifratzean",
@ -80,10 +79,8 @@
"Failed to unban": "Huts egin du debekua kentzean",
"Failure to create room": "Huts egin du gela sortzean",
"Forget room": "Ahaztu gela",
"%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s %(fromPowerLevel)s mailatik %(toPowerLevel)s mailara",
"Can't connect to homeserver - please check your connectivity, ensure your <a>homeserver's SSL certificate</a> is trusted, and that a browser extension is not blocking requests.": "Ezin da hasiera zerbitzarira konektatu, egiaztatu zure konexioa, ziurtatu zure <a>hasiera zerbitzariaren SSL ziurtagiria</a> fidagarritzat jotzen duela zure gailuak, eta nabigatzailearen pluginen batek ez dituela eskaerak blokeatzen.",
"Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or <a>enable unsafe scripts</a>.": "Ezin zara hasiera zerbitzarira HTTP bidez konektatu zure nabigatzailearen barran dagoen URLa HTTS bada. Erabili HTTPS edo <a>gaitu script ez seguruak</a>.",
"%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s erabiltzaileak botere mailaz aldatu du %(powerLevelDiffText)s.",
"Incorrect username and/or password.": "Erabiltzaile-izen edo pasahitz okerra.",
"Incorrect verification code": "Egiaztaketa kode okerra",
"Invalid Email Address": "E-mail helbide baliogabea",
@ -110,7 +107,6 @@
"Reject all %(invitedRooms)s invites": "Baztertu %(invitedRooms)s gelarako gonbidapen guztiak",
"%(brand)s does not have permission to send you notifications - please check your browser settings": "%(brand)sek ez du zuri jakinarazpenak bidaltzeko baimenik, egiaztatu nabigatzailearen ezarpenak",
"%(brand)s was not given permission to send notifications - please try again": "Ez zaio jakinarazpenak bidaltzeko baimena eman %(brand)si, saiatu berriro",
"%(brand)s version:": "%(brand)s bertsioa:",
"Room %(roomId)s not visible": "%(roomId)s gela ez dago ikusgai",
"%(roomName)s does not exist.": "Ez dago %(roomName)s izeneko gela.",
"%(roomName)s is not accessible at this time.": "%(roomName)s ez dago eskuragarri orain.",
@ -250,38 +246,6 @@
"URL previews are disabled by default for participants in this room.": "URLen aurrebistak desgaituta daude gela honetako partaideentzat.",
"A text message has been sent to %(msisdn)s": "Testu mezu bat bidali da hona: %(msisdn)s",
"Jump to read receipt": "Saltatu irakurragirira",
"was banned %(count)s times": {
"one": "debekatua izan da",
"other": "%(count)s aldiz debekatuak izan dira"
},
"were invited %(count)s times": {
"other": "%(count)s aldiz gonbidatuak izan dira",
"one": "gonbidatuak izan dira"
},
"was invited %(count)s times": {
"other": "%(count)s aldiz gonbidatua izan da",
"one": "gonbidatua izan da"
},
"were banned %(count)s times": {
"other": "%(count)s aldiz debekatuak izan dira",
"one": "debekatuak izan dira"
},
"were unbanned %(count)s times": {
"other": "%(count)s aldiz kendu zaie debekua",
"one": "debekua kendu zaie"
},
"was unbanned %(count)s times": {
"other": "%(count)s aldiz kendu zaio debekua",
"one": "debekua kendu zaio"
},
"%(severalUsers)schanged their name %(count)s times": {
"other": "%(severalUsers)s erabiltzaileek bere izena aldatu dute %(count)s aldiz",
"one": "%(severalUsers)s erabiltzaileek bere izena aldatu dute"
},
"%(oneUser)schanged their name %(count)s times": {
"other": "%(oneUser)s erabiltzaileak bere izena aldatu du %(count)s aldiz",
"one": "%(oneUser)s erabiltzaileak bere izena aldatu du"
},
"collapse": "tolestu",
"expand": "hedatu",
"And %(count)s more...": {
@ -289,55 +253,6 @@
},
"Delete Widget": "Ezabatu trepeta",
"Deleting a widget removes it for all users in this room. Are you sure you want to delete this widget?": "Trepeta ezabatzean gelako kide guztientzat kentzen da. Ziur trepeta ezabatu nahi duzula?",
"%(nameList)s %(transitionList)s": "%(nameList)s%(transitionList)s",
"%(severalUsers)sjoined %(count)s times": {
"other": "%(severalUsers)s %(count)s aldiz elkartu dira",
"one": "%(severalUsers)s elkartu dira"
},
"%(oneUser)sjoined %(count)s times": {
"other": "%(oneUser)s%(count)s aldiz elkartu da",
"one": "%(oneUser)s elkartu da"
},
"%(severalUsers)sleft %(count)s times": {
"other": "%(severalUsers)s%(count)s aldiz atera dira",
"one": "%(severalUsers)s atera dira"
},
"%(oneUser)sleft %(count)s times": {
"other": "%(oneUser)s%(count)s aldiz atera da",
"one": "%(oneUser)s atera da"
},
"%(severalUsers)sjoined and left %(count)s times": {
"other": "%(severalUsers)s elkartu eta atera dira %(count)s aldiz",
"one": "%(severalUsers)s elkartu eta atera dira"
},
"%(oneUser)sjoined and left %(count)s times": {
"other": "%(oneUser)s elkartu eta atera da %(count)s aldiz",
"one": "%(oneUser)s elkartu eta atera da"
},
"%(severalUsers)sleft and rejoined %(count)s times": {
"other": "%(severalUsers)s atera eta berriz elkartu dira %(count)s aldiz",
"one": "%(severalUsers)s atera eta berriz elkartu da"
},
"%(oneUser)sleft and rejoined %(count)s times": {
"other": "%(oneUser)s atera eta berriz elkartu da %(count)s aldiz",
"one": "%(oneUser)s atera eta berriz elkartu da"
},
"%(severalUsers)srejected their invitations %(count)s times": {
"other": "%(severalUsers)s erabiltzaileek bere gonbidapenak ukatu dituzte %(count)s aldiz",
"one": "%(severalUsers)s erabiltzaileek bere gonbidapenak ukatu dituzte"
},
"%(oneUser)srejected their invitation %(count)s times": {
"other": "%(oneUser)s erabiltzaileak bere gonbidapena ukatu du %(count)s aldiz",
"one": "%(oneUser)s erabiltzaileak bere gonbidapena ukatu du"
},
"%(severalUsers)shad their invitations withdrawn %(count)s times": {
"other": "%(severalUsers)s erabiltzaileei gonbidapena indargabetu zaie %(count)s aldiz",
"one": "%(severalUsers)s erabiltzaileei gonbidapena indargabetu zaie"
},
"%(oneUser)shad their invitation withdrawn %(count)s times": {
"other": "%(oneUser)s erabiltzaileari gonbidapena indargabetu zaio %(count)s aldiz",
"one": "%(oneUser)s erabiltzaileari gonbidapena indargabetu zaio"
},
"%(items)s and %(count)s others": {
"other": "%(items)s eta beste %(count)s",
"one": "%(items)s eta beste bat"
@ -379,7 +294,6 @@
"Thursday": "Osteguna",
"Search…": "Bilatu…",
"Logs sent": "Egunkariak bidalita",
"Show message in desktop notification": "Erakutsi mezua mahaigaineko jakinarazpenean",
"Yesterday": "Atzo",
"Error encountered (%(errorDetail)s).": "Errorea aurkitu da (%(errorDetail)s).",
"Low Priority": "Lehentasun baxua",
@ -436,7 +350,6 @@
"Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. Please <a>contact your service administrator</a> to continue using the service.": "Zure mezua ez da bidali zure hasiera zerbitzariak hilabeteko erabiltzaile aktiboen muga jo duelako. <a>Jarri kontaktuan zerbitzuaren administratzailearekin</a> zerbitzua erabiltzen jarraitzeko.",
"Your message wasn't sent because this homeserver has exceeded a resource limit. Please <a>contact your service administrator</a> to continue using the service.": "Zure mezua ez da bidali zure hasiera zerbitzariak baliabide mugaren bat jo duelako. <a>Jarri kontaktuan zerbitzuaren administratzailearekin</a> zerbitzua erabiltzen jarraitzeko.",
"Please <a>contact your service administrator</a> to continue using this service.": "<a>Jarri kontaktuan zerbitzuaren administratzailearekin</a> zerbitzu hau erabiltzen jarraitzeko.",
"Forces the current outbound group session in an encrypted room to be discarded": "Uneko irteerako talde saioa zifratutako gela batean baztertzera behartzen du",
"Before submitting logs, you must <a>create a GitHub issue</a> to describe your problem.": "Egunkariak bidali aurretik, <a>GitHub arazo bat sortu</a> behar duzu gertatzen zaizuna azaltzeko.",
"%(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-ek orain 3-5 aldiz memoria gutxiago darabil, beste erabiltzaileen informazioa behar denean besterik ez kargatzen. Itxaron zerbitzariarekin sinkronizatzen garen bitartean!",
"Updating %(brand)s": "%(brand)s eguneratzen",
@ -460,7 +373,6 @@
"Unable to restore backup": "Ezin izan da babes-kopia berrezarri",
"No backup found!": "Ez da babes-kopiarik aurkitu!",
"Failed to decrypt %(failedCount)s sessions!": "Ezin izan dira %(failedCount)s saio deszifratu!",
"Sign in with single sign-on": "Hai saioa urrats batean",
"Failed to perform homeserver discovery": "Huts egin du hasiera-zerbitzarien bilaketak",
"Invalid homeserver discovery response": "Baliogabeko hasiera-zerbitzarien bilaketaren erantzuna",
"Use a few words, avoid common phrases": "Erabili hitz gutxi batzuk, ekidin ohiko esaldiak",
@ -506,9 +418,6 @@
"Invite anyway and never warn me again": "Gonbidatu edonola ere eta ez abisatu inoiz gehiago",
"Invite anyway": "Gonbidatu hala ere",
"The file '%(fileName)s' exceeds this homeserver's size limit for uploads": "'%(fileName)s' fitxategiak igoerarako hasiera-zerbitzari honek duen tamaina muga gainditzen du",
"The other party cancelled the verification.": "Beste parteak egiaztaketa ezeztatu du.",
"Verified!": "Egiaztatuta!",
"You've successfully verified this user.": "Ongi egiaztatu duzu erabiltzaile hau.",
"Got It": "Ulertuta",
"Dog": "Txakurra",
"Cat": "Katua",
@ -569,11 +478,6 @@
"Phone numbers": "Telefono zenbakiak",
"Language and region": "Hizkuntza eta eskualdea",
"Account management": "Kontuen kudeaketa",
"For help with using %(brand)s, click <a>here</a>.": "%(brand)s erabiltzeko laguntza behar baduzu, egin klik <a>hemen</a>.",
"For help with using %(brand)s, click <a>here</a> or start a chat with our bot using the button below.": "%(brand)s erabiltzeko laguntza behar baduzu, egin klik <a>hemen</a> edo hasi txat bat gure botarekin beheko botoia sakatuz.",
"Chat with %(brand)s Bot": "Txateatu %(brand)s botarekin",
"Help & About": "Laguntza eta honi buruz",
"Versions": "Bertsioak",
"Room list": "Gelen zerrenda",
"Autocomplete delay (ms)": "Automatikoki osatzeko atzerapena (ms)",
"Roles & Permissions": "Rolak eta baimenak",
@ -652,7 +556,6 @@
"Power level": "Botere maila",
"Room Settings - %(roomName)s": "Gelaren ezarpenak - %(roomName)s",
"Could not load user profile": "Ezin izan da erabiltzaile-profila kargatu",
"You cannot modify widgets in this room.": "Ezin dituzu gela honetako trepetak aldatu.",
"Upgrade this room to the recommended room version": "Bertsio-berritu gela hau aholkatutako bertsiora",
"Upgrading this room will shut down the current instance of the room and create an upgraded room with the same name.": "Gela hau bertsio-berritzeak gelaren oraingo instantzia itzaliko du eta izen bereko beste gela berri bat sortuko du.",
"Failed to revoke invite": "Gonbidapena indargabetzeak huts egin du",
@ -665,7 +568,6 @@
},
"The file '%(fileName)s' failed to upload.": "Huts egin du '%(fileName)s' fitxategia igotzean.",
"The server does not support the room version specified.": "Zerbitzariak ez du emandako gela-bertsioa onartzen.",
"Please supply a https:// or http:// widget URL": "Eman https:// edo http:// motako trepetaren URL-a",
"Cannot reach homeserver": "Ezin izan da hasiera-zerbitzaria atzitu",
"Ensure you have a stable internet connection, or get in touch with the server admin": "Baieztatu Internet konexio egonkor bat duzula, edo jarri kontaktuan zerbitzariaren administratzailearekin",
"Your %(brand)s is misconfigured": "Zure %(brand)s gaizki konfiguratuta dago",
@ -742,22 +644,10 @@
"Failed to get autodiscovery configuration from server": "Huts egin du aurkikuntza automatikoaren konfigurazioa zerbitzaritik eskuratzean",
"Invalid base_url for m.homeserver": "Baliogabeko base_url m.homeserver zerbitzariarentzat",
"Invalid base_url for m.identity_server": "Baliogabeko base_url m.identity_server zerbitzariarentzat",
"<a>Log in</a> to your new account.": "<a>Hasi saioa</a> zure kontu berrian.",
"Registration Successful": "Ongi erregistratuta",
"Upload all": "Igo denak",
"Your new account (%(newAccountId)s) is registered, but you're already logged into a different account (%(loggedInUserId)s).": "Zure kontu berria (%(newAccountId)s) erregistratuta dago, baina dagoeneko saioa hasi duzu beste kontu batekin (%(loggedInUserId)s).",
"Continue with previous account": "Jarraitu aurreko kontuarekin",
"Upgrading this room requires closing down the current instance of the room and creating a new room in its place. To give room members the best possible experience, we will:": "Gela hau bertsio-berritzeak gelaren oraingo instantzia itzaliko du eta izen bereko beste gela berri bat sortuko du. Kideei esperientziarik onena emateko, hau egingo dugu:",
"Edited at %(date)s. Click to view edits.": "Edizio data: %(date)s. Sakatu edizioak ikusteko.",
"Message edits": "Mezuaren edizioak",
"%(severalUsers)smade no changes %(count)s times": {
"other": "%(severalUsers)s erabiltzaileek ez dute aldaketarik egin %(count)s aldiz",
"one": "%(severalUsers)s erabiltzaileek ez dute aldaketarik egin"
},
"%(oneUser)smade no changes %(count)s times": {
"other": "%(oneUser)s erabiltzaileak ez du aldaketarik egin %(count)s aldiz",
"one": "%(oneUser)s erabiltzaileak ez du aldaketarik egin"
},
"Removing…": "Kentzen…",
"Clear all data": "Garbitu datu guztiak",
"Your homeserver doesn't seem to support this feature.": "Antza zure hasiera-zerbitzariak ez du ezaugarri hau onartzen.",
@ -824,7 +714,6 @@
"If you don't want to use <server /> to discover and be discoverable by existing contacts you know, enter another identity server below.": "Ez baduzu <server /> erabili nahi jendea aurkitzeko eta zure kontaktuek zu aurkitzeko, idatzi beste identitate-zerbitzari bat behean.",
"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.": "Identitate-zerbitzari bat erabiltzea aukerazkoa da. Identitate-zerbitzari bat ez erabiltzea erabakitzen baduzu, ezin izango zaituztete e-mail edo telefonoa erabilita aurkitu eta ezin izango dituzu besteak e-mail edo telefonoa erabiliz gonbidatu.",
"Agree to the identity server (%(serverName)s) Terms of Service to allow yourself to be discoverable by email address or phone number.": "Onartu %(serverName)s identitate-zerbitzariaren erabilera baldintzak besteek zu e-mail helbidea edo telefonoa erabiliz aurkitzea ahalbidetzeko.",
"Clear cache and reload": "Garbitu cachea eta birkargatu",
"Read Marker lifetime (ms)": "Orri-markagailuaren biziraupena (ms)",
"Read Marker off-screen lifetime (ms)": "Orri-markagailuaren biziraupena pantailaz kanpo (ms)",
"Error changing power level requirement": "Errorea botere-maila eskaria aldatzean",
@ -848,16 +737,7 @@
"This invite to %(roomName)s was sent to %(email)s which is not associated with your account": "%(roomName)s gelarako gonbidapena zure kontuarekin lotuta ez dagoen %(email)s helbidera bidali da",
"Use an identity server in Settings to receive invites directly in %(brand)s.": "Erabili identitate zerbitzari bat ezarpenetan gonbidapenak zuzenean %(brand)s-en jasotzeko.",
"Share this email in Settings to receive invites directly in %(brand)s.": "Partekatu e-mail hau ezarpenetan gonbidapenak zuzenean %(brand)s-en jasotzeko.",
"%(count)s unread messages including mentions.": {
"other": "irakurri gabeko %(count)s mezu aipamenak barne.",
"one": "Irakurri gabeko aipamen 1."
},
"%(count)s unread messages.": {
"other": "irakurri gabeko %(count)s mezu.",
"one": "Irakurri gabeko mezu 1."
},
"Show image": "Erakutsi irudia",
"Please <newIssueLink>create a new issue</newIssueLink> on GitHub so that we can investigate this bug.": "<newIssueLink>Sortu txosten berri bat</newIssueLink> GitHub zerbitzarian arazo hau ikertu dezagun.",
"e.g. my-room": "adib. nire-gela",
"Use an identity server to invite by email. <default>Use the default (%(defaultIdentityServerName)s)</default> or manage in <settings>Settings</settings>.": "Erabili identitate-zerbitzari bat e-mail bidez gonbidatzeko. <default>Erabili lehenetsitakoa (%(defaultIdentityServerName)s)</default> edo gehitu bat <settings>Ezarpenak</settings> atalean.",
"Use an identity server to invite by email. Manage in <settings>Settings</settings>.": "Erabili identitate-zerbitzari bat e-mail bidez gonbidatzeko. Kudeatu <settings>Ezarpenak</settings> atalean.",
@ -866,9 +746,6 @@
"Topic (optional)": "Mintzagaia (aukerakoa)",
"Hide advanced": "Ezkutatu aurreratua",
"Show advanced": "Erakutsi aurreratua",
"Please fill why you're reporting.": "Idatzi zergatik salatzen duzun.",
"Report Content to Your Homeserver Administrator": "Salatu edukia zure hasiera-zerbitzariko administratzaileari",
"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.": "Mezu hau salatzeak bere 'gertaera ID'-a bidaliko dio hasiera-zerbitzariko administratzaileari. Gela honetako mezuak zifratuta badaude, zure hasiera-zerbitzariko administratzaileak ezin izango du mezuaren testua irakurri edo irudirik ikusi.",
"To continue you need to accept the terms of this service.": "Jarraitzeko erabilera baldintzak onartu behar dituzu.",
"Document": "Dokumentua",
"Missing captcha public key in homeserver configuration. Please report this to your homeserver administrator.": "Captcha-ren gako publikoa falta da hasiera-zerbitzariaren konfigurazioan. Eman honen berri hasiera-zerbitzariaren administratzaileari.",
@ -884,20 +761,9 @@
"contact the administrators of identity server <idserver />": "<idserver /> identitate-zerbitzariko administratzaileekin kontaktuak jarri",
"wait and try again later": "itxaron eta berriro saiatu",
"Room %(name)s": "%(name)s gela",
"Unread messages.": "Irakurri gabeko mezuak.",
"Failed to deactivate user": "Huts egin du erabiltzailea desaktibatzeak",
"This client does not support end-to-end encryption.": "Bezero honek ez du muturretik muturrerako zifratzea onartzen.",
"Messages in this room are not end-to-end encrypted.": "Gela honetako mezuak ez daude muturretik muturrera zifratuta.",
"Frequently Used": "Maiz erabilia",
"Smileys & People": "Irribartxoak eta jendea",
"Animals & Nature": "Animaliak eta natura",
"Food & Drink": "Jana eta edana",
"Activities": "Jarduerak",
"Travel & Places": "Bidaiak eta tokiak",
"Objects": "Objektuak",
"Symbols": "Ikurrak",
"Flags": "Banderak",
"Quick Reactions": "Erreakzio azkarrak",
"Cancel search": "Ezeztatu bilaketa",
"Jump to first unread room.": "Jauzi irakurri gabeko lehen gelara.",
"Jump to first invite.": "Jauzi lehen gonbidapenera.",
@ -914,7 +780,6 @@
"%(name)s cancelled": "%(name)s utzita",
"%(name)s wants to verify": "%(name)s(e)k egiaztatu nahi du",
"You sent a verification request": "Egiaztaketa eskari bat bidali duzu",
"Match system theme": "Bat egin sistemako azalarekin",
"My Ban List": "Nire debeku-zerrenda",
"This is your list of users/servers you have blocked - don't leave the room!": "Hau blokeatu dituzun erabiltzaile edo zerbitzarien zerrenda da, ez atera gelatik!",
"Cannot connect to integration manager": "Ezin da integrazio kudeatzailearekin konektatu",
@ -965,23 +830,6 @@
"Verification Request": "Egiaztaketa eskaria",
"Error upgrading room": "Errorea gela eguneratzean",
"Double check that your server supports the room version chosen and try again.": "Egiaztatu zure zerbitzariak aukeratutako gela bertsioa onartzen duela eta saiatu berriro.",
"%(senderName)s removed the rule banning users matching %(glob)s": "%(senderName)s erabiltzaileak %(glob)s adierazpenarekin bat datozen erabiltzaileak debekatzen zituen araua kendu du",
"%(senderName)s removed the rule banning rooms matching %(glob)s": "%(senderName)s erabiltzaileak %(glob)s adierazpenarekin bat datozen gelak debekatzen zituen araua kendu du",
"%(senderName)s removed the rule banning servers matching %(glob)s": "%(senderName)s erabiltzaileak %(glob)s adierazpenarekin bat datozen zerbitzariak debekatzen zituen araua kendu du",
"%(senderName)s removed a ban rule matching %(glob)s": "%(senderName)s erabiltzaileak %(glob)s adierazpenarekin bat datorren debeku arau bat kendu du",
"%(senderName)s updated an invalid ban rule": "%(senderName)s erabiltzaileak baliogabeko debeku arau bat eguneratu du",
"%(senderName)s updated the rule banning users matching %(glob)s for %(reason)s": "%(senderName)s erabiltzaileak %(glob)s adierazpenarekin bat datozen erabiltzaileak debekatzen dituen araua eguneratu du, arrazoia: %(reason)s",
"%(senderName)s updated the rule banning rooms matching %(glob)s for %(reason)s": "%(senderName)s erabiltzaileak %(glob)s adierazpenarekin bat datozen gelak debekatzen dituen araua eguneratu du, arrazoia: %(reason)s",
"%(senderName)s updated the rule banning servers matching %(glob)s for %(reason)s": "%(senderName)s erabiltzaileak %(glob)s adierazpenarekin bat datozen zerbitzariak debekatzen dituen araua eguneratu du, arrazoia: %(reason)s",
"%(senderName)s updated a ban rule matching %(glob)s for %(reason)s": "%(senderName)s erabiltzaileak %(glob)s adierazpenarekin bat datorren debeku arau bat eguneratu du, arrazoia: %(reason)s",
"%(senderName)s created a rule banning users matching %(glob)s for %(reason)s": "%(senderName)s erabiltzaileak %(glob)s adierazpenarekin bat datozen erabiltzaileak debekatzen dituen araua sortu du, arrazoia: %(reason)s",
"%(senderName)s created a rule banning rooms matching %(glob)s for %(reason)s": "%(senderName)s erabiltzaileak %(glob)s adierazpenarekin bat datozen gelak debekatzen dituen araua sortu du, arrazoia: %(reason)s",
"%(senderName)s created a rule banning servers matching %(glob)s for %(reason)s": "%(senderName)s erabiltzaileak %(glob)s adierazpenarekin bat datozen zerbitzariak debekatzen dituen araua sortu du, arrazoia: %(reason)s",
"%(senderName)s created a ban rule matching %(glob)s for %(reason)s": "%(senderName)s erabiltzaileak %(glob)s adierazpenarekin bat datorren debeku arau bat sortu du, arrazoia: %(reason)s",
"%(senderName)s changed a rule that was banning users matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s erabiltzaileak erabiltzaileak debekatzen dituen araua aldatu du %(oldGlob)s adierazpenetik %(newGlob)s adierazpenera, arrazoia: %(reason)s",
"%(senderName)s changed a rule that was banning rooms matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s erabiltzaileak gelak debekatzen dituen araua aldatu du %(oldGlob)s adierazpenetik %(newGlob)s adierazpenera, arrazoia: %(reason)s",
"%(senderName)s changed a rule that was banning servers matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s erabiltzaileak zerbitzariak debekatzen dituen araua aldatu du %(oldGlob)s adierazpenetik %(newGlob)s adierazpenera, arrazoia: %(reason)s",
"%(senderName)s updated a ban rule that was matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s erabiltzaileak debeku arau bat aldatu du %(oldGlob)s adierazpenetik %(newGlob)s adierazpenera, arrazoia: %(reason)s",
"Cross-signing public keys:": "Zeharkako sinaduraren gako publikoak:",
"not found": "ez da aurkitu",
"Cross-signing private keys:": "Zeharkako sinaduraren gako pribatuak:",
@ -1043,11 +891,7 @@
"Enable message search in encrypted rooms": "Gaitu mezuen bilaketa gela zifratuetan",
"How fast should messages be downloaded.": "Zeinen azkar deskargatu behar diren mezuak.",
"Waiting for %(displayName)s to verify…": "%(displayName)s egiaztatu bitartean zain…",
"They match": "Bat datoz",
"They don't match": "Ez datoz bat",
"To be secure, do this in person or use a trusted way to communicate.": "Ziurtatzeko, egin hau aurrez aurre edo komunikabide seguru baten bidez.",
"This bridge was provisioned by <user />.": "Zubi hau <user /> erabiltzaileak hornitu du.",
"Show less": "Erakutsi gutxiago",
"Your account has a cross-signing identity in secret storage, but it is not yet trusted by this session.": "Zure kontuak zeharkako sinatze identitate bat du biltegi sekretuan, baina saio honek ez du oraindik fidagarritzat.",
"in memory": "memorian",
"This session is <b>not backing up your keys</b>, but you do have an existing backup you can restore from and add to going forward.": "Saio honek <b>ez du zure gakoen babes-kopia egiten</b>, baina badago berreskuratu eta gehitu deakezun aurreko babes-kopia bat.",
@ -1055,8 +899,6 @@
"Connect this session to Key Backup": "Konektatu saio hau gakoen babes-kopiara",
"This backup is trusted because it has been restored on this session": "Babes-kopia hau fidagarritzat jotzen da saio honetan berrekuratu delako",
"Your keys are <b>not being backed up from this session</b>.": "<b>Ez da zure gakoen babes-kopia egiten saio honetatik</b>.",
"Enable desktop notifications for this session": "Gaitu mahaigaineko jakinarazpenak saio honentzat",
"Enable audible notifications for this session": "Gaitu jakinarazpen entzungarriak saio honentzat",
"Session ID:": "Saioaren ID-a:",
"Session key:": "Saioaren gakoa:",
"Message search": "Mezuen bilaketa",
@ -1096,9 +938,6 @@
"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.",
"Scan this unique code": "Eskaneatu kode bakan hau",
"Compare unique emoji": "Konparatu emoji bakana",
"Compare a unique set of emoji if you don't have a camera on either device": "Konparatu emoji sorta bakana gailuek kamerarik ez badute",
"Sign In or Create Account": "Hasi saioa edo sortu kontua",
"Use your account or create a new one to continue.": "Erabili zure kontua edo sortu berri bat jarraitzeko.",
"Create Account": "Sortu kontua",
@ -1132,19 +971,6 @@
"Mark all as read": "Markatu denak irakurrita gisa",
"Not currently indexing messages for any room.": "Orain ez da inolako gelako mezurik indexatzen.",
"%(doneRooms)s out of %(totalRooms)s": "%(doneRooms)s / %(totalRooms)s",
"%(senderName)s added the alternative addresses %(addresses)s for this room.": {
"other": "%(senderName)s erabiltzaileak %(addresses)s ordezko helbideak gehitu dizkio gela honi.",
"one": "%(senderName)s erabiltzaileak %(addresses)s helbideak gehitu dizkio gela honi."
},
"%(senderName)s removed the alternative addresses %(addresses)s for this room.": {
"other": "%(senderName)s erabiltzaileak %(addresses)s helbideak kendu dizkio gela honi.",
"one": "%(senderName)s erabiltzaileak %(addresses)s ordezko helbideak kendu dizkio gela honi."
},
"Invalid theme schema.": "Baliogabeko azal eskema.",
"Error downloading theme information.": "Errorea azalaren informazioa deskargatzean.",
"Theme added!": "Azala gehituta!",
"Custom theme URL": "Azal pertsonalizatuaren URLa",
"Add theme": "Gehitu azala",
"Scroll to most recent messages": "Korritu azken mezuetara",
"There was an error updating the room's alternative addresses. It may not be allowed by the server or a temporary failure occurred.": "Errore bat gertatu da gelaren ordezko helbideak eguneratzean. Agian zerbitzariak ez du onartzen edo une bateko akatsa izan da.",
"Local address": "Helbide lokala",
@ -1174,24 +1000,6 @@
"Confirm by comparing the following with the User Settings in your other session:": "Berretsi honako hau zure beste saioaren erabiltzaile-ezarpenetan agertzen denarekin alderatuz:",
"Confirm this user's session by comparing the following with their User Settings:": "Egiaztatu erabiltzailearen saio hau, honako hau bestearen erabiltzaile-ezarpenekin alderatuz:",
"If they don't match, the security of your communication may be compromised.": "Ez badatoz bat, komunikazioaren segurtasuna konprometitua egon daiteke.",
"Navigation": "Nabigazioa",
"Calls": "Deiak",
"Room List": "Gelen zerrenda",
"Autocomplete": "Osatze automatikoa",
"Toggle Bold": "Txandakatu lodia",
"Toggle Italics": "Txandakatu etzana",
"Toggle Quote": "Txandakatu aipamena",
"New line": "Lerro berria",
"Toggle microphone mute": "Txandakatu mikrofonoa mututzea",
"Jump to room search": "Jauzi gelaren bilaketara",
"Select room from the room list": "Hautatu gela gelen zerrendan",
"Collapse room list section": "Tolestu gelen zerrendako hautaketa",
"Expand room list section": "Hedatu gelen zerrendako hautaketa",
"Toggle the top left menu": "Txandakatu goi ezkerreko menua",
"Close dialog or context menu": "Itxi elkarrizketa-koadroa edo laster-menua",
"Activate selected button": "Aktibatu hautatutako botoia",
"Toggle right panel": "Txandakatu eskumako panela",
"Cancel autocomplete": "Ezeztatu osatze automatikoa",
"Manually verify all remote sessions": "Egiaztatu eskuz urruneko saio guztiak",
"Self signing private key:": "Norberak sinatutako gako pribatua:",
"cached locally": "cache lokalean",
@ -1201,10 +1009,8 @@
"In encrypted rooms, your messages are secured and only you and the recipient have the unique keys to unlock them.": "Gela zifratuetan, zuon mezuak babestuta daude, zuk zeuk eta hartzaileak bakarrik duzue hauek deszifratzeko gako bakanak.",
"Verify all users in a room to ensure it's secure.": "Egiaztatu gela bateko erabiltzaile guztiak segurua dela baieztatzeko.",
"Sign in with SSO": "Hasi saioa SSO-rekin",
"Cancel replying to a message": "Utzi mezua erantzuteari",
"Use Single Sign On to continue": "Erabili Single sign-on jarraitzeko",
"Confirm adding this email address by using Single Sign On to prove your identity.": "Baieztatu e-mail hau gehitzea Single sign-on bidez zure identitatea frogatuz.",
"Single Sign On": "Single sign-on",
"Confirm adding email": "Baieztatu e-maila gehitzea",
"Click the button below to confirm adding this email address.": "Sakatu beheko botoia e-mail helbide hau gehitzea berresteko.",
"Confirm adding this phone number by using Single Sign On to prove your identity.": "Baieztatu telefono zenbaki hau gehitzea Single sign-on bidez zure identitatea frogatuz.",
@ -1227,12 +1033,7 @@
"Server did not require any authentication": "Zerbitzariak ez du autentifikaziorik eskatu",
"Server did not return valid authentication information.": "Zerbitzariak ez du baliozko autentifikazio informaziorik itzuli.",
"There was a problem communicating with the server. Please try again.": "Arazo bat egon da zerbitzariarekin komunikatzeko. Saiatu berriro.",
"Welcome to %(appName)s": "Ongi etorri %(appName)s-era",
"Send a Direct Message": "Bidali mezu zuzena",
"Explore Public Rooms": "Arakatu gela publikoak",
"Create a Group Chat": "Sortu talde-txata",
"Could not find user in room": "Ezin izan da erabiltzailea gelan aurkitu",
"Please supply a widget URL or embed code": "Eman trepetaren URLa edo txertatu kodea",
"Can't load this message": "Ezin izan da mezu hau kargatu",
"Submit logs": "Bidali egunkariak",
"Reminder: Your browser is unsupported, so your experience may be unpredictable.": "Oroigarria: Ez dugu zure nabigatzailearentzako euskarririk, ezin da zure esperientzia nolakoa izango den aurreikusi.",
@ -1241,16 +1042,13 @@
"Unable to query secret storage status": "Ezin izan da biltegi sekretuaren egoera kontsultatu",
"Currently indexing: %(currentRoom)s": "Orain indexatzen: %(currentRoom)s",
"New login. Was this you?": "Saio berria. Zu izan zara?",
"Opens chat with the given user": "Erabiltzailearekin txata irekitzen du",
"You signed in to a new session without verifying it:": "Saio berria hasi duzu hau egiaztatu gabe:",
"Verify your other session using one of the options below.": "Egiaztatu zure beste saioa beheko aukeretako batekin.",
"Font size": "Letra-tamaina",
"IRC display name width": "IRC-ko pantaila izenaren zabalera",
"Size must be a number": "Tamaina zenbaki bat izan behar da",
"Custom font size can only be between %(min)s pt and %(max)s pt": "Letra tamaina pertsonalizatua %(min)s pt eta %(max)s pt bitartean egon behar du",
"Use between %(min)s pt and %(max)s pt": "Erabili %(min)s pt eta %(max)s pt bitarteko balioa",
"You've successfully verified your device!": "Ongi egiaztatu duzu zure gailua!",
"QR Code": "QR kodea",
"To continue, use Single Sign On to prove your identity.": "Jarraitzeko, erabili Single Sign On zure identitatea frogatzeko.",
"Confirm to continue": "Berretsi jarraitzeko",
"Click the button below to confirm your identity.": "Sakatu azpiko botoia zure identitatea frogatzeko.",
@ -1260,9 +1058,6 @@
"Successfully restored %(sessionCount)s keys": "%(sessionCount)s gako ongi berreskuratuta",
"Confirm encryption setup": "Berretsi zifratze ezarpena",
"Click the button below to confirm setting up encryption.": "Sakatu azpiko botoia zifratze-ezarpena berresteko.",
"Dismiss read marker and jump to bottom": "Baztertu irakurtze-marka eta jauzi beheraino",
"Jump to oldest unread message": "Jauzi irakurri gabeko mezu zaharrenera",
"Upload a file": "Igo fitxategia",
"Joins room with given address": "Emandako helbidea duen gelara elkartzen da",
"Your homeserver has exceeded its user limit.": "Zure hasiera-zerbitzariak erabiltzaile muga gainditu du.",
"Your homeserver has exceeded one of its resource limits.": "Zure hasiera-zerbitzariak bere baliabide mugetako bat gainditu du.",
@ -1274,22 +1069,13 @@
"Your server admin has disabled end-to-end encryption by default in private rooms & Direct Messages.": "Zure zerbitzariko administratzaileak muturretik muturrerako zifratzea desgaitu du lehenetsita gela probatuetan eta mezu zuzenetan.",
"To link to this room, please add an address.": "Gela hau estekatzeko, gehitu helbide bat.",
"No recently visited rooms": "Ez dago azkenaldian bisitatutako gelarik",
"Sort by": "Ordenatu honela",
"Activity": "Jarduera",
"A-Z": "A-Z",
"Message preview": "Mezu-aurrebista",
"List options": "Zerrenda-aukerak",
"Show %(count)s more": {
"other": "Erakutsi %(count)s gehiago",
"one": "Erakutsi %(count)s gehiago"
},
"Room options": "Gelaren aukerak",
"Error creating address": "Errorea helbidea sortzean",
"There was an error creating that address. It may not be allowed by the server or a temporary failure occurred.": "Errorea gertatu da helbidea sortzean. Agian ez du zerbitzariak onartzen edo behin behineko arazo bat egon da.",
"You don't have permission to delete the address.": "Ez duzu helbidea ezabatzeko baimenik.",
"There was an error removing that address. It may no longer exist or a temporary error occurred.": "Errorea gertatu da helbidea kentzean. Agian ez dago jada edo behin behineko arazo bat egon da.",
"Error removing address": "Errorea helbidea kentzean",
"Categories": "Kategoriak",
"Room address": "Gelaren helbidea",
"This address is available to use": "Gelaren helbide hau erabilgarri dago",
"This address is already in use": "Gelaren helbide hau erabilita dago",
@ -1302,10 +1088,7 @@
"Use a different passphrase?": "Erabili pasa-esaldi desberdin bat?",
"Change notification settings": "Aldatu jakinarazpenen ezarpenak",
"Use custom size": "Erabili tamaina pertsonalizatua",
"Use a system font": "Erabili sistemako letra-tipoa",
"System font name": "Sistemaren letra-tipoaren izena",
"Hey you. You're the best!": "Aupa txo. Onena zara!",
"Notification options": "Jakinarazpen ezarpenak",
"Forget Room": "Ahaztu gela",
"This room is public": "Gela hau publikoa da",
"Click to view edits": "Klik egin edizioak ikusteko",
@ -1313,13 +1096,11 @@
"The server has denied your request.": "Zerbitzariak zure eskariari uko egin dio.",
"Wrong file type": "Okerreko fitxategi-mota",
"Looks good!": "Itxura ona du!",
"Integration manager": "Integrazio-kudeatzailea",
"Your %(brand)s doesn't allow you to use an integration manager to do this. Please contact an admin.": "Zure %(brand)s aplikazioak ez dizu hau egiteko integrazio kudeatzaile bat erabiltzen uzten. Kontaktatu administratzaileren batekin.",
"Using this widget may share data <helpIcon /> with %(widgetDomain)s & your integration manager.": "Trepeta hau erabiltzean <helpIcon /> %(widgetDomain)s domeinuarekin eta zure integrazio kudeatzailearekin datuak partekatu daitezke.",
"Integration managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "Integrazio kudeatzaileek konfigurazio datuak jasotzen dituzte, eta trepetak aldatu ditzakete, gelara gonbidapenak bidali, eta botere mailak zure izenean ezarri.",
"Use an integration manager to manage bots, widgets, and sticker packs.": "Erabili integrazio kudeatzaile bat botak, trepetak eta eranskailu multzoak kudeatzeko.",
"Use an integration manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "Erabili <b>(%(serverName)s)</b> integrazio kudeatzailea botak, trepetak eta eranskailu multzoak kudeatzeko.",
"Identity server": "Identitate zerbitzaria",
"Identity server (%(server)s)": "Identitate-zerbitzaria (%(server)s)",
"Could not connect to identity server": "Ezin izan da identitate-zerbitzarira konektatu",
"Not a valid identity server (status code %(code)s)": "Ez da identitate zerbitzari baliogarria (egoera-mezua %(code)s)",
@ -1373,7 +1154,10 @@
"unnamed_room": "Izen gabeko gela",
"stickerpack": "Eranskailu-multzoa",
"system_alerts": "Sistemaren alertak",
"cross_signing": "Zeharkako sinadura"
"cross_signing": "Zeharkako sinadura",
"identity_server": "Identitate zerbitzaria",
"integration_manager": "Integrazio-kudeatzailea",
"qr_code": "QR kodea"
},
"action": {
"continue": "Jarraitu",
@ -1450,13 +1234,26 @@
"send_report": "Bidali salaketa"
},
"a11y": {
"user_menu": "Erabiltzailea-menua"
"user_menu": "Erabiltzailea-menua",
"n_unread_messages_mentions": {
"other": "irakurri gabeko %(count)s mezu aipamenak barne.",
"one": "Irakurri gabeko aipamen 1."
},
"n_unread_messages": {
"other": "irakurri gabeko %(count)s mezu.",
"one": "Irakurri gabeko mezu 1."
},
"unread_messages": "Irakurri gabeko mezuak."
},
"labs": {
"pinning": "Mezuak finkatzea",
"state_counters": "Jarri kontagailu sinpleak gelaren goiburuan",
"custom_themes": "Azal pertsonalizatuak gehitzea onartzen du",
"bridge_state": "Erakutsi zubiei buruzko informazioa gelaren ezarpenetan"
"bridge_state": "Erakutsi zubiei buruzko informazioa gelaren ezarpenetan",
"group_profile": "Profila",
"group_rooms": "Gelak",
"group_voip": "Ahotsa eta bideoa",
"group_encryption": "Zifratzea"
},
"keyboard": {
"home": "Hasiera",
@ -1468,7 +1265,29 @@
"end": "Amaiera",
"alt": "Alt",
"control": "Ctrl",
"shift": "Maius."
"shift": "Maius.",
"category_calls": "Deiak",
"category_room_list": "Gelen zerrenda",
"category_navigation": "Nabigazioa",
"category_autocomplete": "Osatze automatikoa",
"composer_toggle_bold": "Txandakatu lodia",
"composer_toggle_italics": "Txandakatu etzana",
"composer_toggle_quote": "Txandakatu aipamena",
"cancel_reply": "Utzi mezua erantzuteari",
"toggle_microphone_mute": "Txandakatu mikrofonoa mututzea",
"dismiss_read_marker_and_jump_bottom": "Baztertu irakurtze-marka eta jauzi beheraino",
"jump_to_read_marker": "Jauzi irakurri gabeko mezu zaharrenera",
"upload_file": "Igo fitxategia",
"jump_room_search": "Jauzi gelaren bilaketara",
"room_list_select_room": "Hautatu gela gelen zerrendan",
"room_list_collapse_section": "Tolestu gelen zerrendako hautaketa",
"room_list_expand_section": "Hedatu gelen zerrendako hautaketa",
"toggle_top_left_menu": "Txandakatu goi ezkerreko menua",
"toggle_right_panel": "Txandakatu eskumako panela",
"autocomplete_cancel": "Ezeztatu osatze automatikoa",
"close_dialog_menu": "Itxi elkarrizketa-koadroa edo laster-menua",
"activate_button": "Aktibatu hautatutako botoia",
"composer_new_line": "Lerro berria"
},
"composer": {
"format_bold": "Lodia",
@ -1499,7 +1318,8 @@
"github_issue": "GitHub arazo-txostena",
"before_submitting": "Egunkariak bidali aurretik, <a>GitHub arazo bat sortu</a> behar duzu gertatzen zaizuna azaltzeko.",
"collecting_information": "Aplikazioaren bertsio-informazioa biltzen",
"collecting_logs": "Egunkariak biltzen"
"collecting_logs": "Egunkariak biltzen",
"create_new_issue": "<newIssueLink>Sortu txosten berri bat</newIssueLink> GitHub zerbitzarian arazo hau ikertu dezagun."
},
"time": {
"few_seconds_ago": "duela segundo batzuk",
@ -1545,7 +1365,22 @@
"rule_call": "Dei gonbidapena",
"rule_suppress_notices": "Botak bidalitako mezuak",
"rule_tombstone": "Gelak eguneratzean",
"rule_encrypted_room_one_to_one": "Zifratutako mezuak bi pertsonen arteko txatetan"
"rule_encrypted_room_one_to_one": "Zifratutako mezuak bi pertsonen arteko txatetan",
"enable_desktop_notifications_session": "Gaitu mahaigaineko jakinarazpenak saio honentzat",
"show_message_desktop_notification": "Erakutsi mezua mahaigaineko jakinarazpenean",
"enable_audible_notifications_session": "Gaitu jakinarazpen entzungarriak saio honentzat"
},
"appearance": {
"match_system_theme": "Bat egin sistemako azalarekin",
"custom_font": "Erabili sistemako letra-tipoa",
"custom_font_name": "Sistemaren letra-tipoaren izena",
"custom_theme_invalid": "Baliogabeko azal eskema.",
"custom_theme_error_downloading": "Errorea azalaren informazioa deskargatzean.",
"custom_theme_success": "Azala gehituta!",
"custom_theme_url": "Azal pertsonalizatuaren URLa",
"custom_theme_add_button": "Gehitu azala",
"font_size": "Letra-tamaina",
"timeline_image_size_default": "Lehenetsia"
}
},
"devtools": {
@ -1592,7 +1427,15 @@
"removed": "%(senderName)s erabiltzaileak gela honen helbide nagusia kendu du.",
"changed_alternative": "%(senderName)s erabiltzaileak gela honen ordezko helbideak aldatu ditu.",
"changed_main_and_alternative": "%(senderName)s erabiltzaileak gela honen helbide nagusia eta ordezko helbideak aldatu ditu.",
"changed": "%(senderName)s erabiltzaileak gela honen helbideak aldatu ditu."
"changed": "%(senderName)s erabiltzaileak gela honen helbideak aldatu ditu.",
"alt_added": {
"other": "%(senderName)s erabiltzaileak %(addresses)s ordezko helbideak gehitu dizkio gela honi.",
"one": "%(senderName)s erabiltzaileak %(addresses)s helbideak gehitu dizkio gela honi."
},
"alt_removed": {
"other": "%(senderName)s erabiltzaileak %(addresses)s helbideak kendu dizkio gela honi.",
"one": "%(senderName)s erabiltzaileak %(addresses)s ordezko helbideak kendu dizkio gela honi."
}
},
"m.room.third_party_invite": {
"revoked": "%(senderName)s erabiltzaileak %(targetDisplayName)s gelara elkartzeko gonbidapena errefusatu du.",
@ -1625,6 +1468,120 @@
},
"m.call.hangup": {
"dm": "Deia amaitu da"
},
"summary": {
"format": "%(nameList)s%(transitionList)s",
"joined_multiple": {
"other": "%(severalUsers)s %(count)s aldiz elkartu dira",
"one": "%(severalUsers)s elkartu dira"
},
"joined": {
"other": "%(oneUser)s%(count)s aldiz elkartu da",
"one": "%(oneUser)s elkartu da"
},
"left_multiple": {
"other": "%(severalUsers)s%(count)s aldiz atera dira",
"one": "%(severalUsers)s atera dira"
},
"left": {
"other": "%(oneUser)s%(count)s aldiz atera da",
"one": "%(oneUser)s atera da"
},
"joined_and_left_multiple": {
"other": "%(severalUsers)s elkartu eta atera dira %(count)s aldiz",
"one": "%(severalUsers)s elkartu eta atera dira"
},
"joined_and_left": {
"other": "%(oneUser)s elkartu eta atera da %(count)s aldiz",
"one": "%(oneUser)s elkartu eta atera da"
},
"rejoined_multiple": {
"other": "%(severalUsers)s atera eta berriz elkartu dira %(count)s aldiz",
"one": "%(severalUsers)s atera eta berriz elkartu da"
},
"rejoined": {
"other": "%(oneUser)s atera eta berriz elkartu da %(count)s aldiz",
"one": "%(oneUser)s atera eta berriz elkartu da"
},
"rejected_invite_multiple": {
"other": "%(severalUsers)s erabiltzaileek bere gonbidapenak ukatu dituzte %(count)s aldiz",
"one": "%(severalUsers)s erabiltzaileek bere gonbidapenak ukatu dituzte"
},
"rejected_invite": {
"other": "%(oneUser)s erabiltzaileak bere gonbidapena ukatu du %(count)s aldiz",
"one": "%(oneUser)s erabiltzaileak bere gonbidapena ukatu du"
},
"invite_withdrawn_multiple": {
"other": "%(severalUsers)s erabiltzaileei gonbidapena indargabetu zaie %(count)s aldiz",
"one": "%(severalUsers)s erabiltzaileei gonbidapena indargabetu zaie"
},
"invite_withdrawn": {
"other": "%(oneUser)s erabiltzaileari gonbidapena indargabetu zaio %(count)s aldiz",
"one": "%(oneUser)s erabiltzaileari gonbidapena indargabetu zaio"
},
"invited_multiple": {
"other": "%(count)s aldiz gonbidatuak izan dira",
"one": "gonbidatuak izan dira"
},
"invited": {
"other": "%(count)s aldiz gonbidatua izan da",
"one": "gonbidatua izan da"
},
"banned_multiple": {
"other": "%(count)s aldiz debekatuak izan dira",
"one": "debekatuak izan dira"
},
"banned": {
"one": "debekatua izan da",
"other": "%(count)s aldiz debekatuak izan dira"
},
"unbanned_multiple": {
"other": "%(count)s aldiz kendu zaie debekua",
"one": "debekua kendu zaie"
},
"unbanned": {
"other": "%(count)s aldiz kendu zaio debekua",
"one": "debekua kendu zaio"
},
"changed_name_multiple": {
"other": "%(severalUsers)s erabiltzaileek bere izena aldatu dute %(count)s aldiz",
"one": "%(severalUsers)s erabiltzaileek bere izena aldatu dute"
},
"changed_name": {
"other": "%(oneUser)s erabiltzaileak bere izena aldatu du %(count)s aldiz",
"one": "%(oneUser)s erabiltzaileak bere izena aldatu du"
},
"no_change_multiple": {
"other": "%(severalUsers)s erabiltzaileek ez dute aldaketarik egin %(count)s aldiz",
"one": "%(severalUsers)s erabiltzaileek ez dute aldaketarik egin"
},
"no_change": {
"other": "%(oneUser)s erabiltzaileak ez du aldaketarik egin %(count)s aldiz",
"one": "%(oneUser)s erabiltzaileak ez du aldaketarik egin"
}
},
"m.room.power_levels": {
"changed": "%(senderName)s erabiltzaileak botere mailaz aldatu du %(powerLevelDiffText)s.",
"user_from_to": "%(userId)s %(fromPowerLevel)s mailatik %(toPowerLevel)s mailara"
},
"mjolnir": {
"removed_rule_users": "%(senderName)s erabiltzaileak %(glob)s adierazpenarekin bat datozen erabiltzaileak debekatzen zituen araua kendu du",
"removed_rule_rooms": "%(senderName)s erabiltzaileak %(glob)s adierazpenarekin bat datozen gelak debekatzen zituen araua kendu du",
"removed_rule_servers": "%(senderName)s erabiltzaileak %(glob)s adierazpenarekin bat datozen zerbitzariak debekatzen zituen araua kendu du",
"removed_rule": "%(senderName)s erabiltzaileak %(glob)s adierazpenarekin bat datorren debeku arau bat kendu du",
"updated_invalid_rule": "%(senderName)s erabiltzaileak baliogabeko debeku arau bat eguneratu du",
"updated_rule_users": "%(senderName)s erabiltzaileak %(glob)s adierazpenarekin bat datozen erabiltzaileak debekatzen dituen araua eguneratu du, arrazoia: %(reason)s",
"updated_rule_rooms": "%(senderName)s erabiltzaileak %(glob)s adierazpenarekin bat datozen gelak debekatzen dituen araua eguneratu du, arrazoia: %(reason)s",
"updated_rule_servers": "%(senderName)s erabiltzaileak %(glob)s adierazpenarekin bat datozen zerbitzariak debekatzen dituen araua eguneratu du, arrazoia: %(reason)s",
"updated_rule": "%(senderName)s erabiltzaileak %(glob)s adierazpenarekin bat datorren debeku arau bat eguneratu du, arrazoia: %(reason)s",
"created_rule_users": "%(senderName)s erabiltzaileak %(glob)s adierazpenarekin bat datozen erabiltzaileak debekatzen dituen araua sortu du, arrazoia: %(reason)s",
"created_rule_rooms": "%(senderName)s erabiltzaileak %(glob)s adierazpenarekin bat datozen gelak debekatzen dituen araua sortu du, arrazoia: %(reason)s",
"created_rule_servers": "%(senderName)s erabiltzaileak %(glob)s adierazpenarekin bat datozen zerbitzariak debekatzen dituen araua sortu du, arrazoia: %(reason)s",
"created_rule": "%(senderName)s erabiltzaileak %(glob)s adierazpenarekin bat datorren debeku arau bat sortu du, arrazoia: %(reason)s",
"changed_rule_users": "%(senderName)s erabiltzaileak erabiltzaileak debekatzen dituen araua aldatu du %(oldGlob)s adierazpenetik %(newGlob)s adierazpenera, arrazoia: %(reason)s",
"changed_rule_rooms": "%(senderName)s erabiltzaileak gelak debekatzen dituen araua aldatu du %(oldGlob)s adierazpenetik %(newGlob)s adierazpenera, arrazoia: %(reason)s",
"changed_rule_servers": "%(senderName)s erabiltzaileak zerbitzariak debekatzen dituen araua aldatu du %(oldGlob)s adierazpenetik %(newGlob)s adierazpenera, arrazoia: %(reason)s",
"changed_rule_glob": "%(senderName)s erabiltzaileak debeku arau bat aldatu du %(oldGlob)s adierazpenetik %(newGlob)s adierazpenera, arrazoia: %(reason)s"
}
},
"slash_command": {
@ -1657,7 +1614,13 @@
"category_actions": "Ekintzak",
"category_admin": "Kudeatzailea",
"category_advanced": "Aurreratua",
"category_other": "Beste bat"
"category_other": "Beste bat",
"addwidget_missing_url": "Eman trepetaren URLa edo txertatu kodea",
"addwidget_invalid_protocol": "Eman https:// edo http:// motako trepetaren URL-a",
"addwidget_no_permissions": "Ezin dituzu gela honetako trepetak aldatu.",
"discardsession": "Uneko irteerako talde saioa zifratutako gela batean baztertzera behartzen du",
"query": "Erabiltzailearekin txata irekitzen du",
"me": "Ekintza bistaratzen du"
},
"presence": {
"online_for": "Konektatua %(duration)s",
@ -1690,7 +1653,6 @@
"unknown_caller": "Dei-egile ezezaguna",
"call_failed": "Deiak huts egin du"
},
"Messages": "Mezuak",
"Other": "Beste bat",
"Advanced": "Aurreratua",
"room_settings": {
@ -1711,5 +1673,76 @@
"ban": "Debekatu erabiltzaileak",
"notifications.room": "Jakinarazi denei"
}
},
"encryption": {
"verification": {
"sas_no_match": "Ez datoz bat",
"sas_match": "Bat datoz",
"in_person": "Ziurtatzeko, egin hau aurrez aurre edo komunikabide seguru baten bidez.",
"other_party_cancelled": "Beste parteak egiaztaketa ezeztatu du.",
"complete_title": "Egiaztatuta!",
"complete_description": "Ongi egiaztatu duzu erabiltzaile hau.",
"qr_prompt": "Eskaneatu kode bakan hau",
"sas_prompt": "Konparatu emoji bakana",
"sas_description": "Konparatu emoji sorta bakana gailuek kamerarik ez badute"
}
},
"emoji": {
"category_frequently_used": "Maiz erabilia",
"category_smileys_people": "Irribartxoak eta jendea",
"category_animals_nature": "Animaliak eta natura",
"category_food_drink": "Jana eta edana",
"category_activities": "Jarduerak",
"category_travel_places": "Bidaiak eta tokiak",
"category_objects": "Objektuak",
"category_symbols": "Ikurrak",
"category_flags": "Banderak",
"categories": "Kategoriak",
"quick_reactions": "Erreakzio azkarrak"
},
"auth": {
"sign_in_with_sso": "Hai saioa urrats batean",
"sso": "Single sign-on",
"account_clash": "Zure kontu berria (%(newAccountId)s) erregistratuta dago, baina dagoeneko saioa hasi duzu beste kontu batekin (%(loggedInUserId)s).",
"account_clash_previous_account": "Jarraitu aurreko kontuarekin",
"log_in_new_account": "<a>Hasi saioa</a> zure kontu berrian.",
"registration_successful": "Ongi erregistratuta"
},
"export_chat": {
"messages": "Mezuak"
},
"room_list": {
"sort_by": "Ordenatu honela",
"sort_by_activity": "Jarduera",
"sort_by_alphabet": "A-Z",
"sublist_options": "Zerrenda-aukerak",
"show_n_more": {
"other": "Erakutsi %(count)s gehiago",
"one": "Erakutsi %(count)s gehiago"
},
"show_less": "Erakutsi gutxiago",
"notification_options": "Jakinarazpen ezarpenak"
},
"report_content": {
"missing_reason": "Idatzi zergatik salatzen duzun.",
"report_content_to_homeserver": "Salatu edukia zure hasiera-zerbitzariko administratzaileari",
"description": "Mezu hau salatzeak bere 'gertaera ID'-a bidaliko dio hasiera-zerbitzariko administratzaileari. Gela honetako mezuak zifratuta badaude, zure hasiera-zerbitzariko administratzaileak ezin izango du mezuaren testua irakurri edo irudirik ikusi."
},
"onboarding": {
"intro_welcome": "Ongi etorri %(appName)s-era",
"send_dm": "Bidali mezu zuzena",
"explore_rooms": "Arakatu gela publikoak",
"create_room": "Sortu talde-txata"
},
"setting": {
"help_about": {
"brand_version": "%(brand)s bertsioa:",
"help_link": "%(brand)s erabiltzeko laguntza behar baduzu, egin klik <a>hemen</a>.",
"help_link_chat_bot": "%(brand)s erabiltzeko laguntza behar baduzu, egin klik <a>hemen</a> edo hasi txat bat gure botarekin beheko botoia sakatuz.",
"chat_bot": "Txateatu %(brand)s botarekin",
"title": "Laguntza eta honi buruz",
"versions": "Bertsioak",
"clear_cache_reload": "Garbitu cachea eta birkargatu"
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,6 @@
{
"Sign in with": "Sínigh isteach le",
"Already have an account? <a>Sign in here</a>": "An bhfuil cuntas agat cheana? <a>Sínigh isteach anseo</a>",
"Show less": "Taispeáin níos lú",
"Show more": "Taispeáin níos mó",
"Show %(count)s more": {
"one": "Taispeáin %(count)s níos mó",
"other": "Taispeáin %(count)s níos mó"
},
"Switch to dark mode": "Athraigh go mód dorcha",
"Switch to light mode": "Athraigh go mód geal",
"Got an account? <a>Sign in</a>": "An bhfuil cuntas agat? <a>Sínigh isteach</a>",
@ -39,7 +33,6 @@
"Ignored/Blocked": "Neamhairde/Tachta",
"Avoid sequences": "Seachain seicheamh",
"Unrecognised address": "Seoladh nár aithníodh",
"Displays action": "Taispeáin gníomh",
"Verified key": "Eochair deimhnithe",
"Unignored user": "Úsáideoir leis aird",
"Ignored user": "Úsáideoir neamhairde",
@ -241,14 +234,8 @@
"Algorithm:": "Algartam:",
"Information": "Eolas",
"Favourited": "Roghnaithe",
"A-Z": "A-Z",
"Activity": "Gníomhaíocht",
"Feedback": "Aiseolas",
"Ok": "Togha",
"Categories": "Catagóire",
"Autocomplete": "Uathiomlánaigh",
"Calls": "Glaonna",
"Navigation": "Nascleanúint",
"Accepting…": "ag Glacadh leis…",
"Cancelling…": "ag Cealú…",
"exists": "a bheith ann",
@ -257,10 +244,6 @@
"Lock": "Glasáil",
"Unencrypted": "Gan chriptiú",
"None": "Níl aon cheann",
"Flags": "Bratacha",
"Symbols": "Siombailí",
"Objects": "Rudaí",
"Activities": "Gníomhaíochtaí",
"Document": "Cáipéis",
"Italics": "Iodálach",
"Discovery": "Aimsiú",
@ -279,18 +262,6 @@
"Notes": "Nótaí",
"expand": "méadaigh",
"collapse": "cumaisc",
"%(oneUser)sleft %(count)s times": {
"one": "D'fhág %(oneUser)s"
},
"%(severalUsers)sleft %(count)s times": {
"one": "D'fhág %(severalUsers)s"
},
"%(oneUser)sjoined %(count)s times": {
"one": "Tháinig %(oneUser)s isteach"
},
"%(severalUsers)sjoined %(count)s times": {
"one": "Tháinig %(severalUsers)s isteach"
},
"edited": "curtha in eagar",
"Copied!": "Cóipeáilte!",
"Yesterday": "Inné",
@ -331,7 +302,6 @@
"Cryptography": "Cripteagrafaíocht",
"Composer": "Eagarthóir",
"Notifications": "Fógraí",
"Versions": "Leaganacha",
"General": "Ginearálta",
"Account": "Cuntas",
"Profile": "Próifíl",
@ -400,7 +370,6 @@
"Lion": "Leon",
"Cat": "Cat",
"Dog": "Madra",
"Verified!": "Deimhnithe!",
"Reason": "Cúis",
"Moderator": "Modhnóir",
"Restricted": "Teoranta",
@ -434,7 +403,6 @@
"Add Email Address": "Cuir seoladh ríomhphoist",
"Click the button below to confirm adding this email address.": "Cliceáil an cnaipe thíos chun an seoladh ríomhphoist nua a dheimhniú.",
"Confirm adding email": "Deimhnigh an seoladh ríomhphoist nua",
"Single Sign On": "Single Sign On",
"Confirm adding this email address by using Single Sign On to prove your identity.": "Deimhnigh an seoladh ríomhphoist seo le SSO mar cruthúnas céannachta.",
"Explore rooms": "Breathnaigh thart ar na seomraí",
"Create Account": "Déan cuntas a chruthú",
@ -447,7 +415,6 @@
"Are you sure you want to sign out?": "An bhfuil tú cinnte go dteastaíonn uait sínigh amach?",
"Signed Out": "Sínithe Amach",
"Unable to query for supported registration methods.": "Ní féidir iarratas a dhéanamh faoi modhanna cláraithe tacaithe.",
"Host account on": "Óstáil cuntas ar",
"Create account": "Déan cuntas a chruthú",
"Deactivate Account": "Cuir cuntas as feidhm",
"Account management": "Bainistíocht cuntais",
@ -465,7 +432,6 @@
"Global": "Uilíoch",
"Keyword": "Eochairfhocal",
"Report": "Tuairiscigh",
"Disagree": "Easaontaigh",
"Visibility": "Léargas",
"Address": "Seoladh",
"Sent": "Seolta",
@ -533,7 +499,6 @@
"Deops user with given id": "Bain an cumhacht oibritheora ó úsáideoir leis an ID áirithe",
"Decrypt %(text)s": "Díchriptigh %(text)s",
"Custom level": "Leibhéal saincheaptha",
"%(senderName)s changed the power level of %(powerLevelDiffText)s.": "D'athraigh %(senderName)s an leibhéal cumhachta %(powerLevelDiffText)s.",
"Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or <a>enable unsafe scripts</a>.": "Ní féidir ceangal leis an bhfreastalaí baile trí HTTP nuair a bhíonn URL HTTPS i mbarra do bhrabhsálaí. Bain úsáid as HTTPS nó <a> scripteanna neamhshábháilte a chumasú </a>.",
"Can't connect to homeserver - please check your connectivity, ensure your <a>homeserver's SSL certificate</a> is trusted, and that a browser extension is not blocking requests.": "Ní féidir ceangal leis an bhfreastalaí baile - seiceáil do nascacht le do thoil, déan cinnte go bhfuil muinín i dteastas <a>SSL do fhreastalaí baile</a>, agus nach bhfuil síneadh brabhsálaí ag cur bac ar iarratais.",
"common": {
@ -671,7 +636,12 @@
"submit": "Cuir isteach"
},
"labs": {
"pinning": "Ceangal teachtaireachta"
"pinning": "Ceangal teachtaireachta",
"group_profile": "Próifíl",
"group_spaces": "Spásanna",
"group_widgets": "Giuirléidí",
"group_rooms": "Seomraí",
"group_encryption": "Criptiúchán"
},
"keyboard": {
"home": "Tús",
@ -682,7 +652,10 @@
"alt": "Alt",
"control": "Ctrl",
"shift": "Shift",
"number": "[uimhir]"
"number": "[uimhir]",
"category_calls": "Glaonna",
"category_navigation": "Nascleanúint",
"category_autocomplete": "Uathiomlánaigh"
},
"composer": {
"format_bold": "Trom",
@ -702,6 +675,9 @@
"always_show_message_timestamps": "Taispeáin stampaí ama teachtaireachta i gcónaí",
"notifications": {
"rule_call": "Nuair a fhaighim cuireadh glaoigh"
},
"appearance": {
"timeline_image_size_default": "Réamhshocrú"
}
},
"devtools": {
@ -722,6 +698,23 @@
},
"m.call.hangup": {
"dm": "Críochnaíodh an glao"
},
"summary": {
"joined_multiple": {
"one": "Tháinig %(severalUsers)s isteach"
},
"joined": {
"one": "Tháinig %(oneUser)s isteach"
},
"left_multiple": {
"one": "D'fhág %(severalUsers)s"
},
"left": {
"one": "D'fhág %(oneUser)s"
}
},
"m.room.power_levels": {
"changed": "D'athraigh %(senderName)s an leibhéal cumhachta %(powerLevelDiffText)s."
}
},
"slash_command": {
@ -733,7 +726,8 @@
"category_admin": "Riarthóir",
"category_advanced": "Forbartha",
"category_effects": "Tionchair",
"category_other": "Eile"
"category_other": "Eile",
"me": "Taispeáin gníomh"
},
"presence": {
"online": "Ar Líne",
@ -774,7 +768,6 @@
"call_failed_media_permissions": "Tugtar cead an ceamara gréasáin a úsáid",
"call_failed_media_applications": "Níl aon fheidhmchlár eile ag úsáid an cheamara gréasáin"
},
"Messages": "Teachtaireachtaí",
"Other": "Eile",
"Advanced": "Forbartha",
"room_settings": {
@ -789,5 +782,42 @@
"ban": "Toirmisc úsáideoirí",
"notifications.room": "Tabhair fógraí do gach duine"
}
},
"encryption": {
"verification": {
"complete_title": "Deimhnithe!"
}
},
"emoji": {
"category_activities": "Gníomhaíochtaí",
"category_objects": "Rudaí",
"category_symbols": "Siombailí",
"category_flags": "Bratacha",
"categories": "Catagóire"
},
"auth": {
"sso": "Single Sign On",
"sign_in_instead": "An bhfuil cuntas agat cheana? <a>Sínigh isteach anseo</a>",
"server_picker_title": "Óstáil cuntas ar"
},
"export_chat": {
"messages": "Teachtaireachtaí"
},
"room_list": {
"sort_by_activity": "Gníomhaíocht",
"sort_by_alphabet": "A-Z",
"show_n_more": {
"one": "Taispeáin %(count)s níos mó",
"other": "Taispeáin %(count)s níos mó"
},
"show_less": "Taispeáin níos lú"
},
"report_content": {
"disagree": "Easaontaigh"
},
"setting": {
"help_about": {
"versions": "Leaganacha"
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More