Merge remote-tracking branch 'origin/develop' into hs/add-custom-component-modules

This commit is contained in:
Half-Shot 2025-06-12 16:33:17 +01:00
commit 62f62601ef
148 changed files with 3239 additions and 1558 deletions

View File

@ -1,3 +1,34 @@
Changes in [1.11.103](https://github.com/element-hq/element-web/releases/tag/v1.11.103) (2025-06-10)
====================================================================================================
## 🐛 Bug Fixes
+ Check the sender of an event matches owner of session, preventing sender spoofing by homeserver owners.
[13c1d20](https://github.com/matrix-org/matrix-rust-sdk/commit/13c1d2048286bbabf5e7bc6b015aafee98f04d55) (High, [GHSA-x958-rvg6-956w](https://github.com/matrix-org/matrix-rust-sdk/security/advisories/GHSA-x958-rvg6-956w)).
Changes in [1.11.102](https://github.com/element-hq/element-web/releases/tag/v1.11.102) (2025-06-03)
====================================================================================================
## ✨ Features
* EW: Modernize the recovery key input modal ([#29819](https://github.com/element-hq/element-web/pull/29819)). Contributed by @uhoreg.
* New room list: move secondary filters into primary filters ([#29972](https://github.com/element-hq/element-web/pull/29972)). Contributed by @florianduros.
* Prompt the user when key storage is unexpectedly off ([#29912](https://github.com/element-hq/element-web/pull/29912)). Contributed by @andybalaam.
* New room list: move sort menu in room list header ([#29983](https://github.com/element-hq/element-web/pull/29983)). Contributed by @florianduros.
* New room list: rework spacing of room list item ([#29965](https://github.com/element-hq/element-web/pull/29965)). Contributed by @florianduros.
* RLS: Remove forgotten room from skiplist ([#29933](https://github.com/element-hq/element-web/pull/29933)). Contributed by @MidhunSureshR.
* Add room list sorting ([#29951](https://github.com/element-hq/element-web/pull/29951)). Contributed by @dbkr.
* Don't use the minimised width(68px) on the new room list ([#29778](https://github.com/element-hq/element-web/pull/29778)). Contributed by @langleyd.
## 🐛 Bug Fixes
* [Backport staging] Close call options popup menu when option has been selected ([#30054](https://github.com/element-hq/element-web/pull/30054)). Contributed by @RiotRobot.
* RoomListStoreV3: Only add new rooms that pass `VisibilityProvider` check ([#29974](https://github.com/element-hq/element-web/pull/29974)). Contributed by @MidhunSureshR.
* Re-order primary filters ([#29957](https://github.com/element-hq/element-web/pull/29957)). Contributed by @dbkr.
* Fix leaky CSS adding `!` to all H1 elements ([#29964](https://github.com/element-hq/element-web/pull/29964)). Contributed by @t3chguy.
* Fix extensions panel style ([#29273](https://github.com/element-hq/element-web/pull/29273)). Contributed by @langleyd.
* Fix state events being hidden from widgets in read\_events actions ([#29954](https://github.com/element-hq/element-web/pull/29954)). Contributed by @robintown.
* Remove old filter test ([#29963](https://github.com/element-hq/element-web/pull/29963)). Contributed by @dbkr.
Changes in [1.11.101](https://github.com/element-hq/element-web/releases/tag/v1.11.101) (2025-05-20)
====================================================================================================
## ✨ Features

View File

@ -19,7 +19,7 @@ RUN /src/scripts/docker-package.sh
RUN cp /src/config.sample.json /src/webapp/config.json
# App
FROM nginxinc/nginx-unprivileged:alpine-slim@sha256:2acffd86b1bdefb8fa6b48b6e9aadf75430e8ab9c43c54c515ea7df77897f987
FROM nginxinc/nginx-unprivileged:alpine-slim@sha256:66e34aa81c2faf290ea4e4c28a490f2b35a07478265a2d5994c8637506045eee
# Need root user to install packages & manipulate the usr directory
USER root

View File

@ -1,6 +1,6 @@
{
"name": "element-web",
"version": "1.11.101",
"version": "1.11.103",
"description": "Element: the future of secure communication",
"author": "New Vector Ltd.",
"repository": {
@ -71,10 +71,10 @@
"**/pretty-format/react-is": "19.1.0",
"@playwright/test": "1.52.0",
"@types/react": "19.1.6",
"@types/react-dom": "19.1.5",
"@types/react-dom": "19.1.6",
"oidc-client-ts": "3.2.1",
"jwt-decode": "4.0.0",
"caniuse-lite": "1.0.30001720",
"caniuse-lite": "1.0.30001721",
"testcontainers": "^11.0.0",
"wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0",
"wrap-ansi": "npm:wrap-ansi@^7.0.0"
@ -138,7 +138,7 @@
"opus-recorder": "^8.0.3",
"pako": "^2.0.3",
"png-chunks-extract": "^1.0.0",
"posthog-js": "1.248.1",
"posthog-js": "1.249.4",
"qrcode": "1.5.4",
"re-resizable": "6.11.2",
"react": "^19.0.0",
@ -180,7 +180,7 @@
"@babel/preset-typescript": "^7.12.7",
"@babel/runtime": "^7.12.5",
"@casualbot/jest-sonar-reporter": "2.2.7",
"@element-hq/element-call-embedded": "0.12.0",
"@element-hq/element-call-embedded": "0.12.2",
"@element-hq/element-web-playwright-common": "^1.1.5",
"@peculiar/webcrypto": "^1.4.3",
"@playwright/test": "^1.50.1",
@ -214,7 +214,7 @@
"@types/qrcode": "^1.3.5",
"@types/react": "19.1.6",
"@types/react-beautiful-dnd": "^13.0.0",
"@types/react-dom": "19.1.5",
"@types/react-dom": "19.1.6",
"@types/react-transition-group": "^4.4.0",
"@types/sanitize-html": "2.16.0",
"@types/semver": "^7.5.8",

View File

@ -23,7 +23,13 @@ test.describe("Encryption state after registration", () => {
test("Key backup is enabled by default", async ({ page, mailpitClient, app }, testInfo) => {
await page.goto("/#/login");
await page.getByRole("button", { name: "Continue" }).click();
await registerAccountMas(page, mailpitClient, `alice_${testInfo.testId}`, "alice@email.com", "Pa$sW0rD!");
await registerAccountMas(
page,
mailpitClient,
`alice_${testInfo.testId}`,
`alice_${testInfo.testId}@email.com`,
"Pa$sW0rD!",
);
// Wait for the ui to load
await expect(page.locator(".mx_MatrixChat")).toBeVisible();
@ -35,7 +41,13 @@ test.describe("Encryption state after registration", () => {
test("user is prompted to set up recovery", async ({ page, mailpitClient, app }, testInfo) => {
await page.goto("/#/login");
await page.getByRole("button", { name: "Continue" }).click();
await registerAccountMas(page, mailpitClient, `alice_${testInfo.testId}`, "alice@email.com", "Pa$sW0rD!");
await registerAccountMas(
page,
mailpitClient,
`alice_${testInfo.testId}`,
`alice_${testInfo.testId}@email.com`,
"Pa$sW0rD!",
);
await page.getByRole("button", { name: "Add room" }).click();
await page.getByRole("menuitem", { name: "New room" }).click();
@ -64,7 +76,7 @@ test.describe("Key backup reset from elsewhere", () => {
await page.goto("/#/login");
await page.getByRole("button", { name: "Continue" }).click();
await registerAccountMas(page, mailpitClient, testUsername, "alice@email.com", testPassword);
await registerAccountMas(page, mailpitClient, testUsername, `${testUsername}@email.com`, testPassword);
await page.getByRole("button", { name: "Add room" }).click();
await page.getByRole("menuitem", { name: "New room" }).click();

View File

@ -22,6 +22,7 @@ import {
} from "./utils";
import { type Bot } from "../../pages/bot";
import { Toasts } from "../../pages/toasts.ts";
import type { ElementAppPage } from "../../pages/ElementAppPage.ts";
test.describe("Device verification", { tag: "@no-webkit" }, () => {
let aliceBotClient: Bot;
@ -163,38 +164,44 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => {
test("Verify device with Security Phrase during login", async ({ page, app, credentials, homeserver }) => {
await logIntoElement(page, credentials);
// Select the security phrase
await page.locator(".mx_AuthPage").getByRole("button", { name: "Verify with Recovery Key or Phrase" }).click();
// Fill the passphrase
const dialog = page.locator(".mx_Dialog");
await dialog.locator("textarea").fill("new passphrase");
await dialog.getByRole("button", { name: "Continue", disabled: false }).click();
await page.locator(".mx_AuthPage").getByRole("button", { name: "Done" }).click();
// Check that our device is now cross-signed
await checkDeviceIsCrossSigned(app);
// Check that the current device is connected to key backup
// The backup decryption key should be in cache also, as we got it directly from the 4S
await checkDeviceIsConnectedKeyBackup(app, expectedBackupVersion, true);
await enterRecoveryKeyAndCheckVerified(page, app, "new passphrase");
});
test("Verify device with Recovery Key during login", async ({ page, app, credentials, homeserver }) => {
const recoveryKey = (await aliceBotClient.getRecoveryKey()).encodedPrivateKey;
await logIntoElement(page, credentials);
await enterRecoveryKeyAndCheckVerified(page, app, recoveryKey);
});
test("Verify device with Recovery Key from settings", async ({ page, app, credentials }) => {
const recoveryKey = (await aliceBotClient.getRecoveryKey()).encodedPrivateKey;
await logIntoElement(page, credentials);
// Select the security phrase
await page.locator(".mx_AuthPage").getByRole("button", { name: "Verify with Recovery Key or Phrase" }).click();
/* Dismiss "Verify this device" */
const authPage = page.locator(".mx_AuthPage");
await authPage.getByRole("button", { name: "Skip verification for now" }).click();
await authPage.getByRole("button", { name: "I'll verify later" }).click();
await page.waitForSelector(".mx_MatrixChat");
// Fill the recovery key
const settings = await app.settings.openUserSettings("Encryption");
await settings.getByRole("button", { name: "Verify this device" }).click();
await enterRecoveryKeyAndCheckVerified(page, app, recoveryKey);
});
/** Helper for the three tests above which verify by recovery key */
async function enterRecoveryKeyAndCheckVerified(page: Page, app: ElementAppPage, recoveryKey: string) {
await page.getByRole("button", { name: "Verify with Recovery Key or Phrase" }).click();
// Enter the recovery key
const dialog = page.locator(".mx_Dialog");
const aliceRecoveryKey = await aliceBotClient.getRecoveryKey();
await dialog.locator("textarea").fill(aliceRecoveryKey.encodedPrivateKey);
// We use `pressSequentially` here to make sure that the FocusLock isn't causing us any problems
// (cf https://github.com/element-hq/element-web/issues/30089)
await dialog.locator("textarea").pressSequentially(recoveryKey);
await dialog.getByRole("button", { name: "Continue", disabled: false }).click();
await page.locator(".mx_AuthPage").getByRole("button", { name: "Done" }).click();
await page.getByRole("button", { name: "Done" }).click();
// Check that our device is now cross-signed
await checkDeviceIsCrossSigned(app);
@ -202,7 +209,7 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => {
// Check that the current device is connected to key backup
// The backup decryption key should be in cache also, as we got it directly from the 4S
await checkDeviceIsConnectedKeyBackup(app, expectedBackupVersion, true);
});
}
test("Handle incoming verification request with SAS", async ({ page, credentials, homeserver, toasts }) => {
await logIntoElement(page, credentials);

View File

@ -22,13 +22,21 @@ test.describe("Room list filters and sort", () => {
});
function getPrimaryFilters(page: Page): Locator {
return page.getByRole("listbox", { name: "Room list filters" });
return page.getByTestId("primary-filters");
}
function getRoomOptionsMenu(page: Page): Locator {
return page.getByRole("button", { name: "Room Options" });
}
function getFilterExpandButton(page: Page): Locator {
return getPrimaryFilters(page).getByRole("button", { name: "Expand filter list" });
}
function getFilterCollapseButton(page: Page): Locator {
return getPrimaryFilters(page).getByRole("button", { name: "Collapse filter list" });
}
/**
* Get the room list
* @param page
@ -136,6 +144,7 @@ test.describe("Room list filters and sort", () => {
await tile.click();
// Enable Favourite filter
await getFilterExpandButton(page).click();
const primaryFilters = getPrimaryFilters(page);
await primaryFilters.getByRole("option", { name: "Favourite" }).click();
await expect(tile).not.toBeVisible();
@ -223,10 +232,6 @@ test.describe("Room list filters and sort", () => {
expect(await roomList.locator("role=gridcell").count()).toBe(4);
await expect(primaryFilters).toMatchScreenshot("unread-primary-filters.png");
await primaryFilters.getByRole("option", { name: "Favourite" }).click();
await expect(roomList.getByRole("gridcell", { name: "favourite room" })).toBeVisible();
expect(await roomList.locator("role=gridcell").count()).toBe(1);
await primaryFilters.getByRole("option", { name: "People" }).click();
await expect(roomList.getByRole("gridcell", { name: "unread dm" })).toBeVisible();
await expect(roomList.getByRole("gridcell", { name: "invited room" })).toBeVisible();
@ -240,6 +245,12 @@ test.describe("Room list filters and sort", () => {
await expect(roomList.getByRole("gridcell", { name: "Low prio room" })).toBeVisible();
expect(await roomList.locator("role=gridcell").count()).toBe(5);
await getFilterExpandButton(page).click();
await primaryFilters.getByRole("option", { name: "Favourite" }).click();
await expect(roomList.getByRole("gridcell", { name: "favourite room" })).toBeVisible();
expect(await roomList.locator("role=gridcell").count()).toBe(1);
await primaryFilters.getByRole("option", { name: "Mentions" }).click();
await expect(roomList.getByRole("gridcell", { name: "room with mention" })).toBeVisible();
expect(await roomList.locator("role=gridcell").count()).toBe(1);
@ -247,6 +258,9 @@ test.describe("Room list filters and sort", () => {
await primaryFilters.getByRole("option", { name: "Invites" }).click();
await expect(roomList.getByRole("gridcell", { name: "invited room" })).toBeVisible();
expect(await roomList.locator("role=gridcell").count()).toBe(1);
await getFilterCollapseButton(page).click();
await expect(primaryFilters.locator("role=option").first()).toHaveText("Invites");
});
test(
@ -326,6 +340,8 @@ test.describe("Room list filters and sort", () => {
{ tag: "@screenshot" },
async ({ page, app, user }) => {
const primaryFilters = getPrimaryFilters(page);
await getFilterExpandButton(page).click();
await primaryFilters.getByRole("option", { name: filter }).click();
const emptyRoomList = getEmptyRoomList(page);
@ -343,6 +359,8 @@ test.describe("Room list filters and sort", () => {
{ tag: "@screenshot" },
async ({ page, app, user }) => {
const primaryFilters = getPrimaryFilters(page);
await getFilterExpandButton(page).click();
await primaryFilters.getByRole("option", { name: filter }).click();
const emptyRoomList = getEmptyRoomList(page);

View File

@ -255,6 +255,28 @@ test.describe("Room list", () => {
await expect(publicRoom).toMatchScreenshot("room-list-item-public.png");
});
test("should be a low priority room", { tag: "@screenshot" }, async ({ page, app, user }) => {
// @ts-ignore Visibility enum is not accessible
await app.client.createRoom({ name: "low priority room", visibility: "public" });
const roomListView = getRoomList(page);
const publicRoom = roomListView.getByRole("gridcell", { name: "low priority room" });
// Make room low priority
await publicRoom.hover();
const roomItemMenu = publicRoom.getByRole("button", { name: "More Options" });
await roomItemMenu.click();
await page.getByRole("menuitemcheckbox", { name: "Low priority" }).click();
// Should have low priority decoration
await expect(publicRoom.locator(".mx_RoomAvatarView_icon")).toHaveAccessibleName(
"This is a low priority room",
);
// focus the user menu to avoid to have hover decoration
await page.getByRole("button", { name: "User menu" }).focus();
await expect(publicRoom).toMatchScreenshot("room-list-item-low-priority.png");
});
test("should be a video room", { tag: "@screenshot" }, async ({ page, app, user }) => {
await page.getByTestId("room-list-panel").getByRole("button", { name: "Add" }).click();
await page.getByRole("menuitem", { name: "New video room" }).click();
@ -333,10 +355,11 @@ test.describe("Room list", () => {
});
test("should render a message preview", { tag: "@screenshot" }, async ({ page, app, user, bot }) => {
const roomListView = getRoomList(page);
await app.settings.openUserSettings("Preferences");
await page.getByRole("switch", { name: "Show message previews" }).click();
await app.closeDialog();
await page.getByRole("button", { name: "Room Options" }).click();
await page.getByRole("menuitemcheckbox", { name: "Show message previews" }).click();
const roomListView = getRoomList(page);
const roomId = await app.client.createRoom({ name: "activity" });

View File

@ -33,7 +33,7 @@ test.describe("OIDC Native", { tag: ["@no-firefox", "@no-webkit"] }, () => {
await page.getByRole("button", { name: "Continue" }).click();
const userId = `alice_${testInfo.testId}`;
await registerAccountMas(page, mailpitClient, userId, "alice@email.com", "Pa$sW0rD!");
await registerAccountMas(page, mailpitClient, userId, `${userId}@email.com`, "Pa$sW0rD!");
// Eventually, we should end up at the home screen.
await expect(page).toHaveURL(/\/#\/home$/, { timeout: 10000 });
@ -55,7 +55,7 @@ test.describe("OIDC Native", { tag: ["@no-firefox", "@no-webkit"] }, () => {
const newPage = await newPagePromise;
await newPage.getByText("Devices").click();
await newPage.getByText(deviceId).click();
await expect(newPage.getByText("Element")).toBeVisible();
await expect(newPage.getByText("Element", { exact: true })).toBeVisible();
await expect(newPage.getByText("http://localhost:8080/")).toBeVisible();
await expect(newPage).toHaveURL(/\/oauth2_session/);
await newPage.close();
@ -83,7 +83,7 @@ test.describe("OIDC Native", { tag: ["@no-firefox", "@no-webkit"] }, () => {
await page.getByRole("button", { name: "Continue" }).click();
const userId = `alice_${testInfo.testId}`;
await registerAccountMas(page, mailpitClient, userId, "alice@email.com", "Pa$sW0rD!");
await registerAccountMas(page, mailpitClient, userId, `${userId}@email.com`, "Pa$sW0rD!");
await expect(page.getByText("Welcome")).toBeVisible();
await page.goto("about:blank");

View File

@ -21,10 +21,12 @@ test.describe("Preferences user settings tab", () => {
const locator = await app.settings.openUserSettings("Preferences");
await use(locator);
},
// display message preview settings
labsFlags: ["feature_new_room_list"],
});
test("should be rendered properly", { tag: "@screenshot" }, async ({ app, page, user }) => {
await page.setViewportSize({ width: 1024, height: 3300 });
await page.setViewportSize({ width: 1024, height: 4000 });
const tab = await app.settings.openUserSettings("Preferences");
// Assert that the top heading is rendered
await expect(tab.getByRole("heading", { name: "Preferences" })).toBeVisible();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 KiB

After

Width:  |  Height:  |  Size: 272 KiB

View File

@ -32,7 +32,7 @@ Please see LICENSE files in the repository root for full details.
color: $alert;
&::before {
mask-image: url("@vector-im/compound-design-tokens/icons/close.svg");
mask-image: url("@vector-im/compound-design-tokens/icons/error-solid.svg");
background-color: $alert;
}
}

View File

@ -6,7 +6,32 @@
*/
.mx_RoomListPrimaryFilters {
margin: unset;
list-style-type: none;
padding: var(--cpd-space-2x) var(--cpd-space-3x);
padding: var(--cpd-space-2x) var(--cpd-space-4x) var(--cpd-space-2x) var(--cpd-space-3x);
.mx_RoomListPrimaryFilters_wrapping {
display: none;
}
ul {
margin: unset;
padding: unset;
list-style-type: none;
/**
* The InteractionObserver needs the height to be set to work properly.
*/
height: 100%;
flex: 1;
}
.mx_RoomListPrimaryFilters_IconButton {
svg {
transition: transform 0.1s linear;
}
}
.mx_RoomListPrimaryFilters_IconButton[aria-expanded="true"] {
svg {
transform: rotate(180deg);
}
}
}

View File

@ -128,13 +128,19 @@ declare global {
}
interface Electron {
// Legacy
on(channel: ElectronChannel, listener: (event: Event, ...args: any[]) => void): void;
send(channel: ElectronChannel, ...args: any[]): void;
// Initialisation
initialise(): Promise<{
protocol: string;
sessionId: string;
config: IConfigOptions;
supportedSettings: Record<string, boolean>;
}>;
// Settings
setSettingValue(settingName: string, value: any): Promise<void>;
getSettingValue(settingName: string): Promise<any>;
}
interface DesktopCapturerSource {

View File

@ -0,0 +1,29 @@
/*
Copyright 2025 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
export const INVITE_RULES_ACCOUNT_DATA_TYPE = "org.matrix.msc4155.invite_permission_config";
export interface InviteConfigAccountData {
allowed_users?: string[];
blocked_users?: string[];
ignored_users?: string[];
allowed_servers?: string[];
blocked_servers?: string[];
ignored_servers?: string[];
}
/**
* Computed values based on MSC4155. Currently Element Web only supports
* blocking all invites.
*/
export interface ComputedInviteConfig extends Record<string, unknown> {
/**
* Are all invites blocked. This is only about blocking all invites,
* but this being false may still block invites through other rules.
*/
allBlocked: boolean;
}

View File

@ -15,6 +15,7 @@ import type { EmptyObject } from "matrix-js-sdk/src/matrix";
import type { DeviceClientInformation } from "../utils/device/types.ts";
import type { UserWidget } from "../utils/WidgetUtils-types.ts";
import { type MediaPreviewConfig } from "./media_preview.ts";
import { type INVITE_RULES_ACCOUNT_DATA_TYPE, type InviteConfigAccountData } from "./invite-rules.ts";
// Extend Matrix JS SDK types via Typescript declaration merging to support unspecced event fields and types
declare module "matrix-js-sdk/src/types" {
@ -60,7 +61,6 @@ declare module "matrix-js-sdk/src/types" {
};
};
}
export interface AccountDataEvents {
// Analytics account data event
"im.vector.analytics": {
@ -89,6 +89,8 @@ declare module "matrix-js-sdk/src/types" {
accepted: string[];
};
// MSC4155: Invite filtering
[INVITE_RULES_ACCOUNT_DATA_TYPE]: InviteConfigAccountData;
"io.element.msc4278.media_preview_config": MediaPreviewConfig;
}

View File

@ -63,6 +63,7 @@ import { blobIsAnimated } from "./utils/Image.ts";
const PHYS_HIDPI = [0x00, 0x00, 0x16, 0x25, 0x00, 0x00, 0x16, 0x25, 0x01];
export class UploadCanceledError extends Error {}
export class UploadFailedError extends Error {}
interface IMediaConfig {
"m.upload.size"?: number;
@ -355,12 +356,19 @@ export async function uploadFile(
// Pass the encrypted data as a Blob to the uploader.
const blob = new Blob([encryptResult.data]);
const { content_uri: url } = await matrixClient.uploadContent(blob, {
progressHandler,
abortController,
includeFilename: false,
type: "application/octet-stream",
});
let url: string;
try {
({ content_uri: url } = await matrixClient.uploadContent(blob, {
progressHandler,
abortController,
includeFilename: false,
type: "application/octet-stream",
}));
} catch (e) {
if (abortController.signal.aborted) throw new UploadCanceledError();
console.error("Failed to upload file", e);
throw new UploadFailedError();
}
if (abortController.signal.aborted) throw new UploadCanceledError();
// If the attachment is encrypted then bundle the URL along with the information
@ -372,7 +380,14 @@ export async function uploadFile(
} as EncryptedFile,
};
} else {
const { content_uri: url } = await matrixClient.uploadContent(file, { progressHandler, abortController });
let url: string;
try {
({ content_uri: url } = await matrixClient.uploadContent(file, { progressHandler, abortController }));
} catch (e) {
if (abortController.signal.aborted) throw new UploadCanceledError();
console.error("Failed to upload file", e);
throw new UploadFailedError();
}
if (abortController.signal.aborted) throw new UploadCanceledError();
// If the attachment isn't encrypted then include the URL directly.
return { url };
@ -570,7 +585,7 @@ export default class ContentMessages {
const imageInfo = await infoForImageFile(matrixClient, roomId, file);
Object.assign(content.info, imageInfo);
} catch (e) {
if (e instanceof HTTPError) {
if (e instanceof UploadFailedError) {
// re-throw to main upload error handler
throw e;
}

View File

@ -38,10 +38,10 @@ export async function createCrossSigning(cli: MatrixClient): Promise<void> {
export async function uiAuthCallback(
matrixClient: MatrixClient,
makeRequest: (authData: AuthDict) => Promise<void>,
makeRequest: (authData: AuthDict | null) => Promise<void>,
): Promise<void> {
try {
await makeRequest({});
await makeRequest(null);
} catch (error) {
if (!(error instanceof MatrixError) || !error.data || !error.data.flows) {
// Not a UIA response

View File

@ -19,7 +19,6 @@ import AccessSecretStorageDialog, {
type KeyParams,
} from "./components/views/dialogs/security/AccessSecretStorageDialog";
import { ModuleRunner } from "./modules/ModuleRunner";
import QuestionDialog from "./components/views/dialogs/QuestionDialog";
import InteractiveAuthDialog from "./components/views/dialogs/InteractiveAuthDialog";
// This stores the secret storage private keys in memory for the JS SDK. This is
@ -50,17 +49,6 @@ export class AccessCancelledError extends Error {
}
}
async function confirmToDismiss(): Promise<boolean> {
const [sure] = await Modal.createDialog(QuestionDialog, {
title: _t("encryption|cancel_entering_passphrase_title"),
description: _t("encryption|cancel_entering_passphrase_description"),
danger: false,
button: _t("action|go_back"),
cancelButton: _t("action|cancel"),
}).finished;
return !sure;
}
function makeInputToKey(
keyInfo: SecretStorage.SecretStorageKeyDescription,
): (keyParams: KeyParams) => Promise<Uint8Array> {
@ -134,17 +122,6 @@ async function getSecretStorageKey(
return MatrixClientPeg.safeGet().secretStorage.checkKey(key, keyInfo);
},
},
/* className= */ undefined,
/* isPriorityModal= */ false,
/* isStaticModal= */ false,
/* options= */ {
onBeforeClose: async (reason): Promise<boolean> => {
if (reason === "backgroundClick") {
return confirmToDismiss();
}
return true;
},
},
);
const [keyParams] = await finished;
if (!keyParams) {

View File

@ -60,6 +60,7 @@ import { deop, op } from "./slash-commands/op";
import { CommandCategories } from "./slash-commands/interface";
import { Command } from "./slash-commands/command";
import { goto, join } from "./slash-commands/join";
import { manuallyVerifyDevice } from "./components/views/dialogs/ManualDeviceKeyVerificationDialog";
export { CommandCategories, Command };
@ -663,6 +664,36 @@ export const Commands = [
category: CommandCategories.admin,
renderingTypes: [TimelineRenderingType.Room],
}),
new Command({
command: "verify",
args: "<device-id> <device-fingerprint>",
description: _td("slash_command|verify"),
runFn: function (cli, _roomId, _threadId, args) {
if (args) {
const matches = args.match(/^(\S+) +(\S+)$/);
if (matches) {
const deviceId = matches[1];
const fingerprint = matches[2];
const { finished } = Modal.createDialog(QuestionDialog, {
title: _t("slash_command|manual_device_verification_confirm_title"),
description: _t("slash_command|manual_device_verification_confirm_description"),
button: _t("action|verify"),
danger: true,
});
return success(
finished.then(([confirmed]) => {
if (confirmed) manuallyVerifyDevice(cli, deviceId, fingerprint);
}),
);
}
}
return reject(this.getUsage());
},
category: CommandCategories.advanced,
renderingTypes: [TimelineRenderingType.Room],
}),
new Command({
command: "discardsession",
description: _td("slash_command|discardsession"),

View File

@ -370,6 +370,10 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
private unmounted = false;
private permalinkCreators: Record<string, RoomPermalinkCreator> = {};
// The userId from which we received this invite.
// Only populated if the membership of our user is invite.
private inviter?: string;
private roomView = createRef<HTMLDivElement>();
private searchResultsPanel = createRef<ScrollPanel>();
private messagePanel: TimelinePanel | null = null;
@ -1350,6 +1354,11 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
// after a successful peek, or after we join the room).
private onRoomLoaded = (room: Room): void => {
if (this.unmounted) return;
// Store the inviter so that we can know who invited us to this room even if
// the membership event changes.
this.inviter = this.getInviterFromRoom(room);
// Attach a widget store listener only when we get a room
this.context.widgetLayoutStore.on(WidgetLayoutStore.emissionForRoom(room), this.onWidgetLayoutChange);
@ -1729,8 +1738,20 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
});
};
private getInviterFromRoom(room: Room): string | undefined {
const ownUserId = this.context.client?.getSafeUserId();
if (!ownUserId) return;
const myMember = room.getMember(ownUserId);
const memberEvent = myMember?.events.member;
const senderId = memberEvent?.getSender();
if (memberEvent?.getContent().membership === KnownMembership.Invite) return senderId;
}
private onDeclineAndBlockButtonClicked = async (): Promise<void> => {
if (!this.state.room || !this.context.client) return;
const [shouldReject, ignoreUser, reportRoom] = await Modal.createDialog(DeclineAndBlockInviteDialog, {
roomName: this.state.room.name,
}).finished;
@ -1745,11 +1766,20 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
const actions: Promise<unknown>[] = [];
if (ignoreUser) {
const myMember = this.state.room.getMember(this.context.client!.getSafeUserId());
const inviteEvent = myMember!.events.member;
const ignoredUsers = this.context.client.getIgnoredUsers();
ignoredUsers.push(inviteEvent!.getSender()!); // de-duped internally in the js-sdk
actions.push(this.context.client.setIgnoredUsers(ignoredUsers));
const doIgnore = async (): Promise<void> => {
const ownUserId = this.context.client!.getSafeUserId();
if (!this.inviter || this.inviter === ownUserId) {
// This is unlikely to happen since we cache the inviter as early as possible.
// However, we still do this check here to be double sure.
throw new CannotDetermineUserError(
"Cannot determine which user to ignore since the member event has changed.",
);
}
const ignoredUsers = this.context.client!.getIgnoredUsers();
ignoredUsers.push(this.inviter); // de-duped internally in the js-sdk
await this.context.client!.setIgnoredUsers(ignoredUsers);
};
actions.push(doIgnore());
}
if (reportRoom !== false) {
@ -1766,7 +1796,14 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
} catch (error) {
logger.error(`Failed to reject invite: ${error}`);
const msg = error instanceof Error ? error.message : JSON.stringify(error);
let msg: string = "";
if (error instanceof CannotDetermineUserError) {
msg = _t("room|failed_determine_user");
} else if (error instanceof Error) {
msg = error.message;
} else {
msg = JSON.stringify(error);
}
Modal.createDialog(ErrorDialog, {
title: _t("room|failed_reject_invite"),
description: msg,
@ -1783,6 +1820,9 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
return;
}
try {
this.setState({
rejecting: true,
});
await this.context.client.leave(this.state.room.roomId);
defaultDispatcher.dispatch({ action: Action.ViewHomePage });
this.setState({
@ -2612,3 +2652,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
);
}
}
class CannotDetermineUserError extends Error {
public name = "CannotDetermineUserError";
}

View File

@ -10,26 +10,26 @@ import { useEffect, useState } from "react";
import { useTypedEventEmitter } from "../../../hooks/useEventEmitter";
import { useDmMember, usePresence, type Presence } from "../../views/avatars/WithPresenceIndicator";
import { DefaultTagID } from "../../../stores/room-list/models";
export enum AvatarBadgeDecoration {
LowPriority = "LowPriority",
VideoRoom = "VideoRoom",
PublicRoom = "PublicRoom",
Presence = "Presence",
}
export interface RoomAvatarViewState {
/**
* Whether the room avatar has a decoration.
* A decoration can be a public or a video call icon or an indicator of presence.
*/
hasDecoration: boolean;
/**
* Whether the room is public.
*/
isPublic: boolean;
/**
* Whether the room is a video room.
*/
isVideoRoom: boolean;
/**
* The presence of the user in the DM room.
* If null, the user is not in a DM room or presence is not enabled.
*/
presence: Presence | null;
/**
* The decoration that should be rendered.
*/
badgeDecoration?: AvatarBadgeDecoration;
}
/**
@ -41,10 +41,20 @@ export function useRoomAvatarViewModel(room: Room): RoomAvatarViewState {
const roomMember = useDmMember(room);
const presence = usePresence(room, roomMember);
const isPublic = useIsPublic(room);
const isLowPriority = !!room.tags[DefaultTagID.LowPriority];
const hasDecoration = isPublic || isVideoRoom || presence !== null;
let badgeDecoration: AvatarBadgeDecoration | undefined;
if (isLowPriority) {
badgeDecoration = AvatarBadgeDecoration.LowPriority;
} else if (isVideoRoom) {
badgeDecoration = AvatarBadgeDecoration.VideoRoom;
} else if (isPublic) {
badgeDecoration = AvatarBadgeDecoration.PublicRoom;
} else if (presence) {
badgeDecoration = AvatarBadgeDecoration.Presence;
}
return { hasDecoration, isPublic, isVideoRoom, presence };
return { badgeDecoration, presence };
}
/**

View File

@ -32,7 +32,6 @@ import { useMatrixClientContext } from "../../../contexts/MatrixClientContext";
import type { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { createRoom, hasCreateRoomRights } from "./utils";
import { type SortOption, useSorter } from "./useSorter";
import { useMessagePreviewToggle } from "./useMessagePreviewToggle";
/**
* Hook to get the active space and its title.
@ -127,14 +126,6 @@ export interface RoomListHeaderViewState {
* The currently active sort option.
*/
activeSortOption: SortOption;
/**
* Whether message previews must be shown or not.
*/
shouldShowMessagePreview: boolean;
/**
* A function to turn on/off message previews.
*/
toggleMessagePreview: () => void;
}
/**
@ -157,7 +148,6 @@ export function useRoomListHeaderViewModel(): RoomListHeaderViewState {
/* Actions */
const { activeSortOption, sort } = useSorter();
const { shouldShowMessagePreview, toggleMessagePreview } = useMessagePreviewToggle();
const createChatRoom = useCallback((e: Event) => {
defaultDispatcher.fire(Action.CreateChat);
@ -230,7 +220,5 @@ export function useRoomListHeaderViewModel(): RoomListHeaderViewState {
openSpaceSettings,
activeSortOption,
sort,
shouldShowMessagePreview,
toggleMessagePreview,
};
}

View File

@ -37,6 +37,10 @@ export interface RoomListItemMenuViewState {
* Whether the room is a favourite room.
*/
isFavourite: boolean;
/**
* Whether the room is a low priority room.
*/
isLowPriority: boolean;
/**
* Can invite other user's in the room.
*/
@ -117,6 +121,7 @@ export function useRoomListItemMenuViewModel(room: Room): RoomListItemMenuViewSt
const isDm = Boolean(DMRoomMap.shared().getUserIdForRoomId(room.roomId));
const isFavourite = Boolean(roomTags[DefaultTagID.Favourite]);
const isLowPriority = Boolean(roomTags[DefaultTagID.LowPriority]);
const isArchived = Boolean(roomTags[DefaultTagID.Archived]);
const showMoreOptionsMenu = hasAccessToOptionsMenu(room);
@ -200,6 +205,7 @@ export function useRoomListItemMenuViewModel(room: Room): RoomListItemMenuViewSt
showMoreOptionsMenu,
showNotificationMenu,
isFavourite,
isLowPriority,
canInvite,
canCopyRoomLink,
canMarkAsRead,

View File

@ -50,6 +50,7 @@ const filterKeyToNameMap: Map<FilterKey, TranslationKey> = new Map([
[FilterKey.MentionsFilter, _td("room_list|filters|mentions")],
[FilterKey.InvitesFilter, _td("room_list|filters|invites")],
[FilterKey.FavouriteFilter, _td("room_list|filters|favourite")],
[FilterKey.LowPriorityFilter, _td("room_list|filters|low_priority")],
]);
/**

View File

@ -9,13 +9,14 @@ import React, { type JSX } from "react";
import { type Room } from "matrix-js-sdk/src/matrix";
import PublicIcon from "@vector-im/compound-design-tokens/assets/web/icons/public";
import VideoIcon from "@vector-im/compound-design-tokens/assets/web/icons/video-call-solid";
import ArrowDownIcon from "@vector-im/compound-design-tokens/assets/web/icons/arrow-down";
import OnlineOrUnavailableIcon from "@vector-im/compound-design-tokens/assets/web/icons/presence-solid-8x8";
import OfflineIcon from "@vector-im/compound-design-tokens/assets/web/icons/presence-outline-8x8";
import BusyIcon from "@vector-im/compound-design-tokens/assets/web/icons/presence-strikethrough-8x8";
import classNames from "classnames";
import RoomAvatar from "./RoomAvatar";
import { useRoomAvatarViewModel } from "../../viewmodels/avatars/RoomAvatarViewModel";
import { AvatarBadgeDecoration, useRoomAvatarViewModel } from "../../viewmodels/avatars/RoomAvatarViewModel";
import { _t } from "../../../languageHandler";
import { Presence } from "./WithPresenceIndicator";
@ -33,41 +34,21 @@ interface RoomAvatarViewProps {
export function RoomAvatarView({ room }: RoomAvatarViewProps): JSX.Element {
const vm = useRoomAvatarViewModel(room);
// No decoration, we just show the avatar
if (!vm.hasDecoration) return <RoomAvatar size="32px" room={room} />;
if (!vm.badgeDecoration) return <RoomAvatar size="32px" room={room} />;
const icon = getAvatarDecoration(vm.badgeDecoration, vm.presence);
// Presence indicator and video/public icons don't have the same size
// We use different masks
const maskClass =
vm.badgeDecoration === AvatarBadgeDecoration.Presence
? "mx_RoomAvatarView_RoomAvatar_presence"
: "mx_RoomAvatarView_RoomAvatar_icon";
return (
<div className="mx_RoomAvatarView">
<RoomAvatar
className={classNames("mx_RoomAvatarView_RoomAvatar", {
// Presence indicator and video/public icons don't have the same size
// We use different masks
mx_RoomAvatarView_RoomAvatar_icon: vm.isVideoRoom || vm.isPublic,
mx_RoomAvatarView_RoomAvatar_presence: Boolean(vm.presence),
})}
size="32px"
room={room}
/>
{/* If the room is a public video room, we prefer to display only the video icon */}
{vm.isPublic && !vm.isVideoRoom && (
<PublicIcon
width="16px"
height="16px"
className="mx_RoomAvatarView_icon"
color="var(--cpd-color-icon-tertiary)"
aria-label={_t("room|header|room_is_public")}
/>
)}
{vm.isVideoRoom && (
<VideoIcon
width="16px"
height="16px"
className="mx_RoomAvatarView_icon"
color="var(--cpd-color-icon-tertiary)"
aria-label={_t("room|video_room")}
/>
)}
{vm.presence && <PresenceDecoration presence={vm.presence} />}
<RoomAvatar className={classNames("mx_RoomAvatarView_RoomAvatar", maskClass)} size="32px" room={room} />
{icon}
</div>
);
}
@ -126,3 +107,39 @@ function PresenceDecoration({ presence }: PresenceDecorationProps): JSX.Element
);
}
}
function getAvatarDecoration(decoration: AvatarBadgeDecoration, presence: Presence | null): React.ReactNode {
if (decoration === AvatarBadgeDecoration.LowPriority) {
return (
<ArrowDownIcon
width="16px"
height="16px"
className="mx_RoomAvatarView_icon"
color="var(--cpd-color-icon-tertiary)"
aria-label={_t("room|room_is_low_priority")}
/>
);
} else if (decoration === AvatarBadgeDecoration.VideoRoom) {
return (
<VideoIcon
width="16px"
height="16px"
className="mx_RoomAvatarView_icon"
color="var(--cpd-color-icon-tertiary)"
aria-label={_t("room|video_room")}
/>
);
} else if (decoration === AvatarBadgeDecoration.PublicRoom) {
return (
<PublicIcon
width="16px"
height="16px"
className="mx_RoomAvatarView_icon"
color="var(--cpd-color-icon-tertiary)"
aria-label={_t("room|header|room_is_public")}
/>
);
} else if (decoration === AvatarBadgeDecoration.Presence) {
return <PresenceDecoration presence={presence!} />;
}
}

View File

@ -23,13 +23,25 @@ import { getKeyBindingsManager } from "../../../KeyBindingsManager";
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
interface IProps {
// Whether the dialog should have a 'close' button that will
// cause the dialog to be cancelled. This should only be set
// to false if there is nothing the app can sensibly do if the
// dialog is cancelled, eg. "We can't restore your session and
// the app cannot work". Default: true.
/**
* Whether the dialog should have a 'close' button and a keyDown handler which
* will intercept 'Escape'.
*
* This should only be set to `false` if there is nothing the app can sensibly do if the
* dialog is cancelled, eg. "We can't restore your session and
* the app cannot work".
*
* Default: `true`.
*/
"hasCancel"?: boolean;
/**
* Callback that will be called when the 'close' button is clicked or 'Escape' is pressed.
*
* Not used if `hasCancel` is false.
*/
"onFinished"?: () => void;
// called when a key is pressed
"onKeyDown"?: (e: KeyboardEvent | React.KeyboardEvent) => void;
@ -66,7 +78,6 @@ interface IProps {
// optional Posthog ScreenName to supply during the lifetime of this dialog
"screenName"?: ScreenName;
onFinished(): void;
}
/*
@ -103,13 +114,13 @@ export default class BaseDialog extends React.Component<IProps> {
e.stopPropagation();
e.preventDefault();
this.props.onFinished();
this.props.onFinished?.();
break;
}
};
private onCancelClick = (): void => {
this.props.onFinished();
this.props.onFinished?.();
};
public render(): React.ReactNode {

View File

@ -0,0 +1,171 @@
/*
Copyright 2024-2025 New Vector Ltd.
Copyright 2020 The Matrix.org Foundation C.I.C.
Copyright 2019 New Vector Ltd
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
Copyright 2017 Vector Creations Ltd
Copyright 2016 OpenMarket Ltd
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import React, { type ChangeEvent, type JSX, useCallback, useState } from "react";
import { type MatrixClient } from "matrix-js-sdk/src/matrix";
import { _t, UserFriendlyError } from "../../../languageHandler";
import { getDeviceCryptoInfo } from "../../../utils/crypto/deviceInfo";
import QuestionDialog from "./QuestionDialog";
import Modal from "../../../Modal";
import InfoDialog from "./InfoDialog";
import Field from "../elements/Field";
import ErrorDialog from "./ErrorDialog";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
interface Props {
onFinished(confirm?: boolean): void;
}
/**
* A dialog to allow us to verify devices logged in with clients that can't do
* the verification themselves. Intended for use as a dev tool.
*
* Requires entering the fingerprint ("session key") of the device in an attempt
* to prevent users being tricked into verifying a malicious device.
*/
export function ManualDeviceKeyVerificationDialog({ onFinished }: Readonly<Props>): JSX.Element {
const [deviceId, setDeviceId] = useState("");
const [fingerprint, setFingerprint] = useState("");
const client = MatrixClientPeg.safeGet();
const onDialogFinished = useCallback(
async (confirm: boolean) => {
if (confirm) {
await manuallyVerifyDevice(client, deviceId, fingerprint);
}
onFinished(confirm);
},
[client, deviceId, fingerprint, onFinished],
);
const onDeviceIdChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
setDeviceId(e.target.value);
}, []);
const onFingerprintChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
setFingerprint(e.target.value);
}, []);
const body = (
<div>
<p>{_t("encryption|verification|manual|text")}</p>
<div className="mx_DeviceVerifyDialog_cryptoSection">
<Field
className="mx_TextInputDialog_input"
type="text"
label={_t("encryption|verification|manual|device_id")}
value={deviceId}
onChange={onDeviceIdChange}
/>
<Field
className="mx_TextInputDialog_input"
type="text"
label={_t("encryption|verification|manual|fingerprint")}
value={fingerprint}
onChange={onFingerprintChange}
/>
</div>
</div>
);
return (
<QuestionDialog
title={_t("settings|sessions|verify_session")}
description={body}
button={_t("settings|sessions|verify_session")}
onFinished={onDialogFinished}
/>
);
}
/**
* Check the supplied fingerprint matches the fingerprint ("session key") of the
* device with the supplied device ID, and if so, mark the device as verified.
*/
export async function manuallyVerifyDevice(client: MatrixClient, deviceId: string, fingerprint: string): Promise<void> {
try {
await doManuallyVerifyDevice(client, deviceId, fingerprint);
// Tell the user we verified everything
Modal.createDialog(InfoDialog, {
title: _t("encryption|verification|manual|success_title"),
description: (
<div>
<p>{_t("encryption|verification|manual|success_description", { deviceId })}</p>
</div>
),
});
} catch (e: any) {
// Display an error
const error = e instanceof UserFriendlyError ? e.translatedMessage : e.toString();
Modal.createDialog(ErrorDialog, {
title: _t("encryption|verification|manual|failure_title"),
description: (
<div>
<p>{_t("encryption|verification|manual|failure_description", { deviceId, error })}</p>
</div>
),
});
}
}
async function doManuallyVerifyDevice(client: MatrixClient, deviceId: string, fingerprint: string): Promise<void> {
const userId = client.getUserId();
if (!userId) {
throw new UserFriendlyError("encryption|verification|manual|no_userid", {
cause: undefined,
});
}
const crypto = client.getCrypto();
if (!crypto) {
throw new UserFriendlyError("encryption|verification|manual|no_crypto");
}
const device = await getDeviceCryptoInfo(client, userId, deviceId);
if (!device) {
throw new UserFriendlyError("encryption|verification|manual|no_device", {
deviceId,
cause: undefined,
});
}
const deviceTrust = await crypto.getDeviceVerificationStatus(userId, deviceId);
if (deviceTrust?.isVerified()) {
if (device.getFingerprint() === fingerprint) {
throw new UserFriendlyError("encryption|verification|manual|already_verified", {
deviceId,
cause: undefined,
});
} else {
throw new UserFriendlyError("encryption|verification|manual|already_verified_and_wrong_fingerprint", {
deviceId,
cause: undefined,
});
}
}
if (device.getFingerprint() !== fingerprint) {
const fprint = device.getFingerprint();
throw new UserFriendlyError("encryption|verification|manual|wrong_fingerprint", {
fprint,
deviceId,
fingerprint,
cause: undefined,
});
}
// We've passed all the checks - do the device verification
await crypto.crossSignDevice(deviceId);
}

View File

@ -12,6 +12,8 @@ import { useMatrixClientContext } from "../../../../contexts/MatrixClientContext
import BaseTool from "./BaseTool";
import { useAsyncMemo } from "../../../../hooks/useAsyncMemo";
import { _t } from "../../../../languageHandler";
import Modal from "../../../../Modal";
import { ManualDeviceKeyVerificationDialog } from "../ManualDeviceKeyVerificationDialog";
interface KeyBackupProps {
/**
@ -31,6 +33,16 @@ export function Crypto({ onBack }: KeyBackupProps): JSX.Element {
<>
<KeyStorage />
<CrossSigning />
<Session />
<button
type="button"
onClick={() => {
Modal.createDialog(ManualDeviceKeyVerificationDialog);
}}
>
{_t("devtools|manual_device_verification")}
</button>
</>
) : (
<span>{_t("devtools|crypto|crypto_not_available")}</span>
@ -254,3 +266,39 @@ function getCrossSigningStatus(crossSigningReady: boolean, crossSigningPrivateKe
return _t("devtools|crypto|cross_signing_not_ready");
}
/**
* A component that displays information about the current session.
*/
function Session(): JSX.Element {
const matrixClient = useMatrixClientContext();
const sessionData = useAsyncMemo(async () => {
const crypto = matrixClient.getCrypto()!;
const keys = await crypto.getOwnDeviceKeys();
return {
fingerprint: keys.ed25519,
deviceId: matrixClient.deviceId,
};
}, [matrixClient]);
// Show a spinner while loading
if (sessionData === undefined) {
return <InlineSpinner aria-label={_t("common|loading")} />;
}
return (
<table aria-label={_t("devtools|crypto|session")}>
<thead>{_t("devtools|crypto|session")}</thead>
<tbody>
<tr>
<th scope="row">{_t("devtools|crypto|device_id")}</th>
<td>{sessionData.deviceId}</td>
</tr>
<tr>
<th scope="row">{_t("devtools|crypto|session_fingerprint")}</th>
<td>{sessionData.fingerprint}</td>
</tr>
</tbody>
</table>
);
}

View File

@ -14,9 +14,11 @@ import React, { type ChangeEvent, type FormEvent } from "react";
import { type SecretStorage } from "matrix-js-sdk/src/matrix";
import Field from "../../elements/Field";
import { Flex } from "../../../utils/Flex";
import { _t } from "../../../../languageHandler";
import { EncryptionCard } from "../../settings/encryption/EncryptionCard";
import { EncryptionCardButtons } from "../../settings/encryption/EncryptionCardButtons";
import BaseDialog from "../BaseDialog";
// Don't shout at the user that their key is invalid every time they type a key: wait a short time
const VALIDATION_THROTTLE_MS = 200;
@ -83,6 +85,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
this.setState({
recoveryKeyCorrect: null,
});
return;
}
const hasPassphrase = this.props.keyInfo?.passphrase?.salt && this.props.keyInfo?.passphrase?.iterations;
@ -139,30 +142,30 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
}
};
private getKeyValidationClasses(): string {
return classNames({
"mx_AccessSecretStorageDialog_recoveryKeyFeedback": this.state.recoveryKeyCorrect !== null,
"mx_AccessSecretStorageDialog_recoveryKeyFeedback--invalid": this.state.recoveryKeyCorrect === false,
});
}
private getKeyValidationText(): string | null {
if (this.state.recoveryKeyCorrect) {
return null;
} else if (this.state.recoveryKeyCorrect === null) {
return _t("encryption|access_secret_storage_dialog|alternatives");
} else {
return _t("encryption|access_secret_storage_dialog|key_validation_text|wrong_security_key");
}
}
private getRecoveryKeyFeedback(): React.ReactNode | null {
const validationText = this.getKeyValidationText();
if (validationText === null) {
return null;
let validationText: string;
let classes: string | undefined;
if (this.state.recoveryKeyCorrect) {
// The recovery key is good. Empty feedback.
validationText = "\xA0"; // &nbsp;
} else if (this.state.recoveryKeyCorrect === null) {
// The input element is empty. Tell the user they can also use a passphrase.
validationText = _t("encryption|access_secret_storage_dialog|alternatives");
} else {
return <div className={this.getKeyValidationClasses()}>{validationText}</div>;
// The entered key is not (yet) correct. Tell them so.
validationText = _t("encryption|access_secret_storage_dialog|key_validation_text|wrong_security_key");
classes = classNames({
"mx_AccessSecretStorageDialog_recoveryKeyFeedback": true,
"mx_AccessSecretStorageDialog_recoveryKeyFeedback--invalid": true,
});
}
return (
<Flex align="center" className={classes}>
{validationText}
</Flex>
);
}
public render(): React.ReactNode {
@ -205,15 +208,19 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
</div>
);
// We wrap the content in `BaseDialog` mostly so that we get a `FocusLock` container; otherwise, if the
// SettingsDialog is open, then the `FocusLock` in *that* stops us getting the focus.
return (
<EncryptionCard
Icon={LockSolidIcon}
className="mx_AccessSecretStorageDialog"
title={title}
description={_t("encryption|access_secret_storage_dialog|privacy_warning")}
>
{content}
</EncryptionCard>
<BaseDialog fixedWidth={false} hasCancel={false}>
<EncryptionCard
Icon={LockSolidIcon}
className="mx_AccessSecretStorageDialog"
title={title}
description={_t("encryption|access_secret_storage_dialog|privacy_warning")}
>
{content}
</EncryptionCard>
</BaseDialog>
);
}
}

View File

@ -76,6 +76,14 @@ export function EmptyRoomList({ vm }: EmptyRoomListProps): JSX.Element | undefin
filter={vm.activePrimaryFilter}
/>
);
case FilterKey.LowPriorityFilter:
return (
<ActionPlaceholder
title={_t("room_list|empty|no_lowpriority")}
action={_t("room_list|empty|show_activity")}
filter={vm.activePrimaryFilter}
/>
);
default:
return undefined;
}

View File

@ -109,12 +109,12 @@ function MoreOptionsMenu({ vm, setMenuOpen }: MoreOptionsMenuProps): JSX.Element
onSelect={vm.toggleFavorite}
onClick={(evt) => evt.stopPropagation()}
/>
<MenuItem
<ToggleMenuItem
checked={vm.isLowPriority}
Icon={ArrowDownIcon}
label={_t("room_list|more_options|low_priority")}
onSelect={vm.toggleLowPriority}
onClick={(evt) => evt.stopPropagation()}
hideChevron={true}
/>
{vm.canInvite && (
<MenuItem

View File

@ -5,9 +5,9 @@
* Please see LICENSE files in the repository root for full details.
*/
import { IconButton, Menu, MenuTitle, CheckboxMenuItem, Tooltip, RadioMenuItem } from "@vector-im/compound-web";
import { IconButton, Menu, MenuTitle, Tooltip, RadioMenuItem } from "@vector-im/compound-web";
import React, { type Ref, type JSX, useState, useCallback } from "react";
import FilterIcon from "@vector-im/compound-design-tokens/assets/web/icons/filter";
import OverflowHorizontalIcon from "@vector-im/compound-design-tokens/assets/web/icons/overflow-horizontal";
import { _t } from "../../../../languageHandler";
import { SortOption } from "../../../viewmodels/roomlist/useSorter";
@ -20,7 +20,7 @@ interface MenuTriggerProps extends React.ComponentProps<typeof IconButton> {
const MenuTrigger = ({ ref, ...props }: MenuTriggerProps): JSX.Element => (
<Tooltip label={_t("room_list|room_options")}>
<IconButton aria-label={_t("room_list|room_options")} {...props} ref={ref}>
<FilterIcon color="var(--cpd-color-icon-secondary)" />
<OverflowHorizontalIcon color="var(--cpd-color-icon-secondary)" />
</IconButton>
</Tooltip>
);
@ -63,12 +63,6 @@ export function RoomListOptionsMenu({ vm }: Props): JSX.Element {
checked={vm.activeSortOption === SortOption.AToZ}
onSelect={onAtoZSelected}
/>
<MenuTitle title={_t("room_list|appearance")} />
<CheckboxMenuItem
label={_t("room_list|show_message_previews")}
onSelect={vm.toggleMessagePreview}
checked={vm.shouldShowMessagePreview}
/>
</Menu>
);
}

View File

@ -5,8 +5,9 @@
* Please see LICENSE files in the repository root for full details.
*/
import React, { type JSX } from "react";
import { ChatFilter } from "@vector-im/compound-web";
import React, { type JSX, useEffect, useId, useRef, useState, type RefObject } from "react";
import { ChatFilter, IconButton } from "@vector-im/compound-web";
import ChevronDownIcon from "@vector-im/compound-design-tokens/assets/web/icons/chevron-down";
import type { RoomListViewState } from "../../../viewmodels/roomlist/RoomListViewModel";
import { Flex } from "../../../utils/Flex";
@ -23,23 +24,146 @@ interface RoomListPrimaryFiltersProps {
* The primary filters for the room list
*/
export function RoomListPrimaryFilters({ vm }: RoomListPrimaryFiltersProps): JSX.Element {
const id = useId();
const [isExpanded, setIsExpanded] = useState(false);
const { ref, isWrapping: displayChevron, wrappingIndex } = useCollapseFilters<HTMLUListElement>(isExpanded);
const filters = useVisibleFilters(vm.primaryFilters, wrappingIndex);
return (
<Flex
as="ul"
role="listbox"
aria-label={_t("room_list|primary_filters")}
className="mx_RoomListPrimaryFilters"
align="center"
gap="var(--cpd-space-2x)"
wrap="wrap"
data-testid="primary-filters"
gap="var(--cpd-space-3x)"
direction="row-reverse"
>
{vm.primaryFilters.map((filter) => (
<li role="option" aria-selected={filter.active} key={filter.name}>
<ChatFilter selected={filter.active} onClick={filter.toggle}>
{filter.name}
</ChatFilter>
</li>
))}
{displayChevron && (
<IconButton
subtleBackground={true}
aria-expanded={isExpanded}
aria-controls={id}
className="mx_RoomListPrimaryFilters_IconButton"
aria-label={isExpanded ? _t("room_list|collapse_filters") : _t("room_list|expand_filters")}
size="28px"
onClick={() => setIsExpanded((_expanded) => !_expanded)}
>
<ChevronDownIcon color="var(--cpd-color-icon-secondary)" />
</IconButton>
)}
<Flex
id={id}
as="ul"
role="listbox"
aria-label={_t("room_list|primary_filters")}
align="center"
gap="var(--cpd-space-2x)"
wrap="wrap"
ref={ref}
>
{filters.map((filter, i) => (
<li role="option" aria-selected={filter.active} key={i}>
<ChatFilter selected={filter.active} onClick={() => filter.toggle()}>
{filter.name}
</ChatFilter>
</li>
))}
</Flex>
</Flex>
);
}
/**
* A hook to manage the wrapping of filters in the room list.
* It observes the filter list and hides filters that are wrapping when the list is not expanded.
* @param isExpanded
* @returns an object containing:
* - `ref`: a ref to put on the filter list element
* - `isWrapping`: a boolean indicating if the filters are wrapping
* - `wrappingIndex`: the index of the first filter that is wrapping
*/
function useCollapseFilters<T extends HTMLElement>(
isExpanded: boolean,
): { ref: RefObject<T | null>; isWrapping: boolean; wrappingIndex: number } {
const ref = useRef<T>(null);
const [isWrapping, setIsWrapping] = useState(false);
const [wrappingIndex, setWrappingIndex] = useState(-1);
useEffect(() => {
if (!ref.current) return;
const hideFilters = (list: Element): void => {
let isWrapping = false;
Array.from(list.children).forEach((node, i): void => {
const child = node as HTMLElement;
const wrappingClass = "mx_RoomListPrimaryFilters_wrapping";
child.setAttribute("aria-hidden", "false");
child.classList.remove(wrappingClass);
// If the filter list is expanded, all filters are visible
if (isExpanded) return;
// If the previous element is on the left element of the current one, it means that the filter is wrapping
const previousSibling = child.previousElementSibling as HTMLElement | null;
if (previousSibling && child.offsetLeft < previousSibling.offsetLeft) {
if (!isWrapping) setWrappingIndex(i);
isWrapping = true;
}
// If the filter is wrapping, we hide it
child.classList.toggle(wrappingClass, isWrapping);
child.setAttribute("aria-hidden", isWrapping.toString());
});
if (!isWrapping) setWrappingIndex(-1);
setIsWrapping(isExpanded || isWrapping);
};
hideFilters(ref.current);
const observer = new ResizeObserver((entries) => entries.forEach((entry) => hideFilters(entry.target)));
observer.observe(ref.current);
return () => {
observer.disconnect();
};
}, [isExpanded]);
return { ref, isWrapping, wrappingIndex };
}
/**
* A hook to sort the filters by active state.
* The list is sorted if the current filter index is greater than or equal to the wrapping index.
* If the wrapping index is -1, the filters are not sorted.
*
* @param filters - the list of filters to sort.
* @param wrappingIndex - the index of the first filter that is wrapping.
*/
export function useVisibleFilters(
filters: RoomListViewState["primaryFilters"],
wrappingIndex: number,
): RoomListViewState["primaryFilters"] {
// By default, the filters are not sorted
const [sortedFilters, setSortedFilters] = useState(filters);
useEffect(() => {
const isActiveFilterWrapping = filters.findIndex((f) => f.active) >= wrappingIndex;
// If the active filter is not wrapping, we don't need to sort the filters
if (!isActiveFilterWrapping || wrappingIndex === -1) {
setSortedFilters(filters);
return;
}
// Sort the filters with the current filter at first position
setSortedFilters(
filters.slice().sort((filterA, filterB) => {
// If the filter is active, it should be at the top of the list
if (filterA.active && !filterB.active) return -1;
if (!filterA.active && filterB.active) return 1;
// If both filters are active or not, keep their original order
return 0;
}),
);
}, [filters, wrappingIndex]);
return sortedFilters;
}

View File

@ -0,0 +1,47 @@
/*
Copyright 2025 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import React, { type FC, useCallback, useState } from "react";
import { Root } from "@vector-im/compound-web";
import { logger } from "matrix-js-sdk/src/logger";
import { _t } from "../../../../../languageHandler";
import { useSettingValue } from "../../../../../hooks/useSettings";
import SettingsStore from "../../../../../settings/SettingsStore";
import { SettingLevel } from "../../../../../settings/SettingLevel";
import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch";
export const InviteRulesAccountSetting: FC = () => {
const rules = useSettingValue("inviteRules");
const settingsDisabled = SettingsStore.disabledMessage("inviteRules");
const [busy, setBusy] = useState(false);
const onChange = useCallback(async (checked: boolean) => {
try {
setBusy(true);
await SettingsStore.setValue("inviteRules", null, SettingLevel.ACCOUNT, {
allBlocked: !checked,
});
} catch (ex) {
logger.error(`Unable to set invite rules`, ex);
} finally {
setBusy(false);
}
}, []);
return (
<Root className="mx_MediaPreviewAccountSetting_Form">
<LabelledToggleSwitch
className="mx_MediaPreviewAccountSetting_ToggleSwitch"
label={_t("settings|invite_controls|default_label")}
value={!rules.allBlocked}
onChange={onChange}
tooltip={settingsDisabled}
disabled={!!settingsDisabled || busy}
/>
</Root>
);
};

View File

@ -33,6 +33,7 @@ import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch";
import * as TimezoneHandler from "../../../../../TimezoneHandler";
import { type BooleanSettingKey } from "../../../../../settings/Settings.tsx";
import { MediaPreviewAccountSettings } from "./MediaPreviewAccountSettings.tsx";
import { InviteRulesAccountSetting } from "./InviteRulesAccountSettings.tsx";
interface IProps {
closeSettingsFn(success: boolean): void;
@ -242,12 +243,12 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
};
public render(): React.ReactNode {
const roomListSettings = PreferencesUserSettingsTab.ROOM_LIST_SETTINGS;
const browserTimezoneLabel: string = _t("settings|preferences|default_timezone", {
timezone: TimezoneHandler.shortBrowserTimezone(),
});
const newRoomListEnabled = SettingsStore.getValue("feature_new_room_list");
// Always Preprend the default option
const timezones = this.state.timezones.map((tz) => {
return <div key={tz}>{tz}</div>;
@ -263,11 +264,13 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
<SpellCheckSection />
</SettingsSubsection>
{roomListSettings.length > 0 && (
<SettingsSubsection heading={_t("settings|preferences|room_list_heading")}>
{this.renderGroup(roomListSettings)}
</SettingsSubsection>
)}
<SettingsSubsection heading={_t("settings|preferences|room_list_heading")}>
{this.renderGroup(PreferencesUserSettingsTab.ROOM_LIST_SETTINGS)}
{/* The settings is on device level where the other room list settings are on account level */}
{newRoomListEnabled && (
<SettingsFlag name="RoomList.showMessagePreview" level={SettingLevel.DEVICE} />
)}
</SettingsSubsection>
<SettingsSubsection heading={_t("common|spaces")}>
{this.renderGroup(PreferencesUserSettingsTab.SPACES_SETTINGS, SettingLevel.ACCOUNT)}
@ -337,6 +340,7 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
<SettingsSubsection heading={_t("common|moderation_and_safety")} legacy={false}>
<MediaPreviewAccountSettings />
<InviteRulesAccountSetting />
</SettingsSubsection>
<SettingsSubsection heading={_t("settings|preferences|room_directory_heading")}>
@ -355,6 +359,12 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
appName: SdkConfig.get().brand,
})}
/>
<SettingsFlag
name="Electron.enableContentProtection"
level={SettingLevel.PLATFORM}
hideIfCannotSet
label={_t("settings|preferences|Electron.enableContentProtection")}
/>
<SettingsFlag name="Electron.alwaysShowMenuBar" level={SettingLevel.PLATFORM} hideIfCannotSet />
<SettingsFlag name="Electron.autoLaunch" level={SettingLevel.PLATFORM} hideIfCannotSet />
<SettingsFlag name="Electron.warnBeforeExit" level={SettingLevel.PLATFORM} hideIfCannotSet />

View File

@ -38,6 +38,10 @@ function getPinnedEventIds(room?: Room): string[] {
.getState(EventTimeline.FORWARDS)
?.getStateEvents(EventType.RoomPinnedEvents, "")
?.getContent()?.pinned ?? [];
if (!Array.isArray(eventIds)) {
logger.warn("Encountered invalid pinned events state in room", room?.roomId, eventIds);
return [];
}
// Limit the number of pinned events to 100
return eventIds.slice(0, 100);
}

View File

@ -922,8 +922,6 @@
"security_key_title": "Klíč pro obnovení"
},
"bootstrap_title": "Příprava klíčů",
"cancel_entering_passphrase_description": "Chcete určitě zrušit zadávání přístupové fráze?",
"cancel_entering_passphrase_title": "Zrušit zadávání přístupové fráze?",
"confirm_encryption_setup_body": "Kliknutím na tlačítko níže potvrďte nastavení šifrování.",
"confirm_encryption_setup_title": "Potvrďte nastavení šifrování",
"cross_signing_room_normal": "Místnost je koncově šifrovaná",
@ -2100,7 +2098,6 @@
"room_list": {
"add_room_label": "Přidat místnost",
"add_space_label": "Přidat prostor",
"appearance": "Vzhled",
"breadcrumbs_empty": "Žádné nedávno navštívené místnosti",
"breadcrumbs_label": "Nedávno navštívené místnosti",
"empty": {
@ -2158,7 +2155,6 @@
},
"room_options": "Možnosti místnosti",
"show_less": "Zobrazit méně",
"show_message_previews": "Zobrazit náhledy zpráv",
"show_n_more": {
"other": "Zobrazit %(count)s dalších",
"one": "Zobrazit %(count)s další"
@ -3135,6 +3131,7 @@
"upgraderoom": "Aktualizuje místnost na novou verzi",
"upgraderoom_permission_error": "Na provedení tohoto příkazu nemáte dostatečná oprávnění.",
"usage": "Použití",
"verify": "Ověří uživatele, relaci a veřejné klíče",
"view": "Zobrazí místnost s danou adresou",
"whois": "Zobrazuje informace o uživateli"
},

View File

@ -831,6 +831,14 @@
"room_notifications_total": "Cyfanswm: ",
"room_notifications_type": "Math: ",
"room_status": "Statws ystafell",
"room_unread_status_count": {
"zero": "Statws heb eu darllen yn yr ystafell:<strong>%(status)s</strong> , cyfrif:<strong>%(count)s</strong>",
"one": "Statws heb ei ddarllen yn yr ystafell:<strong>%(status)s</strong> , cyfrif:<strong>%(count)s</strong>",
"two": "Statws heb eu darllen yn yr ystafell:<strong>%(status)s</strong> , cyfrif:<strong>%(count)s</strong>",
"few": "Statws heb eu darllen yn yr ystafell:<strong>%(status)s</strong> , cyfrif:<strong>%(count)s</strong>",
"many": "Statws heb eu darllen yn yr ystafell:<strong>%(status)s</strong> , cyfrif:<strong>%(count)s</strong>",
"other": "Statws heb eu darllen yn yr ystafell:<strong>%(status)s</strong> , cyfrif:<strong>%(count)s</strong>"
},
"save_setting_values": "Cadw gwerthoedd gosod",
"see_history": "Gweld hanes",
"send_custom_account_data_event": "Anfon digwyddiad data cyfrif personol",
@ -849,6 +857,14 @@
},
"settings_explorer": "Archwiliwr gosodiadau",
"show_hidden_events": "Dangos digwyddiadau cudd yn y llinell amser",
"spaces": {
"zero": "<%(count) s gofodau>",
"one": "<space>",
"two": "<%(count) s ofod>",
"few": "<%(count) s gofod>",
"many": "<%(count) s gofod>",
"other": "<%(count) s gofod>"
},
"state_key": "Allwedd Cyflwr",
"thread_root_id": "ID Gwraidd Edefyn: %(threadRootId)s",
"threads_timeline": "Llinell amser edafedd",
@ -902,8 +918,6 @@
"security_key_title": "Allwedd Adfer"
},
"bootstrap_title": "Gosod allweddi",
"cancel_entering_passphrase_description": "Ydych chi'n siŵr eich bod am ddiddymu'r cyfrinymadrodd?",
"cancel_entering_passphrase_title": "Diddymu cyflwyno cyfrinymadrodd?",
"confirm_encryption_setup_body": "Clicio'r botwm isod i gadarnhau gosod amgryptio.",
"confirm_encryption_setup_title": "Cadarnhau gosodiad amgryptio",
"cross_signing_room_normal": "Mae'r ystafell hon wedi'i hamgryptio o ben-i-ben",
@ -1155,7 +1169,39 @@
"error_fetching_file": "Gwall wrth nôl ffeil",
"export_info": "Dyma ddechrau allforio o<roomName/>. Wedi'i allforio gan<exporterDetails/> yn %(exportDate)s.",
"export_successful": "Allforio yn llwyddiannus!",
"exported_n_events_in_time": {
"zero": "Wedi nôl %(count)s digwyddiadau o fewn %(seconds)s e",
"one": "Wedi allforio %(count)s digwyddiad o fewn %(seconds)s e",
"two": "Wedi nôl %(count)s ddigwyddiad o fewn %(seconds)s e",
"few": "Wedi nôl %(count)s digwyddiad o fewn %(seconds)s e",
"many": "Wedi nôl %(count)s digwyddiad o fewn %(seconds)s e",
"other": "Wedi nôl %(count)s digwyddiad o fewn %(seconds)s e"
},
"exporting_your_data": "Allforio eich data",
"fetched_n_events": {
"zero": "Wedi nôl %(count)s digwyddiadau hyd yn hyn",
"one": "Wedi nôl %(count)s digwyddiad hyd yn hyn",
"two": "Wedi nôl %(count)s ddigwyddiad hyd yn hyn",
"few": "Wedi nôl %(count)s digwyddiad hyd yn hyn",
"many": "Wedi nôl %(count)s digwyddiad hyd yn hyn",
"other": "Wedi nôl %(count)s digwyddiad hyd yn hyn"
},
"fetched_n_events_in_time": {
"zero": "Wedi nôl %(count)s digwyddiadau o fewn %(seconds)s e",
"one": "Wedi nôl %(count)s digwyddiad o fewn %(seconds)s e",
"two": "Wedi nôl %(count)s ddigwyddiad o fewn %(seconds)s e",
"few": "Wedi nôl %(count)s digwyddiad o fewn %(seconds)s e",
"many": "Wedi nôl %(count)s digwyddiad o fewn %(seconds)s e",
"other": "Wedi nôl %(count)s digwyddiad o fewn %(seconds)s e"
},
"fetched_n_events_with_total": {
"zero": "Wedi nôl %(count)s digwyddiadau allan o %(total)s",
"one": "Wedi nôl %(count)s digwyddiad allan o %(total)s",
"two": "Wedi nôl %(count)s ddigwyddiad allan o %(total)s",
"few": "Wedi nôl %(count)s digwyddiad allan o %(total)s",
"many": "Wedi nôl %(count)s digwyddiad allan o %(total)s",
"other": "Wedi nôl %(count)s digwyddiad allan o %(total)s"
},
"fetching_events": "Wrthi'n nôl digwyddiadau…",
"file_attached": "Ffeil wedi'i Atodi",
"format": "Fformat",
@ -1992,7 +2038,6 @@
"room_list": {
"add_room_label": "Ychwanegu ystafell",
"add_space_label": "Ychwanegu gofod",
"appearance": "Gwedd",
"breadcrumbs_empty": "Dim ystafelloedd yr ymwelwyd â nhw yn ddiweddar",
"breadcrumbs_label": "Ymwelwyd ag ystafelloedd yn ddiweddar",
"empty": {
@ -2042,7 +2087,6 @@
},
"room_options": "Dewisiadau Ystafelloedd",
"show_less": "Dangos llai",
"show_message_previews": "Dangos rhagolygon negeseuon",
"show_previews": "Dangos rhagolwg o negeseuon",
"sort": "Trefnu",
"sort_by": "Trefnu yn ôl",
@ -2966,6 +3010,7 @@
"upgraderoom": "Yn uwchraddio ystafell i fersiwn newydd",
"upgraderoom_permission_error": "Nid oes gennych y caniatâd gofynnol i ddefnyddio'r gorchymyn hwn.",
"usage": "Defnydd",
"verify": "Yn dilysu defnyddiwr, sesiwn, a pubkey tuple",
"view": "Ystafell golygfeydd gyda chyfeiriad a roddwyd",
"whois": "Yn arddangos gwybodaeth am ddefnyddiwr"
},
@ -3432,10 +3477,106 @@
"send_state_sending": "Wrthi'n anfon eich neges…",
"send_state_sent": "Anfonwyd eich neges",
"summary": {
"format": "%(matereList)s %(transitionList)s"
"format": "%(matereList)s %(transitionList)s",
"invite_withdrawn_multiple": {
"zero": "Cafodd %(severalUsers)s eu gwahoddiadau eu dileu",
"one": "Cafodd %(severalUsers)s eu gwahoddiadau eu dileu",
"two": "Cafodd %(severalUsers)s eu gwahoddiadau eu dileu %(count)s gwaith",
"few": "Cafodd %(severalUsers)s eu gwahoddiadau eu dileu %(count)s gwaith",
"many": "Cafodd %(severalUsers)s eu gwahoddiadau eu dileu %(count)s gwaith",
"other": "Cafodd %(severalUsers)s eu gwahoddiadau eu dileu %(count)s gwaith"
},
"joined": {
"zero": "Ymunodd %(oneUser)s %(count)s gwaith",
"one": "Ymunodd %(oneUser)s",
"two": "Ymunodd %(oneUser)s %(count)s gwaith",
"few": "Ymunodd %(oneUser)s %(count)s gwaith",
"many": "Ymunodd %(oneUser)s %(count)s gwaith",
"other": "Ymunodd %(oneUser)s %(count)s gwaith"
},
"joined_and_left": {
"zero": "Ymunodd a gadawodd %(oneUser)s %(count)s gwaith",
"one": "Ymunodd a gadawodd %(oneUser)s %(count)s gwaith",
"two": "Ymunodd a gadawodd %(oneUser)s %(count)s gwaith",
"few": "Ymunodd a gadawodd %(oneUser)s %(count)s gwaith",
"many": "Ymunodd a gadawodd %(oneUser)s %(count)s gwaith",
"other": "Ymunodd a gadawodd %(oneUser)s %(count)s gwaith"
},
"joined_and_left_multiple": {
"zero": "Ymunodd a gadawodd %(severalUsers)s",
"one": "Ymunodd a gadawodd %(severalUsers)s",
"two": "Ymunodd a gadawodd %(severalUsers)s %(count)s gwaith",
"few": "Ymunodd a gadawodd %(severalUsers)s %(count)s gwaith",
"many": "Ymunodd a gadawodd %(severalUsers)s %(count)s gwaith",
"other": "Ymunodd a gadawodd %(severalUsers)s %(count)s gwaith"
},
"joined_multiple": {
"zero": "Ymunodd %(severalUsers)s",
"one": "Ymunodd %(severalUsers)s %(count)s gwaith",
"two": "Ymunodd %(severalUsers)s %(count)s gwaith",
"few": "Ymunodd %(severalUsers)s %(count)s gwaith",
"many": "Ymunodd %(severalUsers)s %(count)s gwaith",
"other": "Ymunodd %(severalUsers)s %(count)s gwaith"
},
"left": {
"zero": "Gadawodd %(oneUser)s",
"one": "Gadawodd %(oneUser)s",
"two": "Gadawodd %(oneUser)s %(count)s gwaith",
"few": "Gadawodd %(oneUser)s %(count)s gwaith",
"many": "Gadawodd %(oneUser)s %(count)s gwaith",
"other": "Gadawodd %(oneUser)s %(count)s gwaith"
},
"left_multiple": {
"zero": "Gadawodd %(severalUsers)s",
"one": "Gadawodd %(severalUsers)s",
"two": "Gadawodd %(severalUsers)s %(count)s gwaith",
"few": "Gadawodd %(severalUsers)s %(count)s gwaith",
"many": "Gadawodd %(severalUsers)s %(count)s gwaith",
"other": "Gadawodd %(severalUsers)s %(count)s gwaith"
},
"rejected_invite": {
"zero": "Gwrthododd %(severalUsers)s eu gwahoddiadau",
"one": "Gwrthododd %(oneUser)s ei wahoddiad",
"two": "Gwrthododd %(oneUser)s eu gwahoddiadau %(count)s gwaith",
"few": "Gwrthododd %(oneUser)s eu gwahoddiadau %(count)s gwaith",
"many": "Gwrthododd %(oneUser)s eu gwahoddiadau %(count)s gwaith",
"other": "Gwrthododd %(oneUser)s eu gwahoddiadau %(count)s gwaith"
},
"rejected_invite_multiple": {
"zero": "Gwrthododd %(severalUsers)s eu gwahoddiadau",
"one": "Gwrthododd %(severalUsers)s eu gwahoddiadau",
"two": "Gwrthododd %(severalUsers)s eu gwahoddiadau %(count)s gwaith",
"few": "Gwrthododd %(severalUsers)s eu gwahoddiadau %(count)s gwaith",
"many": "Gwrthododd %(severalUsers)s eu gwahoddiadau %(count)s gwaith",
"other": "Gwrthododd %(severalUsers)s eu gwahoddiadau %(count)s gwaith"
},
"rejoined": {
"zero": "Ymunodd a gadawodd %(oneUser)s",
"one": "Ymunodd a gadawodd %(oneUser)s",
"two": "Ymunodd a gadawodd %(oneUser)s %(count)s gwaith",
"few": "Ymunodd a gadawodd %(oneUser)s %(count)s gwaith",
"many": "Ymunodd a gadawodd %(oneUser)s %(count)s gwaith",
"other": "Ymunodd a gadawodd %(oneUser)s %(count)s gwaith"
},
"rejoined_multiple": {
"zero": "Ymunodd a gadawodd %(severalUsers)s",
"one": "Ymunodd a gadawodd %(severalUsers)s",
"two": "Ymunodd a gadawodd %(severalUsers)s %(count)s gwaith",
"few": "Ymunodd a gadawodd %(severalUsers)s %(count)s gwaith",
"many": "Ymunodd a gadawodd %(severalUsers)s %(count)s gwaith",
"other": "Ymunodd a gadawodd %(severalUsers)s %(count)s gwaith"
}
},
"thread_info_basic": "O edefyn",
"typing_indicator": {
"more_users": {
"zero": "Mae %(names)s ac mae %(count)s eraill yn teipio...",
"one": "Mae %(names)s ac mae un arall yn teipio...",
"two": "Mae %(names)s ac mae %(count)s eraill yn teipio...",
"few": "Mae %(names)s ac mae %(count)s eraill yn teipio...",
"many": "Mae %(names)s ac mae %(count)s eraill yn teipio...",
"other": "Mae %(names)s ac mae %(count)s eraill yn teipio..."
},
"one_user": "Mae %(displayName)s yn teipio…",
"two_users": "Mae %(materes)s a %(lastPerson)s yn teipio…"
},

View File

@ -911,15 +911,15 @@
"empty_room_was_name": "Leerer Raum (war %(oldName)s)",
"encryption": {
"access_secret_storage_dialog": {
"alternatives": "Wenn Sie einen Sicherheitsschlüssel oder eine Sicherheitsphrase haben, funktioniert das auch.",
"key_validation_text": {
"wrong_security_key": "Falscher Wiederherstellungsschlüssel"
"wrong_security_key": "Der eingegebene Wiederherstellungsschlüssel ist nicht korrekt."
},
"privacy_warning": "Stellen Sie sicher, dass niemand diesen Bildschirm sehen kann!",
"restoring": "Schlüssel aus der Sicherung wiederherstellen",
"security_key_title": "Wiederherstellungsschlüssel"
},
"bootstrap_title": "Schlüssel werden eingerichtet",
"cancel_entering_passphrase_description": "Bist du sicher, dass du die Eingabe der Passphrase abbrechen möchtest?",
"cancel_entering_passphrase_title": "Eingabe der Passphrase abbrechen?",
"confirm_encryption_setup_body": "Klick die Schaltfläche unten um die Einstellungen der Verschlüsselung zu bestätigen.",
"confirm_encryption_setup_title": "Bestätige die Einrichtung der Verschlüsselung",
"cross_signing_room_normal": "Dieser Raum ist Ende-zu-Ende verschlüsselt",
@ -2091,7 +2091,6 @@
"room_list": {
"add_room_label": "Raum hinzufügen",
"add_space_label": "Space hinzufügen",
"appearance": "Erscheinungsbild",
"breadcrumbs_empty": "Keine kürzlich besuchten Räume",
"breadcrumbs_label": "Kürzlich besuchte Räume",
"empty": {
@ -2149,7 +2148,6 @@
},
"room_options": "Chatroomoptionen",
"show_less": "Weniger anzeigen",
"show_message_previews": "Nachrichtenvorschau anzeigen",
"show_n_more": {
"other": "%(count)s weitere anzeigen",
"one": "%(count)s weitere anzeigen"
@ -3125,6 +3123,7 @@
"upgraderoom": "Aktualisiert den Raum auf eine neue Version",
"upgraderoom_permission_error": "Du hast nicht die erforderlichen Berechtigungen, diesen Befehl zu verwenden.",
"usage": "Verwendung",
"verify": "Verifiziert Benutzer, Sitzung und öffentlichen Schlüsselpaare",
"view": "Raum mit angegebener Adresse betrachten",
"whois": "Zeigt Informationen über Benutzer"
},

View File

@ -720,8 +720,6 @@
"security_key_title": "Κλειδί Ασφαλείας"
},
"bootstrap_title": "Ρύθμιση κλειδιών",
"cancel_entering_passphrase_description": "Είστε σίγουρος/η ότι θέλετε να ακυρώσετε την εισαγωγή κωδικού;",
"cancel_entering_passphrase_title": "Ακύρωση εισαγωγής κωδικού;",
"confirm_encryption_setup_body": "Κάντε κλικ στο κουμπί παρακάτω για να επιβεβαιώσετε τη ρύθμιση της κρυπτογράφησης.",
"confirm_encryption_setup_title": "Επιβεβαιώστε τη ρύθμιση κρυπτογράφησης",
"cross_signing_room_normal": "Αυτό το δωμάτιο έχει κρυπτογράφηση από άκρο σε άκρο",
@ -2335,6 +2333,7 @@
"upgraderoom": "Αναβαθμίζει το δωμάτιο σε μια καινούργια έκδοση",
"upgraderoom_permission_error": "Δεν διαθέτετε τις απαιτούμενες άδειες για να χρησιμοποιήσετε αυτήν την εντολή.",
"usage": "Χρήση",
"verify": "Επιβεβαιώνει έναν χρήστη, συνεδρία, και pubkey tuple",
"whois": "Εμφανίζει πληροφορίες για έναν χρήστη"
},
"space": {

View File

@ -786,6 +786,7 @@
"cross_signing_status": "Cross-signing status:",
"cross_signing_untrusted": "Your account has a cross-signing identity in secret storage, but it is not yet trusted by this session.",
"crypto_not_available": "Cryptographic module is not available",
"device_id": "Device ID",
"key_backup_active_version": "Active backup version:",
"key_backup_active_version_none": "None",
"key_backup_inactive_warning": "Your keys are not being backed up from this session.",
@ -798,6 +799,8 @@
"secret_storage_ready": "ready",
"secret_storage_status": "Secret storage:",
"self_signing_private_key_cached_status": "Self signing private key:",
"session": "Session",
"session_fingerprint": "Fingerprint (session key)",
"title": "End-to-end encryption",
"user_signing_private_key_cached_status": "User signing private key:"
},
@ -823,6 +826,7 @@
"low_bandwidth_mode": "Low bandwidth mode",
"low_bandwidth_mode_description": "Requires compatible homeserver.",
"main_timeline": "Main timeline",
"manual_device_verification": "Manual device verification",
"no_receipt_found": "No receipt found",
"notification_state": "Notification state is <strong>%(notificationState)s</strong>",
"notifications_debug": "Notifications debug",
@ -920,8 +924,6 @@
"security_key_title": "Recovery key"
},
"bootstrap_title": "Setting up keys",
"cancel_entering_passphrase_description": "Are you sure you want to cancel entering passphrase?",
"cancel_entering_passphrase_title": "Cancel entering passphrase?",
"confirm_encryption_setup_body": "Click the button below to confirm setting up encryption.",
"confirm_encryption_setup_title": "Confirm encryption setup",
"cross_signing_room_normal": "This room is end-to-end encrypted",
@ -1009,6 +1011,21 @@
"incoming_sas_dialog_waiting": "Waiting for partner to confirm…",
"incoming_sas_user_dialog_text_1": "Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.",
"incoming_sas_user_dialog_text_2": "Verifying this user will mark their session as trusted, and also mark your session as trusted to them.",
"manual": {
"already_verified": "This device is already verified",
"already_verified_and_wrong_fingerprint": "The supplied fingerprint does not match, but the device is already verified!",
"device_id": "Device ID",
"failure_description": "Failed to verify '%(deviceId)s': %(error)s",
"failure_title": "Verification failed",
"fingerprint": "Fingerprint (session key)",
"no_crypto": "Unable to verify device - crypto is not enabled",
"no_device": "Unable to verify device - device '%(deviceId)s' was not found",
"no_userid": "Unable to verify device - cannot find our User ID",
"success_description": "The device (%(deviceId)s) is now cross-signed",
"success_title": "Verification successful",
"text": "Supply the ID and fingerprint of one of your own devices to verify it. NOTE this allows the other device to send and receive messages as you. IF SOMEONE TOLD YOU TO PASTE SOMETHING HERE, IT IS LIKELY YOU ARE BEING SCAMMED!",
"wrong_fingerprint": "Unable to verify device '%(deviceId)s' - the supplied fingerprint '%(fingerprint)s' does not match the device fingerprint, '%(fprint)s'"
},
"no_key_or_device": "It looks like you don't have a Recovery Key or any other devices you can verify against. This device will not be able to access old encrypted messages. In order to verify your identity on this device, you'll need to reset your verification keys.",
"no_support_qr_emoji": "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.",
"other_party_cancelled": "The other party cancelled the verification.",
@ -1957,6 +1974,7 @@
},
"face_pile_tooltip_shortcut": "Including %(commaSeparatedMembers)s",
"face_pile_tooltip_shortcut_joined": "Including you, %(commaSeparatedMembers)s",
"failed_determine_user": "Cannot determine which user to ignore since the member event has changed.",
"failed_reject_invite": "Failed to reject invite",
"forget_room": "Forget this room",
"forget_space": "Forget this space",
@ -2048,6 +2066,7 @@
"read_topic": "Click to read topic",
"rejecting": "Rejecting invite…",
"rejoin_button": "Re-join",
"room_is_low_priority": "This is a low priority room",
"search": {
"all_rooms_button": "Search all rooms",
"placeholder": "Search messages…",
@ -2094,9 +2113,9 @@
"room_list": {
"add_room_label": "Add room",
"add_space_label": "Add space",
"appearance": "Appearance",
"breadcrumbs_empty": "No recently visited rooms",
"breadcrumbs_label": "Recently visited rooms",
"collapse_filters": "Collapse filter list",
"empty": {
"no_chats": "No chats yet",
"no_chats_description": "Get started by messaging someone or by creating a room",
@ -2104,6 +2123,7 @@
"no_favourites": "You don't have favourite chat yet",
"no_favourites_description": "You can add a chat to your favourites in the chat settings",
"no_invites": "You don't have any unread invites",
"no_lowpriority": "You don't have any low priority rooms",
"no_mentions": "You don't have any unread mentions",
"no_people": "You dont have direct chats with anyone yet",
"no_people_description": "You can deselect filters in order to see your other chats",
@ -2113,12 +2133,14 @@
"show_activity": "See all activity",
"show_chats": "Show all chats"
},
"expand_filters": "Expand filter list",
"failed_add_tag": "Failed to add tag %(tagName)s to room",
"failed_remove_tag": "Failed to remove tag %(tagName)s from room",
"failed_set_dm_tag": "Failed to set direct message tag",
"filters": {
"favourite": "Favourites",
"invites": "Invites",
"low_priority": "Low priority",
"mentions": "Mentions",
"people": "People",
"rooms": "Rooms",
@ -2152,7 +2174,6 @@
},
"room_options": "Room Options",
"show_less": "Show less",
"show_message_previews": "Show message previews",
"show_n_more": {
"one": "Show %(count)s more",
"other": "Show %(count)s more"
@ -2687,6 +2708,9 @@
"inline_url_previews_room": "Enable URL previews by default for participants in this room",
"inline_url_previews_room_account": "Enable URL previews for this room (only affects you)",
"insert_trailing_colon_mentions": "Insert a trailing colon after user mentions at the start of a message",
"invite_controls": {
"default_label": "Allow users to invite you to rooms"
},
"jump_to_bottom_on_send": "Jump to the bottom of the timeline when you send a message",
"key_backup": {
"backup_in_progress": "Your keys are being backed up (the first backup could take a few minutes).",
@ -2753,6 +2777,7 @@
"show_in_private": "In private rooms",
"show_media": "Always show"
},
"not_supported": "Your server does not implement this feature.",
"notifications": {
"default_setting_description": "This setting will be applied by default to all your rooms.",
"default_setting_section": "I want to be notified for (Default Setting)",
@ -2810,6 +2835,7 @@
"voip": "Audio and Video calls"
},
"preferences": {
"Electron.enableContentProtection": "Prevent the window contents from being captured by other apps",
"Electron.enableHardwareAcceleration": "Enable hardware acceleration (restart %(appName)s to take effect)",
"always_show_menu_bar": "Always show the window menu bar",
"autocomplete_delay": "Autocomplete delay (ms)",
@ -2982,6 +3008,7 @@
"show_chat_effects": "Show chat effects (animations when receiving e.g. confetti)",
"show_displayname_changes": "Show display name changes",
"show_join_leave": "Show join/leave messages (invites/removes/bans unaffected)",
"show_message_previews": "Show message previews",
"show_nsfw_content": "Show NSFW content",
"show_read_receipts": "Show read receipts sent by other users",
"show_redaction_placeholder": "Show a placeholder for removed messages",
@ -3088,6 +3115,8 @@
"jumptodate": "Jump to the given date in the timeline",
"jumptodate_invalid_input": "We were unable to understand the given date (%(inputDate)s). Try using the format YYYY-MM-DD.",
"lenny": "Prepends ( ͡° ͜ʖ ͡°) to a plain-text message",
"manual_device_verification_confirm_description": "This will allow another device to send and receive messages as you. IF SOMEONE TOLD YOU TO PASTE SOMETHING HERE, IT IS LIKELY YOU ARE BEING SCAMMED! Are you sure you want to verify this other device?",
"manual_device_verification_confirm_title": "Caution: manual device verification",
"me": "Displays action",
"msg": "Sends a message to the given user",
"myavatar": "Changes your profile picture in all rooms",
@ -3128,6 +3157,7 @@
"upgraderoom": "Upgrades a room to a new version",
"upgraderoom_permission_error": "You do not have the required permissions to use this command.",
"usage": "Usage",
"verify": "Manually verify one of your own devices",
"view": "Views room with given address",
"whois": "Displays information about a user"
},

View File

@ -604,8 +604,6 @@
"security_key_title": "Sekureca ŝlosilo"
},
"bootstrap_title": "Agordo de klavoj",
"cancel_entering_passphrase_description": "Ĉu vi certe volas nuligi enigon de pasfrazo?",
"cancel_entering_passphrase_title": "Ĉu nuligi enigon de pasfrazo?",
"confirm_encryption_setup_body": "Klaku sube la butonon por konfirmi agordon de ĉifrado.",
"confirm_encryption_setup_title": "Konfirmi agordon de ĉifrado",
"cross_signing_room_normal": "Ĉi tiu ĉambro uzas tutvojan ĉifradon",
@ -1957,6 +1955,7 @@
"upgraderoom": "Gradaltigas ĉambron al nova versio",
"upgraderoom_permission_error": "Vi ne havas sufiĉajn permesojn por uzi ĉi tiun komandon.",
"usage": "Uzo",
"verify": "Kontrolas opon de uzanto, salutaĵo, kaj publika ŝlosilo",
"whois": "Montras informojn pri uzanto"
},
"space": {

View File

@ -748,8 +748,6 @@
"security_key_title": "Clave de seguridad"
},
"bootstrap_title": "Configurando claves",
"cancel_entering_passphrase_description": "¿Estas seguro que quieres cancelar el ingresar tu contraseña de recuperación?",
"cancel_entering_passphrase_title": "¿Cancelar el ingresar tu contraseña de recuperación?",
"confirm_encryption_setup_body": "Haz clic en el botón de abajo para confirmar la configuración del cifrado.",
"confirm_encryption_setup_title": "Confirmar la configuración de cifrado",
"cross_signing_room_normal": "Esta sala usa cifrado de extremo a extremo",
@ -2485,6 +2483,7 @@
"upgraderoom": "Actualiza una sala a una nueva versión",
"upgraderoom_permission_error": "No tienes los permisos requeridos para usar este comando.",
"usage": "Uso",
"verify": "Verifica a un usuario, sesión y tupla de clave pública",
"whois": "Muestra información sobre un usuario"
},
"space": {

View File

@ -786,6 +786,7 @@
"cross_signing_status": "Risttunnustamise olek:",
"cross_signing_untrusted": "Sinu kasutajakonto risttunnustamise identiteet on krüptitud andmehoidlas olemas, aga see sessioon teda veel ei usalda.",
"crypto_not_available": "Krüptomoodul pole saadaval",
"device_id": "Seadme tunnus",
"key_backup_active_version": "Varukoopia aktiivne versioon:",
"key_backup_active_version_none": "Puudub",
"key_backup_inactive_warning": "See sessioon ei varunda sinu krüptovõtmeid.",
@ -798,6 +799,8 @@
"secret_storage_ready": "on valmis",
"secret_storage_status": "Krüptitud andmeruum:",
"self_signing_private_key_cached_status": "Privaatvõti allkirjastamiseks sinu nimel:",
"session": "Sessioon",
"session_fingerprint": "Sõrmejälg (sessiooni võti)",
"title": "Läbiv krüptimine",
"user_signing_private_key_cached_status": "Kasutaja privaatvõti allkirjastamiseks:"
},
@ -823,6 +826,7 @@
"low_bandwidth_mode": "Vähese ribalaiusega režiim",
"low_bandwidth_mode_description": "Eeldab, et koduserver toetab sellist funktsionaalsust.",
"main_timeline": "Peamine ajajoon",
"manual_device_verification": "Seadme käsitsi verifitseerimine",
"no_receipt_found": "Lugemisteatist ei leidu",
"notification_state": "Teavituste olek: <strong>%(notificationState)s</strong>",
"notifications_debug": "Teavituste silumine",
@ -920,8 +924,6 @@
"security_key_title": "Taastevõti"
},
"bootstrap_title": "Võtame krüptovõtmed kasutusele",
"cancel_entering_passphrase_description": "Kas oled kindel et sa soovid katkestada paroolifraasi sisestamise?",
"cancel_entering_passphrase_title": "Kas katkestame paroolifraasi sisestamise?",
"confirm_encryption_setup_body": "Kinnitamaks, et soovid krüptimist seadistada, klõpsi järgnevat nuppu.",
"confirm_encryption_setup_title": "Krüptimise seadistuse kinnitamine",
"cross_signing_room_normal": "See jututuba on läbivalt krüptitud",
@ -1009,6 +1011,21 @@
"incoming_sas_dialog_waiting": "Ootan teise osapoole kinnitust…",
"incoming_sas_user_dialog_text_1": "Selle kasutaja usaldamiseks peaksid ta verifitseerima. Kui sa pruugid läbivalt krüptitud sõnumeid, siis kasutajate verifitseerimine tagab sulle täiendava meelerahu.",
"incoming_sas_user_dialog_text_2": "Selle kasutaja verifitseerimisel märgitakse tema sessioon usaldusväärseks ning samuti märgitakse sinu sessioon tema jaoks usaldusväärseks.",
"manual": {
"already_verified": "See seade on juba verifitseeritud",
"already_verified_and_wrong_fingerprint": "Viidatud sõrmejälg ei klapi, aga see seade on juba verifitseeritud!",
"device_id": "Seadme tunnus",
"failure_description": "„%(deviceId)s“ seadme verifitseerimine ei õnnestunud: %(error)s",
"failure_title": "Verifitseerimine ei õnnestunud",
"fingerprint": "Sõrmejälg (sessiooni võti)",
"no_crypto": "Seadme verifitseerimine ei õnnestunud - krüptoteenused pole kasutusel",
"no_device": "Seadme verifitseerimine ei õnnestunud - seadet tunnusega „%(deviceId)s“ polnud võimalik leida",
"no_userid": "Seadme verifitseerimine ei õnnestunud - meie kasutajatunnust ei õnnestu leida",
"success_description": "See seade (%(deviceId)s) on nüüd risttunnustatud",
"success_title": "Verifitseerimine õnnestus",
"text": "Verifitseerimiseks sisesta ühe oma seadme tunnus ja sõrmejälg. Palun arvesta, et see võimaldab muul seadmel saata ja vastu võtta sõnumeid esinedes sinuna. KUI KEEGI PALUS SUL SIIA MIDAGI KOPEERIDA, SIIS ON SEE KAHTLANE JA ILMSELT PROOVITAKSE SIND PETTA!",
"wrong_fingerprint": "„%(deviceId)s“ seadme verifitseerimine ei õnnestunud - lisatud sõrmejälg „%(fingerprint)s“ ja seadme sõrmejälg „%(fprint)s“ pole samad"
},
"no_key_or_device": "Tundub, et sul ei ole ei taastevõtit ega muid seadmeid, mida saaksid verifitseerimiseks kasutada. Siin seadmes ei saa lugeda vanu krüptitud sõnumeid. Enda tuvastamiseks selles seadmes pead oma vanad verifitseerimisvõtmed kustutama.",
"no_support_qr_emoji": "See seade, mida sa tahad verifitseerida ei toeta QR-koodi ega emoji-põhist verifitseerimist, aga just neid %(brand)s oskab kasutada. Proovi mõne muu Matrix'i kliendiga.",
"other_party_cancelled": "Teine osapool tühistas verifitseerimise.",
@ -1957,6 +1974,7 @@
},
"face_pile_tooltip_shortcut": "Sealhulgas %(commaSeparatedMembers)s",
"face_pile_tooltip_shortcut_joined": "Seahulgas Sina, %(commaSeparatedMembers)s",
"failed_determine_user": "Kuna liikmelisuse sündmus on muutunud, siis ei saa tuvastada, millist kasutajat peaks eirama.",
"failed_reject_invite": "Kutse tagasilükkamine ei õnnestunud",
"forget_room": "Unusta see jututuba",
"forget_space": "Unusta see kogukond",
@ -2048,6 +2066,7 @@
"read_topic": "Teema lugemiseks klõpsi",
"rejecting": "Hülgan kutset…",
"rejoin_button": "Liitu uuesti",
"room_is_low_priority": "See on vähetähtis jututuba",
"search": {
"all_rooms_button": "Otsi kõikidest jututubadest",
"placeholder": "Otsi sõnumeid…",
@ -2094,7 +2113,6 @@
"room_list": {
"add_room_label": "Lisa jututuba",
"add_space_label": "Lisa kogukonnakeskus",
"appearance": "Välimus",
"breadcrumbs_empty": "Hiljuti külastatud jututubasid ei leidu",
"breadcrumbs_label": "Hiljuti külastatud jututoad",
"empty": {
@ -2119,6 +2137,7 @@
"filters": {
"favourite": "Lemmikud",
"invites": "Kutsed",
"low_priority": "Vähetähtis",
"mentions": "Mainimised",
"people": "Inimesed",
"rooms": "Jututoad",
@ -2152,7 +2171,6 @@
},
"room_options": "Jututoa valikud",
"show_less": "Näita vähem",
"show_message_previews": "Näita sõnumite eelvaateid",
"show_n_more": {
"one": "Näita veel %(count)s vestlust",
"other": "Näita veel %(count)s vestlust"
@ -2687,6 +2705,9 @@
"inline_url_previews_room": "Luba URL'ide vaikimisi eelvaated selles jututoas osalejate jaoks",
"inline_url_previews_room_account": "Luba URL'ide eelvaated selle jututoa jaoks (mõjutab vaid sind)",
"insert_trailing_colon_mentions": "Mainimiste järel näita sõnumi alguses koolonit",
"invite_controls": {
"default_label": "Luba kasutajatel sind kutsida jututubadesse"
},
"jump_to_bottom_on_send": "Sõnumi saatmiseks hüppa ajajoone lõppu",
"key_backup": {
"backup_in_progress": "Sinu krüptovõtmeid varundatakse (esimese varukoopia tegemine võib võtta paar minutit).",
@ -2753,6 +2774,7 @@
"show_in_private": "Privaatsetes jututubades",
"show_media": "Alati"
},
"not_supported": "See funktsionaalsus pole sinu serveris kasutusel.",
"notifications": {
"default_setting_description": "See seadistus kehtib vaikimisi kõikides sinu jututubades.",
"default_setting_section": "Soovin teavitusi (vaikimisi seadistused)",
@ -2810,6 +2832,7 @@
"voip": "Kõned ja videokõned"
},
"preferences": {
"Electron.enableContentProtection": "Blokeeri akna sisu salvestamine teiste rakenduste poolt",
"Electron.enableHardwareAcceleration": "Kasuta riistvaralist kiirendust (jõustamiseks käivita %(appName)s uuesti)",
"always_show_menu_bar": "Näita aknas alati menüüriba",
"autocomplete_delay": "Viivitus automaatsel sõnalõpetusel (ms)",
@ -2982,6 +3005,7 @@
"show_chat_effects": "Näita vestluses edevat graafikat (näiteks kui keegi on saatnud serpentiine)",
"show_displayname_changes": "Näita kuvatava nime muutusi",
"show_join_leave": "Näita jututubade liitumise ja lahkumise teateid (ei käi kutsete, müksamiste ja keelamiste kohta)",
"show_message_previews": "Näita sõnumite eelvaateid",
"show_nsfw_content": "Näita töökeskkonnas mittesobilikku sisu",
"show_read_receipts": "Näita teiste kasutajate lugemisteatiseid",
"show_redaction_placeholder": "Näita kustutatud sõnumite asemel kohatäidet",
@ -3088,6 +3112,8 @@
"jumptodate": "Vaata ajajoont alates sellest kuupäevast",
"jumptodate_invalid_input": "Me ei suutnud sellist kuupäeva mõista (%(inputDate)s). Pigem kasuta aaaa-kk-pp vormingut.",
"lenny": "Lisa ( ͡° ͜ʖ ͡°) smaili vormindamata sõnumi algusesse",
"manual_device_verification_confirm_description": "See võimaldab muul seadmel saata ja vastu võtta sõnumeid esinedes sinuna. KUI KEEGI PALUS SUL SIIA MIDAGI KOPEERIDA, SIIS ON SEE KAHTLANE JA ILMSELT PROOVITAKSE SIND PETTA. Kas sa oled kindel, et soovid seda teist seadet verifitseerida?",
"manual_device_verification_confirm_title": "Hoiatus: seadme käsitsi verifitseerimine",
"me": "Näitab tegevusi",
"msg": "Saadab sõnumi näidatud kasutajale",
"myavatar": "Sellega muudad sinu tunnuspilti kõikides jututubades",
@ -3128,6 +3154,7 @@
"upgraderoom": "Uuendab jututoa uue versioonini",
"upgraderoom_permission_error": "Sul ei ole piisavalt õigusi selle käsu käivitamiseks.",
"usage": "Kasutus",
"verify": "Verifitseeri üks oma seadmetest käsitsi",
"view": "Vaata sellise aadressiga jututuba",
"whois": "Näitab teavet kasutaja kohta"
},

View File

@ -564,8 +564,6 @@
"security_key_title": "کلید امنیتی"
},
"bootstrap_title": "تنظیم کلیدها",
"cancel_entering_passphrase_description": "آیا مطمئن هستید که می خواهید وارد کردن عبارت امنیتی را لغو کنید؟",
"cancel_entering_passphrase_title": "وارد کردن عبارت امنیتی لغو شود؟",
"confirm_encryption_setup_body": "برای تأیید و فعال‌سازی رمزگذاری ، روی دکمه زیر کلیک کنید.",
"confirm_encryption_setup_title": "راه‌اندازی رمزگذاری را تأیید کنید",
"cross_signing_room_normal": "این اتاق به صورت سرتاسر رمزشده است",
@ -1716,6 +1714,7 @@
"upgraderoom": "یک اتاق را به نسخه جدید ارتقا دهید",
"upgraderoom_permission_error": "شما مجوزهای لازم را برای استفاده از این دستور ندارید.",
"usage": "استفاده",
"verify": "یک کاربر، نشست و عبارت کلید عمومی را تائید می‌کند",
"whois": "اطلاعات مربوط به کاربر را نمایش می دهد"
},
"space": {

View File

@ -796,8 +796,6 @@
"security_key_title": "Palautusavain"
},
"bootstrap_title": "Otetaan avaimet käyttöön",
"cancel_entering_passphrase_description": "Haluatko varmasti peruuttaa salasanan syöttämisen?",
"cancel_entering_passphrase_title": "Peruuta salasanan syöttäminen?",
"confirm_encryption_setup_body": "Napsauta alla olevaa painiketta vahvistaaksesi salauksen asettamisen.",
"confirm_encryption_setup_title": "Vahvista salauksen asetukset",
"cross_signing_room_normal": "Tämä huone käyttää päästä päähän -salausta",
@ -1803,7 +1801,6 @@
"room_list": {
"add_room_label": "Lisää huone",
"add_space_label": "Lisää avaruus",
"appearance": "Ulkoasu",
"breadcrumbs_empty": "Ei hiljattain vierailtuja huoneita",
"breadcrumbs_label": "Hiljattain vieraillut huoneet",
"empty": {
@ -1845,7 +1842,6 @@
"open_room": "Avoin huone %(roomName)s"
},
"show_less": "Näytä vähemmän",
"show_message_previews": "Näytä viestien esikatselut",
"show_n_more": {
"one": "Näytä %(count)s lisää",
"other": "Näytä %(count)s lisää"
@ -2699,6 +2695,7 @@
"upgraderoom": "Päivittää huoneen uuteen versioon",
"upgraderoom_permission_error": "Sinulla ei ole vaadittavia oikeuksia tämän komennon käyttämiseksi.",
"usage": "Käyttö",
"verify": "Varmentaa käyttäjän, istunnon ja julkiset avaimet",
"whois": "Näyttää tietoa käyttäjästä"
},
"space": {

View File

@ -911,15 +911,15 @@
"empty_room_was_name": "Salon vide (précédemment %(oldName)s)",
"encryption": {
"access_secret_storage_dialog": {
"alternatives": "Si vous avez une clé de récupération ou une phrase de sécurité, cela fonctionnera également.",
"key_validation_text": {
"wrong_security_key": "Clé de récupération incorrecte"
"wrong_security_key": "La clé de récupération que vous avez saisie est incorrecte."
},
"privacy_warning": "Assurez vous que personne d'autre ne regarde votre écran !",
"restoring": "Restauration des clés depuis la sauvegarde",
"security_key_title": "Clé de récupération"
},
"bootstrap_title": "Configuration des clés",
"cancel_entering_passphrase_description": "Souhaitez-vous vraiment annuler la saisie de la phrase de passe ?",
"cancel_entering_passphrase_title": "Annuler la saisie du mot de passe ?",
"confirm_encryption_setup_body": "Cliquez sur le bouton ci-dessous pour confirmer la configuration du chiffrement.",
"confirm_encryption_setup_title": "Confirmer la configuration du chiffrement",
"cross_signing_room_normal": "Ce salon est chiffré de bout en bout",
@ -1954,6 +1954,7 @@
},
"face_pile_tooltip_shortcut": "Dont %(commaSeparatedMembers)s",
"face_pile_tooltip_shortcut_joined": "Dont vous, %(commaSeparatedMembers)s",
"failed_determine_user": "Impossible de déterminer quel utilisateur à ignorer car l'événement des membres a changé.",
"failed_reject_invite": "Échec du rejet de linvitation",
"forget_room": "Oublier ce salon",
"forget_space": "Oublier cet espace",
@ -2091,7 +2092,6 @@
"room_list": {
"add_room_label": "Ajouter un salon",
"add_space_label": "Ajouter un espace",
"appearance": "Apparence",
"breadcrumbs_empty": "Aucun salon visité récemment",
"breadcrumbs_label": "Salons visités récemment",
"empty": {
@ -2116,6 +2116,7 @@
"filters": {
"favourite": "Favoris",
"invites": "Invitations",
"low_priority": "Faible priorité",
"mentions": "Mentions",
"people": "Personnes",
"rooms": "Salons",
@ -2149,7 +2150,6 @@
},
"room_options": "Options du salon",
"show_less": "En voir moins",
"show_message_previews": "Afficher les aperçus des messages",
"show_n_more": {
"other": "En afficher %(count)s de plus",
"one": "En afficher %(count)s de plus"
@ -2807,6 +2807,7 @@
"voip": "Appels audio et vidéo"
},
"preferences": {
"Electron.enableContentProtection": "Empêcher le contenu de la fenêtre d'être capturé par d'autres applications",
"Electron.enableHardwareAcceleration": "Activer laccélération matérielle (redémarrez %(appName)s pour l'activer)",
"always_show_menu_bar": "Toujours afficher la barre de menu de la fenêtre",
"autocomplete_delay": "Délai pour lautocomplétion (ms)",
@ -2979,6 +2980,7 @@
"show_chat_effects": "Afficher les animations de conversation (animations lors de la réception par ex. de confettis)",
"show_displayname_changes": "Afficher les changements de nom daffichage",
"show_join_leave": "Afficher les messages d'arrivée et de départ (les invitations/expulsions/bannissements ne sont pas concernés)",
"show_message_previews": "Afficher les aperçus des messages",
"show_nsfw_content": "Afficher le contenu sensible (NSFW)",
"show_read_receipts": "Afficher les accusés de lecture envoyés par les autres utilisateurs",
"show_redaction_placeholder": "Afficher les messages supprimés",
@ -3125,6 +3127,7 @@
"upgraderoom": "Met à niveau un salon vers une nouvelle version",
"upgraderoom_permission_error": "Vous navez pas les autorisations nécessaires pour utiliser cette commande.",
"usage": "Utilisation",
"verify": "Vérifie un utilisateur, une session et une collection de clés publiques",
"view": "Affiche le salon avec cette adresse",
"whois": "Affiche des informations à propos de lutilisateur"
},

View File

@ -676,8 +676,6 @@
"security_key_title": "Chave de Seguridade"
},
"bootstrap_title": "Configurando as chaves",
"cancel_entering_passphrase_description": "¿Estás seguro de que non queres escribir a frase de paso?",
"cancel_entering_passphrase_title": "Cancelar a escrita da frase de paso?",
"confirm_encryption_setup_body": "Preme no botón inferior para confirmar os axustes do cifrado.",
"confirm_encryption_setup_title": "Confirma os axustes de cifrado",
"cross_signing_room_normal": "Esta sala está cifrada extremo-a-extremo",
@ -2255,6 +2253,7 @@
"upgraderoom": "Subir a sala de versión",
"upgraderoom_permission_error": "Non tes os permisos suficientes para usar este comando.",
"usage": "Uso",
"verify": "Verifica unha usuaria, sesión e chave pública",
"whois": "Mostra información acerca da usuaria"
},
"space": {

View File

@ -574,8 +574,6 @@
"security_key_title": "מפתח אבטחה"
},
"bootstrap_title": "מגדיר מפתחות",
"cancel_entering_passphrase_description": "האם אתם בטוחים שהינכם רוצים לבטל?",
"cancel_entering_passphrase_title": "בטל הקלדת סיסמא?",
"confirm_encryption_setup_body": "לחץ על הלחצן למטה כדי לאשר את הגדרת ההצפנה.",
"confirm_encryption_setup_title": "אשר את הגדרת ההצפנה",
"cross_signing_room_normal": "חדר זה מוצפן מקצה לקצה",
@ -1874,6 +1872,7 @@
"upgraderoom": "משדרג את החדר לגרסא חדשה",
"upgraderoom_permission_error": "אין לכם הרשאות להשתמש בפקודה זו.",
"usage": "שימוש",
"verify": "מוודא משתמש, התחברות וצמד מפתח ציבורי",
"whois": "מציג מידע אודות משתמש"
},
"space": {

View File

@ -909,14 +909,13 @@
"encryption": {
"access_secret_storage_dialog": {
"key_validation_text": {
"wrong_security_key": "Hibás helyreállítási kulcs"
"wrong_security_key": "A megadott helyreállítási kulcs helytelen."
},
"privacy_warning": "Győződjön meg arról, hogy senki sem látja ezt a képernyőt!",
"restoring": "Kulcsok helyreállítása mentésből",
"security_key_title": "Helyreállítási kulcs"
},
"bootstrap_title": "Kulcsok beállítása",
"cancel_entering_passphrase_description": "Biztos, hogy megszakítja a jelmondat bevitelét?",
"cancel_entering_passphrase_title": "Megszakítja a jelmondat bevitelét?",
"confirm_encryption_setup_body": "Az alábbi gomb megnyomásával erősítsd meg, hogy megadod a titkosítási beállításokat.",
"confirm_encryption_setup_title": "Erősítse meg a titkosítási beállításokat",
"cross_signing_room_normal": "Ez a szoba végpontok közti titkosítást használ",
@ -2076,7 +2075,6 @@
"room_list": {
"add_room_label": "Szoba hozzáadása",
"add_space_label": "Tér hozzáadása",
"appearance": "Megjelenés",
"breadcrumbs_empty": "Nincsenek nemrégiben meglátogatott szobák",
"breadcrumbs_label": "Nemrég meglátogatott szobák",
"empty": {
@ -2132,7 +2130,6 @@
},
"room_options": "Szobabeállítások",
"show_less": "Kevesebb megjelenítése",
"show_message_previews": "Üzenetelőnézetek megjelenítése",
"show_n_more": {
"Még %(count)s megjelenítése": "one"
},
@ -3102,6 +3099,7 @@
"upgraderoom": "Új verzióra fejleszti a szobát",
"upgraderoom_permission_error": "A parancs használatához nincs meg a megfelelő jogosultsága.",
"usage": "Használat",
"verify": "Felhasználó, munkamenet és nyilvános kulcs hármas ellenőrzése",
"view": "Megadott címmel rendelkező szobák megjelenítése",
"whois": "Információt jelenít meg a felhasználóról"
},
@ -3223,8 +3221,8 @@
"start_group_chat_button": "Csoportos csevegés indítása"
},
"stickers": {
"empty": "Nincs engedélyezett matrica csomagod",
"empty_add_prompt": "Adj hozzá párat"
"empty": "Jelenleg nincsenek engedélyezve matricacsomagok",
"empty_add_prompt": "Adjon hozzá néhányat"
},
"terms": {
"column_document": "Dokumentum",

View File

@ -917,8 +917,6 @@
"security_key_title": "Kunci pemulihan"
},
"bootstrap_title": "Menyiapkan kunci",
"cancel_entering_passphrase_description": "Apakah Anda yakin untuk membatalkan pemasukkan frasa sandi?",
"cancel_entering_passphrase_title": "Batalkan memasukkan frasa sandi?",
"confirm_encryption_setup_body": "Klik tombol di bawah untuk mengkonfirmasi menyiapkan enkripsi.",
"confirm_encryption_setup_title": "Konfirmasi pengaturan enkripsi",
"cross_signing_room_normal": "Ruangan ini dienkripsi secara ujung ke ujung",
@ -2086,7 +2084,6 @@
"room_list": {
"add_room_label": "Tambahkan ruangan",
"add_space_label": "Tambahkan space",
"appearance": "Penampilan",
"breadcrumbs_empty": "Tidak ada ruangan yang baru saja dilihat",
"breadcrumbs_label": "Ruangan yang baru saja dilihat",
"empty": {
@ -2144,7 +2141,6 @@
},
"room_options": "Opsi Ruangan",
"show_less": "Tampilkan lebih sedikit",
"show_message_previews": "Tampilkan pratinjau pesan",
"show_n_more": {
"one": "Tampilkan %(count)s lagi",
"other": "Tampilkan %(count)s lagi"
@ -3120,6 +3116,7 @@
"upgraderoom": "Meningkatkan ruangan ke versi yang baru",
"upgraderoom_permission_error": "Anda tidak memiliki izin yang dibutuhkan untuk menggunakan perintah ini.",
"usage": "Penggunaan",
"verify": "Memverifikasi sebuah pengguna, sesi, dan tupel pubkey",
"view": "Menampilkan ruangan dengan alamat yang ditentukan",
"whois": "Menampilkan informasi tentang sebuah pengguna"
},

View File

@ -679,8 +679,6 @@
"security_key_title": "Öryggislykill"
},
"bootstrap_title": "Set upp dulritunarlykla",
"cancel_entering_passphrase_description": "Viltu örugglega hætta við að setja inn lykilfrasa?",
"cancel_entering_passphrase_title": "Hætta við að setja inn lykilfrasa?",
"confirm_encryption_setup_body": "Smelltu á hnappinn hér að neðan til að staðfesta uppsetningu á dulritun.",
"confirm_encryption_setup_title": "Staðfestu uppsetningu dulritunar",
"cross_signing_room_normal": "Þessi spjallrás er enda-í-enda dulrituð",
@ -2185,6 +2183,7 @@
"upgraderoom": "Uppfærir spjallrás í nýja útgáfu",
"upgraderoom_permission_error": "Þú hefur ekki nauðsynlegar heimildir til að nota þessa skipun.",
"usage": "Notkun",
"verify": "Sannreynir auðkenni notanda, setu og dreifilykils",
"whois": "Birtir upplýsingar um notanda"
},
"space": {

View File

@ -801,8 +801,6 @@
"security_key_title": "Chiave di sicurezza"
},
"bootstrap_title": "Configurazione chiavi",
"cancel_entering_passphrase_description": "Sei sicuro di volere annullare l'inserimento della frase?",
"cancel_entering_passphrase_title": "Annullare l'inserimento della password?",
"confirm_encryption_setup_body": "Clicca il pulsante sotto per confermare l'impostazione della crittografia.",
"confirm_encryption_setup_title": "Conferma impostazione crittografia",
"cross_signing_room_normal": "Questa stanza è cifrata end-to-end",
@ -2712,6 +2710,7 @@
"upgraderoom": "Aggiorna una stanza ad una nuova versione",
"upgraderoom_permission_error": "Non hai l'autorizzazione necessaria per usare questo comando.",
"usage": "Utilizzo",
"verify": "Verifica un utente, una sessione e una tupla pubblica",
"view": "Visualizza la stanza con l'indirizzo dato",
"whois": "Mostra le informazioni di un utente"
},

View File

@ -760,8 +760,6 @@
"security_key_title": "セキュリティーキー"
},
"bootstrap_title": "鍵のセットアップ",
"cancel_entering_passphrase_description": "パスフレーズの入力をキャンセルしてよろしいですか?",
"cancel_entering_passphrase_title": "パスフレーズの入力をキャンセルしますか?",
"confirm_encryption_setup_body": "以下のボタンをクリックして、暗号化の設定を承認してください。",
"confirm_encryption_setup_title": "暗号化の設定を承認してください",
"cross_signing_room_normal": "このルームはエンドツーエンドで暗号化されています",
@ -2462,6 +2460,7 @@
"upgraderoom": "ルームを新しいバージョンにアップグレード",
"upgraderoom_permission_error": "このコマンドを実行するのに必要な権限がありません。",
"usage": "用法",
"verify": "ユーザー、セッション、およびpubkeyタプルを認証",
"whois": "ユーザーの情報を表示"
},
"space": {

View File

@ -665,8 +665,6 @@
"security_key_title": "უსაფრთხოების გასაღები"
},
"bootstrap_title": "გასაღებების დაყენება",
"cancel_entering_passphrase_description": "დარწმუნებული ხართ, რომ გსურთ გააუქმოთ პაროლის შეყვანა?",
"cancel_entering_passphrase_title": "გააუქმოს პაროლის შეყვანა?",
"confirm_encryption_setup_body": "დააწკაპუნეთ ქვემოთ მოცემულ ღილაკზე დაშიფვრის დაყენების დასადასტურებლად.",
"confirm_encryption_setup_title": "დაადასტურეთ დაშიფვრის დაყენება",
"cross_signing_room_normal": "",

View File

@ -668,8 +668,6 @@
"security_key_title": "ກະແຈຄວາມປອດໄພ"
},
"bootstrap_title": "ການຕັ້ງຄ່າກະແຈ",
"cancel_entering_passphrase_description": "ທ່ານແນ່ໃຈບໍ່ວ່າຕ້ອງການຍົກເລີກການໃສ່ປະໂຫຍກລະຫັດຜ່ານ?",
"cancel_entering_passphrase_title": "ຍົກເລີກການໃສ່ປະໂຫຍກລະຫັດຜ່ານບໍ?",
"confirm_encryption_setup_body": "ກົດທີ່ປຸ່ມຂ້າງລຸ່ມນີ້ເພື່ອຢືນຢັນການຕັ້ງຄ່າການເຂົ້າລະຫັດ.",
"confirm_encryption_setup_title": "ຢືນຢັນການຕັ້ງຄ່າການເຂົ້າລະຫັດ",
"cross_signing_room_normal": "ຫ້ອງນີ້ຖືກເຂົ້າລະຫັດແບບຕົ້ນທາງ-ເຖິງປາຍທາງ",
@ -2182,6 +2180,7 @@
"upgraderoom": "ຍົກລະດັບຫ້ອງເປັນລຸ້ນໃໝ່",
"upgraderoom_permission_error": "ທ່ານບໍ່ມີສິດໃຊ້ຄໍາສັ່ງນີ້.",
"usage": "ການນໍາໃຊ້",
"verify": "ຢືນຢັນຜູ້ໃຊ້, ລະບົບ, ແລະ pubkey tuple",
"whois": "ສະແດງຂໍ້ມູນກ່ຽວກັບຜູ້ໃຊ້"
},
"space": {

View File

@ -505,8 +505,6 @@
"security_key_title": "Saugumo Raktas"
},
"bootstrap_title": "Raktų nustatymas",
"cancel_entering_passphrase_description": "Ar tikrai norite atšaukti slaptafrazės įvedimą?",
"cancel_entering_passphrase_title": "Atšaukti slaptafrazės įvedimą?",
"confirm_encryption_setup_body": "Paspauskite mygtuką žemiau, kad patvirtintumėte šifravimo nustatymą.",
"confirm_encryption_setup_title": "Patvirtinti šifravimo sąranką",
"cross_signing_room_normal": "Šis kambarys visapusiškai užšifruotas",
@ -1739,6 +1737,7 @@
"upgraderoom": "Atnaujina kambarį į naują versiją",
"upgraderoom_permission_error": "Jūs neturite reikalingų leidimų naudoti šią komandą.",
"usage": "Naudojimas",
"verify": "Patvirtina vartotojo, seanso ir pubkey daugiadalę duomenų struktūrą",
"whois": "Parodo informaciją apie vartotoją"
},
"space": {
@ -1940,9 +1939,12 @@
"unknown": "%(senderDisplayName)s pakeitė prisijungimo taisyklę į %(rule)s"
},
"m.room.member": {
"accepted_3pid_invite": "%(targetName)s priėmė kvietimą, skirtą %(displayName)s",
"accepted_invite": "%(targetName)s priėmė kvietimą",
"ban": "%(senderName)s užblokavo %(targetName)s",
"change_avatar": "%(senderName)s pakeitė savo profilio nuotrauką",
"change_name": "%(oldDisplayName)s pasikeitė savo rodomą vardą į %(displayName)s",
"invite": "%(senderName)s pakvietė %(targetName)s",
"join": "%(targetName)s prisijungė prie kambario",
"kick": "%(senderName)s pašalino %(targetName)s",
"kick_reason": "%(senderName)s pašalino %(targetName)s: %(reason)s",

View File

@ -840,8 +840,6 @@
"security_key_title": "Drošības atslēga"
},
"bootstrap_title": "Atslēgu iestatīšana",
"cancel_entering_passphrase_description": "Vai tiešām atcelt paroles vārdkopas ievadīšanu?",
"cancel_entering_passphrase_title": "Atcelt frāzveida paroles ievadi?",
"confirm_encryption_setup_body": "Noklikšķiniet uz tālāk esošās pogas, lai apstiprinātu šifrēšanas iestatīšanu.",
"confirm_encryption_setup_title": "Apstiprināt šifrēšanas iestatīšanu",
"cross_signing_room_normal": "Šajā istabā tiek veikta pilnīga šifrēšana",
@ -2643,6 +2641,7 @@
"upgraderoom": "Atjaunina istabu uz jaunu versiju",
"upgraderoom_permission_error": "Nav šīs komandas izmantošanai nepieciešamo atļauju.",
"usage": "Lietojums",
"verify": "Verificē lietotāju, sesiju un publiskās atslēgas",
"view": "Skata istabu ar norādīto adresi",
"whois": "Parāda lietotāja informāciju"
},

View File

@ -797,8 +797,6 @@
"security_key_title": "Kitendry fiarovana"
},
"bootstrap_title": "Fametrahana fanalahidy",
"cancel_entering_passphrase_description": "Tena te-hanafoana ny fampidirana fehezanteny ve ianao?",
"cancel_entering_passphrase_title": "Hanafoana ny fidirana amin'ny teny miafina ?",
"confirm_encryption_setup_body": "Kitiho ny bokotra etsy ambany hanamafisana ny fametrahana encryption.",
"confirm_encryption_setup_title": "Hamafiso ny fanamboarana fanafenana",
"cross_signing_room_normal": "Ity efitrano ity dia misy encryption avy hatrany",

View File

@ -786,6 +786,7 @@
"cross_signing_status": "Status for krysssignering:",
"cross_signing_untrusted": "Kontoen din har en krysssigneringsidentitet i hemmelig lagring, men den er ennå ikke klarert av denne sesjonen.",
"crypto_not_available": "Kryptografisk modul er ikke tilgjengelig",
"device_id": "Enhets-ID",
"key_backup_active_version": "Aktiv sikkerhetskopiversion:",
"key_backup_active_version_none": "Ingen",
"key_backup_inactive_warning": "Nøklene dine blir ikke sikkerhetskopiert fra denne sesjonen.",
@ -798,6 +799,8 @@
"secret_storage_ready": "klar",
"secret_storage_status": "Hemmelig lagringsplass:",
"self_signing_private_key_cached_status": "Selvsignert privat nøkkel:",
"session": "Sesjon",
"session_fingerprint": "Fingeravtrykk (sesjonsnøkkel)",
"title": "Ende-til-ende-kryptering",
"user_signing_private_key_cached_status": "Brukersignert privat nøkkel:"
},
@ -823,6 +826,7 @@
"low_bandwidth_mode": "Lav båndbreddemodus",
"low_bandwidth_mode_description": "Krever kompatibel hjemmeserver.",
"main_timeline": "Hovedtidslinje",
"manual_device_verification": "Manuell enhetsverifisering",
"no_receipt_found": "Ingen kvittering funnet",
"notification_state": "Varslingsstatus er <strong>%(notificationState)s</strong>",
"notifications_debug": "Feilsøking av varsler",
@ -920,8 +924,6 @@
"security_key_title": "Gjenopprettingsnøkkel"
},
"bootstrap_title": "Setter opp nøkler",
"cancel_entering_passphrase_description": "Er du sikker på at du vil avbryte inntasting av passordfrase?",
"cancel_entering_passphrase_title": "Avbryte inntastingen av passordfrase?",
"confirm_encryption_setup_body": "Klikk på knappen nedenfor for å bekrefte konfigureringen av kryptering.",
"confirm_encryption_setup_title": "Bekreft krypteringsoppsett",
"cross_signing_room_normal": "Dette rommet er ende-til-ende-kryptert",
@ -1009,6 +1011,17 @@
"incoming_sas_dialog_waiting": "Venter på at partneren skal bekrefte...",
"incoming_sas_user_dialog_text_1": "Bekreft denne brukeren for å markere dem som klarerte. Tillit til brukere gir deg ekstra trygghet når du bruker ende-til-ende-krypterte meldinger.",
"incoming_sas_user_dialog_text_2": "Bekreftelse av denne brukeren vil markere økten som klarert, og også merke økten din som klarert for dem.",
"manual": {
"already_verified": "Denne enheten er allerede verifisert",
"already_verified_and_wrong_fingerprint": "Det medfølgende fingeravtrykket stemmer ikke overens, men enheten er allerede verifisert!",
"device_id": "Enhets-ID",
"failure_description": "Kunne ikke verifisere '%(deviceId)s': %(error)s",
"failure_title": "Verifisering mislyktes",
"fingerprint": "Fingeravtrykk (sesjonsnøkkel)",
"no_crypto": "Kan ikke verifisere enheten - krypto er ikke aktivert",
"no_device": "Kunne ikke verifisere enheten - enheten '%(deviceId)s' ble ikke funnet",
"no_userid": "Kan ikke verifisere enheten - finner ikke bruker-ID"
},
"no_key_or_device": "Det ser ut til at du ikke har en gjenopprettingsnøkkel eller andre enheter du kan verifisere mot. Denne enheten vil ikke kunne få tilgang til gamle krypterte meldinger. For å bekrefte identiteten din på denne enheten, må du tilbakestille verifiseringsnøklene dine.",
"no_support_qr_emoji": "Enheten du prøver å bekrefte støtter ikke skanning av en QR-kode eller emoji-verifikasjon, som er det som %(brand)s støtter. Prøv med en annen klient.",
"other_party_cancelled": "Den andre parten kansellerte verifiseringen.",
@ -1957,6 +1970,7 @@
},
"face_pile_tooltip_shortcut": "Inkludert %(commaSeparatedMembers)s",
"face_pile_tooltip_shortcut_joined": "Inkludert deg, %(commaSeparatedMembers)s",
"failed_determine_user": "Kan ikke avgjøre hvilken bruker som skal ignoreres siden medlemshendelsen har endret seg.",
"failed_reject_invite": "Kunne ikke avvise invitasjonen",
"forget_room": "Glem dette rommet",
"forget_space": "Glem dette området",
@ -2048,6 +2062,7 @@
"read_topic": "Klikk for å lese emnet",
"rejecting": "Avviser invitasjon...",
"rejoin_button": "Bli med igjen",
"room_is_low_priority": "Dette er et lavt prioritert rom",
"search": {
"all_rooms_button": "Søk i alle rom",
"placeholder": "Søk i meldinger...",
@ -2094,7 +2109,6 @@
"room_list": {
"add_room_label": "Legg til et rom",
"add_space_label": "Legg til område",
"appearance": "Utseende",
"breadcrumbs_empty": "Ingen nylig besøkte rom",
"breadcrumbs_label": "Nylig besøkte rom",
"empty": {
@ -2119,6 +2133,7 @@
"filters": {
"favourite": "Favoritter",
"invites": "Invitasjoner",
"low_priority": "Lav prioritet",
"mentions": "Omtaler",
"people": "Personer",
"rooms": "Rom",
@ -2152,7 +2167,6 @@
},
"room_options": "Rominnstillinger",
"show_less": "Vis mindre",
"show_message_previews": "Aktiver forhåndsvisning av meldinger",
"show_n_more": {
"Vis %(count)s til": "Vis %(count)s mer"
},
@ -2686,6 +2700,9 @@
"inline_url_previews_room": "Skru på URL-forhåndsvisninger som standard for deltakerne i dette rommet",
"inline_url_previews_room_account": "Skru på URL-forhåndsvisninger for dette rommet (Påvirker bare deg)",
"insert_trailing_colon_mentions": "Sett inn et etterfølgende kolon etter at brukeromtaler i starten av en melding",
"invite_controls": {
"default_label": "Tillat brukere å invitere deg til rom"
},
"jump_to_bottom_on_send": "Gå til bunnen av tidslinjen når du vil sende en melding",
"key_backup": {
"backup_in_progress": "Nøklene dine blir sikkerhetskopiert (den første sikkerhetskopieringen kan ta noen minutter).",
@ -2752,6 +2769,7 @@
"show_in_private": "I private rom",
"show_media": "Vis alltid"
},
"not_supported": "Serveren din implementerer ikke denne funksjonen.",
"notifications": {
"default_setting_description": "Denne innstillingen vil bli brukt som standard for alle rommene dine.",
"default_setting_section": "Jeg ønsker å bli varslet for (standardinnstilling)",
@ -2809,6 +2827,7 @@
"voip": "Lyd- og videosamtaler"
},
"preferences": {
"Electron.enableContentProtection": "Forhindre at innholdet i vinduet fanges opp av andre apper",
"Electron.enableHardwareAcceleration": "Aktiver maskinvareakselerasjon (start %(appName)s på nytt for at det skal tre i kraft)",
"always_show_menu_bar": "Vis alltid vinduets menylinje",
"autocomplete_delay": "Autofullføringsforsinkelse (ms)",
@ -2981,6 +3000,7 @@
"show_chat_effects": "Vis chatteffekter (animasjoner når du mottar f.eks. konfetti)",
"show_displayname_changes": "Vis visningsnavnendringer",
"show_join_leave": "Vis bli med/forlat meldinger (invitasjoner/fjernede/utestengte upåvirket)",
"show_message_previews": "Vise forhåndsvisninger av meldinger",
"show_nsfw_content": "Vis NSFW-innhold",
"show_read_receipts": "Vis lesekvitteringer sendt av andre brukere",
"show_redaction_placeholder": "Vis en stattholder for fjernede meldinger",
@ -3127,6 +3147,7 @@
"upgraderoom": "Oppgraderer et rom til en ny versjon",
"upgraderoom_permission_error": "Du har ikke de rette tilgangene til å bruke denne kommandoen.",
"usage": "Bruk",
"verify": "Verifiserer en bruker-, økt- og pubkey-tuple",
"view": "Viser rom med oppgitt adresse",
"whois": "Viser informasjon om en bruker"
},

View File

@ -699,8 +699,6 @@
"security_key_title": "Veiligheidssleutel"
},
"bootstrap_title": "Sleutelconfiguratie",
"cancel_entering_passphrase_description": "Weet je zeker, dat je het invoeren van je wachtwoord wilt afbreken?",
"cancel_entering_passphrase_title": "Wachtwoord annuleren?",
"confirm_encryption_setup_body": "Klik op de knop hieronder om het instellen van de versleuting te bevestigen.",
"confirm_encryption_setup_title": "Bevestig versleuting instelling",
"cross_signing_room_normal": "Deze kamer is eind-tot-eind-versleuteld",
@ -2301,6 +2299,7 @@
"upgraderoom": "Upgrade deze kamer naar een nieuwere versie",
"upgraderoom_permission_error": "Je beschikt niet over de vereiste machtigingen om deze opdracht uit te voeren.",
"usage": "Gebruik",
"verify": "Verifieert de combinatie van persoon, sessie en publieke sleutel",
"whois": "Geeft informatie weer over een persoon"
},
"space": {

View File

@ -923,8 +923,6 @@
"security_key_title": "Klucz przywracania"
},
"bootstrap_title": "Konfigurowanie kluczy",
"cancel_entering_passphrase_description": "Czy na pewno chcesz anulować wpisywanie hasła?",
"cancel_entering_passphrase_title": "Anulować wpisywanie hasła?",
"confirm_encryption_setup_body": "Kliknij przycisk poniżej, aby potwierdzić ustawienie szyfrowania.",
"confirm_encryption_setup_title": "Potwierdź ustawienie szyfrowania",
"cross_signing_room_normal": "Ten pokój jest szyfrowany end-to-end",
@ -2105,7 +2103,6 @@
"room_list": {
"add_room_label": "Dodaj pokój",
"add_space_label": "Dodaj przestrzeń",
"appearance": "Wygląd",
"breadcrumbs_empty": "Brak ostatnio odwiedzonych pokojów",
"breadcrumbs_label": "Ostatnio odwiedzane pokoje",
"empty": {
@ -2158,7 +2155,6 @@
},
"room_options": "Opcje pokoju",
"show_less": "Pokaż mniej",
"show_message_previews": "Pokaż podglądy wiadomości",
"show_n_more": {
"one": "Pokaż %(count)s więcej",
"few": "Pokaż %(count)s więcej",
@ -3133,6 +3129,7 @@
"upgraderoom": "Ulepsza pokój do nowej wersji",
"upgraderoom_permission_error": "Nie posiadasz wymaganych uprawnień do użycia tego polecenia.",
"usage": "Użycie",
"verify": "Weryfikuje użytkownika, sesję oraz klucz publiczny",
"view": "Przegląda pokój z podanym adresem",
"whois": "Pokazuje informacje na temat użytkownika"
},

View File

@ -892,8 +892,6 @@
"security_key_title": "Chave de recuperação"
},
"bootstrap_title": "A configurar chaves",
"cancel_entering_passphrase_description": "Tem a certeza que quer cancelar a introdução da frase-passe?",
"cancel_entering_passphrase_title": "Cancelar a introdução da frase-passe?",
"confirm_encryption_setup_body": "Clica no botão abaixo para confirmar a configuração da encriptação.",
"confirm_encryption_setup_title": "Confirma a configuração da encriptação",
"cross_signing_room_normal": "Esta sala é encriptada de ponta a ponta",

View File

@ -786,6 +786,7 @@
"cross_signing_status": "Status de assinatura cruzada:",
"cross_signing_untrusted": "Sua conta tem uma identidade de assinatura cruzada no armazenamento secreto, mas ela ainda não é confiável para esta sessão.",
"crypto_not_available": "O módulo criptográfico não está disponível",
"device_id": "ID do dispositivo",
"key_backup_active_version": "Versão de backup ativo:",
"key_backup_active_version_none": "Nenhuma",
"key_backup_inactive_warning": "Suas chaves não estão sendo copiadas nesta sessão.",
@ -798,6 +799,8 @@
"secret_storage_ready": "pronto",
"secret_storage_status": "Armazenamento secreto:",
"self_signing_private_key_cached_status": "Chave privada auto-assinada:",
"session": "Sessão",
"session_fingerprint": "Impressão digital (chave de sessão)",
"title": "Criptografia de ponta a ponta",
"user_signing_private_key_cached_status": "Chave privada de assinatura do usuário:"
},
@ -823,6 +826,7 @@
"low_bandwidth_mode": "Modo de baixa largura de banda",
"low_bandwidth_mode_description": "Requer servidor doméstico compatível.",
"main_timeline": "Linha do tempo principal",
"manual_device_verification": "Verificação manual do dispositivo",
"no_receipt_found": "Nenhum recibo encontrado",
"notification_state": "O estado da notificação é<strong>%(notificationState)s</strong>",
"notifications_debug": "Depuração de notificações",
@ -920,8 +924,6 @@
"security_key_title": "Chave de recuperação"
},
"bootstrap_title": "Configurar chaves",
"cancel_entering_passphrase_description": "Tem certeza que quer cancelar a introdução da frase de senha?",
"cancel_entering_passphrase_title": "Cancelar a introdução da frase de senha?",
"confirm_encryption_setup_body": "Clique no botão abaixo para confirmar a configuração da criptografia.",
"confirm_encryption_setup_title": "Confirmar a configuração de criptografia",
"cross_signing_room_normal": "Esta sala é criptografada de ponta a ponta",
@ -1009,6 +1011,21 @@
"incoming_sas_dialog_waiting": "Aguardando a confirmação do parceiro…",
"incoming_sas_user_dialog_text_1": "Confirme este usuário para torná-lo confiável. Confiar nos usuários fornece segurança adicional ao trocar mensagens criptografadas de ponta a ponta.",
"incoming_sas_user_dialog_text_2": "Se você confirmar esse usuário, a sessão será marcada como confiável para você e para ele.",
"manual": {
"already_verified": "Este dispositivo já está verificado",
"already_verified_and_wrong_fingerprint": "A impressão digital fornecida não corresponde, mas o dispositivo já foi verificado!",
"device_id": "ID do dispositivo",
"failure_description": "Falha ao verificar '%(deviceId)s': %(error)s",
"failure_title": "A verificação falhou",
"fingerprint": "Impressão digital (chave de sessão)",
"no_crypto": "Não é possível verificar o dispositivo - a criptografia não está ativada",
"no_device": "Não foi possível verificar o dispositivo - o dispositivo '%(deviceId)s' não foi encontrado",
"no_userid": "Não foi possível verificar o dispositivo - não foi possível encontrar nossa ID de usuário",
"success_description": "O dispositivo (%(deviceId)s) agora tem assinatura cruzada",
"success_title": "Verificação bem-sucedida",
"text": "Forneça o ID e a impressão digital de um de seus próprios dispositivos para verificá-lo. OBSERVE que isso permite que o outro dispositivo envie e receba mensagens como você. SE ALGUÉM LHE DISSE PARA COLAR ALGO AQUI, É PROVÁVEL QUE VOCÊ ESTEJA SENDO ENGANADO!",
"wrong_fingerprint": "Não é possível verificar o dispositivo '%(deviceId)s' - a impressão digital fornecida '%(fingerprint)s' não corresponde à impressão digital do dispositivo, '%(fprint)s'"
},
"no_key_or_device": "Parece que você não tem uma chave de segurança ou qualquer outro dispositivo que possa ser verificado. Este dispositivo não poderá acessar mensagens criptografadas antigas. Para verificar sua identidade neste dispositivo, você precisará redefinir suas chaves de verificação.",
"no_support_qr_emoji": "O dispositivo que você está tentando verificar não suporta a leitura de um código QR ou verificação de emoji, que é o que %(brand)s suporta. Tente com um cliente diferente.",
"other_party_cancelled": "Seu contato cancelou a confirmação.",
@ -1956,6 +1973,7 @@
},
"face_pile_tooltip_shortcut": "Incluindo %(commaSeparatedMembers)s",
"face_pile_tooltip_shortcut_joined": "Incluindo você, %(commaSeparatedMembers)s",
"failed_determine_user": "Não é possível determinar qual usuário ignorar, pois o evento do membro foi alterado.",
"failed_reject_invite": "Não foi possível recusar o convite",
"forget_room": "Esquecer esta sala",
"forget_space": "Esqueça este espaço",
@ -2047,6 +2065,7 @@
"read_topic": "Clique para ler o tópico",
"rejecting": "Rejeitando o convite...",
"rejoin_button": "Entrar novamente",
"room_is_low_priority": "Esta é uma sala de baixa prioridade",
"search": {
"all_rooms_button": "Pesquisar todos as salas",
"placeholder": "Pesquisar mensagens...",
@ -2093,7 +2112,6 @@
"room_list": {
"add_room_label": "Adicionar sala",
"add_space_label": "Adicionar espaço",
"appearance": "Aparência",
"breadcrumbs_empty": "Nenhuma sala foi visitada recentemente",
"breadcrumbs_label": "Salas visitadas recentemente",
"empty": {
@ -2118,6 +2136,7 @@
"filters": {
"favourite": "Favoritos",
"invites": "Convites",
"low_priority": "Baixa prioridade",
"mentions": "Menções",
"people": "Pessoas",
"rooms": "Salas",
@ -2151,7 +2170,6 @@
},
"room_options": "Opções da Sala",
"show_less": "Mostrar menos",
"show_message_previews": "Mostrar prévias de mensagens",
"show_n_more": {
"other": "Mostrar %(count)s a mais",
"one": "Mostrar %(count)s a mais"
@ -2686,6 +2704,9 @@
"inline_url_previews_room": "Ativar, para todos os participantes desta sala, a visualização de links",
"inline_url_previews_room_account": "Ativar, para esta sala, a visualização de links (só afeta você)",
"insert_trailing_colon_mentions": "Insira dois pontos à direita após o usuário mencionar no início de uma mensagem",
"invite_controls": {
"default_label": "Permitir que usuários convidem você para salas"
},
"jump_to_bottom_on_send": "Vá para o final da linha do tempo ao enviar uma mensagem",
"key_backup": {
"backup_in_progress": "O backup de suas chaves está sendo feito (o primeiro backup pode demorar alguns minutos).",
@ -2752,6 +2773,7 @@
"show_in_private": "Em salas privadas",
"show_media": "Mostrar sempre"
},
"not_supported": "Seu servidor não implementa esse recurso.",
"notifications": {
"default_setting_description": "Essa configuração será aplicada por padrão a todas as suas salas.",
"default_setting_section": "Quero ser notificado sobre (configuração padrão)",
@ -2809,6 +2831,7 @@
"voip": "Chamadas de áudio e vídeo"
},
"preferences": {
"Electron.enableContentProtection": "Impedir que o conteúdo da janela seja capturado por outros aplicativos",
"Electron.enableHardwareAcceleration": "Ativar a aceleração de hardware (reinicie %(appName)s para fazer efeito)",
"always_show_menu_bar": "Mostrar a barra de menu na janela",
"autocomplete_delay": "Atraso no preenchimento automático (ms)",
@ -2981,6 +3004,7 @@
"show_chat_effects": "Mostrar efeitos na conversa (por exemplo: animações ao receber confetes)",
"show_displayname_changes": "Mostrar alterações de nome e sobrenome",
"show_join_leave": "Mostrar mensagens de entrada/saída (convites/remoções/bans não são afetados)",
"show_message_previews": "Mostrar prévias de mensagens",
"show_nsfw_content": "Mostrar conteúdo NSFW (\"Não seguro para o trabalho\")",
"show_read_receipts": "Mostrar confirmações de leitura dos outros usuários",
"show_redaction_placeholder": "Mostrar um marcador para as mensagens removidas",
@ -3127,6 +3151,7 @@
"upgraderoom": "Atualiza a sala para uma nova versão",
"upgraderoom_permission_error": "Você não tem as permissões necessárias para usar este comando.",
"usage": "Uso",
"verify": "Verifique manualmente um de seus próprios dispositivos",
"view": "Visualizações da sala com o endereço fornecido",
"whois": "Exibe informação sobre um usuário"
},

View File

@ -11,6 +11,7 @@
"other": "%(count)s непрочитанных сообщения(-й), включая упоминания.",
"one": "1 непрочитанное упоминание."
},
"recent_rooms": "Недавние комнаты",
"room_name": "Комната %(name)s",
"room_status_bar": "Строка состояния комнаты",
"seek_bar_label": "Панель поиска аудио",
@ -44,6 +45,8 @@
"create_a_room": "Создать комнату",
"create_account": "Создать учётную запись",
"decline": "Отклонить",
"decline_and_block": "Отклонить и заблокировать",
"decline_invite": "Отклонить приглашение",
"delete": "Удалить",
"deny": "Запретить",
"disable": "Отключить",
@ -102,6 +105,7 @@
"reply": "Ответить",
"reply_in_thread": "Обсудить",
"report_content": "Пожаловаться на сообщение",
"report_room": "Комната отчетов",
"resend": "Переотправить",
"reset": "Сброс",
"resume": "Возобновить",
@ -143,6 +147,7 @@
"view_message": "Посмотреть сообщение",
"view_source": "Исходный код",
"yes": "Да",
"yes_dismiss": "Да, отклонить",
"zoom_in": "Увеличить",
"zoom_out": "Уменьшить"
},
@ -257,6 +262,7 @@
"error_expired": "Срок действия входа истек. Пожалуйста, попробуйте еще раз.",
"error_expired_title": "Вход в систему не был завершён вовремя",
"error_insecure_channel_detected": "Не удалось установить безопасное соединение с новым устройством. Существующие устройства по-прежнему в безопасности, и вам не нужно беспокоиться о них.",
"error_insecure_channel_detected_instructions": "Что дальше?",
"error_insecure_channel_detected_instructions_1": "Попробуйте снова войти на другое устройство с помощью QR-кода, если возникла проблема с сетью",
"error_insecure_channel_detected_instructions_2": "Если вы столкнулись с аналогичной проблемой, попробуйте переподключиться к сети Wi-Fi или используйте мобильный интернет",
"error_insecure_channel_detected_instructions_3": "Если это не помогло, войдите вручную.",
@ -371,6 +377,7 @@
"fallback_button": "Начать аутентификацию",
"mas_cross_signing_reset_cta": "Перейти к учетной записи",
"mas_cross_signing_reset_description": "Сбросьте свои данные через поставщика учетной записи, а затем вернитесь и нажмите «Повторить».",
"mas_cross_signing_reset_title": "Перейдите в свою учетную запись, чтобы сбросить свою личность",
"msisdn": "Текстовое сообщение отправлено на %(msisdn)s",
"msisdn_token_incorrect": "Неверный код проверки",
"msisdn_token_prompt": "Введите полученный код:",
@ -507,8 +514,10 @@
"matrix": "Matrix",
"message": "Отправить личное сообщение",
"message_layout": "Макет сообщения",
"message_timestamp_invalid": "Недопустимая метка времени",
"microphone": "Микрофон",
"model": "Модель",
"moderation_and_safety": "Модерация и безопасность",
"modern": "Современный",
"mute": "Приглушить",
"n_members": {
@ -731,6 +740,12 @@
"twemoji": "<twemoji>Изображение смайликов Twemoji</twemoji> © <author> Twitter, Inc и другие авторы </author> используются в соответствии с условиями <terms> CC-BY 4.0</terms>.",
"twemoji_colr": "<colr>twemoji-colr</colr> шрифт от автора © <author>Mozilla Foundation</author> используется на условиях <terms>Apache 2.0</terms>."
},
"decline_invitation_dialog": {
"confirm": "Вы действительно хотите отклонить приглашение присоединиться \"%(roomName)s\"?",
"reason_description": "Опишите причину сообщения о проблеме.",
"report_room_description": "Сообщите об этой комнате своему поставщику учетной записи.",
"title": "Отклонить приглашение"
},
"desktop_default_device_name": "%(brand)s Рабочий стол: %(platformName)s",
"devtools": {
"active_widgets": "Активные виджеты",
@ -741,14 +756,20 @@
"crypto": {
"4s_public_key_in_account_data": "в данных учётной записи",
"4s_public_key_not_in_account_data": "не найдено",
"4s_public_key_status": "Публичный ключ секретного хранилища:",
"backup_key_cached": "сохранено локально",
"backup_key_cached_status": "Кэшированный резервный ключ:",
"backup_key_not_stored": "не сохранено",
"backup_key_stored": "в секретном хранилище",
"backup_key_stored_status": "Сохраненный резервный ключ:",
"backup_key_well_formed": "корректный",
"cross_signing": "Кросс-подпись",
"cross_signing_cached": "сохранено локально",
"cross_signing_not_ready": "Кросс-подпись не настроена.",
"cross_signing_private_keys_in_storage": "в секретном хранилище",
"cross_signing_private_keys_in_storage_status": "Приватные ключи для кросс-подписи:",
"cross_signing_private_keys_not_in_storage": "не найдено в хранилище",
"cross_signing_public_keys_on_device": "в памяти",
"cross_signing_public_keys_on_device_status": "Публичные ключи для кросс-подписи:",
"cross_signing_ready": "Кросс-подпись готова к использованию.",
"cross_signing_status": "Статус кросс-подписи:",
@ -757,10 +778,17 @@
"key_backup_active_version": "Активная резервная версия:",
"key_backup_active_version_none": "Нет",
"key_backup_inactive_warning": "Резервное копирование ваших ключей из этого сеанса не выполняется.",
"key_backup_latest_version": "Последняя версия резервной копии на сервере:",
"key_storage": "Хранилище ключей",
"master_private_key_cached_status": "Приватный мастер-ключ:",
"not_found": "не найдено",
"not_found_locally": "не найдено локально",
"secret_storage_not_ready": "не готов",
"secret_storage_ready": "готово",
"title": "Сквозное шифрование"
"secret_storage_status": "Секретное хранилище:",
"self_signing_private_key_cached_status": "Самоподписанный закрытый ключ:",
"title": "Сквозное шифрование",
"user_signing_private_key_cached_status": "Закрытый ключ подписи пользователей:"
},
"developer_mode": "Режим разработчика",
"developer_tools": "Инструменты разработчика",
@ -801,9 +829,9 @@
"room_notifications_type": "Тип: ",
"room_status": "Статус комнаты",
"room_unread_status_count": {
"one": "Статус непрочитанной комнаты: %(status)s%(status)s</strong>, количество: <strong>%(count)s</strong>",
"few": "Статус непрочитанных комнат: %(status)s%(status)s</strong>, количество: <strong>%(count)s</strong>",
"many": "Статус непрочитанных комнат: %(status)s%(status)s</strong>, количество: <strong>%(count)s</strong>"
"one": "Статус непрочитанной комнаты: <strong>%(status)s</strong>, количество: <strong>%(count)s</strong>",
"few": "Статус непрочитанных комнат: <strong>%(status)s</strong>, количество: <strong>%(count)s</strong>",
"many": "Статус непрочитанных комнат: <strong>%(status)s</strong>, количество: <strong>%(count)s</strong>"
},
"save_setting_values": "Сохранить значения настроек",
"see_history": "Посмотреть историю",
@ -818,6 +846,9 @@
"setting_colon": "Настройки:",
"setting_definition": "Установка определения:",
"setting_id": "ID настроек",
"settings": {
"elementCallUrl": "URL-адрес Element Call"
},
"settings_explorer": "Посмотреть настройки",
"show_hidden_events": "Показывать скрытые события в ленте сообщений",
"spaces": {
@ -827,7 +858,7 @@
},
"state_key": "Ключ состояния",
"thread_root_id": "Идентификатор Root ID: %(threadRootId)s",
"threads_timeline": "Хронология тем",
"threads_timeline": "Хронология обсуждений",
"title": "Инструменты разработчика",
"toggle_event": "переключить событие",
"toolbox": "Панель инструментов",
@ -871,15 +902,15 @@
"empty_room_was_name": "Пустая комната (без %(oldName)s)",
"encryption": {
"access_secret_storage_dialog": {
"alternatives": "Если у вас есть ключ безопасности или защитная фраза, это тоже подойдет.",
"key_validation_text": {
"wrong_security_key": "Неправильный ключ восстановления"
"wrong_security_key": "Введенный ключ восстановления неверен."
},
"privacy_warning": "Убедитесь, что никто не видит этот экран!",
"restoring": "Восстановление ключей из резервной копии",
"security_key_title": "Ключ восстановления"
},
"bootstrap_title": "Настройка ключей",
"cancel_entering_passphrase_description": "Вы уверены, что хотите отменить ввод кодовой фразы?",
"cancel_entering_passphrase_title": "Отменить ввод кодовой фразы?",
"confirm_encryption_setup_body": "Нажмите кнопку ниже, чтобы подтвердить настройку шифрования.",
"confirm_encryption_setup_title": "Подтвердите настройку шифрования",
"cross_signing_room_normal": "Эта комната зашифрована сквозным шифрованием",
@ -914,6 +945,8 @@
"title": "Новый метод восстановления",
"warning": "Если вы не задали новый способ восстановления, злоумышленник может получить доступ к вашей учётной записи. Смените пароль учётной записи и сразу же задайте новый способ восстановления в настройках."
},
"pinned_identity_changed": "Идентичность %(displayName)s (<b>%(userId)s</b>), похоже, изменилась. <a>Узнать больше</a>",
"pinned_identity_changed_no_displayname": "Похоже, что личность <b>%(userId)s</b> изменилась. <a>Узнайте больше</a>",
"recovery_method_removed": {
"description_1": "Этот сеанс обнаружил, что ваши секретная фраза и ключ безопасности для защищенных сообщений были удалены.",
"description_2": "Если вы сделали это по ошибке, вы можете настроить защищённые сообщения в этом сеансе, что снова зашифрует историю сообщений в этом сеансе с помощью нового метода восстановления.",
@ -923,6 +956,7 @@
"reset_all_button": "Забыли или потеряли все варианты восстановления? <a>Сбросить всё</a>",
"set_up_recovery": "Настроить восстановление",
"set_up_recovery_later": "Не сейчас",
"set_up_recovery_toast_description": "Создайте ключ восстановления, который можно использовать для восстановления зашифрованной истории сообщений в случае потери доступа к своим устройствам.",
"set_up_toast_description": "Защита от потери доступа к зашифрованным сообщениям и данным",
"set_up_toast_title": "Настроить безопасное резервное копирование",
"setup_secure_backup": {
@ -962,7 +996,7 @@
"incoming_sas_dialog_waiting": "Ожидаем подтверждения от партнера…",
"incoming_sas_user_dialog_text_1": "Проверить этого пользователя, чтобы отметить его, как доверенного. Доверенные пользователи дают вам больше уверенности при использовании шифрованных сообщений.",
"incoming_sas_user_dialog_text_2": "Подтверждение этого пользователя сделает его сеанс доверенным у вас, а также сделает ваш сеанс доверенным у него.",
"no_key_or_device": "Похоже, у вас нет бумажного ключа, или других сеансов, с которыми вы могли бы свериться. В этом сеансе вы не сможете получить доступ к старым зашифрованным сообщениям. Чтобы подтвердить свою личность в этом сеансе, вам нужно будет сбросить свои ключи шифрования.",
"no_key_or_device": "Похоже, у вас нет Ключа Восстановления, или других сеансов, с которыми вы могли бы свериться. В этом сеансе вы не сможете получить доступ к старым зашифрованным сообщениям. Чтобы подтвердить свою личность в этом сеансе, вам нужно будет сбросить свои ключи шифрования.",
"no_support_qr_emoji": "Устройство, которое вы пытаетесь проверить, не поддерживает сканирование QR-кода или проверку смайликов, которые поддерживает %(brand)s. Попробуйте использовать другой клиент.",
"other_party_cancelled": "Другая сторона отменила проверку.",
"prompt_encrypted": "Подтвердите всех пользователей в комнате, чтобы обеспечить безопасность.",
@ -1012,8 +1046,8 @@
"verify_emoji_prompt_qr": "Если вы не можете отсканировать код выше, попробуйте сравнить уникальные смайлы.",
"verify_later": "Я заверю позже",
"verify_using_device": "Сверить с другим сеансом",
"verify_using_key": "Заверить бумажным ключом",
"verify_using_key_or_phrase": "Проверка с помощью ключа безопасности или фразы",
"verify_using_key": "Подтвердить Ключом Восстановления",
"verify_using_key_or_phrase": "Проверка с помощью Ключа или Фразы Восстановления",
"waiting_for_user_accept": "Ожидание принятия от %(displayName)s…",
"waiting_other_device": "Ожидает проверки на другом устройстве…",
"waiting_other_device_details": "Ожидает проверки на другом устройстве, %(deviceName)s (%(deviceId)s)…",
@ -1064,6 +1098,10 @@
},
"error_app_open_in_another_tab": "%(brand)s был открыт в другой вкладке.",
"error_app_opened_in_another_window": "%(brand)s открыт в другом окне. Нажмите \"%(label)s\" чтобы использовать %(brand)s в данном окне и отключить другое.",
"error_database_closed_description": {
"for_desktop": "Возможно, ваш диск переполнен. Освободите место и перезагрузите компьютер.",
"for_web": "Если вы очистили данные браузера, то это сообщение ожидаемо. %(brand)s также может быть открыт в другой вкладке, или ваш диск заполнен. Пожалуйста, освободите место и перезагрузите"
},
"error_database_closed_title": "База данных неожиданно закрылась",
"error_dialog": {
"copy_room_link_failed": {
@ -1098,7 +1136,11 @@
"m.sticker": "%(senderName)s: %(stickerName)s",
"m.text": "%(senderName)s: %(message)s",
"prefix": {
"poll": "Опрос"
"audio": "Аудио",
"file": "Файл",
"image": "Изображение",
"poll": "Опрос",
"video": "Видео"
}
},
"export_chat": {
@ -1170,7 +1212,7 @@
"platform_username": "Ваша платформа и имя пользователя будут отмечены, чтобы мы могли максимально использовать ваш отзыв.",
"pro_type": "СОВЕТ ДЛЯ ПРОФЕССИОНАЛОВ: если вы запустите ошибку, отправьте <debugLogsLink>журналы отладки</debugLogsLink>, чтобы помочь нам отследить проблему.",
"send_feedback_action": "Отправить отзыв",
"sent": "Отзыв отправлен"
"sent": "Отзыв отправлен! Спасибо, мы очень благодарны!"
},
"file_panel": {
"empty_description": "Прикрепите файлы из чата или просто перетащите их в комнату.",
@ -1191,6 +1233,7 @@
"change": "Изменить сервер идентификации",
"change_prompt": "Отключиться от сервера идентификации <current /> и вместо этого подключиться к <new />?",
"change_server_prompt": "Если вы не хотите использовать <server /> для обнаружения вас и быть обнаруженным вашими существующими контактами, введите другой идентификационный сервер ниже.",
"changed": "Ваш сервер идентификации изменен",
"checking": "Проверка сервера",
"description_connected": "В настоящее время вы используете <server></server> для поиска вами ваших контактов а также вас вашими оппонентами. Вы можете изменить ваш сервер идентификации ниже.",
"description_disconnected": "Вы в настоящее время не используете сервер идентификации. Чтобы найти известные вам контакты, и чтобы они могли найти вас, укажите сервер ниже.",
@ -1222,6 +1265,7 @@
"other": "В %(spaceName)s и %(count)s других пространствах."
},
"incompatible_browser": {
"continue": "Продолжить в любом случае",
"detail_no_continue": "Попробуйте обновить этот браузер, если вы используете не последнюю версию, и повторите попытку.",
"learn_more": "Подробнее",
"linux": "Linux",
@ -1356,12 +1400,14 @@
"navigate_next_message_edit": "Перейдите к следующему сообщению для редактирования",
"navigate_prev_history": "Предыдущая недавно посещенная комната или пространство",
"navigate_prev_message_edit": "Перейдите к предыдущему сообщению для редактирования",
"next_landmark": "Перейти к следующему ориентиру",
"next_room": "Следующая команата или ЛС",
"next_unread_room": "Следующая непрочитанная комната или ЛС",
"number": "[количество]",
"open_user_settings": "Открыть пользовательские настройки",
"page_down": "Page Down",
"page_up": "Page Up",
"prev_landmark": "Перейти к предыдущему ориентиру",
"prev_room": "Предыдущая комната или ЛС",
"prev_unread_room": "Предыдущая непрочитанная комната или ЛС",
"room_list_collapse_section": "Свернуть секцию списка комнат",
@ -1372,7 +1418,7 @@
"scroll_down_timeline": "Листать ленту сообщений вниз",
"scroll_up_timeline": "Листать временную шкалу вверх",
"search": "Поиск (должен быть включен)",
"send_sticker": "Отправить наклейку",
"send_sticker": "Отправить стикер",
"shift": "Shift",
"space": "Подпространство",
"switch_to_space": "Перейти к пространству по номеру",
@ -1406,8 +1452,12 @@
"dynamic_room_predecessors": "Родитель динамической комнаты",
"dynamic_room_predecessors_description": "Включите MSC3946 (для поддержки архивных комнат)",
"element_call_video_rooms": "Видеокомнаты Element Call",
"exclude_insecure_devices": "Исключить небезопасные устройства при отправке/получении сообщений",
"exclude_insecure_devices_description": "Когда этот режим включен, зашифрованные сообщения не будут передаваться непроверенным устройствам, а сообщения с непроверенных устройств будут отображаться как ошибка. Обратите внимание, что если вы включите этот режим, возможно, вы не сможете общаться с пользователями, которые не подтвердили свои устройства.",
"experimental_description": "Время экспериментов? Попробуйте наши последние наработки. Эти функции не заверешены; они могут быть нестабильными, постоянно меняющимися, или вовсе отброшенными. <a>Узнайте больше</a>.",
"experimental_section": "Предпросмотр",
"extended_profiles_msc_support": "Требуется, чтобы ваш сервер поддерживал MSC4133",
"feature_disable_call_per_sender_encryption": "Отключить шифрование для каждого отправителя Element Call",
"feature_wysiwyg_composer_description": "Используйте форматированный текст вместо Markdown в редакторе сообщений.",
"group_calls": "Новый опыт группового вызова",
"group_developer": "Разработка",
@ -1419,6 +1469,7 @@
"group_rooms": "Комнаты",
"group_spaces": "Пространства",
"group_themes": "Темы",
"group_threads": "Обсуждения",
"group_ui": "Пользовательский интерфейс",
"group_voip": "Голос и видео",
"group_widgets": "Виджеты",
@ -1440,6 +1491,7 @@
"notification_settings_beta_caption": "Представляем вам более простой способ изменения настроек уведомлений. Настройте свои настройки так %(brand)s, как вам удобно.",
"notification_settings_beta_title": "Настройки уведомлений",
"notifications": "Включить панель уведомлений в заголовке комнаты",
"release_announcement": "Объявление о новой версии",
"render_reaction_images": "Обработка пользовательских изображений в реакциях",
"render_reaction_images_description": "Иногда их называют \"пользовательскими эмодзи\".",
"report_to_moderators": "Пожаловаться модераторам",
@ -1447,7 +1499,7 @@
"sliding_sync": "Режим Sliding Sync",
"sliding_sync_description": "В активной разработке, нельзя отключить.",
"sliding_sync_disabled_notice": "Выйдите из системы и снова войдите, чтобы отключить",
"sliding_sync_server_no_support": "На вашем сервере отсутствует встроенная поддержка",
"sliding_sync_server_no_support": "На вашем сервере отсутствует поддержка",
"under_active_development": "В активной разработке.",
"unrealiable_e2e": "Ненадежно в зашифрованных комнатах",
"video_rooms": "Видеокомнаты",
@ -1499,6 +1551,8 @@
"last_person_warning": "Вы здесь единственный человек. Если вы уйдете, никто не сможет присоединиться в будущем, включая вас.",
"leave_room_question": "Уверены, что хотите покинуть '%(roomName)s'?",
"leave_space_question": "Уверены, что хотите покинуть пространство \"%(spaceName)s\"?",
"room_leave_admin_warning": "Вы единственный администратор в данной комнате. Если вы покинете ее, никто не сможет изменить настройки комнаты или выполнить другие важные действия.",
"room_leave_mod_warning": "Вы единственный модератор в этой комнате. Если вы уйдете, никто не сможет изменить настройки комнаты или выполнить другие важные действия.",
"room_rejoin_warning": "Эта комната не является публичной. Вы не сможете войти без приглашения.",
"space_rejoin_warning": "Это пространство не публично. Вы не сможете вновь войти без приглашения."
},
@ -1563,10 +1617,13 @@
},
"filter_placeholder": "Поиск по участникам",
"invite_button_no_perms_tooltip": "У вас нет разрешения приглашать пользователей",
"invited_label": "Приглашены",
"no_matches": "Нет совпадений",
"power_label": "%(userName)s (уровень прав %(powerLevelNumber)s)"
},
"member_list_back_action_label": "Участники комнаты",
"message_edit_dialog_title": "Правки сообщения",
"migrating_crypto": "Наберитесь терпения. Мы обновляем %(brand)s, чтобы сделать шифрование быстрые и надежнее.",
"mobile_guide": {
"toast_accept": "Использовать приложение",
"toast_description": "%(brand)s работает в экспериментальном режиме в мобильном браузере. Для лучших впечатлений и новейших функций используйте наше родное бесплатное приложение.",
@ -1592,6 +1649,8 @@
"keyword": "Ключевое слово",
"keyword_new": "Новое ключевое слово",
"level_activity": "Активность",
"level_highlight": "Выделение",
"level_muted": "Звук отключен",
"level_none": "Пусто",
"level_notification": "Уведомление",
"level_unsent": "Не отправлено",
@ -1771,6 +1830,7 @@
"description": "Все прикрепленные сообщения можно найти здесь. Наведите курсор на любое сообщение и нажмите «Закрепить», чтобы добавить его.",
"title": "Все новые закрепленные сообщения"
},
"reply_thread": "Ответ на сообщение в <link>обсуждениях</link>",
"unpin_all": {
"button": "Открепить все сообщения",
"content": "Убедитесь, что вы действительно хотите удалить все прикреплённые сообщения. Это действие нельзя отменить.",
@ -1869,7 +1929,8 @@
},
"face_pile_tooltip_label": {
"one": "Посмотреть 1 участника",
"other": "Просмотреть всех %(count)s участников"
"few": "Посмотреть %(count)s участника",
"many": "Посмотреть %(count)s участников"
},
"face_pile_tooltip_shortcut": "Включая %(commaSeparatedMembers)s",
"face_pile_tooltip_shortcut_joined": "Включая вас, %(commaSeparatedMembers)s",
@ -2017,7 +2078,9 @@
"no_favourites": "У вас пока нет чатов в Избранное",
"no_favourites_description": "Вы можете добавить в Избранное в настройках чата",
"no_people": "У вас пока нет личных чатов",
"no_people_description": "Вы можете убрать фильтры, чтобы увидеть другие ваши чаты",
"no_rooms": "Вы еще не находитесь ни в одной комнате",
"no_rooms_description": "Вы можете убрать фильтры, чтобы увидеть другие ваши чаты",
"no_unread": "Поздравляю! У вас нет непрочитанных сообщений",
"show_chats": "Показать все чаты"
},
@ -2039,12 +2102,14 @@
"list_title": "Список комнат",
"more_options": {
"copy_link": "Скопировать ссылку на комнату",
"favourited": "Избранное",
"leave_room": "Покинуть комнату",
"low_priority": "Низкий приоритет",
"mark_read": "Отметить как прочитанное",
"mark_unread": "Отметить как непрочитанное"
},
"notification_options": "Настройки уведомлений",
"primary_filters": "Фильтры комнат",
"redacting_messages_status": {
"one": "Удаляются сообщения в %(count)s комнате",
"other": "Удаляются сообщения в %(count)s комнатах"
@ -2404,6 +2469,9 @@
"code_block_expand_default": "По умолчанию отображать блоки кода целиком",
"code_block_line_numbers": "Показывать номера строк в блоках кода",
"disable_historical_profile": "Показать текущее изображение профиля и имя пользователя в истории сообщений",
"discovery": {
"title": "Как вас найти"
},
"emoji_autocomplete": "Предлагать смайлики при наборе",
"enable_markdown": "Использовать Markdown",
"enable_markdown_description": "Начинайте сообщения с <code>/plain</code>, чтобы отправлять их без markdown.",
@ -2434,6 +2502,7 @@
"confirm": "Удалить хранилище ключей",
"description": "Удаление хранилища ключей приведёт к удалению вашей идентификации и ключей сообщений с сервера, а также отключению следующих функций безопасности:",
"list_first": "Нет зашифрованной истории сообщений на новых устройствах",
"list_second": "Вы потеряете доступ к своим зашифрованным сообщениям, если вы выйдете из %(brand)s везде",
"title": "Вы уверены, что хотите отключить хранение ключей и удалить их?"
},
"device_not_verified_button": "Проверить это устройство",
@ -2453,8 +2522,15 @@
"enter_recovery_key": "Введите ключ восстановления",
"forgot_recovery_key": "Забыли ключ восстановления?",
"save_key_description": "Не сообщайте эту информацию никому!",
"save_key_title": "Ключ восстановления"
}
"save_key_title": "Ключ восстановления",
"set_up_recovery": "Настройка восстановления",
"set_up_recovery_confirm_button": "Завершить настройку",
"set_up_recovery_confirm_title": "Для подтверждения введите ключ восстановления",
"set_up_recovery_save_key_description": "Запишите ключ восстановления в безопасном месте, например в диспетчере паролей, зашифрованной заметке или физическом сейфе.",
"set_up_recovery_save_key_title": "Сохраните ключ восстановления в безопасном месте",
"title": "Восстановление"
},
"title": "Шифрование"
},
"general": {
"account_management_section": "Управление учётной записью",
@ -2468,6 +2544,14 @@
"add_msisdn_dialog_title": "Добавить номер телефона",
"add_msisdn_instructions": "Текстовое сообщение было отправлено +%(msisdn)s. Пожалуйста, введите проверочный код, который он содержит.",
"add_msisdn_misconfigured": "Поток add/bind с MSISDN настроен неправильно",
"allow_spellcheck": "Разрешить проверку орфографии",
"application_language": "Язык приложения",
"application_language_reload_hint": "Приложение перезагрузится после выбора другого языка",
"avatar_remove_progress": "Удаление изображения…",
"avatar_save_progress": "Загрузка изображения...",
"avatar_upload_error_text": "Формат файла не поддерживается или размер изображения превышает %(size)s.",
"avatar_upload_error_text_generic": "Формат файла может не поддерживаться.",
"avatar_upload_error_title": "Не удалось загрузить изображение профиля",
"confirm_adding_email_body": "Нажмите кнопку ниже для подтверждения этого почтового адреса.",
"confirm_adding_email_title": "Подтвердите добавление почтового адреса",
"deactivate_confirm_body": "Вы уверены, что хотите деактивировать свою учётную запись? Это необратимое действие.",
@ -2483,10 +2567,13 @@
"deactivate_confirm_erase_label": "Скрыть мои сообщения от новых участников",
"deactivate_section": "Деактивировать учётную запись",
"deactivate_warning": "Деактивация вашей учётной записи является необратимым действием — будьте осторожны!",
"discovery_email_empty": "Параметры поиска по электронной почты появятся после добавления её выше.",
"discovery_email_empty": "Параметры поиска по электронной почты появятся после её добавления.",
"discovery_email_verification_instructions": "Проверьте ссылку в вашем почтовом ящике(папка \"Входящие\")",
"discovery_msisdn_empty": "Параметры поиска по номеру телефона появятся после его добавления.",
"discovery_needs_terms": "Подтвердите условия предоставления услуг сервера идентификации (%(serverName)s), чтобы вас можно было обнаружить по адресу электронной почты или номеру телефона.",
"discovery_needs_terms_title": "Позвольте людям найти вас",
"display_name": "Отображаемое имя",
"display_name_error": "Невозможно установить отображаемое имя",
"email_address_in_use": "Этот адрес электронной почты уже используется",
"email_address_label": "Адрес электронной почты",
"email_not_verified": "Ваш адрес электронной почты еще не проверен",
@ -2511,7 +2598,7 @@
"error_share_msisdn_discovery": "Не удается предоставить общий доступ к номеру телефона",
"identity_server_no_token": "Не найден токен доступа для идентификации",
"identity_server_not_set": "Сервер идентификации не установлен",
"language_section": "Язык и регион",
"language_section": "Язык",
"msisdn_in_use": "Этот номер телефона уже используется",
"msisdn_label": "Номер телефона",
"msisdn_verification_field_label": "Код подтверждения",
@ -2520,9 +2607,14 @@
"oidc_manage_button": "Настройки аккаунта",
"password_change_section": "Установите новый пароль…",
"password_change_success": "Ваш пароль успешно изменён.",
"personal_info": "Личная информация",
"profile_subtitle": "Так вас видят другие пользователи приложения.",
"remove_email_prompt": "Удалить %(email)s?",
"remove_msisdn_prompt": "Удалить %(phone)s?",
"spell_check_locale_placeholder": "Выберите регион"
"spell_check_locale_placeholder": "Выберите регион",
"unable_to_load_emails": "Не удалось загрузить адреса электронной почты",
"unable_to_load_msisdns": "Не удалось загрузить номера телефонов",
"username": "Имя пользователя"
},
"inline_url_previews_default": "Предпросмотр ссылок по умолчанию",
"inline_url_previews_room": "Включить предпросмотр ссылок для участников этой комнаты по умолчанию",
@ -2545,13 +2637,13 @@
"enter_phrase_description": "Введите секретную фразу, известную только вам, так как она используется для защиты ваших данных. В целях безопасности не следует повторно использовать пароль своей учетной записи.",
"enter_phrase_title": "Введите секретную фразу",
"enter_phrase_to_confirm": "Введите секретную фразу второй раз, чтобы подтвердить ее.",
"generate_security_key_description": "Мы создадим ключ безопасности для вас, чтобы вы могли хранить его в надежном месте, например, в менеджере паролей или сейфе.",
"generate_security_key_description": "Мы создадим ключ восстановления, который вы сможете хранить в безопасном месте, например в менеджере паролей или сейфе.",
"generate_security_key_title": "Создание ключа безопасности",
"pass_phrase_match_failed": "Они не совпадают.",
"pass_phrase_match_success": "Они совпадают!",
"phrase_strong_enough": "Отлично! Эта контрольная фраза выглядит достаточно сильной.",
"secret_storage_query_failure": "Невозможно запросить состояние секретного хранилища",
"security_key_safety_reminder": "Храните ключ безопасности в надежном месте, например в менеджере паролей или сейфе, так как он используется для защиты ваших зашифрованных данных.",
"security_key_safety_reminder": "Храните Ключ Восстановления в надежном месте, например в менеджере паролей или сейфе, так как он используется для защиты ваших зашифрованных данных.",
"set_phrase_again": "Задать другой пароль.",
"settings_reminder": "Вы также можете настроить безопасное резервное копирование и управлять своими ключами в настройках.",
"title_confirm_phrase": "Подтвердите секретную фразу",
@ -2577,12 +2669,20 @@
"phrase_strong_enough": "Отлично! Эта парольная фраза выглядит достаточно надежной"
},
"keyboard": {
"dialog_title": "<strong>Настройки:</strong> Клавиатура",
"title": "Горячие клавиши"
},
"labs": {
"dialog_title": "<strong>Настройки:</strong> Лаборатория"
},
"labs_mjolnir": {
"dialog_title": "<strong>Настройки:</strong> Игнорируемые пользователи"
},
"notifications": {
"default_setting_description": "Эта настройка будет применена по умолчанию ко всем вашим комнатам.",
"default_setting_section": "Я хочу получать уведомления о (настройка по умолчанию)",
"desktop_notification_message_preview": "Показать предварительный просмотр сообщения в уведомлении на рабочем столе",
"dialog_title": "<strong>Настройки:</strong> Уведомления",
"email_description": "Получать по электронной почте сводку пропущенных уведомлений",
"email_section": "Информация об электронной почте",
"email_select": "Выберите, на какие электронные письма вы хотите отправлять резюме. Управляйте электронной почтой в <button>Настройках</button>.",
@ -2627,7 +2727,7 @@
"rule_encrypted_room_one_to_one": "Зашифрованные сообщения в персональных чатах",
"rule_invite_for_me": "Приглашения в комнаты",
"rule_message": "Сообщения в конференциях",
"rule_room_one_to_one": "Сообщения в 1:1 чатах",
"rule_room_one_to_one": "Сообщения в личных чатах",
"rule_roomnotif": "Сообщения, содержащие @room",
"rule_suppress_notices": "Сообщения от ботов",
"rule_tombstone": "При обновлении комнат",
@ -2641,12 +2741,14 @@
"code_blocks_heading": "Блоки кода",
"compact_modern": "Использовать более компактный \"Современный\" макет",
"composer_heading": "Редактор",
"dialog_title": "<strong>Настройки:</strong> Параметры",
"enable_hardware_acceleration": "Включить аппаратное ускорение",
"enable_tray_icon": "Показывать значок в трее и сворачивать в него окно при закрытии",
"keyboard_heading": "Горячие клавиши",
"keyboard_view_shortcuts_button": "Чтобы просмотреть все сочетания клавиш, <a>нажмите здесь</a>.",
"media_heading": "Медиа",
"presence_description": "Поделитесь своей активностью и статусом с другими.",
"publish_timezone": "Опубликовать часовой пояс в профиле",
"rm_lifetime": "Задержка прочтения сообщения (мс)",
"rm_lifetime_offscreen": "Задержка прочтения сообщения при отсутствии активности (мс)",
"room_directory_heading": "Каталог комнат",
@ -2654,7 +2756,8 @@
"show_avatars_pills": "Показывать аватары в упоминаниях пользователей, комнатах и событиях",
"show_polls_button": "Показывать кнопку опроса",
"surround_text": "Обводить выделенный текст при вводе специальных символов",
"time_heading": "Отображение времени"
"time_heading": "Отображение времени",
"user_timezone": "Установить часовой пояс"
},
"prompt_invite": "Подтверждать отправку приглашений на потенциально недействительные matrix ID",
"replace_plain_emoji": "Автоматически заменять текстовые смайлики на графические",
@ -2663,6 +2766,8 @@
"bulk_options_accept_all_invites": "Принять все приглашения (%(invitedRooms)s)",
"bulk_options_reject_all_invites": "Отклонить все %(invitedRooms)s приглашения",
"bulk_options_section": "Основные опции",
"dehydrated_device_enabled": "Устройство в автономном режиме",
"dialog_title": "<strong>Настройки:</strong> Безопасность и конфиденциальность",
"e2ee_default_disabled_warning": "Администратор вашего сервера отключил сквозное шифрование по умолчанию в приватных комнатах и диалогах.",
"enable_message_search": "Включить поиск сообщений в зашифрованных комнатах",
"encryption_section": "Шифрование",
@ -2725,6 +2830,7 @@
"device_unverified_description_current": "Заверьте текущий сеанс для усиления защиты переписки.",
"device_verified_description": "Этот сеанс готов к безопасному обмену сообщениями.",
"device_verified_description_current": "Ваш текущий сеанс готов к защищенной переписке.",
"dialog_title": "<strong>Настройки:</strong> Сеансы",
"error_pusher_state": "Не удалось установить состояние push-службы",
"error_set_name": "Не удалось установить имя сессии",
"filter_all": "Все",
@ -2741,6 +2847,7 @@
"inactive_sessions_list_description": "Сочтите выйти из старых сеансов (%(inactiveAgeDays)s дней и более), которые вы более не используете.",
"ip": "IP-адрес",
"last_activity": "Последняя активность",
"manage": "Управление этим сеансом",
"mobile_session": "Сеанс мобильного устройства",
"n_sessions_selected": {
"one": "%(count)s сеанс выбран",
@ -2766,8 +2873,9 @@
"session_id": "ID сеанса",
"show_details": "Показать подробности",
"sign_in_with_qr": "Привязать новое устройство",
"sign_in_with_qr_button": "Показать QR код",
"sign_in_with_qr_description": "Вы можете использовать это устройство для входа на новом устройство с помощью QR-кода. Вам необходимо отсканировать данный QR-код на новом устройстве.",
"sign_in_with_qr_button": "Показать QR-код",
"sign_in_with_qr_description": "Используйте QR-код для входа на другое устройство и настройки безопасного обмена сообщениями.",
"sign_in_with_qr_unsupported": "Не поддерживается вашим поставщиком учетных записей",
"sign_out": "Выйти из этого сеанса",
"sign_out_all_other_sessions": "Выйти из всех остальных сеансов (%(otherSessionsCount)s)",
"sign_out_confirm_description": {
@ -2809,7 +2917,9 @@
"show_redaction_placeholder": "Плашки вместо удалённых сообщений",
"show_stickers_button": "Показывать кнопку наклеек",
"show_typing_notifications": "Уведомлять о наборе текста",
"showbold": "Показывать всю активность в списке комнат (точки или количество непрочитанных сообщений)",
"sidebar": {
"dialog_title": "<strong>Настройки:</strong> Боковая панель",
"metaspaces_favourites_description": "Сгруппируйте все свои любимые комнаты и людей в одном месте.",
"metaspaces_home_all_rooms": "Показать все комнаты",
"metaspaces_home_all_rooms_description": "Показать все комнаты на Главной, даже если они находятся в пространстве.",
@ -2818,10 +2928,14 @@
"metaspaces_orphans_description": "Сгруппируйте все комнаты, которые не являются частью пространства, в одном месте.",
"metaspaces_people_description": "Сгруппируйте всех своих людей в одном месте.",
"metaspaces_subsection": "Пространства для показа",
"metaspaces_video_rooms": "Видеокомнаты и конференции",
"metaspaces_video_rooms_description": "Сгруппировать все частные видеокомнаты и конференции.",
"metaspaces_video_rooms_description_invite_extension": "В конференции вы можете приглашать людей за пределами matrix.",
"spaces_explainer": "Пространства — это способ сгруппировать комнаты и людей. Помимо пространств, в которых вы находитесь, вы также можете использовать готовые помещения.",
"title": "Боковая панель"
},
"start_automatically": "Автозапуск при входе в систему",
"tac_only_notifications": "Показывать уведомления только в центре активностей обсуждений",
"use_12_hour_format": "Отображать время в 12 часовом формате (напр. 2:30pm)",
"use_command_enter_send_message": "Cmd + Enter, чтобы отправить сообщение",
"use_command_f_search": "Используйте Command + F для поиска в ленте сообщений",
@ -2835,6 +2949,7 @@
"audio_output_empty": "Аудиовыход не обнаружен",
"auto_gain_control": "Авторегулировка усиления",
"connection_section": "Соединение",
"dialog_title": "<strong>Настройки:</strong> Голос и видео",
"echo_cancellation": "Эхоподавление",
"enable_fallback_ice_server": "Разрешить резервный сервер помощи при вызове (%(server)s)",
"enable_fallback_ice_server_description": "Только применяется, когда у домашнего сервера нет своего TURN-сервера. Ваш IP-адрес будет виден на время звонка.",
@ -2853,8 +2968,12 @@
"warning": "<w>ВНИМАНИЕ:</w> <description/>"
},
"share": {
"link_copied": "Ссылка скопирована",
"permalink_message": "Ссылка на выбранное сообщение",
"permalink_most_recent": "Ссылка на последнее сообщение",
"share_call": "Ссылка-приглашение на конференцию",
"share_call_subtitle": "Ссылка для внешних пользователей, желающих присоединиться к вызову без учетной записи matrix:",
"title_link": "Поделиться ссылкой",
"title_message": "Поделиться сообщением",
"title_room": "Поделиться комнатой",
"title_user": "Поделиться пользователем"
@ -2939,6 +3058,7 @@
"upgraderoom": "Обновляет комнату до новой версии",
"upgraderoom_permission_error": "У вас нет необходимых разрешений для использования этой команды.",
"usage": "Использование",
"verify": "Проверяет пользователя, сеанс и публичные ключи",
"view": "Просмотр комнаты с указанным адресом",
"whois": "Показать информацию о пользователе"
},
@ -3088,18 +3208,26 @@
"thread_view_back_action_label": "Вернуться к обсуждению",
"threads": {
"all_threads": "Все обсуждения",
"all_threads_description": "Показывает все обсуждения из текущей комнаты",
"all_threads_description": "Отобразит все обсуждения из текущей комнаты",
"count_of_reply": {
"one": "%(count)s ответ",
"few": "%(count)s ответа",
"many": "%(count)s ответов"
},
"empty_description": "Используйте “%(replyInThread)s” при наведении курсора на сообщение.",
"empty_title": "Обсуждения помогают поддерживать тему разговоров и их легко отслеживать.",
"error_start_thread_existing_relation": "Невозможно создать обсуждение из события с существующей связью",
"mark_all_read": "Отметить все как прочитанные",
"my_threads": "Мои обсуждения",
"my_threads_description": "Показывает все обсуждения, в которых вы принимали участие",
"open_thread": "Открыть ветку",
"my_threads_description": "Отобразит все обсуждения, в которых вы принимали участие",
"open_thread": "Открыть обсуждение",
"show_thread_filter": "Показать:"
},
"threads_activity_centre": {
"header": "Активность обсуждений",
"no_rooms_with_threads_notifs": "У вас пока нет комнат с уведомлениями в обсуждениях.",
"no_rooms_with_unread_threads": "У вас пока нет комнат с непрочитанными обсуждениями."
},
"time": {
"about_day_ago": "около суток назад",
"about_hour_ago": "около часа назад",
@ -3141,9 +3269,19 @@
},
"creation_summary_dm": "%(creator)s начал(а) этот чат.",
"creation_summary_room": "%(creator)s создал(а) и настроил(а) комнату.",
"decryption_failure": {
"blocked": "Отправитель заблокировал получение этого сообщения, поскольку ваше устройство не проверено.",
"historical_event_no_key_backup": "История сообщений недоступна на этом устройстве",
"historical_event_unverified_device": "Вам необходимо подтвердить это устройство для доступа к истории сообщений.",
"historical_event_user_not_joined": "У вас нет доступа к этому сообщению",
"sender_identity_previously_verified": "Подтвержденная личность изменилась",
"unable_to_decrypt": "Не удалось расшифровать сообщение"
},
"disambiguated_profile": "%(displayName)s (%(matrixId)s)",
"download_action_decrypting": "Расшифровка",
"download_action_downloading": "Загрузка",
"download_failed": "Загрузка не удалась",
"e2e_state": "Состояние сквозного шифрования",
"edits": {
"tooltip_label": "Изменено %(date)s. Нажмите для посмотра истории изменений.",
"tooltip_sub": "Нажмите для просмотра правок",
@ -3197,7 +3335,7 @@
},
"m.file": {
"error_decrypting": "Ошибка расшифровки вложения",
"error_invalid": "Недопустимый файл%(extra)s"
"error_invalid": "Недопустимый формат файла"
},
"m.image": {
"error": "Невозможно показать изображение из-за ошибки",

View File

@ -929,8 +929,6 @@
"security_key_title": "Kľúč na obnovenie"
},
"bootstrap_title": "Príprava kľúčov",
"cancel_entering_passphrase_description": "Naozaj chcete zrušiť zadávanie prístupovej frázy?",
"cancel_entering_passphrase_title": "Zrušiť zadanie prístupovej frázy?",
"confirm_encryption_setup_body": "Kliknutím na tlačidlo nižšie potvrdíte nastavenie šifrovania.",
"confirm_encryption_setup_title": "Potvrdiť nastavenie šifrovania",
"cross_signing_room_normal": "Táto miestnosť je end-to-end šifrovaná",
@ -2124,7 +2122,6 @@
"room_list": {
"add_room_label": "Pridať miestnosť",
"add_space_label": "Pridať priestor",
"appearance": "Vzhľad",
"breadcrumbs_empty": "Žiadne nedávno navštívené miestnosti",
"breadcrumbs_label": "Nedávno navštívené miestnosti",
"empty": {
@ -2149,6 +2146,7 @@
"filters": {
"favourite": "Obľúbené",
"invites": "Pozvánky",
"low_priority": "Nízka priorita",
"mentions": "Zmienky",
"people": "Ľudia",
"rooms": "Miestnosti",
@ -2184,7 +2182,6 @@
},
"room_options": "Možnosti miestnosti",
"show_less": "Zobraziť menej",
"show_message_previews": "Zobraziť náhľady správ",
"show_n_more": {
"one": "Zobraziť %(count)s ďalšiu",
"few": "Zobraziť %(count)s ďalšie",
@ -3167,6 +3164,7 @@
"upgraderoom": "Aktualizuje miestnosť na novšiu verziu",
"upgraderoom_permission_error": "Na použitie tohoto príkazu nemáte dostatočné povolenia.",
"usage": "Použitie",
"verify": "Overí používateľa, reláciu a verejné kľúče",
"view": "Zobrazí miestnosti s danou adresou",
"whois": "Zobrazuje informácie o používateľovi"
},

View File

@ -762,8 +762,6 @@
"security_key_title": "Kyç Sigurie"
},
"bootstrap_title": "Ujdisje kyçesh",
"cancel_entering_passphrase_description": "Jeni i sigurt se doni të anulohet dhënie frazëkalimi?",
"cancel_entering_passphrase_title": "Të anulohet dhënue frazëkalimi?",
"confirm_encryption_setup_body": "Klikoni mbi butonin më poshtë që të ripohoni ujdisjen e fshehtëzimit.",
"confirm_encryption_setup_title": "Ripohoni ujdisje fshehtëzimi",
"cross_signing_room_normal": "Kjo dhomë është e fshehtëzuar skaj-më-skaj",
@ -2532,6 +2530,7 @@
"upgraderoom": "E kalon një dhomë te një version i ri i përmirësuar",
"upgraderoom_permission_error": "Skeni lejet e domosdoshme për përdorimin e këtij urdhri.",
"usage": "Përdorim",
"verify": "Verifikon një përdorues, sesion dhe një set kyçesh publikë",
"whois": "Shfaq të dhëna rreth një përdoruesi"
},
"space": {

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