Compare commits
325 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8124a72516 | |||
| bd2e34fb63 | |||
| bdf74e89f3 | |||
| 65cc9ef940 | |||
| a838a03a1f | |||
| 7587fd76ee | |||
| b475cc7e9a | |||
| 93149f1cbd | |||
| 352d25f2bb | |||
| 00f08ab2dc | |||
| 07918562dd | |||
| 33d04f0303 | |||
| 34523cf51a | |||
| 8bfd4868c0 | |||
| fa409739c8 | |||
| 4e8774a9a8 | |||
| 92f276e20f | |||
| 394d6f269c | |||
| 116f716d3a | |||
| 65d19d3274 | |||
| d5eace30ed | |||
| 6c9df17d12 | |||
| 44909589b8 | |||
| b00095aaa8 | |||
| d7ad2f1dad | |||
| 2c1270ec79 | |||
| e57d872fc8 | |||
| 9fe64b7cd4 | |||
| b652dfe69a | |||
| 8401c2612a | |||
| 426fdc70a1 | |||
| 0454916b65 | |||
| ac183daff8 | |||
| 327ca090c5 | |||
| ef15fd0666 | |||
| 0cff8bd98e | |||
| e32e1dd388 | |||
| 098edab1b4 | |||
| 15627e4512 | |||
| 1af16e92db | |||
| 346a1e8ebb | |||
| 350d47c94a | |||
| c5675eeb9b | |||
| f224c104e0 | |||
| b4395d948f | |||
| 4355307ba0 | |||
| 7052751e38 | |||
| 491f7c538e | |||
| 2ae8b9bf75 | |||
| 6839258111 | |||
| 8752897bc3 | |||
| fadd19d847 | |||
| eec2facab1 | |||
| 86bc4d54b6 | |||
| b4a36ad465 | |||
| 53df7dd24d | |||
| aa4e116e01 | |||
| 9b22ca3cd2 | |||
| 32f86da98d | |||
| 9f7e30820b | |||
| efefd549a2 | |||
| 600b9224b3 | |||
| 2b9ec0336d | |||
| b6a7188fb5 | |||
| 6292ef6bfe | |||
| 8874ee112c | |||
| 142529ad69 | |||
| f6f6538bd6 | |||
| a139257967 | |||
| ca1d44a53d | |||
| fd72779f00 | |||
| fbb5632896 | |||
| c812b723dc | |||
| c8b12d9496 | |||
| 353233672a | |||
| 59ef54974d | |||
| 9c65d36101 | |||
| 5481f35727 | |||
| 7ecb7f89e6 | |||
| d611bad03b | |||
| 328efce428 | |||
| 313f250273 | |||
| ae4620d7d6 | |||
| ec105aadf5 | |||
| 024b02324e | |||
| b864918686 | |||
| 925e61e40c | |||
| 8ead25eaa3 | |||
| 84556c0672 | |||
| 1ba090b914 | |||
| c65147678a | |||
| 70714dd7f7 | |||
| d360d59b0b | |||
| f454dd593c | |||
| 6945329581 | |||
| 0d222e8ac0 | |||
| dd84da15b0 | |||
| 8a3468658b | |||
| 72d55e485a | |||
| 0bd571d068 | |||
| 0eea289b89 | |||
| 9dd9fd9176 | |||
| e7787f4c3f | |||
| 8c9edd5ea9 | |||
| bb0e80ba16 | |||
| 7edafe6b35 | |||
| a90ca1ff22 | |||
| 2a808f9b58 | |||
| cd453bc6fa | |||
| 771d10ac6b | |||
| 5f49c25952 | |||
| 804fccf650 | |||
| 864d022f45 | |||
| b27a549ef8 | |||
| bf2561f937 | |||
| fa2b13864a | |||
| 7ce16c5b2d | |||
| f3c8438bd8 | |||
| 64076c6cf9 | |||
| 28966c8397 | |||
| 8bc7e7c281 | |||
| 404410b8a2 | |||
| 1aa9b29eb5 | |||
| 033cb2e038 | |||
| d3b068cbad | |||
| 55a1a21f08 | |||
| 360d6d0ee1 | |||
| f090f30e7e | |||
| 224edafabd | |||
| 809965f693 | |||
| 5f236c577f | |||
| f7f55024ab | |||
| 1db7a9b07c | |||
| c62aed4e0c | |||
| df6b7d0d21 | |||
| 5cb4a2fe5a | |||
| b41d801cab | |||
| d4d74dd8f8 | |||
| 9f648803f9 | |||
| b6239bd53c | |||
| 99f03221c9 | |||
| 78563ef09e | |||
| c0e19454e3 | |||
| d595e4fd83 | |||
| f73285db3e | |||
| cbe17409bb | |||
| e302b37b6a | |||
| 5866c4340a | |||
| 9c0d17c79c | |||
| 37c78bf6b1 | |||
| 4de42be688 | |||
| 8753fe3980 | |||
| 5724e65d8e | |||
| 1febb3ef91 | |||
| 10867d1246 | |||
| 0b0b8a96ff | |||
| 947a47943b | |||
| d3b12561b3 | |||
| 2228da3eb9 | |||
| d57c376b21 | |||
| 3f6347b6c9 | |||
| 189a04b94b | |||
| 6efa8743ff | |||
| 42a7b6e8ee | |||
| b829c6a06f | |||
| 66f68093f0 | |||
| bb0713b686 | |||
| 0856fdc146 | |||
| 45890c71a2 | |||
| 3f6021bcd1 | |||
| 76c34e29bb | |||
| e3be2981ff | |||
| 03c434074a | |||
| aeffd942ec | |||
| 1a72a4e17b | |||
| bbdbbe1081 | |||
| 668fbe1827 | |||
| 58e1a0212d | |||
| 39805d080e | |||
| a82726a991 | |||
| a0521d1fdf | |||
| 8684b2c050 | |||
| d7283aa552 | |||
| f422208399 | |||
| d0fca495cb | |||
| 0bddf30de9 | |||
| 748ec818ac | |||
| 80530f0006 | |||
| 68f7f2b301 | |||
| 5672b5cfcc | |||
| f31207583e | |||
| 56b790da74 | |||
| b2d74abf2f | |||
| ee8223f0a9 | |||
| c4e5bde5bf | |||
| 4ca7c1a8fa | |||
| eabbeffd09 | |||
| 1e78825b0b | |||
| 3ab0aacabf | |||
| 1407a1d5b4 | |||
| 56d22104ad | |||
| d7127562d7 | |||
| 9a1db7e664 | |||
| 58938dbd4f | |||
| ad38d9698a | |||
| 7c245acaaf | |||
| bbc995e2c9 | |||
| 94cd9590b5 | |||
| f5a1a7d952 | |||
| 3eb8075913 | |||
| e498271420 | |||
| dbb14e0df4 | |||
| e32c534b89 | |||
| b044764310 | |||
| 68a277143a | |||
| d8cb49e892 | |||
| 5d47bb3c56 | |||
| 6d77a0a557 | |||
| 06753c7748 | |||
| 894b8edc2c | |||
| 743c22d980 | |||
| ae795df530 | |||
| 33f8ce2759 | |||
| 704b3dbb29 | |||
| 58fb7c4fcb | |||
| c296eb0e43 | |||
| 55bbc301ef | |||
| 30bc4a06f2 | |||
| 7ea9aeb174 | |||
| b4f397ed6a | |||
| 8c56ecbd04 | |||
| e62002e7fc | |||
| 4d7d61dae7 | |||
| a8c79fdd46 | |||
| 5262350b40 | |||
| 27928480d5 | |||
| 274da99787 | |||
| 5d0343c480 | |||
| 4a9cd02fbc | |||
| 3796fdc966 | |||
| ae71a92ab7 | |||
| d4849a2a79 | |||
| bf498a5d18 | |||
| 1770e1d815 | |||
| 6967f99626 | |||
| cff46137b9 | |||
| e98a19eb3f | |||
| 0f72fe3511 | |||
| 94313173f0 | |||
| b46189d05f | |||
| e4f919e58f | |||
| c0385ccdfa | |||
| 6f8c5a0e76 | |||
| da6eca78f0 | |||
| 4eb0863f3a | |||
| 32a54c5b71 | |||
| a6466e80e0 | |||
| 4f03acab0c | |||
| b5b28b9986 | |||
| 711cb0a05c | |||
| ea6475fa1e | |||
| 6d74805a65 | |||
| 5d1e15f308 | |||
| 6a2ed331fa | |||
| 762e5ad0ff | |||
| 9a61d870d6 | |||
| 9354d9d0c2 | |||
| d20f62b11b | |||
| 9093631f8b | |||
| 175aca596e | |||
| e8fffe35d2 | |||
| 99ba9eb235 | |||
| 003c608cc5 | |||
| c4f38cf1b2 | |||
| 60cd7fd5cc | |||
| 5f6729b737 | |||
| 5198533242 | |||
| 814cb99105 | |||
| ce78d1999e | |||
| 7f5876c079 | |||
| 34c41cd527 | |||
| 3d84c611ae | |||
| 5e381e17ea | |||
| 63c99282de | |||
| 2f4dc6e3e4 | |||
| a0ec5ed9dd | |||
| a4a509f2de | |||
| edaac3eecd | |||
| 2f1cb3eace | |||
| 1158ce61fa | |||
| 5c2c002f3f | |||
| 3fa61c01b2 | |||
| f61c700092 | |||
| fd5b3813d4 | |||
| a2ba9c4999 | |||
| 9e2696a395 | |||
| 8bc676e2d0 | |||
| 4f29cf6b7a | |||
| 6e3a6b986a | |||
| fd6fb944ad | |||
| 0be5693779 | |||
| 1062e2c6dd | |||
| 39bd882a27 | |||
| 85f28d017d | |||
| f776ea7133 | |||
| d8a2ac75a8 | |||
| b730815842 | |||
| 3ba5c08c13 | |||
| c69ebd8898 | |||
| e8db3cff77 | |||
| e2c573b1eb | |||
| 97990b2877 | |||
| 80ad39e877 | |||
| 6635113f0b | |||
| aad1b71782 | |||
| 73d101c55f | |||
| 23b3fc62cb | |||
| 7b1333c9b8 | |||
| e80717f63d | |||
| 6199ab596f | |||
| 01b946926f | |||
| 64908ae642 | |||
| bbe6931906 | |||
| 2c4775f357 | |||
| 5743f263b6 |
@@ -0,0 +1,34 @@
|
||||
---
|
||||
name: constrained-tests
|
||||
description: Slow-CI simulation — run unit tests on saturated CPU to reproduce CI-style flakiness locally. Suggest when new/reworked suite lean heavy on awaits (deferFulfillment, waitForConfirmation, TestClock, timeouts) or test fail only on CI. Not for every change.
|
||||
---
|
||||
|
||||
# Constrained test runs
|
||||
|
||||
CI runners shared + slow. Background tasks starve, awaits stretch, scheduler races flake there, pass locally. `--constrained` saturate CPU with hog tasks — same conditions, local.
|
||||
|
||||
## When
|
||||
|
||||
- PR add/rework suite heavy on timing-sensitive async: `deferFulfillment`, `waitForConfirmation`, `TestClock`, `transitionValues`, timeouts.
|
||||
- Test fail on CI, pass locally.
|
||||
- Not routine changes, not sync suites — slow, no gain.
|
||||
|
||||
## How
|
||||
|
||||
Full unit test workflow (what CI run):
|
||||
|
||||
```bash
|
||||
swift run tools ci unit-tests --constrained
|
||||
```
|
||||
|
||||
One suite, iterate on new tests (prefer while developing):
|
||||
|
||||
```bash
|
||||
swift run tools ci run-tests --scheme UnitTests --test-name MyNewTests --constrained
|
||||
```
|
||||
|
||||
Hog count automatic (2× cores). Suite survive ~10 constrained iterations → good shape.
|
||||
|
||||
## Failures mean
|
||||
|
||||
Failure under constraint = real bug in test (sometimes code under test): assertion race async work, transient state observation missed, timeout too tight. Fix synchronisation, no blind timeout bump. Helpers in `UnitTests/Sources/TestUtilities/` (`deferFulfillment`, `deferFailure`, `waitForConfirmation`). Wait on durable state, not transient.
|
||||
@@ -0,0 +1,99 @@
|
||||
---
|
||||
name: periphery-cleanup
|
||||
description: Dead-code sweep with Periphery — scan the Pro-configured project, delete unused code, guard false positives (keep-alive handles, future-use code), run unit tests, purge scan cache. Use when user want "clean up dead code", "run periphery", "remove unused code".
|
||||
---
|
||||
|
||||
# Periphery cleanup
|
||||
|
||||
Periphery = static analysis, find unused code. Scan build ALL schemes — slow (cold ~30-60 min). Maintenance thing, run rare.
|
||||
|
||||
## Scan — always on the Pro variant
|
||||
|
||||
Scan run on the Pro-configured project so every source get analysed (plain config leave hook implementations + their call sites out, flood report with false "unused"):
|
||||
|
||||
```bash
|
||||
git submodule update --init --recursive # once, if submodules missing
|
||||
swift run pipeline configure-element-pro
|
||||
periphery scan --relative-results --quiet > periphery-report.txt
|
||||
```
|
||||
|
||||
Config live in `.periphery.yml` — schemes already cover every target, don't narrow. Two deliberate settings there:
|
||||
- `retain_unused_protocol_func_params: true` — protocol signatures are contracts (hooks, delegates); params unused in every conformance stay. NEVER annotate protocol function parameters, config already handle them.
|
||||
- `index_exclude: compound-ios/**` — Compound excluded: its Inspector app + package tests live outside this project's schemes, so their usage invisible → findings there unreliable (e.g. making things internal break the Inspector). Never act on Compound code from this scan.
|
||||
|
||||
Report line format: `path:line:col: warning: <kind> '<name>'`. Build fail → fix build first, scan need compiling project.
|
||||
|
||||
## Comment hygiene — strip, scan, restore
|
||||
|
||||
Every run: existing `periphery:ignore` comments hide drift — code change, comment stay, nobody notice it useless. So:
|
||||
|
||||
1. **Strip + remember.** Before the scan, remove every `periphery:ignore` comment (both spellings: `periphery:ignore` and `periphery: ignore`) and stash them: `git diff > /tmp/periphery-comments.patch` right after stripping, or just rely on `git diff` against HEAD to recall what was where.
|
||||
2. **Scan.** The report now show ground truth: every declaration that genuinely need protection re-flag.
|
||||
3. **Restore only what re-flag.** For each finding that match the false-positive table, put the comment back (same reason strings). Findings that DON'T re-flag = comments that were stale → stay deleted. Anything newly flagged that isn't a false positive = real dead code → delete it.
|
||||
|
||||
Result: comment set always minimal, always true. The clutter never accumulate.
|
||||
|
||||
## Triage — kind → action
|
||||
|
||||
| Warning | Action |
|
||||
|---|---|
|
||||
| Unused function / property / enum / struct / init | Check false-positive table FIRST. True dead → delete whole declaration + helpers/extensions only it used |
|
||||
| Assign-only property | DANGER ZONE. Prime keep-alive suspect — read table below before touch |
|
||||
| Unused parameter | Protocol params never appear (config retain them). ObjC selector / system callback → `ignore:parameters <name> - <reason>`. Free signature → remove param + fix call sites |
|
||||
| Redundant protocol conformance | `TestablePreview` → SKIP, always (see below). Others: verify nothing need conformance (generics, tests, mocks), then remove conformance only, keep type |
|
||||
| Redundant public accessibility | Drop `public`, make internal — EXCEPT member that satisfy a public protocol in a public type (e.g. `previews`), Swift refuse internal there; skip or internalise whole type |
|
||||
| Superfluous ignore comment | Declaration referenced now — comment dead, code alive. Remove comment ONLY, never declaration |
|
||||
|
||||
Never touch `Generated/` directories, never edit `Localizable.strings`. Delete bottom-up per file — line numbers stay valid.
|
||||
|
||||
## False positives — mark, no delete
|
||||
|
||||
Stored-never-read variable often alive ON PURPOSE: keep task / SDK object / coordinator alive past declaration scope. Delete = app break silent (observation stop, flow deallocate, rust handle drop). Mark instead: `// periphery:ignore - <reason>` line above declaration (NEVER `periphery:ignore:all` — whole files that shouldn't be reported, like hand-written mocks, belong in `report_exclude` in `.periphery.yml` instead). Comment go ABOVE any doc comment, never between doc and declaration. Reuse existing reasons from codebase:
|
||||
|
||||
| Pattern | How recognise | Reason string |
|
||||
|---|---|---|
|
||||
| Rust SDK handle | `TaskHandle`, observation token from SDK, stored after `observe`/`subscribe` call | `required for instance retention in the rust codebase` |
|
||||
| Keep-alive reference | child flow coordinator, service stored so updates keep flowing | `retaining purpose` or `used to avoid deallocation` or `keep alive to keep receiving updates.` |
|
||||
| Cancellable task handle | `@CancellableTask` property, `Task` stored so reassign/nil cancel previous | `auto cancels when reassigned` |
|
||||
| SDK enum exhaustiveness | unused `init` switching over SDK enum | `Unused, but added to detect new cases when updating the SDK.` |
|
||||
| MVVM-C architecture | empty `ViewModelAction` enum from screen template, unused VM protocol — NEVER delete VM protocols, convention keep them | `required for the architecture` (keep the mark even if a superfluous-comment warning appear — it document intent) |
|
||||
| Property wrapper internals | `@propertyWrapper`, `@dynamicMemberLookup` subscript | `property wrappers generate false positives` / `subscript are seen as false positives` |
|
||||
| ObjC selector parameter | parameter only touched by runtime (`displayLink`, `sender` etc.) | `ignore:parameters <name> - required for objc selector` |
|
||||
| Underscored SwiftUI protocol | `_body` from `TextFieldStyle` etc. — called by SwiftUI, members inside resolve transitively | `called by SwiftUI via the TextFieldStyle protocol` |
|
||||
| SDK delegate requirement | method required by rust SDK delegate protocol (e.g. `didRefreshTokens`) | `required by the SDK's delegate protocol` |
|
||||
| Synthesized conformance | field only read via synthesized Hashable/Equatable/Codable (cache keys, diffing models) | `used via the synthesized Hashable conformance` |
|
||||
| Encoded/decoded schema field | Codable field parsed or serialized but not consumed yet | `documents the schema, parsed but not consumed yet` / `part of the encoded payload` |
|
||||
| Release-only code | compiled out in Debug scan (`#if !DEBUG` paths, nightly checks) | `only used in release builds` |
|
||||
| `TestablePreview` conformance | flagged "Redundant protocol conformance" on every preview | NO marker, NO removal — Sourcery read conformance, generate snapshot + a11y tests from it. Remove = tests silently vanish. Skip finding, bulk noise |
|
||||
|
||||
**Unsure if keep-alive?** Property type Task / AnyCancellable / TaskHandle / coordinator / SDK proxy, assigned inside async or stream setup → smell like keep-alive. ASK USER before delete. Show declaration, where assigned, your read on it.
|
||||
|
||||
## Future-use code
|
||||
|
||||
Unused but look intentional — API pair completeness, feature half-landed, "team will need soon". No silent delete, no silent keep. Present to user: what, where, opinion keep-or-delete. User say keep → mark `// periphery:ignore - might be useful to have`.
|
||||
|
||||
## Mock cascade after protocol deletions
|
||||
|
||||
Delete protocol member → Sourcery regenerate mock WITHOUT its `fooReturnValue` / `fooClosure` helpers → hand-written mock `Configuration` inits and test set-up lines still assigning those helpers break the build. Those lines are inert setup for API nothing call — more dead code, not evidence of use. After protocol deletions: grep non-Generated `Mocks/` + `UnitTests/` for `<name>ReturnValue`, `<name>Closure`, direct assignments to deleted members — delete them too. Compiler walk you to the stragglers; that expected, not a false positive.
|
||||
|
||||
Careful with same-name members: one mock file often configure SEVERAL protocols (proxy-level `inviter` vs info-level `inviter`). Strip only lines whose target member actually deleted — the wrong one compile fine (member still exist) but silently un-configure previews; snapshot tests catch it, so run them before calling done.
|
||||
|
||||
## Verify — on the PLAIN project
|
||||
|
||||
Restore the plain configuration BEFORE running tests — snapshots are recorded against plain Element X; Pro branding fail ~8 preview tests falsely:
|
||||
|
||||
```bash
|
||||
git restore project.yml ElementX.xcodeproj/project.pbxproj "ElementX/Resources/AppIcon.icon/Assets/AppIcon.png"
|
||||
xcodegen
|
||||
swift run tools ci unit-tests
|
||||
```
|
||||
|
||||
Sourcery regenerate mocks on build — deleted protocol members clean themselves. All tests pass before call done. Note: the CI helper pipe through `xcbeautify` — if not installed the exit code lie even when tests pass; check the `.xcresult` summary.
|
||||
|
||||
## Purge cache — always
|
||||
|
||||
Periphery DerivedData cache eat tens of GBs. Scan run rare → cache worthless between runs. Last step, no skip:
|
||||
|
||||
```bash
|
||||
rm -rf ~/Library/Caches/com.github.peripheryapp
|
||||
```
|
||||
@@ -1,5 +1,5 @@
|
||||
UITests/Sources/__Snapshots__/** filter=lfs diff=lfs merge=lfs -text
|
||||
DevelopmentAssets/Media/** filter=lfs diff=lfs merge=lfs -text
|
||||
Components/DevelopmentAssets/Media/** filter=lfs diff=lfs merge=lfs -text
|
||||
UnitTests/__Snapshots__/** filter=lfs diff=lfs merge=lfs -text
|
||||
PreviewTests/Sources/__Snapshots__/** filter=lfs diff=lfs merge=lfs -text
|
||||
compound-ios/Tests/CompoundTests/__Snapshots__/** filter=lfs diff=lfs merge=lfs -text
|
||||
|
||||
@@ -6,7 +6,7 @@ git lfs post-checkout "$@"
|
||||
export PATH="$PATH:/opt/homebrew/bin"
|
||||
|
||||
# ignores updates of 'Secrets.swift' to avoid pushing sensitive data by mistake
|
||||
git update-index --assume-unchanged Secrets/Secrets.swift
|
||||
git update-index --assume-unchanged Components/Secrets/Secrets.swift
|
||||
|
||||
LOCAL_SCRIPT_PATH="$HOME/.local/elementx_local_dev/post-checkout"
|
||||
if [ -x "$LOCAL_SCRIPT_PATH" ]; then
|
||||
|
||||
@@ -28,6 +28,10 @@ changelog:
|
||||
labels:
|
||||
- pr-wip
|
||||
|
||||
- title: 💼 Element Pro
|
||||
labels:
|
||||
- pr-element-pro
|
||||
|
||||
- title: Others
|
||||
labels:
|
||||
- pr-misc
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
if: github.repository == 'element-hq/element-x-ios'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
name: Danger CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [labeled, synchronize, opened, reopened]
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Danger
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
|
||||
permissions:
|
||||
contents: read # HealthChat: this fork is INTERNAL, so a metadata-only token 404s on checkout. Upstream is public, hence permissions: {} there.
|
||||
issues: read # HealthChat: Danger reads the PR via the issues API (a PR is an issue there); pull-requests alone 403s on GET /issues/{n}.
|
||||
pull-requests: write # HealthChat: Danger posts its report comment and inline SwiftLint review comments (Dangerfile.swift:5 sets inline: true) with GITHUB_TOKEN.
|
||||
|
||||
concurrency:
|
||||
# Only allow a single run of this workflow on each branch, automatically cancelling older runs.
|
||||
group: ${{ format('danger-ci-{0}', github.ref) }}
|
||||
cancel-in-progress: true
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Danger
|
||||
uses: danger/swift@434d7c25f3b02d490a340b23f5e78dd15a5670bc # 3.22.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
cancel-in-progress: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
@@ -47,7 +47,9 @@ jobs:
|
||||
if: failure()
|
||||
with:
|
||||
name: Results
|
||||
path: test_output/IntegrationTests.xcresult.zip
|
||||
path: |
|
||||
test_output/IntegrationTests.xcresult.zip
|
||||
test_output/console*
|
||||
retention-days: 7
|
||||
if-no-files-found: ignore
|
||||
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
name: PR Checks
|
||||
|
||||
on:
|
||||
# Privilege escalation necessary to comment on pull requests from forks.
|
||||
# 🚨 We must not check out or execute any code here, and be careful around use of user-controlled inputs.
|
||||
pull_request_target: # zizmor: ignore[dangerous-triggers]
|
||||
types: [opened, reopened, edited, synchronize, labeled, unlabeled]
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
pr-checks:
|
||||
name: PR Checks
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
|
||||
concurrency:
|
||||
# Only allow a single run of this workflow on each branch, automatically cancelling older runs.
|
||||
group: ${{ format('pr-checks-{0}', github.ref) }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- name: Check the pull request
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
with:
|
||||
script: |
|
||||
const pr = context.payload.pull_request;
|
||||
const body = pr.body ?? "";
|
||||
|
||||
const files = await github.paginate(github.rest.pulls.listFiles, {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: pr.number
|
||||
});
|
||||
const paths = files.map(file => file.filename.toLowerCase());
|
||||
|
||||
const warnings = [];
|
||||
const failures = [];
|
||||
|
||||
if (pr.additions > 1000) {
|
||||
warnings.push("This pull request seems relatively large. Please consider splitting it into multiple smaller ones.");
|
||||
}
|
||||
|
||||
if (!body) {
|
||||
warnings.push("Please provide a description for this PR.");
|
||||
}
|
||||
|
||||
if (paths.some(path => path.includes("/view")) && !body.includes("user-attachments")) {
|
||||
warnings.push("You seem to have made changes to views. Please consider adding screenshots.");
|
||||
}
|
||||
|
||||
if (paths.some(path => path.includes(".xcassets") && path.endsWith(".png"))) {
|
||||
warnings.push("You seem to have made changes to some resource images. Please consider using an SVG or PDF.");
|
||||
}
|
||||
|
||||
if (pr.title.endsWith("…") || /^(Fixes|Fix) #\d+/.test(pr.title) || /^\w+\(\w+\):/.test(pr.title)) {
|
||||
failures.push("Please provide a complete title that can be used as a changelog entry.");
|
||||
}
|
||||
|
||||
if (pr.labels.filter(label => label.name.startsWith("pr-")).length !== 1) {
|
||||
failures.push("Please add a `pr-` label to categorise the changelog entry.");
|
||||
}
|
||||
|
||||
warnings.forEach(warning => core.warning(warning));
|
||||
failures.forEach(failure => core.error(failure));
|
||||
|
||||
// Keep a single comment up to date rather than adding a new one on every run.
|
||||
const marker = "<!-- pr-checks -->";
|
||||
const comments = await github.paginate(github.rest.issues.listComments, {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pr.number
|
||||
});
|
||||
const existing = comments.find(comment => comment.body.includes(marker));
|
||||
|
||||
if (warnings.length || failures.length) {
|
||||
const lines = [...failures.map(failure => `- ❌ ${failure}`),
|
||||
...warnings.map(warning => `- ⚠️ ${warning}`)];
|
||||
const commentBody = `${marker}\n### PR Checks\n\n${lines.join("\n")}`;
|
||||
|
||||
if (existing) {
|
||||
await github.rest.issues.updateComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
comment_id: existing.id,
|
||||
body: commentBody
|
||||
});
|
||||
} else {
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pr.number,
|
||||
body: commentBody
|
||||
});
|
||||
}
|
||||
} else if (existing) {
|
||||
await github.rest.issues.deleteComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
comment_id: existing.id
|
||||
});
|
||||
}
|
||||
|
||||
if (failures.length) {
|
||||
core.setFailed(`${failures.length} check(s) failed, see the comment on the pull request.`);
|
||||
}
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
ref: ${{ github.head_ref }}
|
||||
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
|
||||
@@ -13,17 +13,21 @@ jobs:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/stale@eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899 # v10.3.0
|
||||
- uses: actions/stale@4391f3da665fdf50b6810c1a66712fb9ba21aa93 # v11
|
||||
with:
|
||||
only-labels: "X-Needs-Info"
|
||||
labels-to-remove-when-unstale: "X-Needs-Info"
|
||||
|
||||
# Issues
|
||||
only-issue-labels: "X-Needs-Info"
|
||||
days-before-issue-stale: 30
|
||||
days-before-issue-close: 7
|
||||
days-before-pr-stale: 30
|
||||
days-before-pr-close: 7
|
||||
stale-pr-label: "stale"
|
||||
stale-pr-message: "This pull request has seen no activity for the past 30 days and will now be marked as stale. Please update it or leave a comment within the next 7 days to keep it open."
|
||||
close-pr-message: "This pull request is being closed due to inactivity."
|
||||
stale-issue-label: "stale"
|
||||
labels-to-remove-when-unstale: "X-Needs-Info"
|
||||
stale-issue-label: "Stale"
|
||||
stale-issue-message: "This issue has been awaiting further information for the past 30 days so will now be marked as stale. Please provide the requested information within the next 7 days to keep it open."
|
||||
close-issue-message: "This issue is being closed due to inactivity after further information was requested."
|
||||
|
||||
# Pull requests
|
||||
days-before-pr-stale: 30
|
||||
days-before-pr-close: 7
|
||||
stale-pr-label: "Stale"
|
||||
stale-pr-message: "This pull request has seen no activity for the past 30 days and will now be marked as stale. Please update it or leave a comment within the next 7 days to keep it open."
|
||||
close-pr-message: "This pull request is being closed due to inactivity."
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
if: github.repository == 'element-hq/element-x-ios'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
||||
@@ -41,12 +41,27 @@ jobs:
|
||||
- name: Setup environment
|
||||
run: source ci_scripts/ci_common.sh && setup_github_actions_environment
|
||||
|
||||
- name: Restore compilation cache
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
with:
|
||||
path: ~/Library/Developer/Xcode/CompilationCache.noindex
|
||||
key: compilation-cache-unit-tests-enterprise-${{ github.sha }}
|
||||
restore-keys: compilation-cache-unit-tests-enterprise-
|
||||
|
||||
- name: Configure Enterprise
|
||||
run: swift run -q pipeline configure-element-pro
|
||||
|
||||
- name: Run tests
|
||||
run: swift run -q tools ci unit-tests --skip-previews
|
||||
|
||||
- name: Save compilation cache
|
||||
# Only develop populates the cache, all of the other runs simply read from it.
|
||||
if: ${{ !cancelled() && github.event_name == 'push' && github.ref == 'refs/heads/develop' }}
|
||||
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
with:
|
||||
path: ~/Library/Developer/Xcode/CompilationCache.noindex
|
||||
key: compilation-cache-unit-tests-enterprise-${{ github.sha }}
|
||||
|
||||
- name: Archive artifacts
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
# We only care about artefacts if the tests fail
|
||||
|
||||
@@ -71,6 +71,13 @@ jobs:
|
||||
# of which Xcode built a given run.
|
||||
xcodebuild -version
|
||||
|
||||
- name: Restore compilation cache
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
with:
|
||||
path: ~/Library/Developer/Xcode/CompilationCache.noindex
|
||||
key: compilation-cache-unit-tests-${{ github.sha }}
|
||||
restore-keys: compilation-cache-unit-tests-
|
||||
|
||||
- name: Run tests
|
||||
# HealthChat: previews are skipped. PreviewTests renders a snapshot for every preview in the
|
||||
# app and was the entire reason this job could not fit in an hour — it never once finished,
|
||||
@@ -86,6 +93,14 @@ jobs:
|
||||
CI_SKIP_TESTS: VoiceMessageCacheTests
|
||||
run: swift run -q tools ci unit-tests --skip-previews
|
||||
|
||||
- name: Save compilation cache
|
||||
# Only develop populates the cache, all of the other runs simply read from it.
|
||||
if: ${{ !cancelled() && github.event_name == 'push' && github.ref == 'refs/heads/develop' }}
|
||||
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
with:
|
||||
path: ~/Library/Developer/Xcode/CompilationCache.noindex
|
||||
key: compilation-cache-unit-tests-${{ github.sha }}
|
||||
|
||||
- name: Archive artifacts
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
# We only care about artefacts if the tests fail
|
||||
|
||||
@@ -18,9 +18,9 @@ jobs:
|
||||
actions: read # HealthChat: upload-sarif additionally needs this on private/internal repos; public upstream does not.
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Run zizmor 🌈
|
||||
uses: zizmorcore/zizmor-action@192e21d79ab29983730a13d1382995c2307fbcaa # v0.5.7
|
||||
uses: zizmorcore/zizmor-action@70fb788f84895a7701f5643d103d587e460b5c99 # v0.6.3
|
||||
|
||||
@@ -47,8 +47,8 @@ build
|
||||
test_output
|
||||
|
||||
# Only commit Pkl packages (there may be other caches in here).
|
||||
Secrets/vendor/*
|
||||
!Secrets/vendor/package-2
|
||||
Components/Secrets/vendor/*
|
||||
!Components/Secrets/vendor/package-2
|
||||
|
||||
# fastlane release outputs
|
||||
out/
|
||||
|
||||
@@ -1,19 +1,31 @@
|
||||
project: ElementX.xcodeproj
|
||||
# Periphery scans all targets built by these schemes. The ElementX scheme also
|
||||
# builds NSE, ShareExtension and MatrixRustSDKMocks as dependencies. Always run
|
||||
# the scan with the project configured for the Pro variant so that all of the
|
||||
# sources are analysed (see the periphery-cleanup skill).
|
||||
schemes:
|
||||
- ElementX
|
||||
- UnitTests
|
||||
- PreviewTests
|
||||
- UITests
|
||||
- IntegrationTests
|
||||
targets:
|
||||
- ElementX
|
||||
- NSE
|
||||
- ShareExtension
|
||||
- UnitTests
|
||||
- PreviewTests
|
||||
- UITests
|
||||
- IntegrationTests
|
||||
- AccessibilityTests
|
||||
# Compound is excluded: its Inspector app and package tests aren't part of any
|
||||
# scheme in this project, so usage from them is invisible to the analysis.
|
||||
index_exclude:
|
||||
- "**/*?.build/**/*"
|
||||
- "**/SourcePackages/checkouts/**"
|
||||
- "compound-ios/**"
|
||||
report_exclude:
|
||||
- ElementX/Sources/Mocks/Generated/GeneratedMocks.swift
|
||||
- ElementX/Sources/Mocks/Generated/SDKGeneratedMocks.swift
|
||||
- "**/Generated/**"
|
||||
# Hand-written mocks: configuration surface is deliberately broader than any test uses.
|
||||
- "**/Mocks/**"
|
||||
- "ElementX/Sources/Services/AppLock/LAContextMock.swift"
|
||||
# Pure payload schema, fields exist to be encoded.
|
||||
- "ElementX/Sources/Services/Notification/Manager/APNSPayload.swift"
|
||||
# Backports: everything gated on #available, cleaned up with each OS drop.
|
||||
- "ElementX/Sources/Other/SwiftUI/Backports.swift"
|
||||
retain_swift_ui_previews: true
|
||||
# Protocol signatures are contracts (hooks, delegates) — parameters unused in
|
||||
# every current conformance are still part of the interface's design.
|
||||
retain_unused_protocol_func_params: true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--swiftversion 5.6
|
||||
|
||||
--exclude **/Sources/**/Generated,vendor,**/Package.swift,Secrets/**
|
||||
--exclude **/Sources/**/Generated,vendor,**/Package.swift,Components/Secrets/**,build
|
||||
|
||||
--disable wrapMultiLineStatementBraces
|
||||
--disable hoistPatternLet
|
||||
|
||||
@@ -3,6 +3,7 @@ disabled_rules:
|
||||
- unused_setter_value
|
||||
- redundant_discardable_let
|
||||
- identifier_name
|
||||
- void_function_in_ternary
|
||||
|
||||
opt_in_rules:
|
||||
- force_unwrapping
|
||||
@@ -17,7 +18,7 @@ included:
|
||||
excluded:
|
||||
- "*/Sources/Generated/*"
|
||||
- Tools/Sources # Our command-line tools use a lot of print commands.
|
||||
- Secrets
|
||||
- Components/Secrets
|
||||
- compound-ios/Inspector
|
||||
|
||||
line_length:
|
||||
|
||||
@@ -14,6 +14,9 @@ PRs must follow rules. Prefer Xcode MCP tools over terminal commands.
|
||||
- **SwiftLint** (.swiftlint.yml) + **SwiftFormat** (.swiftformat) enforce style on build. Warnings show in Xcode. Build before **XcodeRefreshCodeIssuesInFile**.
|
||||
- Follow [Swift API Design Guidelines](https://www.swift.org/documentation/api-design-guidelines/) everywhere, Rust SDK wrappers too (`ID` not `Id`, `URL` not `Url`, `configuration` not `config` or `cfg`).
|
||||
- File headers live in `IDETemplateMacros.plist`.
|
||||
- **Import `SwiftUI`, not `UIKit`** — need `UIPasteboard` etc, `SwiftUI` bring it. `SwiftUI` re-export `Foundation` too, so no `import Foundation` beside it.
|
||||
- **Clean Code** (Robert C. Martin) Newspaper order: headline first, detail down. Stepdown rule: caller above callee, calls point down. Tests: test cases first, helpers below. Swift idiom always win on clash.
|
||||
- **Member order in type**: properties (stored + computed, public + private) → `init` → functions. `View` types: properties → `init` → views (`body` first) → functions.
|
||||
|
||||
### Comments
|
||||
|
||||
@@ -52,6 +55,7 @@ PRs must follow rules. Prefer Xcode MCP tools over terminal commands.
|
||||
|
||||
## Pull Request Guidelines
|
||||
|
||||
- New branch from `develop` must not track `develop`.
|
||||
- Sentence-style titles (no conventional commits).
|
||||
- Exactly one `pr-` label (see `.github/release.yml`).
|
||||
- Title = changelog entry — descriptive, no "Fixes #…".
|
||||
@@ -386,7 +390,7 @@ Same pattern for publishers.
|
||||
| `app.yml` | App-level XcodeGen config |
|
||||
| `.swiftlint.yml` | SwiftLint rules |
|
||||
| `.swiftformat` | SwiftFormat rules |
|
||||
| `Dangerfile.swift` | Danger PR checks |
|
||||
| `.github/workflows/pr-checks.yml` | PR metadata checks (title, labels, size, screenshots) |
|
||||
| `Package.swift` | SPM manifest (Tools CLI) |
|
||||
| `localazy.json` | Localazy translation config |
|
||||
| `codecov.yml` | Codecov config |
|
||||
|
||||
@@ -53,6 +53,9 @@ final class AccessibilityTests: XCTestCase {
|
||||
private func performAccessibilityAuditForPreview(named name: String) {
|
||||
// Alows us to log the name of the preview that is being tested
|
||||
XCTContext.runActivity(named: name) { _ in
|
||||
// Previews that focus a text field bring up the system keyboard, which we can't fix.
|
||||
let keyboardFrame = app.keyboards.firstMatch.exists ? app.keyboards.firstMatch.frame : .null
|
||||
|
||||
do {
|
||||
// We have removed `textClipped` and `contrast` for now
|
||||
try app.performAccessibilityAudit(for: [.dynamicType, .elementDetection, .hitRegion, .sufficientElementDescription, .trait]) { issue in
|
||||
@@ -66,6 +69,11 @@ final class AccessibilityTests: XCTestCase {
|
||||
return true
|
||||
}
|
||||
|
||||
// The system keyboard's own elements aren't ours to fix
|
||||
if keyboardFrame.contains(element.frame) {
|
||||
return true
|
||||
}
|
||||
|
||||
// We are fine with elements that only partially support dynamic types
|
||||
guard issue.compactDescription != Self.partiallyUnsupportedDynamicTypeMessage else {
|
||||
return true
|
||||
@@ -98,7 +106,6 @@ final class AccessibilityTests: XCTestCase {
|
||||
|
||||
private static let partiallyUnsupportedDynamicTypeMessage = "Dynamic Type font sizes are partially unsupported"
|
||||
private static let notHumanReadableMessage = "Label not human-readable"
|
||||
private static let elementHasNoDescription = "Element has no description"
|
||||
|
||||
/// Use this array to filter add specific filters to ignore specific issues for certain elements
|
||||
private static let ignoredA11yIdentifiers: [String: [FilterType]] = [
|
||||
@@ -108,11 +115,7 @@ final class AccessibilityTests: XCTestCase {
|
||||
/// Use this array to filter add specific filters to ignore specific tests
|
||||
private static let ignoredA11yTest: [String: [FilterType]] = [
|
||||
// It's an image rendering test doesn't need to have descriptions
|
||||
"RoomAvatarImage_Previews-0": [.auditType(.sufficientElementDescription)],
|
||||
// Empty container slots of the principal search toolbar, system chrome with nothing to describe
|
||||
"SearchScreen_Previews-Empty": [.emptyContainerDescription],
|
||||
"SearchScreen_Previews-No results": [.emptyContainerDescription],
|
||||
"SearchScreen_Previews-Loaded": [.emptyContainerDescription]
|
||||
"RoomAvatarImage_Previews-0": [.auditType(.sufficientElementDescription)]
|
||||
]
|
||||
}
|
||||
|
||||
@@ -121,8 +124,6 @@ private enum FilterType {
|
||||
case compactDescription(String)
|
||||
/// Filter by the type of the issue
|
||||
case auditType(XCUIAccessibilityAuditType)
|
||||
/// Filter "no description" issues on empty container elements (label + identifier empty), e.g. system toolbar slots
|
||||
case emptyContainerDescription
|
||||
}
|
||||
|
||||
private extension Array where Element == FilterType {
|
||||
@@ -134,14 +135,6 @@ private extension Array where Element == FilterType {
|
||||
return true
|
||||
case .compactDescription(issue.compactDescription):
|
||||
return true
|
||||
case .emptyContainerDescription:
|
||||
if issue.auditType == .sufficientElementDescription,
|
||||
let element = issue.element,
|
||||
element.elementType == .other,
|
||||
element.label.isEmpty,
|
||||
element.identifier.isEmpty {
|
||||
return true
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
|
||||
extension AccessibilityTests {
|
||||
|
||||
func testActiveCallTimelineItemView() async throws {
|
||||
try await performAccessibilityAudit(named: "ActiveCallTimelineItemView_Previews")
|
||||
}
|
||||
|
||||
func testAdvancedSettingsScreen() async throws {
|
||||
try await performAccessibilityAudit(named: "AdvancedSettingsScreen_Previews")
|
||||
}
|
||||
@@ -55,6 +59,10 @@ extension AccessibilityTests {
|
||||
try await performAccessibilityAudit(named: "AvatarHeaderView_Previews")
|
||||
}
|
||||
|
||||
func testAvatarSettingsButtonLabel() async throws {
|
||||
try await performAccessibilityAudit(named: "AvatarSettingsButtonLabel_Previews")
|
||||
}
|
||||
|
||||
func testBadgeLabel() async throws {
|
||||
try await performAccessibilityAudit(named: "BadgeLabel_Previews")
|
||||
}
|
||||
@@ -183,6 +191,26 @@ extension AccessibilityTests {
|
||||
try await performAccessibilityAudit(named: "FullscreenDialog_Previews")
|
||||
}
|
||||
|
||||
func testGalleryRoomTimelineView() async throws {
|
||||
try await performAccessibilityAudit(named: "GalleryRoomTimelineView_Previews")
|
||||
}
|
||||
|
||||
func testHealthChatExtendedProfileSection() async throws {
|
||||
try await performAccessibilityAudit(named: "HealthChatExtendedProfileSection_Previews")
|
||||
}
|
||||
|
||||
func testHealthChatInviteMemberScreen() async throws {
|
||||
try await performAccessibilityAudit(named: "HealthChatInviteMemberScreen_Previews")
|
||||
}
|
||||
|
||||
func testHealthChatMemberDirectoryScreen() async throws {
|
||||
try await performAccessibilityAudit(named: "HealthChatMemberDirectoryScreen_Previews")
|
||||
}
|
||||
|
||||
func testHealthChatProfileEditScreen() async throws {
|
||||
try await performAccessibilityAudit(named: "HealthChatProfileEditScreen_Previews")
|
||||
}
|
||||
|
||||
func testHighlightedTimelineItemModifier() async throws {
|
||||
try await performAccessibilityAudit(named: "HighlightedTimelineItemModifier_Previews")
|
||||
}
|
||||
@@ -479,6 +507,10 @@ extension AccessibilityTests {
|
||||
try await performAccessibilityAudit(named: "ReadReceiptsSummaryView_Previews")
|
||||
}
|
||||
|
||||
func testRedactConfirmationView() async throws {
|
||||
try await performAccessibilityAudit(named: "RedactConfirmationView_Previews")
|
||||
}
|
||||
|
||||
func testRedactedRoomTimelineView() async throws {
|
||||
try await performAccessibilityAudit(named: "RedactedRoomTimelineView_Previews")
|
||||
}
|
||||
@@ -647,10 +679,6 @@ extension AccessibilityTests {
|
||||
try await performAccessibilityAudit(named: "SeparatorRoomTimelineView_Previews")
|
||||
}
|
||||
|
||||
func testServerConfirmationScreen() async throws {
|
||||
try await performAccessibilityAudit(named: "ServerConfirmationScreen_Previews")
|
||||
}
|
||||
|
||||
func testServerSelection() async throws {
|
||||
try await performAccessibilityAudit(named: "ServerSelection_Previews")
|
||||
}
|
||||
@@ -663,6 +691,14 @@ extension AccessibilityTests {
|
||||
try await performAccessibilityAudit(named: "SessionVerification_Previews")
|
||||
}
|
||||
|
||||
func testSettingsScreenUserStatusPickerView() async throws {
|
||||
try await performAccessibilityAudit(named: "SettingsScreenUserStatusPickerView_Previews")
|
||||
}
|
||||
|
||||
func testSettingsScreenUserStatusRow() async throws {
|
||||
try await performAccessibilityAudit(named: "SettingsScreenUserStatusRow_Previews")
|
||||
}
|
||||
|
||||
func testSettingsScreen() async throws {
|
||||
try await performAccessibilityAudit(named: "SettingsScreen_Previews")
|
||||
}
|
||||
@@ -739,10 +775,6 @@ extension AccessibilityTests {
|
||||
try await performAccessibilityAudit(named: "SwipeRightAction_Previews")
|
||||
}
|
||||
|
||||
func testSwipeToReplyView() async throws {
|
||||
try await performAccessibilityAudit(named: "SwipeToReplyView_Previews")
|
||||
}
|
||||
|
||||
func testTextRoomTimelineView() async throws {
|
||||
try await performAccessibilityAudit(named: "TextRoomTimelineView_Previews")
|
||||
}
|
||||
|
||||
@@ -9,9 +9,6 @@
|
||||
}
|
||||
],
|
||||
"defaultOptions" : {
|
||||
"addressSanitizer" : {
|
||||
"enabled" : true
|
||||
},
|
||||
"codeCoverage" : {
|
||||
"targets" : [
|
||||
{
|
||||
@@ -21,7 +18,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"defaultTestExecutionTimeAllowance" : 120,
|
||||
"defaultTestExecutionTimeAllowance" : 240,
|
||||
"environmentVariableEntries" : [
|
||||
|
||||
],
|
||||
@@ -36,8 +33,7 @@
|
||||
"identifier" : "C0C687DE1D270F9895FEE186",
|
||||
"name" : "AccessibilityTests"
|
||||
},
|
||||
"testTimeoutsEnabled" : true,
|
||||
"undefinedBehaviorSanitizerEnabled" : true
|
||||
"testTimeoutsEnabled" : true
|
||||
},
|
||||
"testTargets" : [
|
||||
{
|
||||
|
||||
@@ -1,3 +1,376 @@
|
||||
## Changes in 26.09.0 (2026-09-08)
|
||||
|
||||
### What's Changed
|
||||
|
||||
✨ Features
|
||||
* Autoplay the next voice message if it is the next timeline item. by @Velin92 in https://github.com/element-hq/element-x-ios/pull/6089
|
||||
* Add a Mentions room list filter by @ara4n in https://github.com/element-hq/element-x-ios/pull/5885
|
||||
* Add support for `<details>` and `<summary>` tags by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6077
|
||||
* Redaction reason by @Velin92 in https://github.com/element-hq/element-x-ios/pull/6098
|
||||
|
||||
🙌 Improvements
|
||||
* Advance the join room screen if we're autojoined by the server by @ara4n in https://github.com/element-hq/element-x-ios/pull/5875
|
||||
* Updates to Notification Settings by @americanrefugee in https://github.com/element-hq/element-x-ios/pull/6075
|
||||
* Use server name from user id function by @Velin92 in https://github.com/element-hq/element-x-ios/pull/6082
|
||||
|
||||
🐛 Bugfixes
|
||||
* Fix crash when activating incompatible room filters by @sergeyospanov in https://github.com/element-hq/element-x-ios/pull/6087
|
||||
* hide the forward action on live location shares by @thepearl in https://github.com/element-hq/element-x-ios/pull/6091
|
||||
* Fix photo picker selection tint on iOS 26 by @thepearl in https://github.com/element-hq/element-x-ios/pull/6095
|
||||
* Fix the tab rail flickering on narrow iPad windows by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6107
|
||||
* Minor quicklook fixes. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/6112
|
||||
* Use disambiguated display name for avatar change events by @Velin92 in https://github.com/element-hq/element-x-ios/pull/6131
|
||||
|
||||
🗣 Translations
|
||||
* Translations update by @RiotRobot in https://github.com/element-hq/element-x-ios/pull/6088
|
||||
* Translations update by @RiotRobot in https://github.com/element-hq/element-x-ios/pull/6111
|
||||
|
||||
🧱 Build
|
||||
* Pin project dependencies to exact versions given we have Renovate. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/6078
|
||||
* Try using Danger with the Node/Docker fix? by @pixlwave in https://github.com/element-hq/element-x-ios/pull/6079
|
||||
* Replace danger-swift with a actions/github-script version by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6080
|
||||
* Bump the calendar version ready for the next release by @RiotRobot in https://github.com/element-hq/element-x-ios/pull/6092
|
||||
|
||||
Others
|
||||
* Use the `ClientFactory` pattern everywhere replacing raw `ClientBuilders`. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/6054
|
||||
* Add tests for the UserSessionStore. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/6065
|
||||
* Update Project Dependencies by @renovate[bot] in https://github.com/element-hq/element-x-ios/pull/6068
|
||||
* Allow copying blocked user id by @Velin92 in https://github.com/element-hq/element-x-ios/pull/6071
|
||||
* Don't focus the user status text field during tests. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/6076
|
||||
* Limit link previews width in the timeline to 300 points. by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6069
|
||||
* Fix UI test snapshots following copy changes and filter reordering by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6100
|
||||
* Feature flag tweaks by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6096
|
||||
* Update dependency siteline/SwiftUI-Introspect to v26.0.2 by @renovate[bot] in https://github.com/element-hq/element-x-ios/pull/6104
|
||||
* Update zizmorcore/zizmor-action action to v0.6.3 by @renovate[bot] in https://github.com/element-hq/element-x-ios/pull/6109
|
||||
* Bump the RustSDK to v26.09.07 by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6110
|
||||
* Update the Enterprise submodule. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/6114
|
||||
* Update the SDK. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/6134
|
||||
|
||||
### New Contributors
|
||||
* @sergeyospanov made their first contribution in https://github.com/element-hq/element-x-ios/pull/6087
|
||||
* @thepearl made their first contribution in https://github.com/element-hq/element-x-ios/pull/6091
|
||||
|
||||
**Full Changelog**: https://github.com/element-hq/element-x-ios/compare/release/26.08.4...release/26.09.0
|
||||
|
||||
## Changes in 26.08.4 (2026-08-25)
|
||||
|
||||
### What's Changed
|
||||
|
||||
✨ Features
|
||||
* Enable the User Status feature on supported homeservers. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/6059
|
||||
|
||||
🐛 Bugfixes
|
||||
* Attributed string builder tweaks by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6055
|
||||
|
||||
🗣 Translations
|
||||
* Translations update by @RiotRobot in https://github.com/element-hq/element-x-ios/pull/6058
|
||||
|
||||
🚧 In development 🚧
|
||||
* More tweaks for User Status. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/6051
|
||||
|
||||
Others
|
||||
* Various tweaks and fixes by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6045
|
||||
* Update dependency element-hq/compound-design-tokens to v10.2.4 by @renovate[bot] in https://github.com/element-hq/element-x-ios/pull/6048
|
||||
* Update the Enterprise submodule by @pixlwave in https://github.com/element-hq/element-x-ios/pull/6053
|
||||
* Fix missing back pagination attempt by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6056
|
||||
* Stop the integration tests from backgrounding the web authentication session by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6060
|
||||
* Preserve the blank lines typed after a list by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6061
|
||||
* Update the Enterprise submodule. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/6063
|
||||
* Fixed one accessibility test and an UI test snapshot by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6064
|
||||
* Update sdk to 26.08.25 by @Velin92 in https://github.com/element-hq/element-x-ios/pull/6067
|
||||
|
||||
|
||||
**Full Changelog**: https://github.com/element-hq/element-x-ios/compare/release/26.08.3...release/26.08.4
|
||||
|
||||
## Changes in 26.08.3 (2026-08-20)
|
||||
|
||||
### What's Changed
|
||||
|
||||
✨ Features
|
||||
* Load MapLibre lazily instead of at every app launch by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6012
|
||||
|
||||
🙌 Improvements
|
||||
* Offer Retry and Remove actions with a reason when tapping a failed message by @ara4n in https://github.com/element-hq/element-x-ios/pull/5988
|
||||
* Update the toolbars in the Chats/Spaces screens. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/6043
|
||||
|
||||
🐛 Bugfixes
|
||||
* Avoid race conditions between the home screen's crash alert and Sentry's `onLastRunStatusDetermined` by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6017
|
||||
* Prevent invalid composer mode crashes by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6018
|
||||
* Delay secondary room summary provider setup by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6038
|
||||
|
||||
🗣 Translations
|
||||
* Translations update by @RiotRobot in https://github.com/element-hq/element-x-ios/pull/6036
|
||||
|
||||
🧱 Build
|
||||
* Re-run XcodeGen. by @RiotRobot in https://github.com/element-hq/element-x-ios/pull/6040
|
||||
|
||||
🚧 In development 🚧
|
||||
* Update the SDK fixing some user status bugs. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/6037
|
||||
* Fix the emoji picker's title when setting a custom status. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/6039
|
||||
|
||||
Others
|
||||
* Update Project Dependencies by @renovate[bot] in https://github.com/element-hq/element-x-ios/pull/6011
|
||||
* Move various top level folder to the `Components` one by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6014
|
||||
* Update dependency PostHog to v3.69.1 by @renovate[bot] in https://github.com/element-hq/element-x-ios/pull/6013
|
||||
* Avoid re-applying identical room list filters by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6016
|
||||
* Detach the Client's `cacheAccountURL` call by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6019
|
||||
* Update the Enterprise submodule. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/6023
|
||||
* Fix the flaky ElementCallServiceTests by replacing TestClock by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6022
|
||||
* Implement TimelineItemProvider diff `truncate` mechanism by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6029
|
||||
* Update the SDK. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/6030
|
||||
* Attempt another kind of fix for the encryption settings UI test by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6035
|
||||
* Fail fast on the integration tests when encountering the first failed assert by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6041
|
||||
* Various unit test improvements by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6042
|
||||
* Update the Enterprise submodule. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/6049
|
||||
|
||||
|
||||
**Full Changelog**: https://github.com/element-hq/element-x-ios/compare/release/26.08.2...release/26.08.3
|
||||
|
||||
## Changes in 26.08.2 (2026-08-11)
|
||||
|
||||
### What's Changed
|
||||
|
||||
✨ Features
|
||||
* Allow tapping the avatar in the room member bottom sheet to view it fullscreen by @danderson-cont in https://github.com/element-hq/element-x-ios/pull/5989
|
||||
|
||||
🙌 Improvements
|
||||
* Remove map tiler url from matrix wellknown by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5983
|
||||
* Combine the Server Selection screen into the Server Confirmation screen and add autocompletion when entering an account provider. by @mredig in https://github.com/element-hq/element-x-ios/pull/5949
|
||||
|
||||
🐛 Bugfixes
|
||||
* Fix broken avatar aspect ratio in the share sheet and notifications by @ara4n in https://github.com/element-hq/element-x-ios/pull/5972
|
||||
* Fix Pro Max In Call Rotation Bug by @mredig in https://github.com/element-hq/element-x-ios/pull/5990
|
||||
* Update the SDK with a fix for read receipts. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5991
|
||||
* Fix tracing span panic when accessed from multiple threads by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/5996
|
||||
* Make sure the Tab Rail's background matches the split view's detail background. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/6003
|
||||
* Fix a simulcast bug in Element Call. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/6009
|
||||
|
||||
🗣 Translations
|
||||
* Translations update by @RiotRobot in https://github.com/element-hq/element-x-ios/pull/5999
|
||||
|
||||
🧱 Build
|
||||
* Add an HTTP_PROXY environment variable too (also disabled). by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5984
|
||||
* Annotate failures for Github Actions so they're easier to spot. by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6004
|
||||
* Run XcodeGen by @RiotRobot in https://github.com/element-hq/element-x-ios/pull/6006
|
||||
* Drop the `addressSanitizer` and `undefinedBehaviorSanitizer` from the Accessibility and UI tests by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6008
|
||||
* Reinforce text typing within XCUITests by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6007
|
||||
|
||||
🚧 In development 🚧
|
||||
* Add timeouts after verifying the device owner when linking a new device. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5970
|
||||
* Show loading/failure states when setting/clearing user status. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5993
|
||||
* Enable automatic call status under the User Status feature flag. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5994
|
||||
|
||||
Others
|
||||
* Update dependency pointfreeco/swift-snapshot-testing to v1.19.4 by @renovate[bot] in https://github.com/element-hq/element-x-ios/pull/5981
|
||||
* Add hooks for the RoomDetails, RoomMemberDetails and UserProfile screens. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5980
|
||||
* Improve the room member part of the UI test user session flows by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/5985
|
||||
* Update the SDK and handle some API breaks. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5986
|
||||
* Update Contributing.md with snapshot testing instructions by @mredig in https://github.com/element-hq/element-x-ios/pull/5974
|
||||
* Update zizmorcore/zizmor-action action to v0.6.2 by @renovate[bot] in https://github.com/element-hq/element-x-ios/pull/5998
|
||||
* Set the finalised OAuth Client URI path to match the new EXI page. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5992
|
||||
* Improve integration test diagnostics in an attempt to catch run crashes by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6000
|
||||
* Prevent invalid snapshots on timeline replies by waiting for the keyboard to appear for longer by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/6001
|
||||
* Update the SDK. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/6010
|
||||
|
||||
|
||||
**Full Changelog**: https://github.com/element-hq/element-x-ios/compare/release/26.08.1...release/26.08.2
|
||||
|
||||
## Changes in 26.08.1 (2026-08-04)
|
||||
|
||||
### What's Changed
|
||||
|
||||
✨ Features
|
||||
* Render replies to gallery items by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5942
|
||||
* Render gallery items in the media browser/gallery by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5955
|
||||
|
||||
🙌 Improvements
|
||||
* Allow previews in the timeline to include filtered galleries by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5943
|
||||
* Set gallery sending limit to 60 when the gallery ff is on by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5960
|
||||
* Add a custom TabRail on iPad instead of the top tab bar. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5964
|
||||
* Small gallery tweaks by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5957
|
||||
* Add call icon next to members in call by @nankeen by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5968
|
||||
|
||||
🐛 Bugfixes
|
||||
* Fix rageshake upload progress bar by @danderson-cont in https://github.com/element-hq/element-x-ios/pull/5950
|
||||
* Fix for pagination getting stuck loading when swiping media previews in the timeline by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5963
|
||||
* Manually publish room list range updates when the content isn't scrollable by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/5956
|
||||
|
||||
🗣 Translations
|
||||
* Translations update by @RiotRobot in https://github.com/element-hq/element-x-ios/pull/5965
|
||||
|
||||
🦻 Accessibility
|
||||
* A11y for Galleries by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5969
|
||||
|
||||
🚧 In development 🚧
|
||||
* Fix a couple of missing `UserStatus` values. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5944
|
||||
* Allow clearing your own call status. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5959
|
||||
|
||||
Others
|
||||
* Fix for some flaky tests part 2 by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5939
|
||||
* Update the Enterprise submodule. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5953
|
||||
* Update zizmorcore/zizmor-action action to v0.6.1 by @renovate[bot] in https://github.com/element-hq/element-x-ios/pull/5961
|
||||
* Update Project Dependencies by @renovate[bot] in https://github.com/element-hq/element-x-ios/pull/5940
|
||||
* Update actions/stale action to v11 by @renovate[bot] in https://github.com/element-hq/element-x-ios/pull/5971
|
||||
* Accessibility tests fixes by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/5976
|
||||
* Disable the store pausing feature as we encountered cases in which it doesn't work properly by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/5977
|
||||
* Fix various UI test snapshots by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/5975
|
||||
* Tweak the stalebot configuration by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/5978
|
||||
|
||||
|
||||
**Full Changelog**: https://github.com/element-hq/element-x-ios/compare/release/26.08.0...release/26.08.1
|
||||
|
||||
## Changes in 26.08.0 (2026-07-28)
|
||||
|
||||
### What's Changed
|
||||
|
||||
✨ Features
|
||||
* Add support for active call item rendering in timeline by @BillCarsonFr in https://github.com/element-hq/element-x-ios/pull/5775
|
||||
* Add content scanner to the NSE Client by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5926
|
||||
* Render image and video in galleries as a grid by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5929
|
||||
* Render galleries with non-visual attachments as a list by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5932
|
||||
* Open a full-screen preview when tapping a gallery item by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5936
|
||||
|
||||
🙌 Improvements
|
||||
* Report user presence on app lifecycle transitions by @lhjt in https://github.com/element-hq/element-x-ios/pull/5838
|
||||
* Content scanner also checks for thumbnails by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5911
|
||||
* Remove the requiresExtraAccountSetup badge. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5921
|
||||
* Implements push notifications for LLS via MSC4505 by @ara4n in https://github.com/element-hq/element-x-ios/pull/5872
|
||||
|
||||
🐛 Bugfixes
|
||||
* Enable client pausing and resuming for all builds by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/5904
|
||||
|
||||
🗣 Translations
|
||||
* Translations update by @RiotRobot in https://github.com/element-hq/element-x-ios/pull/5901
|
||||
* Translations update by @RiotRobot in https://github.com/element-hq/element-x-ios/pull/5931
|
||||
|
||||
🧱 Build
|
||||
* Re-run xcodegen. by @RiotRobot in https://github.com/element-hq/element-x-ios/pull/5907
|
||||
* Bump the calendar version ready for the next release by @RiotRobot in https://github.com/element-hq/element-x-ios/pull/5937
|
||||
|
||||
📄 Documentation
|
||||
* Group Element Pro changes into a dedicated release notes section by @manuroe in https://github.com/element-hq/element-x-ios/pull/5899
|
||||
|
||||
🚧 In development 🚧
|
||||
* Add the UI for your own user status in the Settings screen. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5888
|
||||
* Support sending gallery messages behind a feature flag by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5909
|
||||
* Update the SDK and hook up the status from Room Heroes. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5905
|
||||
* Hook up the emoji picker to the custom status row. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5902
|
||||
* Search tab tweaks by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/5910
|
||||
* Add support for showing the user's own status over their avatar on the app's Settings button. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5912
|
||||
* Add a warning to the Link New Device instructions. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5916
|
||||
* Add the gallery timeline item rendered as a placeholder by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5928
|
||||
* Gate user status behind server support as well as the feature flag. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5920
|
||||
|
||||
Others
|
||||
* Update dependency pointfreeco/swift-snapshot-testing to v1.19.3 by @renovate[bot] in https://github.com/element-hq/element-x-ios/pull/5892
|
||||
* Update enterprise by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5894
|
||||
* Update dependency Sentry to v9.21.0 by @renovate[bot] in https://github.com/element-hq/element-x-ios/pull/5891
|
||||
* Update actions/stale action to v10.4.0 by @renovate[bot] in https://github.com/element-hq/element-x-ios/pull/5898
|
||||
* Several small, independent accessibility fixes (VoiceOver labels/traits, contrast) by @unclejay80 in https://github.com/element-hq/element-x-ios/pull/5890
|
||||
* Periphery cleanup by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5893
|
||||
* Various project warning fixes by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/5908
|
||||
* Add signed in flag to the developer options screen hook by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5914
|
||||
* Update zizmorcore/zizmor-action action to v0.6.0 by @renovate[bot] in https://github.com/element-hq/element-x-ios/pull/5917
|
||||
* Update SDK to 26.07.22 by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5919
|
||||
* Small tweaks to the Presence feature. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5918
|
||||
* Fix call timeline item snapshots. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5923
|
||||
* Bump the RustSDK to v26.07.23 by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/5925
|
||||
* Update actions/checkout action to v7.0.1 by @renovate[bot] in https://github.com/element-hq/element-x-ios/pull/5935
|
||||
* Add an `oAuthClientURIPath` option to AppSettings. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5934
|
||||
* update sdk to 26-7-28 by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5938
|
||||
|
||||
### New Contributors
|
||||
* @unclejay80 made their first contribution in https://github.com/element-hq/element-x-ios/pull/5890
|
||||
* @lhjt made their first contribution in https://github.com/element-hq/element-x-ios/pull/5838
|
||||
|
||||
**Full Changelog**: https://github.com/element-hq/element-x-ios/compare/release/26.07.4...release/26.08.0
|
||||
|
||||
## Changes in 26.07.4 (2026-07-15)
|
||||
|
||||
### What's Changed
|
||||
|
||||
✨ Features
|
||||
* Force Disable E2EE for Element Pro by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5866
|
||||
|
||||
🙌 Improvements
|
||||
* Use dark theme for Element Call by @toger5 in https://github.com/element-hq/element-x-ios/pull/5860
|
||||
|
||||
🐛 Bugfixes
|
||||
* Fix for NSE and ShareExtension individual builds by @mredig in https://github.com/element-hq/element-x-ios/pull/5856
|
||||
* Fix CurrentValuePublisher.map dropping updates when the mapped publisher is chained inline by @ara4n in https://github.com/element-hq/element-x-ios/pull/5870
|
||||
* Fix a bug where rooms couldn't be opened when returning to the foreground whilst offline. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5867
|
||||
|
||||
🗣 Translations
|
||||
* Translations update by @RiotRobot in https://github.com/element-hq/element-x-ios/pull/5865
|
||||
|
||||
🧱 Build
|
||||
* Fix UI tests by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5862
|
||||
* Add CurrentValuePublisherTests to the UnitTests target by @ara4n in https://github.com/element-hq/element-x-ios/pull/5884
|
||||
|
||||
🚧 In development 🚧
|
||||
* Display other users' User Status. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5859
|
||||
|
||||
Others
|
||||
* Update the SDK and Compound tokens. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5857
|
||||
* Use deferFulfillment in flow coordinator tests by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5861
|
||||
* Update the SDK and handle API breaks. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5871
|
||||
* Fix for flaky tests by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5869
|
||||
* Constrained tests tool implementation + skill by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5873
|
||||
* Update dependency Mantis to v3 by @renovate[bot] in https://github.com/element-hq/element-x-ios/pull/5887
|
||||
* Update Project Dependencies by @renovate[bot] in https://github.com/element-hq/element-x-ios/pull/5886
|
||||
* Update the SDK. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5889
|
||||
|
||||
|
||||
**Full Changelog**: https://github.com/element-hq/element-x-ios/compare/release/26.07.3...release/26.07.4
|
||||
|
||||
## Changes in 26.07.3 (2026-07-09)
|
||||
|
||||
### What's Changed
|
||||
|
||||
✨ Features
|
||||
* Content Scanning View by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5831
|
||||
* Content scanning view for reply preview by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5842
|
||||
* Scanning states for the media events timeline screen by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5847
|
||||
* Media Preview content scanning by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5851
|
||||
|
||||
🙌 Improvements
|
||||
* Don't keep re-prompting the user to migrate if they get spontaneously logged out. by @ara4n in https://github.com/element-hq/element-x-ios/pull/5844
|
||||
* New location request permission strings by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5854
|
||||
|
||||
🐛 Bugfixes
|
||||
* Fix voice message recording crashes caused by an isolation assertion failure by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/5820
|
||||
* Stop reserving space for the non-existant icon background in ListRowLabel on iOS 26. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5822
|
||||
* Fix for the media browser showing also images and videos in file mode by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5853
|
||||
|
||||
🗣 Translations
|
||||
* Translations update by @RiotRobot in https://github.com/element-hq/element-x-ios/pull/5845
|
||||
|
||||
🦻 Accessibility
|
||||
* Fix AccessibilityTests hang on previews expecting expired transient state by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/5821
|
||||
* Remove the "unflip" of the timeline when in voice over mode by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5835
|
||||
|
||||
🧱 Build
|
||||
* Remove Hyperion from the Compound Inspector app. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5828
|
||||
* Switch back to using the stable version of SwiftFormat. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5850
|
||||
* Introduce a build setting to detect Nightly builds. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5852
|
||||
|
||||
🚧 In development 🚧
|
||||
* Make LinkNewDeviceScreen fall back to the App Lock PIN code when there's no passcode. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5794
|
||||
* Add the content scanner URL to the app settings by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5823
|
||||
* User Status preparation. by @pixlwave in https://github.com/element-hq/element-x-ios/pull/5825
|
||||
* Content Scanner Service by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5826
|
||||
* Add message support to the new search tab by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/5829
|
||||
|
||||
Others
|
||||
* Bump the RustSDK to a new "apple-release" profile build distribution by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/5834
|
||||
* Update the readme to fix the unit tests shield and remove the SonarCloud ones by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/5832
|
||||
* Fix various project warnings by @stefanceriu in https://github.com/element-hq/element-x-ios/pull/5833
|
||||
* Swift format enforce isEmpty rule by @Velin92 in https://github.com/element-hq/element-x-ios/pull/5843
|
||||
* Update Project Dependencies by @renovate[bot] in https://github.com/element-hq/element-x-ios/pull/5818
|
||||
|
||||
|
||||
**Full Changelog**: https://github.com/element-hq/element-x-ios/compare/release/26.07.0...release/26.07.3
|
||||
|
||||
## Changes in 26.07.1 (2026-07-03)
|
||||
|
||||
### What's Changed
|
||||
|
||||
@@ -30,7 +30,7 @@ Only once all of the above is met should you open a PR with your proposed change
|
||||
* Don't submit large PRs, especially if not previously talked about. Anything above 200 lines is large (excluding generated code e.g. tests, translations, mocks)
|
||||
* Please don't open unfinished PRs and expect us to fill in the details
|
||||
* If you would like our opinion/direction on unfinished code please link your branch or idea in the ticket
|
||||
* Please limit the number of commits in a single PR. We are perfectly happy with splitting work across multiple sessions as long as they're logically independant and show promise of progress (ideally expressed through a ticket)
|
||||
* Please limit the number of commits in a single PR. We are perfectly happy with splitting work across multiple sessions as long as they're logically independent and show promise of progress (ideally expressed through a ticket)
|
||||
* Each and every commit should stand on its own, clearly explaining what it does and why
|
||||
* Once a PR goes into review please don't rewrite the history unless agreed so with the reviewer.
|
||||
* Tweaks and fixes following review can be directly committed (to be interactively rebased later) or as fixups
|
||||
@@ -95,6 +95,14 @@ git lfs install
|
||||
|
||||
If you make changes to the UI you may cause existing UI and Preview test snapshots to fail. The UITests run user flows and record snapshots while doing so using the settings defined under [checkEnvironments](https://github.com/element-hq/element-x-ios/blob/c29175d1f924e58b9646a200dbab0301fce3c258/UITests/Sources/Application.swift#L35-L37) while the PreviewTests use the settings defined in [PreviewTests.swift](https://github.com/element-hq/element-x-ios/blob/c29175d1f924e58b9646a200dbab0301fce3c258/PreviewTests/Sources/PreviewTests.swift#L18-L20). The snapshots are stored under `Sources/__Snapshots__` in their respective target's folder.
|
||||
|
||||
To run the preview tests:
|
||||
|
||||
1. Use an iPhone SE (3rd generation) simulator running iOS 26.5.
|
||||
2. On that simulator, go to Settings -> General -> Language & Region and select United States as the region, with English (US) as the only preferred language. This is a one time setup, as long as you keep using the same simulator.
|
||||
3. Select the `PreviewTests` scheme and run the tests.
|
||||
|
||||
Newly created screens will automatically have their screenshots added based off their `TestablePreview` Swift previews. If you are modifying an existing screen, you will first need to delete the old snapshots for that screen before running the tests. Alternatively, if you enable `RECORD_FAILURES` in the preview test plans's environment variables (`PreviewTests/SupportingFiles/Previewtests.xctestplan`), it will overwrite snapshot failures with the updated screenshot.
|
||||
|
||||
### Githooks
|
||||
|
||||
The project uses its own shared githooks stored in the .githooks folder, you will need to configure git to use such folder, this is already done if you have run the setup tool with `swift run tools setup-project` otherwise you would need to run:
|
||||
@@ -142,7 +150,7 @@ Our [changelog](CHANGES.md) is automatically generated by GitHub, based on the P
|
||||
For Swift coding style we use [SwiftLint](https://github.com/realm/SwiftLint) to check some conventions at compile time (rules are located in the `.swiftlint.yml` file).
|
||||
Otherwise please have a look to [Apple Swift conventions](https://swift.org/documentation/api-design-guidelines.html#conventions). We are also using some of the conventions of [raywenderlich.com Swift style guide](https://github.com/raywenderlich/swift-style-guide).
|
||||
|
||||
We enforce the coding style by running checks on the CI for every PR through [Danger](Dangerfile.swift), [SwiftLint](.swiftlint.yml), [SwiftFormat](.swiftformat) and [SonarCloud](https://sonarcloud.io/project/overview?id=element-x-ios)
|
||||
We enforce the coding style by running checks on the CI for every PR through [PR Checks](.github/workflows/pr-checks.yml), [SwiftLint](.swiftlint.yml), [SwiftFormat](.swiftformat) and [SonarCloud](https://sonarcloud.io/project/overview?id=element-x-ios)
|
||||
|
||||
We also gather coverage reports on every PR through [Codecov](https://app.codecov.io/gh/element-hq/element-x-ios) and will eventually start enforcing minimums.
|
||||
|
||||
|
||||
@@ -5,7 +5,10 @@ import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "BuildExtensions",
|
||||
platforms: [.macOS(.v15)],
|
||||
platforms: [
|
||||
.macOS(.v15),
|
||||
.iOS(.v18) // Only necessary for Previews
|
||||
],
|
||||
products: [
|
||||
.library(name: "Macros", targets: ["Macros"])
|
||||
],
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Copyright 2026 Element Creations Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
/// Exposes a `Mutex`-backed hook as a read-only computed property, alongside a `register<Name>`
|
||||
/// peer that swaps in a replacement hook.
|
||||
///
|
||||
/// The `default` argument provides the hook used until (and unless) a replacement is registered.
|
||||
/// The enclosing type must have `Synchronization` in scope for the generated `Mutex` storage.
|
||||
@attached(accessor)
|
||||
@attached(peer, names: arbitrary)
|
||||
public macro AppHook<Value>(default: Value) =
|
||||
#externalMacro(module: "MacrosImplementation", type: "AppHookMacro")
|
||||
@@ -0,0 +1,98 @@
|
||||
//
|
||||
// Copyright 2026 Element Creations Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import SwiftSyntax
|
||||
import SwiftSyntaxMacros
|
||||
|
||||
/// Implements `@AppHook`. The generated property reads through a `Mutex`-backed store, and a
|
||||
/// generated `register<Name>` method swaps in a replacement hook.
|
||||
enum AppHookMacro {
|
||||
enum DiagnosticError: Error, CustomStringConvertible {
|
||||
case notAStoredProperty
|
||||
case missingTypeAnnotation
|
||||
case missingDefault
|
||||
|
||||
var description: String {
|
||||
switch self {
|
||||
case .notAStoredProperty:
|
||||
"@AppHook can only be applied to a stored property."
|
||||
case .missingTypeAnnotation:
|
||||
"@AppHook requires an explicit type annotation."
|
||||
case .missingDefault:
|
||||
"@AppHook requires a default value."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct AppHook {
|
||||
let name: String
|
||||
let type: TypeSyntax
|
||||
let defaultValue: ExprSyntax
|
||||
|
||||
var storageName: TokenSyntax {
|
||||
"_\(raw: name)"
|
||||
}
|
||||
|
||||
var registerMethodName: TokenSyntax {
|
||||
"register\(raw: name.prefix(1).uppercased() + name.dropFirst())"
|
||||
}
|
||||
}
|
||||
|
||||
private static func appHook(for declaration: some DeclSyntaxProtocol, node: AttributeSyntax) throws -> AppHook {
|
||||
guard let variable = declaration.as(VariableDeclSyntax.self),
|
||||
let binding = variable.bindings.first,
|
||||
let identifier = binding.pattern.as(IdentifierPatternSyntax.self)?.identifier else {
|
||||
throw DiagnosticError.notAStoredProperty
|
||||
}
|
||||
guard let type = binding.typeAnnotation?.type.trimmed else {
|
||||
throw DiagnosticError.missingTypeAnnotation
|
||||
}
|
||||
|
||||
var defaultValue: ExprSyntax?
|
||||
if let list = node.arguments?.as(LabeledExprListSyntax.self) {
|
||||
for argument in list where argument.label?.text == "default" {
|
||||
defaultValue = argument.expression
|
||||
}
|
||||
}
|
||||
guard let defaultValue else {
|
||||
throw DiagnosticError.missingDefault
|
||||
}
|
||||
|
||||
return AppHook(name: identifier.text, type: type, defaultValue: defaultValue)
|
||||
}
|
||||
}
|
||||
|
||||
extension AppHookMacro: AccessorMacro {
|
||||
static func expansion(of node: AttributeSyntax,
|
||||
providingAccessorsOf declaration: some DeclSyntaxProtocol,
|
||||
in context: some MacroExpansionContext) throws -> [AccessorDeclSyntax] {
|
||||
let appHook = try appHook(for: declaration, node: node)
|
||||
return [
|
||||
"""
|
||||
get {
|
||||
\(appHook.storageName).withLock { $0 }
|
||||
}
|
||||
"""
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
extension AppHookMacro: PeerMacro {
|
||||
static func expansion(of node: AttributeSyntax,
|
||||
providingPeersOf declaration: some DeclSyntaxProtocol,
|
||||
in context: some MacroExpansionContext) throws -> [DeclSyntax] {
|
||||
let appHook = try appHook(for: declaration, node: node)
|
||||
return [
|
||||
"private let \(appHook.storageName) = Mutex<\(appHook.type)>(\(appHook.defaultValue))",
|
||||
"""
|
||||
func \(appHook.registerMethodName)(_ hook: \(appHook.type)) {
|
||||
\(appHook.storageName).withLock { $0 = hook }
|
||||
}
|
||||
"""
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -10,5 +10,5 @@ import SwiftSyntaxMacros
|
||||
|
||||
@main
|
||||
struct BuildExtensionsPlugin: CompilerPlugin {
|
||||
let providingMacros: [Macro.Type] = [UserPreferenceMacro.self]
|
||||
let providingMacros: [Macro.Type] = [UserPreferenceMacro.self, AppHookMacro.self]
|
||||
}
|
||||
@@ -14,7 +14,7 @@ import SwiftSyntaxMacros
|
||||
///
|
||||
/// A `volatile` preference instead reads and writes through a generated in-memory store, so its
|
||||
/// value is never persisted and resets on each launch.
|
||||
public enum UserPreferenceMacro {
|
||||
enum UserPreferenceMacro {
|
||||
enum DiagnosticError: Error, CustomStringConvertible {
|
||||
case notAStoredProperty
|
||||
case missingTypeAnnotation
|
||||
@@ -85,9 +85,9 @@ public enum UserPreferenceMacro {
|
||||
}
|
||||
|
||||
extension UserPreferenceMacro: AccessorMacro {
|
||||
public static func expansion(of node: AttributeSyntax,
|
||||
providingAccessorsOf declaration: some DeclSyntaxProtocol,
|
||||
in context: some MacroExpansionContext) throws -> [AccessorDeclSyntax] {
|
||||
static func expansion(of node: AttributeSyntax,
|
||||
providingAccessorsOf declaration: some DeclSyntaxProtocol,
|
||||
in context: some MacroExpansionContext) throws -> [AccessorDeclSyntax] {
|
||||
let preference = try preference(for: declaration, node: node)
|
||||
|
||||
if preference.isVolatile {
|
||||
@@ -137,9 +137,9 @@ extension UserPreferenceMacro: AccessorMacro {
|
||||
}
|
||||
|
||||
extension UserPreferenceMacro: PeerMacro {
|
||||
public static func expansion(of node: AttributeSyntax,
|
||||
providingPeersOf declaration: some DeclSyntaxProtocol,
|
||||
in context: some MacroExpansionContext) throws -> [DeclSyntax] {
|
||||
static func expansion(of node: AttributeSyntax,
|
||||
providingPeersOf declaration: some DeclSyntaxProtocol,
|
||||
in context: some MacroExpansionContext) throws -> [DeclSyntax] {
|
||||
let preference = try preference(for: declaration, node: node)
|
||||
let type = preference.type
|
||||
let name = preference.name
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:0b1465b1e379f4356e0cbde2ecc1a9cd2a58c7a69be7ca9f7b3b2df2e911e60c
|
||||
size 2004302
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// Copyright 2026 Element Creations Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
/// Implemented by MapLibreShim's entry point, which the app instantiates after
|
||||
/// `dlopen`-ing the framework.
|
||||
public protocol MapLibreShimProtocol {
|
||||
/// Routes MapLibre's logs into the app's logger. Call once after loading the shim.
|
||||
func configureLogging(_ handler: @escaping @Sendable (MapLogSeverity, String) -> Void)
|
||||
|
||||
/// Builds the interactive map view. The app-side `MapLibreMapView` forwards every
|
||||
/// body evaluation here so SwiftUI updates flow through to the underlying map.
|
||||
func makeMapView(configuration: MapViewConfiguration) -> AnyView
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// Copyright 2026 Element Creations Ltd.
|
||||
// Copyright 2023-2025 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import CoreLocation
|
||||
import Foundation
|
||||
|
||||
/**
|
||||
Behavior mode of the current user's location, can be hidden, only shown and shown following the user
|
||||
*/
|
||||
public enum ShowUserLocationMode: Equatable {
|
||||
/// this mode will show the user pin in map
|
||||
case show
|
||||
/// this mode will show the user pin in map and track him, panning the map automatically
|
||||
case showAndFollow
|
||||
/// this mode will not show the user pin in map
|
||||
case hide
|
||||
/// this mode will not show the user pin in map and will follow the marker with the given id,
|
||||
/// panning the map automatically.
|
||||
case hideAndFollowMarker(id: String)
|
||||
|
||||
/// The id of the marker the map should follow when in the `hideAndFollowMarker` mode, nil otherwise.
|
||||
public var followedMarkerID: String? {
|
||||
guard case .hideAndFollowMarker(let id) = self else { return nil }
|
||||
return id
|
||||
}
|
||||
}
|
||||
|
||||
public enum MapLibreError: Error, Hashable {
|
||||
case failedLoadingMap
|
||||
case failedLocatingUser
|
||||
}
|
||||
|
||||
/// The severity of a map log message forwarded to the app.
|
||||
public enum MapLogSeverity {
|
||||
case error
|
||||
case warning
|
||||
case info
|
||||
case debug
|
||||
case verbose
|
||||
}
|
||||
|
||||
/// A marker shown on the map, identified so that it can be moved in place when its coordinate changes.
|
||||
public struct MapAnnotation {
|
||||
public let id: String
|
||||
public let coordinate: CLLocationCoordinate2D
|
||||
|
||||
public init(id: String, coordinate: CLLocationCoordinate2D) {
|
||||
self.id = id
|
||||
self.coordinate = coordinate
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
//
|
||||
// Copyright 2026 Element Creations Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import CoreLocation
|
||||
import SwiftUI
|
||||
|
||||
/// Everything the map implementation needs in order to render, expressed without app
|
||||
/// types so that the implementation framework can be loaded on demand.
|
||||
public struct MapViewConfiguration {
|
||||
/// the final zoom level used when the first user location emit
|
||||
public let zoomLevel: Double
|
||||
/// The initial zoom level used when the map it firstly loaded and the user location is not yet available, in case of annotations this property is not being used
|
||||
public let initialZoomLevel: Double
|
||||
|
||||
/// The initial map center
|
||||
public let mapCenter: CLLocationCoordinate2D
|
||||
|
||||
/// Map annotations
|
||||
public let annotations: [MapAnnotation]
|
||||
|
||||
/// The style to load the map with, for either the dark or the light appearance.
|
||||
public let styleURL: (_ isDark: Bool) -> URL?
|
||||
|
||||
public let tintColor: UIColor
|
||||
|
||||
/// The content of the marker representing the annotation with the given id.
|
||||
public let markerView: (_ annotationID: String) -> AnyView?
|
||||
|
||||
/// Behavior mode of the current user's location, can be hidden, only shown and shown following the user
|
||||
public let showsUserLocationMode: Binding<ShowUserLocationMode>
|
||||
/// Bind view errors if any
|
||||
public let error: Binding<MapLibreError?>
|
||||
/// Coordinate of the center of the map
|
||||
public let mapCenterCoordinate: Binding<CLLocationCoordinate2D?>
|
||||
public let hasLoadedUserLocation: Binding<Bool>
|
||||
public let isLocationAuthorized: Binding<Bool?>
|
||||
/// The radius of uncertainty for the location, measured in meters.
|
||||
public let geolocationUncertainty: Binding<CLLocationAccuracy?>
|
||||
|
||||
/// Called when the user pan on the map
|
||||
public let userDidPan: (() -> Void)?
|
||||
|
||||
public init(zoomLevel: Double,
|
||||
initialZoomLevel: Double,
|
||||
mapCenter: CLLocationCoordinate2D,
|
||||
annotations: [MapAnnotation] = [],
|
||||
styleURL: @escaping (_ isDark: Bool) -> URL?,
|
||||
tintColor: UIColor,
|
||||
markerView: @escaping (_ annotationID: String) -> AnyView?,
|
||||
showsUserLocationMode: Binding<ShowUserLocationMode>,
|
||||
error: Binding<MapLibreError?>,
|
||||
mapCenterCoordinate: Binding<CLLocationCoordinate2D?>,
|
||||
hasLoadedUserLocation: Binding<Bool>,
|
||||
isLocationAuthorized: Binding<Bool?>,
|
||||
geolocationUncertainty: Binding<CLLocationAccuracy?>,
|
||||
userDidPan: (() -> Void)? = nil) {
|
||||
self.zoomLevel = zoomLevel
|
||||
self.initialZoomLevel = initialZoomLevel
|
||||
self.mapCenter = mapCenter
|
||||
self.annotations = annotations
|
||||
self.styleURL = styleURL
|
||||
self.tintColor = tintColor
|
||||
self.markerView = markerView
|
||||
self.showsUserLocationMode = showsUserLocationMode
|
||||
self.error = error
|
||||
self.mapCenterCoordinate = mapCenterCoordinate
|
||||
self.hasLoadedUserLocation = hasLoadedUserLocation
|
||||
self.isLocationAuthorized = isLocationAuthorized
|
||||
self.geolocationUncertainty = geolocationUncertainty
|
||||
self.userDidPan = userDidPan
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
# The types shared between the app and the MapLibreShim framework. The app links this
|
||||
# (tiny, initialiser-free) framework instead of MapLibre, see MapLibreShim's target.yml.
|
||||
name: MapLibreInterface
|
||||
|
||||
targets:
|
||||
MapLibreInterface:
|
||||
type: framework
|
||||
platform: iOS
|
||||
|
||||
settings:
|
||||
base:
|
||||
PRODUCT_BUNDLE_IDENTIFIER: $(BASE_BUNDLE_IDENTIFIER).maplibre-interface
|
||||
GENERATE_INFOPLIST_FILE: YES
|
||||
SWIFT_VERSION: 6.2
|
||||
SWIFT_APPROACHABLE_CONCURRENCY: YES
|
||||
SWIFT_DEFAULT_ACTOR_ISOLATION: MainActor
|
||||
|
||||
sources:
|
||||
- path: ../Sources
|
||||
@@ -8,7 +8,7 @@
|
||||
import CoreLocation
|
||||
import QuartzCore
|
||||
|
||||
/// Smoothly animates a `LocationAnnotation`'s coordinate from its current
|
||||
/// Smoothly animates a `MapLibreAnnotation`'s coordinate from its current
|
||||
/// position to a new one using a `CADisplayLink` for frame-accurate updates.
|
||||
///
|
||||
/// ## How it works
|
||||
@@ -26,7 +26,7 @@ import QuartzCore
|
||||
/// cancels the previous one and begins from the annotation's current position.
|
||||
final class CoordinateAnimator {
|
||||
private var displayLink: CADisplayLink?
|
||||
private weak var annotation: LocationAnnotation?
|
||||
private weak var annotation: MapLibreAnnotation?
|
||||
private let startCoordinate: CLLocationCoordinate2D
|
||||
private let endCoordinate: CLLocationCoordinate2D
|
||||
private let duration: CFTimeInterval
|
||||
@@ -36,7 +36,7 @@ final class CoordinateAnimator {
|
||||
/// while the display link is running. Keyed by annotation ID.
|
||||
private static var activeAnimators: [String: CoordinateAnimator] = [:]
|
||||
|
||||
private init(annotation: LocationAnnotation,
|
||||
private init(annotation: MapLibreAnnotation,
|
||||
to end: CLLocationCoordinate2D,
|
||||
duration: CFTimeInterval) {
|
||||
self.annotation = annotation
|
||||
@@ -48,7 +48,7 @@ final class CoordinateAnimator {
|
||||
/// Starts animating the annotation's coordinate to `end` over `duration` seconds.
|
||||
/// If the annotation is already being animated, the in-flight animation is
|
||||
/// cancelled and a new one starts from the current position.
|
||||
static func animate(annotation: LocationAnnotation,
|
||||
static func animate(annotation: MapLibreAnnotation,
|
||||
to end: CLLocationCoordinate2D,
|
||||
duration: CFTimeInterval) {
|
||||
guard annotation.coordinate.latitude != end.latitude
|
||||
@@ -0,0 +1,60 @@
|
||||
//
|
||||
// Copyright 2026 Element Creations Ltd.
|
||||
// Copyright 2023-2025 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import CoreLocation
|
||||
import MapLibre
|
||||
import MapLibreInterface
|
||||
import SwiftUI
|
||||
|
||||
final class MapLibreAnnotation: NSObject, MLNAnnotation, Identifiable {
|
||||
let id: String
|
||||
// @objc dynamic is required to make animations work
|
||||
@objc dynamic var coordinate: CLLocationCoordinate2D
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
init(_ annotation: MapAnnotation) {
|
||||
id = annotation.id
|
||||
coordinate = annotation.coordinate
|
||||
super.init()
|
||||
}
|
||||
}
|
||||
|
||||
final class MapLibreAnnotationView: MLNUserLocationAnnotationView {
|
||||
private var hostingController: UIHostingController<AnyView>?
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
override init(annotation: MLNAnnotation?, reuseIdentifier: String?) {
|
||||
super.init(annotation: annotation, reuseIdentifier:
|
||||
reuseIdentifier)
|
||||
}
|
||||
|
||||
convenience init(annotation: MapLibreAnnotation, content: AnyView?) {
|
||||
self.init(annotation: annotation, reuseIdentifier: "\(Self.self)")
|
||||
let hostingController = UIHostingController(rootView: content ?? AnyView(EmptyView()))
|
||||
self.hostingController = hostingController
|
||||
let view: UIView = hostingController.view
|
||||
view.backgroundColor = .clear
|
||||
view.anchorPoint = .init(x: 0.5, y: 1.0)
|
||||
addSubview(view)
|
||||
view.bounds.size = view.intrinsicContentSize
|
||||
}
|
||||
|
||||
func updateContent(_ content: AnyView?) {
|
||||
hostingController?.rootView = content ?? AnyView(EmptyView())
|
||||
if let hostedView = hostingController?.view {
|
||||
hostedView.bounds.size = hostedView.intrinsicContentSize
|
||||
}
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
//
|
||||
// Copyright 2026 Element Creations Ltd.
|
||||
// Copyright 2023-2025 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import MapLibre
|
||||
import MapLibreInterface
|
||||
import SwiftUI
|
||||
|
||||
struct MapLibreMapView: UIViewRepresentable {
|
||||
// MARK: - Properties
|
||||
|
||||
@Environment(\.colorScheme) private var colorScheme
|
||||
|
||||
let configuration: MapViewConfiguration
|
||||
|
||||
// MARK: - UIViewRepresentable
|
||||
|
||||
func makeUIView(context: Context) -> MLNMapView {
|
||||
let mapView = makeMapView()
|
||||
mapView.delegate = context.coordinator
|
||||
setupMap(mapView: mapView)
|
||||
return mapView
|
||||
}
|
||||
|
||||
func updateUIView(_ mapView: MLNMapView, context: Context) {
|
||||
// Don't set the same value twice. Otherwise, if there is an error loading the map, a loop
|
||||
// is caused as the `error` binding being set, which triggers this update, which sets a
|
||||
// new URL, which causes another error, and so it goes on round and round in a circle.
|
||||
let dynamicMapURL = configuration.styleURL(colorScheme == .dark)
|
||||
if mapView.styleURL != dynamicMapURL {
|
||||
mapView.styleURL = dynamicMapURL
|
||||
}
|
||||
|
||||
// If the center coordinate was updated externally (not by the map itself), move the map.
|
||||
// Not applied while following a marker, where the camera is driven by the marker's position.
|
||||
if configuration.showsUserLocationMode.wrappedValue.followedMarkerID == nil,
|
||||
let newCenter = configuration.mapCenterCoordinate.wrappedValue,
|
||||
newCenter.latitude != context.coordinator.lastReportedCenter?.latitude
|
||||
|| newCenter.longitude != context.coordinator.lastReportedCenter?.longitude {
|
||||
context.coordinator.lastReportedCenter = newCenter
|
||||
mapView.setCenter(newCenter, animated: true)
|
||||
}
|
||||
|
||||
// Update existing annotation views with fresh SwiftUI content.
|
||||
// This handles the case where the annotation's view data changes after
|
||||
// the annotation was initially placed (e.g. user avatar loads asynchronously).
|
||||
updateAnnotations(in: mapView)
|
||||
|
||||
showUserLocation(in: mapView)
|
||||
|
||||
context.coordinator.updateMarkerFollowing(in: mapView, markerID: configuration.showsUserLocationMode.wrappedValue.followedMarkerID)
|
||||
}
|
||||
|
||||
func makeCoordinator() -> Coordinator {
|
||||
Coordinator(self)
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func setupMap(mapView: MLNMapView) {
|
||||
mapView.addAnnotations(configuration.annotations.map(MapLibreAnnotation.init))
|
||||
mapView.zoomLevel = configuration.annotations.isEmpty ? configuration.initialZoomLevel : configuration.zoomLevel
|
||||
mapView.centerCoordinate = configuration.mapCenter
|
||||
}
|
||||
|
||||
private func updateAnnotations(in mapView: MLNMapView) {
|
||||
let existingByID = Dictionary(uniqueKeysWithValues:
|
||||
(mapView.annotations ?? []).compactMap { $0 as? MapLibreAnnotation }.map { ($0.id, $0) })
|
||||
let updatedByID = Dictionary(uniqueKeysWithValues: configuration.annotations.map { ($0.id, $0) })
|
||||
|
||||
let existingIDs = Set(existingByID.keys)
|
||||
let updatedIDs = Set(updatedByID.keys)
|
||||
|
||||
// Remove annotations that are no longer present
|
||||
let removedIDs = existingIDs.subtracting(updatedIDs)
|
||||
if !removedIDs.isEmpty {
|
||||
let toRemove = removedIDs.compactMap { existingByID[$0] }
|
||||
mapView.removeAnnotations(toRemove)
|
||||
}
|
||||
|
||||
// Add new annotations
|
||||
let addedIDs = updatedIDs.subtracting(existingIDs)
|
||||
if !addedIDs.isEmpty {
|
||||
let toAdd = addedIDs.compactMap { updatedByID[$0] }.map(MapLibreAnnotation.init)
|
||||
mapView.addAnnotations(toAdd)
|
||||
}
|
||||
|
||||
// Update existing annotations that are still present
|
||||
let keptIDs = existingIDs.intersection(updatedIDs)
|
||||
for id in keptIDs {
|
||||
guard let existingAnnotation = existingByID[id],
|
||||
let updatedAnnotation = updatedByID[id] else {
|
||||
continue
|
||||
}
|
||||
CoordinateAnimator.animate(annotation: existingAnnotation,
|
||||
to: updatedAnnotation.coordinate,
|
||||
duration: 1.0)
|
||||
if let annotationView = mapView.view(for: existingAnnotation) as? MapLibreAnnotationView {
|
||||
annotationView.updateContent(configuration.markerView(id))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func makeMapView() -> MLNMapView {
|
||||
let mapView = MLNMapView(frame: .zero, styleURL: configuration.styleURL(colorScheme == .dark))
|
||||
mapView.logoViewPosition = .topLeft
|
||||
mapView.attributionButtonPosition = .topLeft
|
||||
mapView.attributionButtonMargins = .init(x: mapView.logoView.frame.maxX + 8, y: mapView.logoView.center.y / 2)
|
||||
mapView.tintColor = configuration.tintColor
|
||||
mapView.allowsRotating = false
|
||||
mapView.allowsTilting = false
|
||||
return mapView
|
||||
}
|
||||
|
||||
private func showUserLocation(in mapView: MLNMapView) {
|
||||
switch (configuration.showsUserLocationMode.wrappedValue, configuration.annotations) {
|
||||
case (.showAndFollow, _):
|
||||
mapView.userTrackingMode = .follow
|
||||
case (.show, let annotations) where !annotations.isEmpty:
|
||||
// In the show mode, if there are annotations, we check the authorizationStatus,
|
||||
// if it's not determined, we wont prompt the user with a request for permissions,
|
||||
// because they should be able to see the annotations without sharing their location information.
|
||||
guard mapView.locationManager.authorizationStatus != .notDetermined else { return }
|
||||
fallthrough
|
||||
case (.show, _):
|
||||
mapView.showsUserLocation = true
|
||||
mapView.setUserTrackingMode(.none, animated: false, completionHandler: nil)
|
||||
case (.hide, _), (.hideAndFollowMarker, _):
|
||||
// In hideAndFollowMarker mode the camera following is handled by the coordinator.
|
||||
mapView.showsUserLocation = false
|
||||
mapView.setUserTrackingMode(.none, animated: false, completionHandler: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Coordinator
|
||||
|
||||
extension MapLibreMapView {
|
||||
class Coordinator: NSObject, MLNMapViewDelegate {
|
||||
// MARK: - Properties
|
||||
|
||||
var mapLibreView: MapLibreMapView
|
||||
|
||||
private var previousUserLocation: MLNUserLocation?
|
||||
/// Tracks the last center coordinate reported by the map (or set programmatically),
|
||||
/// so that `updateUIView` can tell apart external binding changes from internal ones.
|
||||
var lastReportedCenter: CLLocationCoordinate2D?
|
||||
|
||||
/// The annotation the camera is currently locked on while in the `hideAndFollowMarker` mode.
|
||||
private weak var followedAnnotation: MapLibreAnnotation?
|
||||
/// Observes the followed annotation's coordinate, updated every frame by the `CoordinateAnimator`.
|
||||
private var followedAnnotationObservation: NSKeyValueObservation?
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
init(_ mapLibreView: MapLibreMapView) {
|
||||
self.mapLibreView = mapLibreView
|
||||
}
|
||||
|
||||
// MARK: - Marker following
|
||||
|
||||
/// Keeps the camera locked on the marker with the given id, or stops following when nil.
|
||||
func updateMarkerFollowing(in mapView: MLNMapView, markerID: String?) {
|
||||
guard let markerID else {
|
||||
stopFollowingMarker()
|
||||
return
|
||||
}
|
||||
|
||||
guard let annotation = (mapView.annotations ?? [])
|
||||
.compactMap({ $0 as? MapLibreAnnotation })
|
||||
.first(where: { $0.id == markerID }) else {
|
||||
// The marker isn't on the map (yet), resolve it again on the next update.
|
||||
stopFollowingMarker()
|
||||
return
|
||||
}
|
||||
|
||||
guard annotation !== followedAnnotation else { return }
|
||||
startFollowingMarker(annotation, in: mapView)
|
||||
}
|
||||
|
||||
private func startFollowingMarker(_ annotation: MapLibreAnnotation, in mapView: MLNMapView) {
|
||||
followedAnnotation = annotation
|
||||
followedAnnotationObservation = nil
|
||||
|
||||
// Animate to the marker first, attaching the per-frame tracking only on completion
|
||||
// so that it doesn't cancel the transition.
|
||||
mapView.setCenter(annotation.coordinate,
|
||||
zoomLevel: mapView.zoomLevel,
|
||||
direction: -1, // negative value keeps the current direction
|
||||
animated: true) { [weak self, weak annotation, weak mapView] in
|
||||
guard let self, let annotation, let mapView, annotation === followedAnnotation else { return }
|
||||
|
||||
// Mirror every animated coordinate update to keep the camera as smooth as the marker.
|
||||
followedAnnotationObservation = annotation.observe(\.coordinate) { [weak mapView] annotation, _ in
|
||||
// The coordinate is only ever updated by SwiftUI so KVO fires on the main actor.
|
||||
MainActor.assumeIsolated {
|
||||
mapView?.setCenter(annotation.coordinate, animated: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func stopFollowingMarker() {
|
||||
followedAnnotation = nil
|
||||
followedAnnotationObservation = nil
|
||||
}
|
||||
|
||||
// MARK: - MLNMapViewDelegate
|
||||
|
||||
func mapView(_ mapView: MLNMapView, viewFor annotation: MLNAnnotation) -> MLNAnnotationView? {
|
||||
guard let annotation = annotation as? MapLibreAnnotation else {
|
||||
return nil
|
||||
}
|
||||
return MapLibreAnnotationView(annotation: annotation, content: mapLibreView.configuration.markerView(annotation.id))
|
||||
}
|
||||
|
||||
func mapViewDidFailLoadingMap(_ mapView: MLNMapView, withError error: Error) {
|
||||
if mapLibreView.configuration.error.wrappedValue != .failedLoadingMap {
|
||||
mapLibreView.configuration.error.wrappedValue = .failedLoadingMap
|
||||
}
|
||||
}
|
||||
|
||||
func mapView(_ mapView: MLNMapView, didUpdate userLocation: MLNUserLocation?) {
|
||||
guard let userLocation else { return }
|
||||
mapLibreView.configuration.hasLoadedUserLocation.wrappedValue = true
|
||||
|
||||
if previousUserLocation == nil, mapLibreView.configuration.annotations.isEmpty {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||
mapView.setCenter(userLocation.coordinate, zoomLevel: self.mapLibreView.configuration.zoomLevel, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
previousUserLocation = userLocation
|
||||
updateGeolocationUncertainty(location: userLocation)
|
||||
}
|
||||
|
||||
func mapView(_ mapView: MLNMapView, didChangeLocationManagerAuthorization manager: MLNLocationManager) {
|
||||
switch manager.authorizationStatus {
|
||||
case .denied, .restricted:
|
||||
mapLibreView.configuration.isLocationAuthorized.wrappedValue = false
|
||||
case .authorizedAlways, .authorizedWhenInUse:
|
||||
mapLibreView.configuration.isLocationAuthorized.wrappedValue = true
|
||||
case .notDetermined:
|
||||
mapLibreView.configuration.isLocationAuthorized.wrappedValue = nil
|
||||
@unknown default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
func mapView(_ mapView: MLNMapView, regionDidChangeAnimated animated: Bool) {
|
||||
// While following a marker, don't flood the center binding with per-frame camera updates.
|
||||
// Leaving `lastReportedCenter` untouched avoids an external re-centering when following stops.
|
||||
guard mapLibreView.configuration.showsUserLocationMode.wrappedValue.followedMarkerID == nil else { return }
|
||||
|
||||
// Avoid `Publishing changes from within view update` warnings
|
||||
DispatchQueue.main.async { [mapLibreView, weak self] in
|
||||
let center = mapView.centerCoordinate
|
||||
self?.lastReportedCenter = center
|
||||
mapLibreView.configuration.mapCenterCoordinate.wrappedValue = center
|
||||
}
|
||||
}
|
||||
|
||||
func mapView(_ mapView: MLNMapView, shouldChangeFrom oldCamera: MLNMapCamera, to newCamera: MLNMapCamera, reason: MLNCameraChangeReason) -> Bool {
|
||||
// Send userDidPan only for gestures that actually change the map center. The reason
|
||||
// is an option set and gestures can come combined with other reasons, so check for
|
||||
// containment instead of an exact match.
|
||||
let centerChangingGestures: MLNCameraChangeReason = [.gesturePan, .gesturePinch, .gestureRotate]
|
||||
if !reason.isDisjoint(with: centerChangingGestures) {
|
||||
// Stop following immediately, the camera would fight the gesture otherwise.
|
||||
stopFollowingMarker()
|
||||
mapLibreView.configuration.userDidPan?()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// MARK: Callout
|
||||
|
||||
func mapView(_ mapView: MLNMapView, annotationCanShowCallout annotation: MLNAnnotation) -> Bool {
|
||||
false
|
||||
}
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private func updateGeolocationUncertainty(location: MLNUserLocation) {
|
||||
guard let clLocation = location.location, clLocation.horizontalAccuracy >= 0 else {
|
||||
mapLibreView.configuration.geolocationUncertainty.wrappedValue = nil
|
||||
return
|
||||
}
|
||||
|
||||
mapLibreView.configuration.geolocationUncertainty.wrappedValue = clLocation.horizontalAccuracy
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// Copyright 2026 Element Creations Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import MapLibre
|
||||
import MapLibreInterface
|
||||
import SwiftUI
|
||||
|
||||
/// The shim's entry point: the app looks this class up by name through the ObjC runtime
|
||||
/// after `dlopen`-ing the framework, keeping MapLibre off the app's launch path.
|
||||
@objc(MapLibreShim)
|
||||
public final class MapLibreShim: NSObject, MapLibreShimProtocol {
|
||||
public func configureLogging(_ handler: @escaping @Sendable (MapLogSeverity, String) -> Void) {
|
||||
MLNLoggingConfiguration.shared.loggingLevel = .debug
|
||||
MLNLoggingConfiguration.shared.handler = { loggingLevel, _, _, message in
|
||||
switch loggingLevel {
|
||||
case .error:
|
||||
handler(.error, message)
|
||||
case .warning:
|
||||
handler(.warning, message)
|
||||
case .info:
|
||||
handler(.info, message)
|
||||
case .debug:
|
||||
handler(.debug, message)
|
||||
case .verbose:
|
||||
handler(.verbose, message)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func makeMapView(configuration: MapViewConfiguration) -> AnyView {
|
||||
AnyView(MapLibreMapView(configuration: configuration))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
# The interactive map, split out of the app so MapLibre's static initialisers stay off the
|
||||
# launch path: the app links only the tiny MapLibreInterface framework, while MapLibreShim (the
|
||||
# only image linking MapLibre) is embedded unlinked and dlopen'd on first map use.
|
||||
name: MapLibreShim
|
||||
|
||||
targets:
|
||||
MapLibreShim:
|
||||
type: framework
|
||||
platform: iOS
|
||||
|
||||
settings:
|
||||
base:
|
||||
PRODUCT_BUNDLE_IDENTIFIER: $(BASE_BUNDLE_IDENTIFIER).maplibre-shim
|
||||
GENERATE_INFOPLIST_FILE: YES
|
||||
SWIFT_VERSION: 6.2
|
||||
SWIFT_APPROACHABLE_CONCURRENCY: YES
|
||||
SWIFT_DEFAULT_ACTOR_ISOLATION: MainActor
|
||||
|
||||
dependencies:
|
||||
- target: MapLibreInterface
|
||||
embed: false
|
||||
- package: MapLibre
|
||||
embed: false
|
||||
|
||||
sources:
|
||||
- path: ../Sources
|
||||
|
Before Width: | Height: | Size: 387 KiB After Width: | Height: | Size: 387 KiB |
|
Before Width: | Height: | Size: 572 B After Width: | Height: | Size: 572 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 818 B After Width: | Height: | Size: 818 B |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
@@ -1,52 +0,0 @@
|
||||
import Danger
|
||||
import Foundation
|
||||
|
||||
SwiftLint.lint(.modifiedAndCreatedFiles(directory: nil),
|
||||
inline: true,
|
||||
configFile: nil,
|
||||
strict: false,
|
||||
quiet: true,
|
||||
swiftlintPath: nil,
|
||||
markdownAction: { _ in })
|
||||
|
||||
let danger = Danger()
|
||||
|
||||
/// All of the new and modified files together.
|
||||
let editedFiles = danger.git.modifiedFiles + danger.git.createdFiles
|
||||
|
||||
// Warn when there is a big PR
|
||||
if (danger.github.pullRequest.additions ?? 0) > 1000 {
|
||||
warn("This pull request seems relatively large. Please consider splitting it into multiple smaller ones.")
|
||||
}
|
||||
|
||||
// Check that the PR has a description
|
||||
if danger.github.pullRequest.body?.isEmpty ?? true {
|
||||
warn("Please provide a description for this PR.")
|
||||
}
|
||||
|
||||
/// Check for screenshots on view changes
|
||||
let hasChangedViews = editedFiles.contains { $0.lowercased().contains("/view") }
|
||||
if hasChangedViews {
|
||||
if (danger.github.pullRequest.body?.contains("user-attachments") ?? false) == false {
|
||||
warn("You seem to have made changes to views. Please consider adding screenshots.")
|
||||
}
|
||||
}
|
||||
|
||||
/// Check for pngs on resources
|
||||
let hasPngs = editedFiles.contains { $0.lowercased().contains(".xcassets") && $0.lowercased().hasSuffix(".png") }
|
||||
if hasPngs {
|
||||
warn("You seem to have made changes to some resource images. Please consider using an SVG or PDF.")
|
||||
}
|
||||
|
||||
// Check for nice PR titles
|
||||
let prTitle = danger.github.pullRequest.title
|
||||
let fixesRegex = try! Regex("(Fixes|Fix) #\\d+")
|
||||
let semanticRegex = try! Regex("\\w+\\(\\w+\\):")
|
||||
if prTitle.hasSuffix("…") || prTitle.starts(with: fixesRegex) || prTitle.starts(with: semanticRegex) {
|
||||
fail("Please provide a complete title that can be used as a changelog entry.")
|
||||
}
|
||||
|
||||
// Check for changelog tags
|
||||
if danger.github.issue.labels.filter({ $0.name.hasPrefix("pr-") }).count != 1 {
|
||||
fail("Please add a `pr-` label to categorise the changelog entry.")
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:cc39671ee91a08779e4149589a4635fa6b91519b07bfb2dee621ccab031a75c5
|
||||
size 5825201
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"originHash" : "1c7d307d80ee561100a0432a5ae13f345392a1175c7f6c17c2eb0da269382c57",
|
||||
"originHash" : "f1791683f9f09408a7746ce0e163941b3ce7e83e84f1a73b2fecc2b5d2f2f4b6",
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "compound-design-tokens",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/element-hq/compound-design-tokens",
|
||||
"state" : {
|
||||
"revision" : "6e33c5bf3cbb4c29dbe5fc063d24b375849c0fac",
|
||||
"version" : "10.2.2"
|
||||
"revision" : "86c15ef71798581d1e0cc39a7f99e598ad572419",
|
||||
"version" : "11.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -60,8 +60,8 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/element-hq/element-call-swift",
|
||||
"state" : {
|
||||
"revision" : "d2ecef5a54e5718ed6344dde6f72a4da42f1fcd9",
|
||||
"version" : "0.20.2"
|
||||
"revision" : "13eac3567461a9825018e10e9f4475f68215dae7",
|
||||
"version" : "0.24.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -95,8 +95,8 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/onevcat/Kingfisher",
|
||||
"state" : {
|
||||
"revision" : "ac632bd26a1c00f139ff62fd01806f21cf67325e",
|
||||
"version" : "8.10.0"
|
||||
"revision" : "410984bf301f4fa224fe56277b3f8672cc465c79",
|
||||
"version" : "8.11.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -131,8 +131,8 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/guoyingtao/Mantis",
|
||||
"state" : {
|
||||
"revision" : "b3c237aff54b8307440157a2f5956bdea2e76791",
|
||||
"version" : "2.31.2"
|
||||
"revision" : "0960be1feed2e62f62a5fddbb8d72b26008db881",
|
||||
"version" : "3.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -140,8 +140,8 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/maplibre/maplibre-gl-native-distribution",
|
||||
"state" : {
|
||||
"revision" : "84a79bc375a301169390ac110c868f06c857b83f",
|
||||
"version" : "6.27.0"
|
||||
"revision" : "5ee345ca5d65238a6fce29bba87816204be7df20",
|
||||
"version" : "6.28.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -167,8 +167,8 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/element-hq/matrix-rust-components-swift",
|
||||
"state" : {
|
||||
"revision" : "24c26f6697e03e42d176c61b5923ac958f5fa32d",
|
||||
"version" : "26.7.3"
|
||||
"revision" : "56ec8d0458a688018bbd9f1f2fd70fae7919f415",
|
||||
"version" : "26.9.9"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -194,8 +194,8 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/PostHog/posthog-ios",
|
||||
"state" : {
|
||||
"revision" : "6e70aa24bbd3778182fe039f7f5800a17674a6d6",
|
||||
"version" : "3.61.1"
|
||||
"revision" : "c0218386c49115cce6b05a50b41f4f60bc995acb",
|
||||
"version" : "3.69.6"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -203,8 +203,8 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/getsentry/sentry-cocoa",
|
||||
"state" : {
|
||||
"revision" : "43abfbf9a26089ad34604c718ad0935440caf1d4",
|
||||
"version" : "9.18.0"
|
||||
"revision" : "cd213f98af160e6497eeff0707bc3f6a205b159c",
|
||||
"version" : "9.26.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -230,17 +230,8 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-async-algorithms",
|
||||
"state" : {
|
||||
"revision" : "d0b4a06d0f173a2f3be27d3ea21b3c3aa18db440",
|
||||
"version" : "1.1.4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-clocks",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/pointfreeco/swift-clocks",
|
||||
"state" : {
|
||||
"revision" : "72d749bf341b78851203066ab421869b783ec42a",
|
||||
"version" : "1.1.0"
|
||||
"revision" : "3da39bbc4e687d4192af7c9cf4eab805745a0b9c",
|
||||
"version" : "1.1.5"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -252,15 +243,6 @@
|
||||
"version" : "1.6.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-concurrency-extras",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/pointfreeco/swift-concurrency-extras",
|
||||
"state" : {
|
||||
"revision" : "5a3825302b1a0d744183200915a47b508c828e6f",
|
||||
"version" : "1.3.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-custom-dump",
|
||||
"kind" : "remoteSourceControl",
|
||||
@@ -293,8 +275,8 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/pointfreeco/swift-snapshot-testing",
|
||||
"state" : {
|
||||
"revision" : "ad5e3190cc63dc288f28546f9c6827efc1e9d495",
|
||||
"version" : "1.19.2"
|
||||
"revision" : "59a99c458de4d2dee580529b61b4f78dca7b7fa6",
|
||||
"version" : "1.19.4"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -311,8 +293,8 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/scinfu/SwiftSoup.git",
|
||||
"state" : {
|
||||
"revision" : "49dcadd93161f4a44b4994d3a3e8de9f085aface",
|
||||
"version" : "2.13.5"
|
||||
"revision" : "8d6ad267714cac3ae747cefdd21f7a6665006e1f",
|
||||
"version" : "2.13.7"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -329,8 +311,8 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/tevelee/SwiftUI-Flow.git",
|
||||
"state" : {
|
||||
"revision" : "798364823cdfc6afb4aff43eff5a3ddbca89b54f",
|
||||
"version" : "3.4.0"
|
||||
"revision" : "19e86b750b3c67260cbb28c459004c0dfdb11899",
|
||||
"version" : "3.5.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -338,8 +320,8 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/siteline/SwiftUI-Introspect",
|
||||
"state" : {
|
||||
"revision" : "26986a57e31c813f98262ddb62d4b07d40008535",
|
||||
"version" : "26.0.1"
|
||||
"revision" : "dd0888ef99d2809863b04e46cad52d1dfd8fc840",
|
||||
"version" : "26.0.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -87,6 +87,11 @@
|
||||
value = "localhost:9090"
|
||||
isEnabled = "NO">
|
||||
</EnvironmentVariable>
|
||||
<EnvironmentVariable
|
||||
key = "HTTP_PROXY"
|
||||
value = "localhost:9090"
|
||||
isEnabled = "NO">
|
||||
</EnvironmentVariable>
|
||||
<EnvironmentVariable
|
||||
key = "UI_TESTS_SCREEN"
|
||||
value = ""
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
"NSCameraUsageDescription" = "يحتاج Element X إلى الوصول إلى الكاميرا لالتقاط الصور أو مقاطع الفيديو وإرسالها كرسائل.";
|
||||
"NSFaceIDUsageDescription" = "يُستخدم Face ID لحماية الوصول إلى حسابك.";
|
||||
"NSLocationAlwaysAndWhenInUseUsageDescription" = "لمشاركة موقعك المباشر، يحتاج Element X إلى الوصول إلى الموقع عندما يكون التطبيق في الخلفية.";
|
||||
"NSLocationWhenInUseUsageDescription" = "امنح الوصول إلى الموقع حتى يتمكن Element X من مشاركة موقعك.";
|
||||
"NSMicrophoneUsageDescription" = "يحتاج Element X إلى الوصول إلى الميكروفون لتسجيل الرسائل الصوتية وإرسالها.";
|
||||
"NSPhotoLibraryUsageDescription" = "يتيح لك هذا حفظ الصور ومقاطع الفيديو في مكتبة الصور لديك.";
|
||||
@@ -0,0 +1,64 @@
|
||||
"aeroplane" = "طَائِرة";
|
||||
"anchor" = "مِرسَاة";
|
||||
"apple" = "تُفَّاحَة";
|
||||
"ball" = "كُرَة";
|
||||
"banana" = "مَوزَة";
|
||||
"bell" = "جَرَس";
|
||||
"bicycle" = "دَرّاجَة";
|
||||
"book" = "كِتَاب";
|
||||
"butterfly" = "فَرَاشَة";
|
||||
"cactus" = "صبار";
|
||||
"cake" = "كَعكَة";
|
||||
"cat" = "هِرَّة";
|
||||
"clock" = "سَاعَة";
|
||||
"cloud" = "سَحابَة";
|
||||
"corn" = "ذُرَة";
|
||||
"dog" = "كلب";
|
||||
"elephant" = "فِيل";
|
||||
"fire" = "نار";
|
||||
"fish" = "سَمَكة";
|
||||
"flag" = "عَلَم";
|
||||
"flower" = "زَهرَة";
|
||||
"folder" = "مُجَلَّد";
|
||||
"gift" = "هَدِيَّة";
|
||||
"glasses" = "نَظَّارَة";
|
||||
"globe" = "كُرَةٌ أرضِيَّة";
|
||||
"guitar" = "غيتار";
|
||||
"hammer" = "مِطرَقَة";
|
||||
"hat" = "قُبَّعَة";
|
||||
"headphones" = "سَمّاعَة رَأس";
|
||||
"heart" = "قَلب";
|
||||
"horse" = "حِصَان";
|
||||
"hourglass" = "سَاعَةٌ رَملِيَّة";
|
||||
"key" = "مِفتَاح";
|
||||
"light_bulb" = "مِصبَاح";
|
||||
"lion" = "أَسَد";
|
||||
"lock" = "قُفل";
|
||||
"moon" = "قَمَر";
|
||||
"mushroom" = "فُطر";
|
||||
"octopus" = "أُخطُبُوط";
|
||||
"panda" = "باندَا";
|
||||
"paperclip" = "مِشبَكُ وَرَق";
|
||||
"pencil" = "قَلَمُ رَصاص";
|
||||
"penguin" = "بطريق";
|
||||
"pig" = "خِنزِير";
|
||||
"pin" = "دَبُّوس";
|
||||
"pizza" = "بِيتزا";
|
||||
"rabbit" = "أَرنَب";
|
||||
"robot" = "رُوبُوت";
|
||||
"rocket" = "صَارُوخ";
|
||||
"rooster" = "دِيك";
|
||||
"santa" = "سانتا";
|
||||
"scissors" = "مِقَصّ";
|
||||
"smiley" = "اِبتِسَامَة";
|
||||
"spanner" = "مِفتَاحُ رَبط";
|
||||
"strawberry" = "فَراوِلَة";
|
||||
"telephone" = "تِلِفُون";
|
||||
"thumbs_up" = "رَفعُ إِبهَام";
|
||||
"train" = "قِطَار";
|
||||
"tree" = "شَجَرَة";
|
||||
"trophy" = "كَأسُ النَّصر";
|
||||
"trumpet" = "بُوق";
|
||||
"turtle" = "سُلحفاة";
|
||||
"umbrella" = "مِظَلَّة";
|
||||
"unicorn" = "حصان وحيد القرن";
|
||||
@@ -1,6 +1,6 @@
|
||||
"NSCameraUsageDescription" = "Каб зрабіць фота ці відэа і адправіць іх у выглядзе паведамлення, Element X патрабуе доступу да камеры.";
|
||||
"NSFaceIDUsageDescription" = "Face ID выкарыстоўваецца для доступу да праграмы.";
|
||||
"NSLocationAlwaysAndWhenInUseUsageDescription" = "To share your live location, Element X needs location access when the app is in the background.";
|
||||
"NSLocationAlwaysAndWhenInUseUsageDescription" = "To share your location live in chats, location access is needed when the app is in the background.";
|
||||
"NSLocationWhenInUseUsageDescription" = "Дайце доступ да месцазнаходжання, каб Element X мог падзяліцца вашым месцазнаходжаннем.";
|
||||
"NSMicrophoneUsageDescription" = "Каб запісваць і адпраўляць паведамленні з гукам, Element X патрабуе доступу да мікрафона.";
|
||||
"NSPhotoLibraryUsageDescription" = "Дазваляе захоўваць фатаграфіі і відэа ў вашу бібліятэку.";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"a11y_add_avatar" = "Add avatar";
|
||||
"a11y_add_avatar" = "Дадаць аватар";
|
||||
"a11y_add_reaction" = "Дадаць рэакцыю: %1$@";
|
||||
"a11y_address" = "Адрас";
|
||||
"a11y_avatar" = "Аватар";
|
||||
@@ -6,16 +6,23 @@
|
||||
"a11y_collapse_message_text_field" = "Minimise message text field";
|
||||
"a11y_create_poll_votes_allowed_decrease" = "Decrease votes allowed per person";
|
||||
"a11y_create_poll_votes_allowed_increase" = "Increase votes allowed per person";
|
||||
"a11y_custom_emoji" = "Custom emoji";
|
||||
"a11y_delete" = "Выдаліць";
|
||||
"a11y_duration" = "Duration: %1$@";
|
||||
"a11y_duration" = "Працягласць: %1$@";
|
||||
"a11y_edit_avatar" = "Змяніць аватар";
|
||||
"a11y_edit_room_address_hint" = "Поўны адрас будзе %1$@";
|
||||
"a11y_expand_message_text_field" = "Expand message text field";
|
||||
"a11y_gallery_attachment" = "Gallery, attachment %1$d";
|
||||
"a11y_gallery_failed_scan" = "Gallery, failed scan %1$d";
|
||||
"a11y_gallery_image" = "Gallery, image %1$d";
|
||||
"a11y_gallery_scanning" = "Gallery, scanning %1$d";
|
||||
"a11y_gallery_video" = "Gallery, video %1$d";
|
||||
"a11y_hide_password" = "Схаваць пароль";
|
||||
"a11y_info" = "Інфармацыя";
|
||||
"a11y_join_call" = "Далучыцца да выкліку";
|
||||
"a11y_jump_to_bottom" = "Перайсці ўніз";
|
||||
"a11y_jump_to_unread" = "Jump to unread";
|
||||
"a11y_jump_to_unread" = "Перайсці да непрачытаных";
|
||||
"a11y_jump_to_unread_messages" = "Jump to first unread message";
|
||||
"a11y_notifications_mentions_only" = "Толькі згадкі";
|
||||
"a11y_notifications_muted" = "Гук адключаны";
|
||||
"a11y_notifications_new_mentions" = "Новыя згадкі";
|
||||
@@ -33,7 +40,7 @@
|
||||
"a11y_poll_end" = "Апытанне скончана";
|
||||
"a11y_polls_will_remove_selection" = "Will remove previous selection";
|
||||
"a11y_polls_winning_answer" = "This is the winning answer";
|
||||
"a11y_position" = "Position: %1$@";
|
||||
"a11y_position" = "Пазіцыя: %1$@";
|
||||
"a11y_qr_code" = "QR-код";
|
||||
"a11y_react_with" = "Рэагаваць з %1$@";
|
||||
"a11y_react_with_other_emojis" = "Рэагаваць з іншымі эмодзі";
|
||||
@@ -50,6 +57,7 @@
|
||||
"a11y_start_call" = "Пазваніць";
|
||||
"a11y_start_video_call" = "Start a video call";
|
||||
"a11y_start_voice_call" = "Start a voice call";
|
||||
"a11y_status" = "Статус";
|
||||
"a11y_tombstoned_room" = "Tombstoned room";
|
||||
"a11y_user_menu" = "Меню карыстальніка";
|
||||
"a11y_video_preview" = "Video preview";
|
||||
@@ -75,7 +83,7 @@
|
||||
"action_call" = "Званок";
|
||||
"action_cancel" = "Скасаваць";
|
||||
"action_cancel_for_now" = "Адмяніць пакуль";
|
||||
"action_choose_file" = "Choose file";
|
||||
"action_choose_file" = "Выбраць файл";
|
||||
"action_choose_photo" = "Выбраць фота";
|
||||
"action_clear" = "Ачысціць";
|
||||
"action_close" = "Закрыць";
|
||||
@@ -90,7 +98,7 @@
|
||||
"action_copy_text" = "Скапіяваць тэкст";
|
||||
"action_create" = "Стварыць";
|
||||
"action_create_room" = "Стварыце пакой";
|
||||
"action_create_space" = "Create space";
|
||||
"action_create_space" = "Стварыць прастору";
|
||||
"action_deactivate" = "Дэактываваць";
|
||||
"action_deactivate_account" = "Дэактываваць уліковы запіс";
|
||||
"action_decline" = "Адхіліць";
|
||||
@@ -135,13 +143,14 @@
|
||||
"action_manage_account_and_devices" = "Manage account & devices";
|
||||
"action_manage_devices" = "Кіраванне прыладамі";
|
||||
"action_manage_rooms" = "Manage rooms";
|
||||
"action_mark_as_read" = "Пазначыць як прачытанае";
|
||||
"action_message" = "Паведамленне";
|
||||
"action_minimize" = "Minimise";
|
||||
"action_next" = "Далей";
|
||||
"action_no" = "Не";
|
||||
"action_not_now" = "Не зараз";
|
||||
"action_ok" = "Добра";
|
||||
"action_open_context_menu" = "Open context menu";
|
||||
"action_open_context_menu" = "Адкрыць кантэкстнае меню";
|
||||
"action_open_settings" = "Налады";
|
||||
"action_open_with" = "Адкрыць з дапамогай";
|
||||
"action_pin" = "Замацаваць";
|
||||
@@ -165,6 +174,7 @@
|
||||
"action_retry_decryption" = "Паўтарыць расшыфроўку";
|
||||
"action_save" = "Захаваць";
|
||||
"action_search" = "Пошук";
|
||||
"action_select" = "Select";
|
||||
"action_select_all" = "Выбраць усё";
|
||||
"action_send" = "Адправіць";
|
||||
"action_send_edited_message" = "Send edited message";
|
||||
@@ -209,7 +219,7 @@
|
||||
"call_invalid_audio_device_bluetooth_devices_disabled" = "Element Call does not support using Bluetooth audio devices in this Android version. Please select a different audio device.";
|
||||
"common_about" = "Аб праграме";
|
||||
"common_acceptable_use_policy" = "Палітыка дапушчальнага выкарыстання";
|
||||
"common_add_account" = "Add an account";
|
||||
"common_add_account" = "Дадаць уліковы запіс";
|
||||
"common_add_another_account" = "Add account";
|
||||
"common_adding_caption" = "Adding caption";
|
||||
"common_advanced_settings" = "Пашыраныя налады";
|
||||
@@ -230,15 +240,15 @@
|
||||
"common_copied_to_clipboard" = "Скапіравана ў буфер абмену";
|
||||
"common_copyright" = "Аўтарскае права";
|
||||
"common_creating_room" = "Стварэнне пакоя…";
|
||||
"common_creating_space" = "Creating space…";
|
||||
"common_creating_space" = "Стварэнне прасторы…";
|
||||
"common_current_user_canceled_knock" = "Request canceled";
|
||||
"common_current_user_left_room" = "Выйшаў з пакоя";
|
||||
"common_current_user_left_space" = "Left space";
|
||||
"common_current_user_rejected_invite" = "Invite declined";
|
||||
"common_date_date_at_time" = "%1$@ at %2$@";
|
||||
"common_date_date_at_time" = "%1$@ у %2$@";
|
||||
"common_date_this_month" = "This month";
|
||||
"common_decryption_error" = "Памылка расшыфроўкі";
|
||||
"common_description" = "Description";
|
||||
"common_description" = "Апісанне";
|
||||
"common_developer_options" = "Параметры распрацоўшчыка";
|
||||
"common_device_id" = "Device ID";
|
||||
"common_direct_chat" = "Прамы чат";
|
||||
@@ -249,7 +259,7 @@
|
||||
"common_editing" = "Рэдагаванне";
|
||||
"common_editing_caption" = "Editing caption";
|
||||
"common_emote" = "* %1$@ %2$@";
|
||||
"common_empty_file" = "Empty file";
|
||||
"common_empty_file" = "Пусты файл";
|
||||
"common_encryption" = "Encryption";
|
||||
"common_encryption_enabled" = "Шыфраванне ўключана";
|
||||
"common_ends_at" = "Ends at %1$@";
|
||||
@@ -261,11 +271,11 @@
|
||||
"common_favourite" = "Абраць";
|
||||
"common_favourited" = "Абранае";
|
||||
"common_file" = "Файл";
|
||||
"common_file_deleted" = "File deleted";
|
||||
"common_file_saved" = "File saved";
|
||||
"common_file_deleted" = "Файл выдалены";
|
||||
"common_file_saved" = "Файл захаваны";
|
||||
"common_forward_message" = "Перасылка паведамлення";
|
||||
"common_frequently_used" = "Frequently used";
|
||||
"common_gallery" = "Gallery";
|
||||
"common_gallery" = "Галерэя";
|
||||
"common_gif" = "GIF";
|
||||
"common_group_call_in_progress" = "Group call in progress";
|
||||
"common_image" = "Відарыс";
|
||||
@@ -294,6 +304,7 @@
|
||||
"common_no_space_name" = "No space name";
|
||||
"common_not_encrypted" = "Не зашыфравана";
|
||||
"common_offline" = "Па-за сеткай";
|
||||
"common_on_a_call" = "On a call";
|
||||
"common_open_source_licenses" = "Ліцэнзіі з адкрытым зыходным кодам";
|
||||
"common_optic_id_ios" = "Optic ID";
|
||||
"common_or" = "або";
|
||||
@@ -328,7 +339,7 @@
|
||||
"common_report_a_problem" = "Паведаміць аб праблеме";
|
||||
"common_report_submitted" = "Скарга прынята";
|
||||
"common_rich_text_editor" = "Рэдактар фарматаванага тэксту";
|
||||
"common_role" = "Role";
|
||||
"common_role" = "Роля";
|
||||
"common_room" = "Пакой";
|
||||
"common_room_name" = "Назва пакоя";
|
||||
"common_room_name_placeholder" = "напрыклад, назва вашага праекта";
|
||||
@@ -393,11 +404,11 @@
|
||||
"common_verify_identity" = "Verify identity";
|
||||
"common_verify_user" = "Verify user";
|
||||
"common_video" = "Відэа";
|
||||
"common_video_quality_high" = "High quality";
|
||||
"common_video_quality_high" = "Высокая якасць";
|
||||
"common_video_quality_high_description" = "Best quality but larger file size";
|
||||
"common_video_quality_low" = "Low quality";
|
||||
"common_video_quality_low" = "Нізкая якасць";
|
||||
"common_video_quality_low_description" = "Fastest upload speed and smallest file size";
|
||||
"common_video_quality_standard" = "Standard quality";
|
||||
"common_video_quality_standard" = "Стандартная якасць";
|
||||
"common_video_quality_standard_description" = "Balance of quality and upload speed";
|
||||
"common_voice_message" = "Галасавое паведамленне";
|
||||
"common_waiting" = "Чакаем…";
|
||||
@@ -410,7 +421,8 @@
|
||||
"confirm_recovery_key_banner_secondary_button_title" = "Forgot your recovery key?";
|
||||
"confirm_recovery_key_banner_title" = "Ваша сховішча ключоў не сінхранізавана";
|
||||
"content_scanner_not_found" = "Download not available.";
|
||||
"content_scanner_not_found_title" = "File not found";
|
||||
"content_scanner_not_found_title" = "Something went wrong";
|
||||
"content_scanner_scanning" = "Scanning…";
|
||||
"content_scanner_unsafe_message" = "Preview and download have been disabled.";
|
||||
"content_scanner_unsafe_title" = "The file is not safe";
|
||||
"crash_detection_dialog_content" = "Пры апошнім выкарыстанні %1$@ адбыўся збой. Хочаце абагуліць справаздачу аб збоі?";
|
||||
@@ -433,7 +445,7 @@
|
||||
"crypto_identity_change_profile_pin_violation" = "%1$@’s digital identity was reset.";
|
||||
"crypto_identity_change_verification_violation_new" = "%1$@’s %2$@ digital identity was reset. %3$@";
|
||||
"crypto_identity_change_withdraw_verification_action" = "Withdraw verification";
|
||||
"dialog_allow_access" = "Allow access";
|
||||
"dialog_allow_access" = "Дазволіць доступ";
|
||||
"dialog_confirm_link_message" = "The link %1$@ is taking you to another site %2$@\n\nAre you sure you want to continue?";
|
||||
"dialog_confirm_link_title" = "Double-check this link";
|
||||
"dialog_default_video_quality_selector_subtitle" = "Select the default quality of videos you upload.";
|
||||
@@ -484,6 +496,11 @@
|
||||
"error_no_compatible_app_found" = "Не знойдзена сумяшчальная праграма для выканання гэтага дзеяння.";
|
||||
"error_room_address_already_exists" = "This room address already exists. Please try editing the room address field or change the room name";
|
||||
"error_room_address_invalid_symbols" = "Some characters are not allowed. Only letters, digits and the following symbols are supported ! $ & ‘ ( ) * + / ; = ? @ [ ] - . _";
|
||||
"error_sending_failure_invalid_mime_type" = "Invalid mime type: %@";
|
||||
"error_sending_failure_missing_media_content" = "Missing media content";
|
||||
"error_sending_failure_other" = "Error details: %@";
|
||||
"error_sending_failure_sending_from_unverified_device" = "Sending from unverified device";
|
||||
"error_sending_failure_unknown" = "Unknown error";
|
||||
"error_some_messages_have_not_been_sent" = "Некаторыя паведамленні не былі адпраўлены";
|
||||
"error_unknown" = "Выбачце, адбылася памылка";
|
||||
"error.account_already_logged_in" = "You're already logged in on this device as %1$@.";
|
||||
@@ -513,6 +530,8 @@
|
||||
"notification_invitation_action_reject" = "Адхіліць";
|
||||
"notification_invite_body" = "Запрасіў(-ла) вас у чат";
|
||||
"notification_invite_body_with_sender" = "%1$@ запрасіў(-ла) вас у чат";
|
||||
"notification_knock_request_body" = "Requested to join";
|
||||
"notification_live_location_started_body" = "Started sharing their live location";
|
||||
"notification_mentioned_you_body" = "Згадаў(-ла) вас: %1$@";
|
||||
"notification_new_messages" = "Новыя паведамленні";
|
||||
"notification_reaction_body" = "Адрэагаваў(-ла) на %1$@";
|
||||
@@ -697,14 +716,22 @@
|
||||
"screen_change_server_error_element_pro_required_title" = "Element Pro required";
|
||||
"screen_change_server_error_invalid_homeserver" = "Нам не ўдалося звязацца з гэтым хатнім серверам. Упэўніцеся, што вы правільна ўвялі URL-адрас хатняга сервера. Калі URL-адрас пазначаны правільна, звярніцеся да адміністратара хатняга сервера за дадатковай дапамогай.";
|
||||
"screen_change_server_error_invalid_well_known" = "Sliding sync недаступны з-за праблемы ў вядомым файле:\n%1$@";
|
||||
"screen_change_server_error_no_sliding_sync_message" = "The selected account provider does not support sliding sync. An upgrade to the server is needed to use %1$@.";
|
||||
"screen_change_server_error_no_sliding_sync_message" = "The selected account provider does not support sliding sync. The server needs to be upgraded to use %1$@.";
|
||||
"screen_change_server_error_unauthorized_homeserver" = "%1$@ is not allowed to connect to %2$@.";
|
||||
"screen_change_server_error_unauthorized_homeserver_content" = "This app has been configured to allow: %1$@.";
|
||||
"screen_change_server_error_unauthorized_homeserver_title" = "Account provider %1$@ not allowed.";
|
||||
"screen_change_server_form_header" = "URL хатняга сервера";
|
||||
"screen_change_server_form_notice" = "Enter a domain address.";
|
||||
"screen_change_server_navigation_title_login" = "Sign in";
|
||||
"screen_change_server_navigation_title_register" = "Create account";
|
||||
"screen_change_server_subtitle" = "Які адрас вашага сервера?";
|
||||
"screen_change_server_textfield_footer_login" = "If your account is provided by your company or a community, then change the account provider (example: companyname.com).";
|
||||
"screen_change_server_textfield_footer_register" = "Create an account on matrix.org for free. If you want to create an account with a different provider, then change it accordingly (example: communityname.org).";
|
||||
"screen_change_server_textfield_header" = "Account provider";
|
||||
"screen_change_server_textfield_placeholder" = "example.com";
|
||||
"screen_change_server_title" = "Выберыце свой сервер";
|
||||
"screen_change_server_title_login" = "Enter your account provider";
|
||||
"screen_change_server_title_register" = "Choose an account provider";
|
||||
"screen_chat_backup_key_backup_action_disable" = "Выключыць рэзервовае капіраванне";
|
||||
"screen_chat_backup_key_backup_action_enable" = "Уключыце рэзервовае капіраванне";
|
||||
"screen_chat_backup_key_backup_description" = "Надзейна захоўвайце вашу крыптаграфічную ідэнтыфікацыю і ключы паведамленняў на серверы. Гэта дазволіць вам праглядаць гісторыю паведамленняў на любых новых прыладах.%1$@ .";
|
||||
@@ -751,7 +778,7 @@
|
||||
"screen_create_room_private_option_description" = "Толькі запрошаныя людзі могуць атрымаць доступ да гэтага пакоя. Усе паведамленні абаронены end-to-end шыфраваннем.";
|
||||
"screen_create_room_private_option_title" = "Private";
|
||||
"screen_create_room_public_option_description" = "Любы можа знайсці гэты пакой. \nВы можаце змяніць гэта ў любы час у наладах пакоя.";
|
||||
"screen_create_room_public_option_short_description" = "Anyone can join.";
|
||||
"screen_create_room_public_option_short_description" = "Anyone can join, including people outside your organisation.";
|
||||
"screen_create_room_public_option_title" = "Public";
|
||||
"screen_create_room_room_access_section_knocking_option_description" = "Anyone can ask to join but an administrator or a moderator must accept the request.";
|
||||
"screen_create_room_room_access_section_knocking_option_title" = "Папрасіце далучыцца";
|
||||
@@ -759,7 +786,7 @@
|
||||
"screen_create_room_room_access_section_knocking_restricted_option_title" = "Ask to join";
|
||||
"screen_create_room_room_access_section_private_option_description" = "Only people invited can join.";
|
||||
"screen_create_room_room_access_section_private_option_title" = "Private";
|
||||
"screen_create_room_room_access_section_public_option_description" = "Anyone can join.";
|
||||
"screen_create_room_room_access_section_public_option_description" = "Anyone can join, including people outside your organisation.";
|
||||
"screen_create_room_room_access_section_public_option_title" = "Public";
|
||||
"screen_create_room_room_access_section_restricted_option_description" = "Anyone in %1$@ can join.";
|
||||
"screen_create_room_room_access_section_restricted_option_title" = "Standard";
|
||||
@@ -924,6 +951,10 @@
|
||||
"screen_knock_requests_list_empty_state_title" = "No pending request to join";
|
||||
"screen_knock_requests_list_initial_loading_title" = "Loading requests to join…";
|
||||
"screen_knock_requests_list_title" = "Requests to join";
|
||||
"screen_labs_enable_gallery" = "Gallery messages";
|
||||
"screen_labs_enable_gallery_description" = "Send multiple images or videos in one go. Stable on mobile, but not yet supported by web.";
|
||||
"screen_labs_enable_knocking" = "Ask to join";
|
||||
"screen_labs_enable_knocking_description" = "Users can request access to a room that is not open for anyone to join. Stable on mobile, web implementation exists but is experimental.";
|
||||
"screen_labs_enable_threads" = "Enable thread replies";
|
||||
"screen_labs_enable_threads_description" = "The app will restart to apply this change.";
|
||||
"screen_labs_header_description" = "Try out our latest ideas in development. These features are not finalised; they may be unstable, may change.";
|
||||
@@ -932,11 +963,11 @@
|
||||
"screen_leave_space_choose_owners_action" = "Choose owners";
|
||||
"screen_leave_space_last_admin_info" = "%1$@ (Admin)";
|
||||
"screen_leave_space_subtitle" = "Select the rooms you’d like to leave which you're not the only administrator for:";
|
||||
"screen_leave_space_subtitle_last_admin" = "You need to assign another admin for this space before you can leave.";
|
||||
"screen_leave_space_subtitle_last_admin" = "You need to assign another administrator for this space before you can leave.";
|
||||
"screen_leave_space_subtitle_last_owner" = "You are the only owner of %1$@. You need to transfer ownership to someone else before you leave.";
|
||||
"screen_leave_space_subtitle_only_last_admin" = "You will not be removed from the following room(s) because you're the only administrator:";
|
||||
"screen_leave_space_title" = "Leave %1$@?";
|
||||
"screen_leave_space_title_last_admin" = "You are the only admin for %1$@";
|
||||
"screen_leave_space_title_last_admin" = "You are the only administrator for %1$@";
|
||||
"screen_leave_space_title_last_owner" = "Transfer ownership";
|
||||
"screen_link_new_device_authentication_reason_ios" = "Confirm it's you before linking a new device.";
|
||||
"screen_link_new_device_desktop_scanning_title" = "Сканіраваць QR-код";
|
||||
@@ -944,6 +975,7 @@
|
||||
"screen_link_new_device_desktop_step3" = "Адсканіруйце QR-код з дапамогай гэтай прылады";
|
||||
"screen_link_new_device_desktop_submit" = "Гатовы да сканіравання";
|
||||
"screen_link_new_device_desktop_title" = "Open %1$@ on a desktop computer to get the QR code";
|
||||
"screen_link_new_device_desktop_warning" = "Only scan a QR code after following the steps above on your own device. Never scan a code sent by another person.";
|
||||
"screen_link_new_device_enter_number_error_numbers_do_not_match" = "The numbers don’t match";
|
||||
"screen_link_new_device_enter_number_notice" = "Enter 2-digit code";
|
||||
"screen_link_new_device_enter_number_subtitle" = "This will verify that the connection to your other device is secure.";
|
||||
@@ -970,6 +1002,8 @@
|
||||
"screen_live_location_sheet_nobody_sharing" = "Nobody is sharing their location";
|
||||
"screen_live_location_sheet_sharing_live_location" = "Sharing live location";
|
||||
"screen_live_location_sheet_title" = "On the map";
|
||||
"screen_local_network_opt_in_subtitle" = "Your homeserver is on your local network. To connect, %1$@ needs permission to reach devices on this network.";
|
||||
"screen_local_network_opt_in_title" = "Allow access to local network";
|
||||
"screen_login_error_deactivated_account" = "Гэты ўліковы запіс быў выдалены.";
|
||||
"screen_login_error_invalid_credentials" = "Няправільнае імя карыстальніка і/або пароль";
|
||||
"screen_login_error_invalid_user_id" = "Гэта несапраўдны ідэнтыфікатар карыстальніка. Чаканы фармат: ‘@user:homeserver.org’";
|
||||
@@ -1020,7 +1054,7 @@
|
||||
"screen_missing_key_backup_open_element_classic" = "Open Element Classic";
|
||||
"screen_missing_key_backup_step_1" = "Open Element Classic on your device";
|
||||
"screen_missing_key_backup_step_2_ios" = "Go to User settings > Security";
|
||||
"screen_missing_key_backup_step_3_ios" = "Scroll down to Secure Backup and tap on Set up";
|
||||
"screen_missing_key_backup_step_3_ios" = "Scroll down to Chat Backup and tap on Set up";
|
||||
"screen_missing_key_backup_step_4" = "Follow the instructions to enable your key storage";
|
||||
"screen_missing_key_backup_step_5" = "Come back to %1$@";
|
||||
"screen_missing_key_backup_title" = "Enable your key storage before proceeding to %1$@";
|
||||
@@ -1189,7 +1223,7 @@
|
||||
"screen_report_content_hint" = "Прычына, па якой вы паскардзіліся на гэты змест";
|
||||
"screen_report_room_leave_failed_alert_message" = "Your report was submitted successfully, but we encountered an issue while trying to leave the room. Please try again.";
|
||||
"screen_report_room_leave_failed_alert_title" = "Unable to Leave Room";
|
||||
"screen_report_room_reason_footer" = "Report this room to your admin. If the messages are encrypted, your admin will not be able to read them.";
|
||||
"screen_report_room_reason_footer" = "Report this chat to your account provider. If the messages are encrypted, your account provider will not be able to read them.";
|
||||
"screen_report_room_reason_placeholder" = "Describe the reason to report…";
|
||||
"screen_report_room_title" = "Report room";
|
||||
"screen_reset_encryption_confirmation_alert_action" = "Так, скінуць зараз";
|
||||
@@ -1256,6 +1290,10 @@
|
||||
"screen_room_change_role_section_users" = "Удзельнікі";
|
||||
"screen_room_change_role_unsaved_changes_description" = "У вас ёсць незахаваныя змены.";
|
||||
"screen_room_change_role_unsaved_changes_title" = "Захаваць змены?";
|
||||
"screen_room_confirm_removal_message" = "Are you sure you wish to remove this message?";
|
||||
"screen_room_confirm_removal_reason_label" = "Reason (optional)";
|
||||
"screen_room_confirm_removal_reason_placeholder" = "Enter…";
|
||||
"screen_room_confirm_removal_title" = "Confirm removal";
|
||||
"screen_room_details_add_topic_title" = "Дадаць тэму";
|
||||
"screen_room_details_badge_encrypted" = "Зашыфраваны";
|
||||
"screen_room_details_badge_not_encrypted" = "Не зашыфраваны";
|
||||
@@ -1301,6 +1339,7 @@
|
||||
"screen_room_invite_again_alert_message" = "Вы хочаце запрасіць іх назад?";
|
||||
"screen_room_invite_again_alert_title" = "Вы адзін у гэтым чаце";
|
||||
"screen_room_live_location_banner" = "Sharing live location";
|
||||
"screen_room_maximum_messages_selected" = "Maximum messages selected";
|
||||
"screen_room_member_details_block_alert_action" = "Заблакіраваць";
|
||||
"screen_room_member_details_block_alert_description" = "Заблакіраваныя карыстальнікі не змогуць адпраўляць вам паведамленні, і ўсе іх паведамленні будуць схаваны. Вы можаце разблакіраваць іх у любы час.";
|
||||
"screen_room_member_details_block_user" = "Заблакіраваць карыстальніка";
|
||||
@@ -1341,7 +1380,8 @@
|
||||
"screen_room_notification_settings_error_setting_mode" = "Не ўдалося наладзіць рэжым, паспрабуйце яшчэ раз.";
|
||||
"screen_room_notification_settings_mentions_only_disclaimer" = "Ваш хатні сервер не падтрымлівае гэту опцыю ў зашыфраваных пакоях, вы не атрымаеце апавяшчэнне ў гэтым пакоі.";
|
||||
"screen_room_notification_settings_mode_all_messages" = "Усе паведамленні";
|
||||
"screen_room_notification_settings_mode_mentions_and_keywords" = "Толькі згадванні і ключавыя словы";
|
||||
"screen_room_notification_settings_mode_mentions_and_keywords" = "Mentions and replies only";
|
||||
"screen_room_notification_settings_mode_mute" = "Mute";
|
||||
"screen_room_notification_settings_room_custom_settings_title" = "У гэтым пакоі паведаміце мяне пра";
|
||||
"screen_room_pinned_banner_indicator" = "%1$@ з %2$@";
|
||||
"screen_room_pinned_banner_indicator_description" = "%1$@ Замацаваныя паведамленні";
|
||||
@@ -1402,6 +1442,8 @@
|
||||
"screen_roomlist_filter_invites_empty_state_title" = "У вас няма непрынятых запрашэнняў.";
|
||||
"screen_roomlist_filter_low_priority" = "Нізкі прыярытэт";
|
||||
"screen_roomlist_filter_low_priority_empty_state_title" = "You don’t have any low priority chats yet";
|
||||
"screen_roomlist_filter_mention" = "Mention";
|
||||
"screen_roomlist_filter_mention_empty_state_title" = "You don’t have any unread mentions";
|
||||
"screen_roomlist_filter_mixed_empty_state_subtitle" = "Вы можаце прыбраць фільтры, каб убачыць іншыя вашыя чаты.";
|
||||
"screen_roomlist_filter_mixed_empty_state_title" = "У вас няма чатаў для гэтай катэгорыі";
|
||||
"screen_roomlist_filter_people" = "Людзі";
|
||||
@@ -1427,7 +1469,7 @@
|
||||
"screen_security_and_privacy_encryption_section_footer" = "Once enabled, encryption cannot be disabled.";
|
||||
"screen_security_and_privacy_encryption_section_header" = "Encryption";
|
||||
"screen_security_and_privacy_encryption_toggle_title" = "Enable end-to-end encryption";
|
||||
"screen_security_and_privacy_room_access_anyone_option_description" = "Anyone can join.";
|
||||
"screen_security_and_privacy_room_access_anyone_option_description" = "Anyone can join, including people outside your organisation.";
|
||||
"screen_security_and_privacy_room_access_anyone_option_title" = "Anyone";
|
||||
"screen_security_and_privacy_room_access_footer" = "Choose which spaces’ members can join this room without an invitation. %1$@";
|
||||
"screen_security_and_privacy_room_access_footer_manage_spaces_action" = "Manage spaces";
|
||||
@@ -1488,6 +1530,8 @@
|
||||
"screen_session_verification_request_title" = "Verification requested";
|
||||
"screen_session_verification_they_dont_match" = "Яны не супадаюць";
|
||||
"screen_session_verification_they_match" = "Яны супадаюць";
|
||||
"screen_session_verification_unavailable_subtitle" = "Please use another device or recovery key.";
|
||||
"screen_session_verification_unavailable_title" = "Verification with this device is currently unavailable";
|
||||
"screen_session_verification_use_another_device_subtitle" = "Make sure you have the app open in the other device before starting verification from here.";
|
||||
"screen_session_verification_use_another_device_title" = "Open the app on another verified device";
|
||||
"screen_session_verification_user_initiator_subtitle" = "For extra security, verify this user by comparing a set of emojis on your devices. Do this by using a trusted way to communicate.";
|
||||
@@ -1500,6 +1544,14 @@
|
||||
"screen_session_verification_waiting_subtitle" = "Once accepted you’ll be able to continue with the verification.";
|
||||
"screen_session_verification_waiting_to_accept_subtitle" = "Для працягу працы прыміце запыт на запуск працэсу праверкі ў іншым сеансе.";
|
||||
"screen_session_verification_waiting_to_accept_title" = "Чаканне прыняцця запыту";
|
||||
"screen_settings_user_status_away" = "Away";
|
||||
"screen_settings_user_status_be_right_back" = "Be right back";
|
||||
"screen_settings_user_status_custom" = "Custom…";
|
||||
"screen_settings_user_status_custom_hint" = "Custom status…";
|
||||
"screen_settings_user_status_focus_time" = "Focus time";
|
||||
"screen_settings_user_status_in_a_meeting" = "In a meeting";
|
||||
"screen_settings_user_status_on_the_road" = "On the road";
|
||||
"screen_settings_user_status_placeholder" = "What's your status?";
|
||||
"screen_share_location_live_location_disclaimer_title" = "Your live location history will be stored in the room and visible to members after the session ends.";
|
||||
"screen_share_location_live_location_duration_picker_title" = "Choose how long to share your live location.";
|
||||
"screen_share_location_live_location_missing_permissions" = "You do not have permissions to share your live location in this room";
|
||||
@@ -1539,7 +1591,7 @@
|
||||
"screen_space_list_parent_space" = "%1$@ space";
|
||||
"screen_space_list_title" = "Прасторы";
|
||||
"screen_space_menu_action_members" = "View members";
|
||||
"screen_space_remove_rooms_confirmation_content" = "Removing a room will not affect the room access. To change the access go to Room info > Privacy & security.";
|
||||
"screen_space_remove_rooms_confirmation_content" = "Removing a room will not affect the room access. To change the access go to Room info > Security & privacy.";
|
||||
"screen_space_remove_rooms_confirmation_title_ios" = "Remove rooms from %1$@?";
|
||||
"screen_space_settings_leave_space" = "Пакінуць прастору";
|
||||
"screen_space_settings_roles_and_permissions" = "Ролі і дазволы";
|
||||
@@ -1690,6 +1742,7 @@
|
||||
"troubleshoot_notifications_test_push_loop_back_failure_2" = "Памылка: %1$@.";
|
||||
"troubleshoot_notifications_test_push_loop_back_failure_3" = "Памылка, немагчыма праверыць push-апавяшчэнне.";
|
||||
"troubleshoot_notifications_test_push_loop_back_failure_4" = "Памылка, тайм-аўт у чаканні push-апавяшчэння.";
|
||||
"troubleshoot_notifications_test_push_loop_back_failure_rate_limit" = "Error: the push gateway is rate limiting this device, so notifications won't be reliable. Please set up a different push gateway.";
|
||||
"troubleshoot_notifications_test_push_loop_back_success" = "Зварот цыклу назад заняў %1$d мс.";
|
||||
"troubleshoot_notifications_test_push_loop_back_title" = "Тэст Націсніце кнопку вярнуцца";
|
||||
"troubleshoot_notifications_test_unified_push_description" = "Пераканайцеся, што размеркавальнікі UnifiedPush даступныя.";
|
||||
|
||||
@@ -20,6 +20,22 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>a11y_gallery_more_media</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Gallery, %1$d more media</string>
|
||||
<key>other</key>
|
||||
<string>Gallery, %1$d more medias</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>a11y_polls_percent_of_total</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -54,6 +70,38 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>common_gallery_reply_attachments</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%1$d attachment…</string>
|
||||
<key>other</key>
|
||||
<string>%1$d attachments…</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>common_gallery_reply_media_items</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%1$d media item…</string>
|
||||
<key>other</key>
|
||||
<string>%1$d media items…</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>common_many_members</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -224,6 +272,22 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>notification_gallery_body</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Shared %1$d attachment</string>
|
||||
<key>other</key>
|
||||
<string>Shared %1$d attachments</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>notification_invitations</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -296,6 +360,22 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen.room.timeline_redacted_messages</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%1$d removed message</string>
|
||||
<key>other</key>
|
||||
<string>%1$d removed messages</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen_advanced_settings_live_location_update_distance</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -496,6 +576,22 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen_room_selection_count</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%1$d message selected</string>
|
||||
<key>other</key>
|
||||
<string>%1$d messages selected</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen_room_timeline_reaction_a11y</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -598,7 +694,7 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen_timeline_active_call_extra_joined_count</key>
|
||||
<key>screen_timeline_active_call_joined_count</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
@@ -607,9 +703,9 @@
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>+ %1$d joined</string>
|
||||
<string>%1$d joined</string>
|
||||
<key>other</key>
|
||||
<string>+ %1$d joined</string>
|
||||
<string>%1$d joined</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"NSCameraUsageDescription" = "За да правите снимки или видеа и да ги изпращате като съобщение, Element X се нуждае от достъп до камерата.";
|
||||
"NSFaceIDUsageDescription" = "Face ID is used to protect access to your account.";
|
||||
"NSLocationAlwaysAndWhenInUseUsageDescription" = "To share your live location, Element X needs location access when the app is in the background.";
|
||||
"NSLocationAlwaysAndWhenInUseUsageDescription" = "To share your location live in chats, location access is needed when the app is in the background.";
|
||||
"NSLocationWhenInUseUsageDescription" = "Предоставете достъп до местоположението, за да може Element X да споделя местоположението ви.";
|
||||
"NSMicrophoneUsageDescription" = "За да записвате и изпращате съобщения с аудио, Element X се нуждае от достъп до микрофона.";
|
||||
"NSPhotoLibraryUsageDescription" = "This lets you save images and videos to your photo library.";
|
||||
|
||||
@@ -6,16 +6,23 @@
|
||||
"a11y_collapse_message_text_field" = "Minimise message text field";
|
||||
"a11y_create_poll_votes_allowed_decrease" = "Decrease votes allowed per person";
|
||||
"a11y_create_poll_votes_allowed_increase" = "Increase votes allowed per person";
|
||||
"a11y_custom_emoji" = "Custom emoji";
|
||||
"a11y_delete" = "Изтриване";
|
||||
"a11y_duration" = "Duration: %1$@";
|
||||
"a11y_edit_avatar" = "Edit avatar";
|
||||
"a11y_edit_room_address_hint" = "Пълният адрес ще бъде %1$@";
|
||||
"a11y_expand_message_text_field" = "Expand message text field";
|
||||
"a11y_gallery_attachment" = "Gallery, attachment %1$d";
|
||||
"a11y_gallery_failed_scan" = "Gallery, failed scan %1$d";
|
||||
"a11y_gallery_image" = "Gallery, image %1$d";
|
||||
"a11y_gallery_scanning" = "Gallery, scanning %1$d";
|
||||
"a11y_gallery_video" = "Gallery, video %1$d";
|
||||
"a11y_hide_password" = "Скриване на паролата";
|
||||
"a11y_info" = "Info";
|
||||
"a11y_join_call" = "Присъединяване към обаждане";
|
||||
"a11y_jump_to_bottom" = "Скок към най-долу";
|
||||
"a11y_jump_to_unread" = "Jump to unread";
|
||||
"a11y_jump_to_unread_messages" = "Jump to first unread message";
|
||||
"a11y_notifications_mentions_only" = "Само споменавания";
|
||||
"a11y_notifications_muted" = "Заглушено";
|
||||
"a11y_notifications_new_mentions" = "Нови споменавания";
|
||||
@@ -50,6 +57,7 @@
|
||||
"a11y_start_call" = "Започнете обаждане";
|
||||
"a11y_start_video_call" = "Start a video call";
|
||||
"a11y_start_voice_call" = "Start a voice call";
|
||||
"a11y_status" = "Status";
|
||||
"a11y_tombstoned_room" = "Tombstoned room";
|
||||
"a11y_user_menu" = "Потребителско меню";
|
||||
"a11y_video_preview" = "Video preview";
|
||||
@@ -135,6 +143,7 @@
|
||||
"action_manage_account_and_devices" = "Manage account & devices";
|
||||
"action_manage_devices" = "Управление на устройствата";
|
||||
"action_manage_rooms" = "Manage rooms";
|
||||
"action_mark_as_read" = "Mark as read";
|
||||
"action_message" = "Съобщение";
|
||||
"action_minimize" = "Minimise";
|
||||
"action_next" = "Напред";
|
||||
@@ -165,6 +174,7 @@
|
||||
"action_retry_decryption" = "Повторен опит за разшифроване";
|
||||
"action_save" = "Запазване";
|
||||
"action_search" = "Търсене";
|
||||
"action_select" = "Select";
|
||||
"action_select_all" = "Select all";
|
||||
"action_send" = "Изпращане";
|
||||
"action_send_edited_message" = "Send edited message";
|
||||
@@ -199,7 +209,7 @@
|
||||
"banner_migrate_to_native_sliding_sync_action" = "Log Out & Upgrade";
|
||||
"banner_migrate_to_native_sliding_sync_app_force_logout_title" = "%1$@ no longer supports the old protocol. Please log out and log back in to continue using the app.";
|
||||
"banner_migrate_to_native_sliding_sync_description" = "Your server now supports a new, faster protocol. Log out and log back in to upgrade now. Doing this now will help you avoid a forced logout when the old protocol is removed later.";
|
||||
"banner_migrate_to_native_sliding_sync_force_logout_title" = "Your homeserver no longer supports the old protocol. Please log out and log back in to continue using the app.";
|
||||
"banner_migrate_to_native_sliding_sync_force_logout_title" = "Your account provider no longer supports the old protocol. Please sign out and sign back in to continue using the app.";
|
||||
"banner_migrate_to_native_sliding_sync_title" = "Upgrade available";
|
||||
"banner_new_sound_message" = "Your notification ping has been updated—clearer, quicker, and less disruptive.";
|
||||
"banner_new_sound_title" = "We’ve refreshed your sounds";
|
||||
@@ -294,6 +304,7 @@
|
||||
"common_no_space_name" = "Няма име на пространство";
|
||||
"common_not_encrypted" = "Без шифроване";
|
||||
"common_offline" = "Офлайн";
|
||||
"common_on_a_call" = "On a call";
|
||||
"common_open_source_licenses" = "Лицензи за отворен код";
|
||||
"common_optic_id_ios" = "Optic ID";
|
||||
"common_or" = "или";
|
||||
@@ -410,7 +421,8 @@
|
||||
"confirm_recovery_key_banner_secondary_button_title" = "Forgot your recovery key?";
|
||||
"confirm_recovery_key_banner_title" = "Хранилището ви за ключове не е синхронизирано";
|
||||
"content_scanner_not_found" = "Download not available.";
|
||||
"content_scanner_not_found_title" = "File not found";
|
||||
"content_scanner_not_found_title" = "Something went wrong";
|
||||
"content_scanner_scanning" = "Scanning…";
|
||||
"content_scanner_unsafe_message" = "Preview and download have been disabled.";
|
||||
"content_scanner_unsafe_title" = "The file is not safe";
|
||||
"crash_detection_dialog_content" = "%1$@ се срина при последното използване. Искате ли да споделите доклад за срива с нас?";
|
||||
@@ -472,7 +484,7 @@
|
||||
"emoji_picker_category_recent" = "Recent emojis";
|
||||
"emoji_picker_category_symbols" = "Символи";
|
||||
"emoji_picker_search_placeholder" = "Search emojis";
|
||||
"error_account_creation_not_possible" = "Your homeserver needs to be upgraded to support Matrix Authentication Service and account creation.";
|
||||
"error_account_creation_not_possible" = "Your account provider needs to be upgraded to support Matrix Authentication Service and account creation.";
|
||||
"error_failed_creating_the_permalink" = "Неуспешно създаване на постоянна връзка";
|
||||
"error_failed_loading_map" = "%1$@ не успя да зареди картата. Моля, опитайте отново по-късно.";
|
||||
"error_failed_loading_messages" = "Неуспешно зареждане на съобщения";
|
||||
@@ -484,6 +496,11 @@
|
||||
"error_no_compatible_app_found" = "No compatible app was found to handle this action.";
|
||||
"error_room_address_already_exists" = "This room address already exists. Please try editing the room address field or change the room name";
|
||||
"error_room_address_invalid_symbols" = "Some characters are not allowed. Only letters, digits and the following symbols are supported ! $ & ‘ ( ) * + / ; = ? @ [ ] - . _";
|
||||
"error_sending_failure_invalid_mime_type" = "Invalid mime type: %@";
|
||||
"error_sending_failure_missing_media_content" = "Missing media content";
|
||||
"error_sending_failure_other" = "Error details: %@";
|
||||
"error_sending_failure_sending_from_unverified_device" = "Sending from unverified device";
|
||||
"error_sending_failure_unknown" = "Unknown error";
|
||||
"error_some_messages_have_not_been_sent" = "Някои съобщения не са изпратени";
|
||||
"error_unknown" = "Съжаляваме, възникна грешка";
|
||||
"error.account_already_logged_in" = "You're already logged in on this device as %1$@.";
|
||||
@@ -513,6 +530,8 @@
|
||||
"notification_invitation_action_reject" = "Reject";
|
||||
"notification_invite_body" = "Поканиха ви за чат";
|
||||
"notification_invite_body_with_sender" = "%1$@ invited you to chat";
|
||||
"notification_knock_request_body" = "Requested to join";
|
||||
"notification_live_location_started_body" = "Started sharing their live location";
|
||||
"notification_mentioned_you_body" = "Ви спомена: %1$@";
|
||||
"notification_new_messages" = "Нови съобщения";
|
||||
"notification_reaction_body" = "Реагира с %1$@";
|
||||
@@ -697,14 +716,22 @@
|
||||
"screen_change_server_error_element_pro_required_title" = "Element Pro required";
|
||||
"screen_change_server_error_invalid_homeserver" = "Не можахме да достигнем този сървър. Моля, проверете дали сте въвели правилно URL адреса на сървъра. Ако URL адресът е правилен, свържете се с администратора на вашия сървър за допълнителна помощ.";
|
||||
"screen_change_server_error_invalid_well_known" = "Server isn't available due to an issue in the .well-known file:\n%1$@";
|
||||
"screen_change_server_error_no_sliding_sync_message" = "The selected account provider does not support sliding sync. An upgrade to the server is needed to use %1$@.";
|
||||
"screen_change_server_error_no_sliding_sync_message" = "The selected account provider does not support sliding sync. The server needs to be upgraded to use %1$@.";
|
||||
"screen_change_server_error_unauthorized_homeserver" = "%1$@ is not allowed to connect to %2$@.";
|
||||
"screen_change_server_error_unauthorized_homeserver_content" = "This app has been configured to allow: %1$@.";
|
||||
"screen_change_server_error_unauthorized_homeserver_title" = "Account provider %1$@ not allowed.";
|
||||
"screen_change_server_form_header" = "URL адрес на сървъра";
|
||||
"screen_change_server_form_notice" = "Enter a domain address.";
|
||||
"screen_change_server_navigation_title_login" = "Sign in";
|
||||
"screen_change_server_navigation_title_register" = "Create account";
|
||||
"screen_change_server_subtitle" = "Какъв е адресът на вашия сървър?";
|
||||
"screen_change_server_textfield_footer_login" = "If your account is provided by your company or a community, then change the account provider (example: companyname.com).";
|
||||
"screen_change_server_textfield_footer_register" = "Create an account on matrix.org for free. If you want to create an account with a different provider, then change it accordingly (example: communityname.org).";
|
||||
"screen_change_server_textfield_header" = "Account provider";
|
||||
"screen_change_server_textfield_placeholder" = "example.com";
|
||||
"screen_change_server_title" = "Изберете своя сървър";
|
||||
"screen_change_server_title_login" = "Enter your account provider";
|
||||
"screen_change_server_title_register" = "Choose an account provider";
|
||||
"screen_chat_backup_key_backup_action_disable" = "Изтриване на хранилището за ключове";
|
||||
"screen_chat_backup_key_backup_action_enable" = "Включване на резервните копия";
|
||||
"screen_chat_backup_key_backup_description" = "Съхранявайте сигурно криптографската си самоличност и ключовете за съобщения на сървъра. Това ще ви позволи да преглеждате историята на съобщенията си на всички нови устройства.%1$@ .";
|
||||
@@ -719,7 +746,7 @@
|
||||
"screen_chat_backup_recovery_action_setup" = "Get recovery key";
|
||||
"screen_chat_backup_recovery_action_setup_description" = "Your chats are automatically backed up with end-to-end encryption. To restore this backup and retain your digital identity when you lose access to all your devices, you will need your recovery key.";
|
||||
"screen_create_account_title" = "Създаване на акаунт";
|
||||
"screen_create_new_recovery_key_list_item_1" = "Open %1$@ in a desktop device";
|
||||
"screen_create_new_recovery_key_list_item_1" = "Open %1$@ on a desktop device";
|
||||
"screen_create_new_recovery_key_list_item_2" = "Sign into your account again";
|
||||
"screen_create_new_recovery_key_list_item_3" = "When asked to verify your device, select %1$@";
|
||||
"screen_create_new_recovery_key_list_item_3_reset_all" = "“Reset all”";
|
||||
@@ -751,7 +778,7 @@
|
||||
"screen_create_room_private_option_description" = "Само поканени хора имат достъп до тази стая. Всички съобщения са шифровани от край до край.";
|
||||
"screen_create_room_private_option_title" = "Private";
|
||||
"screen_create_room_public_option_description" = "Всеки може да намери тази стая.\nМожете да промените това по всяко време в настройките на стаята.";
|
||||
"screen_create_room_public_option_short_description" = "Anyone can join.";
|
||||
"screen_create_room_public_option_short_description" = "Anyone can join, including people outside your organisation.";
|
||||
"screen_create_room_public_option_title" = "Public";
|
||||
"screen_create_room_room_access_section_knocking_option_description" = "Anyone can ask to join but an administrator or a moderator must accept the request.";
|
||||
"screen_create_room_room_access_section_knocking_option_title" = "Allow ask to join";
|
||||
@@ -888,7 +915,7 @@
|
||||
"screen_join_room_loading_alert_title" = "We couldn’t display this room preview";
|
||||
"screen_join_room_space_not_supported_description" = "%1$@ does not support spaces yet. You can access spaces on web.";
|
||||
"screen_join_room_space_not_supported_title" = "Spaces are not supported yet";
|
||||
"screen_join_room_subtitle_knock" = "Click the button below and a room administrator will be notified. You’ll be able to join the conversation once approved.";
|
||||
"screen_join_room_subtitle_knock" = "Tap the button below and a chat administrator will be notified. You'll be able to join the conversation once approved.";
|
||||
"screen_join_room_subtitle_no_preview" = "You must be a member of this room to view the message history.";
|
||||
"screen_join_room_title_knock" = "Want to join this room?";
|
||||
"screen_join_room_title_no_preview" = "Preview is not available";
|
||||
@@ -924,6 +951,10 @@
|
||||
"screen_knock_requests_list_empty_state_title" = "No pending request to join";
|
||||
"screen_knock_requests_list_initial_loading_title" = "Loading requests to join…";
|
||||
"screen_knock_requests_list_title" = "Requests to join";
|
||||
"screen_labs_enable_gallery" = "Gallery messages";
|
||||
"screen_labs_enable_gallery_description" = "Send multiple images or videos in one go. Stable on mobile, but not yet supported by web.";
|
||||
"screen_labs_enable_knocking" = "Ask to join";
|
||||
"screen_labs_enable_knocking_description" = "Users can request access to a room that is not open for anyone to join. Stable on mobile, web implementation exists but is experimental.";
|
||||
"screen_labs_enable_threads" = "Включване на отговори в нишка";
|
||||
"screen_labs_enable_threads_description" = "The app will restart to apply this change.";
|
||||
"screen_labs_header_description" = "Try out our latest ideas in development. These features are not finalised; they may be unstable, may change.";
|
||||
@@ -932,11 +963,11 @@
|
||||
"screen_leave_space_choose_owners_action" = "Choose owners";
|
||||
"screen_leave_space_last_admin_info" = "%1$@ (Admin)";
|
||||
"screen_leave_space_subtitle" = "Select the rooms you’d like to leave which you're not the only administrator for:";
|
||||
"screen_leave_space_subtitle_last_admin" = "You need to assign another admin for this space before you can leave.";
|
||||
"screen_leave_space_subtitle_last_admin" = "You need to assign another administrator for this space before you can leave.";
|
||||
"screen_leave_space_subtitle_last_owner" = "You are the only owner of %1$@. You need to transfer ownership to someone else before you leave.";
|
||||
"screen_leave_space_subtitle_only_last_admin" = "You will not be removed from the following room(s) because you're the only administrator:";
|
||||
"screen_leave_space_title" = "Leave %1$@?";
|
||||
"screen_leave_space_title_last_admin" = "You are the only admin for %1$@";
|
||||
"screen_leave_space_title_last_admin" = "You are the only administrator for %1$@";
|
||||
"screen_leave_space_title_last_owner" = "Transfer ownership";
|
||||
"screen_link_new_device_authentication_reason_ios" = "Confirm it's you before linking a new device.";
|
||||
"screen_link_new_device_desktop_scanning_title" = "Scan the QR code";
|
||||
@@ -944,6 +975,7 @@
|
||||
"screen_link_new_device_desktop_step3" = "Scan the QR code with this device";
|
||||
"screen_link_new_device_desktop_submit" = "Ready to scan";
|
||||
"screen_link_new_device_desktop_title" = "Open %1$@ on a desktop computer to get the QR code";
|
||||
"screen_link_new_device_desktop_warning" = "Only scan a QR code after following the steps above on your own device. Never scan a code sent by another person.";
|
||||
"screen_link_new_device_enter_number_error_numbers_do_not_match" = "The numbers don’t match";
|
||||
"screen_link_new_device_enter_number_notice" = "Enter 2-digit code";
|
||||
"screen_link_new_device_enter_number_subtitle" = "This will verify that the connection to your other device is secure.";
|
||||
@@ -970,6 +1002,8 @@
|
||||
"screen_live_location_sheet_nobody_sharing" = "Nobody is sharing their location";
|
||||
"screen_live_location_sheet_sharing_live_location" = "Sharing live location";
|
||||
"screen_live_location_sheet_title" = "On the map";
|
||||
"screen_local_network_opt_in_subtitle" = "Your homeserver is on your local network. To connect, %1$@ needs permission to reach devices on this network.";
|
||||
"screen_local_network_opt_in_title" = "Allow access to local network";
|
||||
"screen_login_error_deactivated_account" = "Този акаунт бе деактивиран.";
|
||||
"screen_login_error_invalid_credentials" = "Неправилно потребителско име и/или парола";
|
||||
"screen_login_error_invalid_user_id" = "Това не е валиден потребителски идентификатор. Очакван формат: ‘@user:homeserver.org’";
|
||||
@@ -1020,7 +1054,7 @@
|
||||
"screen_missing_key_backup_open_element_classic" = "Open Element Classic";
|
||||
"screen_missing_key_backup_step_1" = "Open Element Classic on your device";
|
||||
"screen_missing_key_backup_step_2_ios" = "Go to User settings > Security";
|
||||
"screen_missing_key_backup_step_3_ios" = "Scroll down to Secure Backup and tap on Set up";
|
||||
"screen_missing_key_backup_step_3_ios" = "Scroll down to Chat Backup and tap on Set up";
|
||||
"screen_missing_key_backup_step_4" = "Follow the instructions to enable your key storage";
|
||||
"screen_missing_key_backup_step_5" = "Come back to %1$@";
|
||||
"screen_missing_key_backup_title" = "Enable your key storage before proceeding to %1$@";
|
||||
@@ -1189,7 +1223,7 @@
|
||||
"screen_report_content_hint" = "Причина за докладване на това съдържание";
|
||||
"screen_report_room_leave_failed_alert_message" = "Your report was submitted successfully, but we encountered an issue while trying to leave the room. Please try again.";
|
||||
"screen_report_room_leave_failed_alert_title" = "Unable to Leave Room";
|
||||
"screen_report_room_reason_footer" = "Report this room to your admin. If the messages are encrypted, your admin will not be able to read them.";
|
||||
"screen_report_room_reason_footer" = "Report this chat to your account provider. If the messages are encrypted, your account provider will not be able to read them.";
|
||||
"screen_report_room_reason_placeholder" = "Describe the reason to report…";
|
||||
"screen_report_room_title" = "Докладване на стаята";
|
||||
"screen_reset_encryption_confirmation_alert_action" = "Yes, reset now";
|
||||
@@ -1256,6 +1290,10 @@
|
||||
"screen_room_change_role_section_users" = "Членове";
|
||||
"screen_room_change_role_unsaved_changes_description" = "You have unsaved changes.";
|
||||
"screen_room_change_role_unsaved_changes_title" = "Save changes?";
|
||||
"screen_room_confirm_removal_message" = "Are you sure you wish to remove this message?";
|
||||
"screen_room_confirm_removal_reason_label" = "Reason (optional)";
|
||||
"screen_room_confirm_removal_reason_placeholder" = "Enter…";
|
||||
"screen_room_confirm_removal_title" = "Confirm removal";
|
||||
"screen_room_details_add_topic_title" = "Добавяне на тема";
|
||||
"screen_room_details_badge_encrypted" = "С шифроване";
|
||||
"screen_room_details_badge_not_encrypted" = "Без шифроване";
|
||||
@@ -1301,6 +1339,7 @@
|
||||
"screen_room_invite_again_alert_message" = "Искате ли да ги поканите обратно?";
|
||||
"screen_room_invite_again_alert_title" = "Вие сте сами в този чат";
|
||||
"screen_room_live_location_banner" = "Sharing live location";
|
||||
"screen_room_maximum_messages_selected" = "Maximum messages selected";
|
||||
"screen_room_member_details_block_alert_action" = "Блокиране";
|
||||
"screen_room_member_details_block_alert_description" = "Блокираните потребители няма да могат да ви изпращат съобщения и всички техни съобщения ще бъдат скрити. Можете да ги отблокирате по всяко време.";
|
||||
"screen_room_member_details_block_user" = "Блокиране на потребителя";
|
||||
@@ -1339,9 +1378,10 @@
|
||||
"screen_room_notification_settings_error_loading_settings" = "Възникна грешка при зареждането на настройките за известия.";
|
||||
"screen_room_notification_settings_error_restoring_default" = "Неуспешно възстановяване на режима по подразбиране, моля, опитайте отново.";
|
||||
"screen_room_notification_settings_error_setting_mode" = "Неуспешно задаване на режима, моля, опитайте отново.";
|
||||
"screen_room_notification_settings_mentions_only_disclaimer" = "Your homeserver does not support this option in encrypted rooms, you won't get notified in this room.";
|
||||
"screen_room_notification_settings_mentions_only_disclaimer" = "Your account provider does not support this option in encrypted chats, you won't get notified in this chat.";
|
||||
"screen_room_notification_settings_mode_all_messages" = "Всички съобщения";
|
||||
"screen_room_notification_settings_mode_mentions_and_keywords" = "Само споменавания и ключови думи";
|
||||
"screen_room_notification_settings_mode_mentions_and_keywords" = "Mentions and replies only";
|
||||
"screen_room_notification_settings_mode_mute" = "Mute";
|
||||
"screen_room_notification_settings_room_custom_settings_title" = "В тази стая, да бъда известяван за";
|
||||
"screen_room_pinned_banner_indicator" = "%1$@ of %2$@";
|
||||
"screen_room_pinned_banner_indicator_description" = "%1$@ Pinned messages";
|
||||
@@ -1402,6 +1442,8 @@
|
||||
"screen_roomlist_filter_invites_empty_state_title" = "Нямате чакащи покани.";
|
||||
"screen_roomlist_filter_low_priority" = "Нисък приоритет";
|
||||
"screen_roomlist_filter_low_priority_empty_state_title" = "You don’t have any low priority chats yet";
|
||||
"screen_roomlist_filter_mention" = "Mention";
|
||||
"screen_roomlist_filter_mention_empty_state_title" = "You don’t have any unread mentions";
|
||||
"screen_roomlist_filter_mixed_empty_state_subtitle" = "Можете да премахнете избора на филтрите, за да видите другите си чатове";
|
||||
"screen_roomlist_filter_mixed_empty_state_title" = "You don’t have chats for this selection";
|
||||
"screen_roomlist_filter_people" = "Хора";
|
||||
@@ -1488,6 +1530,8 @@
|
||||
"screen_session_verification_request_title" = "Поискано е потвърждение";
|
||||
"screen_session_verification_they_dont_match" = "Те не съвпадат";
|
||||
"screen_session_verification_they_match" = "Те съвпадат";
|
||||
"screen_session_verification_unavailable_subtitle" = "Please use another device or recovery key.";
|
||||
"screen_session_verification_unavailable_title" = "Verification with this device is currently unavailable";
|
||||
"screen_session_verification_use_another_device_subtitle" = "Уверете се, че приложението е отворено на другото устройство, преди да започнете потвърждението оттук.";
|
||||
"screen_session_verification_use_another_device_title" = "Отворете приложението на друго потвърдено устройство";
|
||||
"screen_session_verification_user_initiator_subtitle" = "For extra security, verify this user by comparing a set of emojis on your devices. Do this by using a trusted way to communicate.";
|
||||
@@ -1500,6 +1544,14 @@
|
||||
"screen_session_verification_waiting_subtitle" = "След като бъдете приети, ще можете да продължите потвърждението.";
|
||||
"screen_session_verification_waiting_to_accept_subtitle" = "Приемете заявката, за да започнете процеса на потвърждаване в другата си сесия, за да продължите.";
|
||||
"screen_session_verification_waiting_to_accept_title" = "В очакване на приемане на заявка";
|
||||
"screen_settings_user_status_away" = "Away";
|
||||
"screen_settings_user_status_be_right_back" = "Be right back";
|
||||
"screen_settings_user_status_custom" = "Custom…";
|
||||
"screen_settings_user_status_custom_hint" = "Custom status…";
|
||||
"screen_settings_user_status_focus_time" = "Focus time";
|
||||
"screen_settings_user_status_in_a_meeting" = "In a meeting";
|
||||
"screen_settings_user_status_on_the_road" = "On the road";
|
||||
"screen_settings_user_status_placeholder" = "What's your status?";
|
||||
"screen_share_location_live_location_disclaimer_title" = "Your live location history will be stored in the room and visible to members after the session ends.";
|
||||
"screen_share_location_live_location_duration_picker_title" = "Choose how long to share your live location.";
|
||||
"screen_share_location_live_location_missing_permissions" = "You do not have permissions to share your live location in this room";
|
||||
@@ -1539,7 +1591,7 @@
|
||||
"screen_space_list_parent_space" = "%1$@ пространство";
|
||||
"screen_space_list_title" = "Пространства";
|
||||
"screen_space_menu_action_members" = "Преглед на членовете";
|
||||
"screen_space_remove_rooms_confirmation_content" = "Removing a room will not affect the room access. To change the access go to Room info > Privacy & security.";
|
||||
"screen_space_remove_rooms_confirmation_content" = "Removing a room will not affect the room access. To change the access go to Room info > Security & privacy.";
|
||||
"screen_space_remove_rooms_confirmation_title_ios" = "Remove rooms from %1$@?";
|
||||
"screen_space_settings_leave_space" = "Напускане на пространството";
|
||||
"screen_space_settings_roles_and_permissions" = "Роли и разрешения";
|
||||
@@ -1690,6 +1742,7 @@
|
||||
"troubleshoot_notifications_test_push_loop_back_failure_2" = "Грешка: %1$@";
|
||||
"troubleshoot_notifications_test_push_loop_back_failure_3" = "Error, cannot test push.";
|
||||
"troubleshoot_notifications_test_push_loop_back_failure_4" = "Error, timeout waiting for push.";
|
||||
"troubleshoot_notifications_test_push_loop_back_failure_rate_limit" = "Error: the push gateway is rate limiting this device, so notifications won't be reliable. Please set up a different push gateway.";
|
||||
"troubleshoot_notifications_test_push_loop_back_success" = "Push loop back took %1$d ms.";
|
||||
"troubleshoot_notifications_test_push_loop_back_title" = "Test Push loop back";
|
||||
"troubleshoot_notifications_test_unified_push_description" = "Ensure that UnifiedPush distributors are available.";
|
||||
|
||||
@@ -18,6 +18,22 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>a11y_gallery_more_media</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Gallery, %1$d more media</string>
|
||||
<key>other</key>
|
||||
<string>Gallery, %1$d more medias</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>a11y_polls_percent_of_total</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -50,6 +66,38 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>common_gallery_reply_attachments</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%1$d attachment…</string>
|
||||
<key>other</key>
|
||||
<string>%1$d attachments…</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>common_gallery_reply_media_items</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%1$d media item…</string>
|
||||
<key>other</key>
|
||||
<string>%1$d media items…</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>common_many_members</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -210,6 +258,22 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>notification_gallery_body</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Shared %1$d attachment</string>
|
||||
<key>other</key>
|
||||
<string>Shared %1$d attachments</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>notification_invitations</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -274,6 +338,22 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen.room.timeline_redacted_messages</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%1$d removed message</string>
|
||||
<key>other</key>
|
||||
<string>%1$d removed messages</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen_advanced_settings_live_location_update_distance</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -466,6 +546,22 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen_room_selection_count</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%1$d message selected</string>
|
||||
<key>other</key>
|
||||
<string>%1$d messages selected</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen_room_timeline_reaction_a11y</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -562,7 +658,7 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen_timeline_active_call_extra_joined_count</key>
|
||||
<key>screen_timeline_active_call_joined_count</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
@@ -571,9 +667,9 @@
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>+ %1$d joined</string>
|
||||
<string>%1$d joined</string>
|
||||
<key>other</key>
|
||||
<string>+ %1$d joined</string>
|
||||
<string>%1$d joined</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"NSCameraUsageDescription" = "Per fer fotos o vídeos i enviar-los com a missatge, Element X necessita accés a la càmera.";
|
||||
"NSFaceIDUsageDescription" = "Face ID s'utilitza per accedir a l'aplicació.";
|
||||
"NSLocationAlwaysAndWhenInUseUsageDescription" = "To share your live location, Element X needs location access when the app is in the background.";
|
||||
"NSLocationAlwaysAndWhenInUseUsageDescription" = "To share your location live in chats, location access is needed when the app is in the background.";
|
||||
"NSLocationWhenInUseUsageDescription" = "Concedeix accés a la ubicació perquè Element X pugui compartir la teva ubicació.";
|
||||
"NSMicrophoneUsageDescription" = "Per gravar i enviar missatges amb àudio, Element X necessita accedir al micròfon.";
|
||||
"NSPhotoLibraryUsageDescription" = "Això permet desar imatges i vídeos a la biblioteca de fotos.";
|
||||
|
||||
@@ -6,16 +6,23 @@
|
||||
"a11y_collapse_message_text_field" = "Minimise message text field";
|
||||
"a11y_create_poll_votes_allowed_decrease" = "Decrease votes allowed per person";
|
||||
"a11y_create_poll_votes_allowed_increase" = "Increase votes allowed per person";
|
||||
"a11y_custom_emoji" = "Custom emoji";
|
||||
"a11y_delete" = "Elimina";
|
||||
"a11y_duration" = "Duration: %1$@";
|
||||
"a11y_edit_avatar" = "Edit avatar";
|
||||
"a11y_edit_room_address_hint" = "The full address will be %1$@";
|
||||
"a11y_expand_message_text_field" = "Expand message text field";
|
||||
"a11y_gallery_attachment" = "Gallery, attachment %1$d";
|
||||
"a11y_gallery_failed_scan" = "Gallery, failed scan %1$d";
|
||||
"a11y_gallery_image" = "Gallery, image %1$d";
|
||||
"a11y_gallery_scanning" = "Gallery, scanning %1$d";
|
||||
"a11y_gallery_video" = "Gallery, video %1$d";
|
||||
"a11y_hide_password" = "Amaga contrasenya";
|
||||
"a11y_info" = "Info";
|
||||
"a11y_join_call" = "Uneix-te a la trucada";
|
||||
"a11y_jump_to_bottom" = "Vés al final";
|
||||
"a11y_jump_to_unread" = "Jump to unread";
|
||||
"a11y_jump_to_unread_messages" = "Jump to first unread message";
|
||||
"a11y_notifications_mentions_only" = "Només mencions";
|
||||
"a11y_notifications_muted" = "Silenciat";
|
||||
"a11y_notifications_new_mentions" = "Noves mencions";
|
||||
@@ -50,6 +57,7 @@
|
||||
"a11y_start_call" = "Inicia trucada";
|
||||
"a11y_start_video_call" = "Start a video call";
|
||||
"a11y_start_voice_call" = "Start a voice call";
|
||||
"a11y_status" = "Status";
|
||||
"a11y_tombstoned_room" = "Tombstoned room";
|
||||
"a11y_user_menu" = "Menú d'usuari";
|
||||
"a11y_video_preview" = "Video preview";
|
||||
@@ -135,6 +143,7 @@
|
||||
"action_manage_account_and_devices" = "Manage account & devices";
|
||||
"action_manage_devices" = "Gestiona dispositius";
|
||||
"action_manage_rooms" = "Manage rooms";
|
||||
"action_mark_as_read" = "Mark as read";
|
||||
"action_message" = "Envia missatge";
|
||||
"action_minimize" = "Minimise";
|
||||
"action_next" = "Següent";
|
||||
@@ -165,6 +174,7 @@
|
||||
"action_retry_decryption" = "Torna a intentar desxifrar";
|
||||
"action_save" = "Desa";
|
||||
"action_search" = "Cerca";
|
||||
"action_select" = "Select";
|
||||
"action_select_all" = "Select all";
|
||||
"action_send" = "Envia";
|
||||
"action_send_edited_message" = "Send edited message";
|
||||
@@ -294,6 +304,7 @@
|
||||
"common_no_space_name" = "No space name";
|
||||
"common_not_encrypted" = "Sense xifrar";
|
||||
"common_offline" = "Fora de línia";
|
||||
"common_on_a_call" = "On a call";
|
||||
"common_open_source_licenses" = "Llicències de codi obert";
|
||||
"common_optic_id_ios" = "Optic ID";
|
||||
"common_or" = "o";
|
||||
@@ -410,7 +421,8 @@
|
||||
"confirm_recovery_key_banner_secondary_button_title" = "Has oblidat la clau de recuperació?";
|
||||
"confirm_recovery_key_banner_title" = "L'emmagatzematge de claus no està sincronitzat";
|
||||
"content_scanner_not_found" = "Download not available.";
|
||||
"content_scanner_not_found_title" = "File not found";
|
||||
"content_scanner_not_found_title" = "Something went wrong";
|
||||
"content_scanner_scanning" = "Scanning…";
|
||||
"content_scanner_unsafe_message" = "Preview and download have been disabled.";
|
||||
"content_scanner_unsafe_title" = "The file is not safe";
|
||||
"crash_detection_dialog_content" = "%1$@ ha fallat l'últim cop que es va utilitzar. Vols enviar un informe d'errors?";
|
||||
@@ -484,6 +496,11 @@
|
||||
"error_no_compatible_app_found" = "No s'ha trobat cap aplicació compatible per gestionar aquesta acció.";
|
||||
"error_room_address_already_exists" = "Aquesta adreça de sala ja existeix. Prova d'editar el camp d'adreça o de canviar el nom de sala";
|
||||
"error_room_address_invalid_symbols" = "Alguns caràcters no estan permesos. Només s'admeten lletres, dígits i els símbols següents: ! $ & ‘ ( ) * + / ; = ? @ [ ] - . _";
|
||||
"error_sending_failure_invalid_mime_type" = "Invalid mime type: %@";
|
||||
"error_sending_failure_missing_media_content" = "Missing media content";
|
||||
"error_sending_failure_other" = "Error details: %@";
|
||||
"error_sending_failure_sending_from_unverified_device" = "Sending from unverified device";
|
||||
"error_sending_failure_unknown" = "Unknown error";
|
||||
"error_some_messages_have_not_been_sent" = "Alguns missatges no s'han enviat";
|
||||
"error_unknown" = "S'ha produït un error";
|
||||
"error.account_already_logged_in" = "You're already logged in on this device as %1$@.";
|
||||
@@ -513,6 +530,8 @@
|
||||
"notification_invitation_action_reject" = "Rebutja";
|
||||
"notification_invite_body" = "T'ha convidat a xatejar";
|
||||
"notification_invite_body_with_sender" = "%1$@ t'ha convidat a xatejar";
|
||||
"notification_knock_request_body" = "Requested to join";
|
||||
"notification_live_location_started_body" = "Started sharing their live location";
|
||||
"notification_mentioned_you_body" = "T'ha mencionat: %1$@";
|
||||
"notification_new_messages" = "Missatges nous";
|
||||
"notification_reaction_body" = "Ha reaccionat amb %1$@";
|
||||
@@ -697,14 +716,22 @@
|
||||
"screen_change_server_error_element_pro_required_title" = "Element Pro required";
|
||||
"screen_change_server_error_invalid_homeserver" = "No s'ha pogut accedir a aquest servidor. Comprova que hagis introduït correctament l'URL del servidor. Si ja és correcte, posa't en contacte amb l'administrador del servidor per a més informació.";
|
||||
"screen_change_server_error_invalid_well_known" = "Servidor no disponible a causa d'un problema al fitxer .well-known:\n%1$@";
|
||||
"screen_change_server_error_no_sliding_sync_message" = "The selected account provider does not support sliding sync. An upgrade to the server is needed to use %1$@.";
|
||||
"screen_change_server_error_no_sliding_sync_message" = "The selected account provider does not support sliding sync. The server needs to be upgraded to use %1$@.";
|
||||
"screen_change_server_error_unauthorized_homeserver" = "%1$@ is not allowed to connect to %2$@.";
|
||||
"screen_change_server_error_unauthorized_homeserver_content" = "This app has been configured to allow: %1$@.";
|
||||
"screen_change_server_error_unauthorized_homeserver_title" = "Account provider %1$@ not allowed.";
|
||||
"screen_change_server_form_header" = "URL del servidor";
|
||||
"screen_change_server_form_notice" = "Introdueix un domini.";
|
||||
"screen_change_server_navigation_title_login" = "Sign in";
|
||||
"screen_change_server_navigation_title_register" = "Create account";
|
||||
"screen_change_server_subtitle" = "Quina és l'adreça del teu servidor?";
|
||||
"screen_change_server_textfield_footer_login" = "If your account is provided by your company or a community, then change the account provider (example: companyname.com).";
|
||||
"screen_change_server_textfield_footer_register" = "Create an account on matrix.org for free. If you want to create an account with a different provider, then change it accordingly (example: communityname.org).";
|
||||
"screen_change_server_textfield_header" = "Account provider";
|
||||
"screen_change_server_textfield_placeholder" = "example.com";
|
||||
"screen_change_server_title" = "Selecciona el teu servidor";
|
||||
"screen_change_server_title_login" = "Enter your account provider";
|
||||
"screen_change_server_title_register" = "Choose an account provider";
|
||||
"screen_chat_backup_key_backup_action_disable" = "Elimina l'emmagatzematge de claus";
|
||||
"screen_chat_backup_key_backup_action_enable" = "Activa còpia de seguretat";
|
||||
"screen_chat_backup_key_backup_description" = "Emmagatzema la teva identitat criptogràfica i les claus de missatge de forma segura al servidor. Això et permetrà veure l'historial de missatges en qualsevol dispositiu nou. %1$@.";
|
||||
@@ -751,7 +778,7 @@
|
||||
"screen_create_room_private_option_description" = "Només s'hi poden unir les persones convidades.";
|
||||
"screen_create_room_private_option_title" = "Private";
|
||||
"screen_create_room_public_option_description" = "Tothom pot trobar aquesta sala.\nPots canviar-ho en qualsevol moment a la configuració de sala.";
|
||||
"screen_create_room_public_option_short_description" = "Anyone can join.";
|
||||
"screen_create_room_public_option_short_description" = "Anyone can join, including people outside your organisation.";
|
||||
"screen_create_room_public_option_title" = "Public";
|
||||
"screen_create_room_room_access_section_knocking_option_description" = "Qualsevol persona pot sol·licitar unir-s'hi però un administrador o moderador l'haurà d'acceptar";
|
||||
"screen_create_room_room_access_section_knocking_option_title" = "Permet sol·licituds d'unió";
|
||||
@@ -924,6 +951,10 @@
|
||||
"screen_knock_requests_list_empty_state_title" = "No hi ha sol·licituds d'unió pendents";
|
||||
"screen_knock_requests_list_initial_loading_title" = "Carregant sol·licituds d'unió…";
|
||||
"screen_knock_requests_list_title" = "Sol·licituds d'unió";
|
||||
"screen_labs_enable_gallery" = "Gallery messages";
|
||||
"screen_labs_enable_gallery_description" = "Send multiple images or videos in one go. Stable on mobile, but not yet supported by web.";
|
||||
"screen_labs_enable_knocking" = "Ask to join";
|
||||
"screen_labs_enable_knocking_description" = "Users can request access to a room that is not open for anyone to join. Stable on mobile, web implementation exists but is experimental.";
|
||||
"screen_labs_enable_threads" = "Enable thread replies";
|
||||
"screen_labs_enable_threads_description" = "The app will restart to apply this change.";
|
||||
"screen_labs_header_description" = "Try out our latest ideas in development. These features are not finalised; they may be unstable, may change.";
|
||||
@@ -932,11 +963,11 @@
|
||||
"screen_leave_space_choose_owners_action" = "Choose owners";
|
||||
"screen_leave_space_last_admin_info" = "%1$@ (Admin)";
|
||||
"screen_leave_space_subtitle" = "Select the rooms you’d like to leave which you're not the only administrator for:";
|
||||
"screen_leave_space_subtitle_last_admin" = "You need to assign another admin for this space before you can leave.";
|
||||
"screen_leave_space_subtitle_last_admin" = "You need to assign another administrator for this space before you can leave.";
|
||||
"screen_leave_space_subtitle_last_owner" = "You are the only owner of %1$@. You need to transfer ownership to someone else before you leave.";
|
||||
"screen_leave_space_subtitle_only_last_admin" = "You will not be removed from the following room(s) because you're the only administrator:";
|
||||
"screen_leave_space_title" = "Leave %1$@?";
|
||||
"screen_leave_space_title_last_admin" = "You are the only admin for %1$@";
|
||||
"screen_leave_space_title_last_admin" = "You are the only administrator for %1$@";
|
||||
"screen_leave_space_title_last_owner" = "Transfer ownership";
|
||||
"screen_link_new_device_authentication_reason_ios" = "Confirm it's you before linking a new device.";
|
||||
"screen_link_new_device_desktop_scanning_title" = "Escaneja el QR";
|
||||
@@ -944,6 +975,7 @@
|
||||
"screen_link_new_device_desktop_step3" = "Escaneja el codi QR amb aquest dispositiu";
|
||||
"screen_link_new_device_desktop_submit" = "Preparat per escanejar";
|
||||
"screen_link_new_device_desktop_title" = "Open %1$@ on a desktop computer to get the QR code";
|
||||
"screen_link_new_device_desktop_warning" = "Only scan a QR code after following the steps above on your own device. Never scan a code sent by another person.";
|
||||
"screen_link_new_device_enter_number_error_numbers_do_not_match" = "The numbers don’t match";
|
||||
"screen_link_new_device_enter_number_notice" = "Enter 2-digit code";
|
||||
"screen_link_new_device_enter_number_subtitle" = "This will verify that the connection to your other device is secure.";
|
||||
@@ -970,6 +1002,8 @@
|
||||
"screen_live_location_sheet_nobody_sharing" = "Nobody is sharing their location";
|
||||
"screen_live_location_sheet_sharing_live_location" = "Sharing live location";
|
||||
"screen_live_location_sheet_title" = "On the map";
|
||||
"screen_local_network_opt_in_subtitle" = "Your homeserver is on your local network. To connect, %1$@ needs permission to reach devices on this network.";
|
||||
"screen_local_network_opt_in_title" = "Allow access to local network";
|
||||
"screen_login_error_deactivated_account" = "Aquest compte s'ha desactivat.";
|
||||
"screen_login_error_invalid_credentials" = "Usuari i/o contrasenya incorrectes";
|
||||
"screen_login_error_invalid_user_id" = "Identificador d'usuari invàlid. Format esperat: ‘@usuari:servidor.org’";
|
||||
@@ -1020,7 +1054,7 @@
|
||||
"screen_missing_key_backup_open_element_classic" = "Open Element Classic";
|
||||
"screen_missing_key_backup_step_1" = "Open Element Classic on your device";
|
||||
"screen_missing_key_backup_step_2_ios" = "Go to User settings > Security";
|
||||
"screen_missing_key_backup_step_3_ios" = "Scroll down to Secure Backup and tap on Set up";
|
||||
"screen_missing_key_backup_step_3_ios" = "Scroll down to Chat Backup and tap on Set up";
|
||||
"screen_missing_key_backup_step_4" = "Follow the instructions to enable your key storage";
|
||||
"screen_missing_key_backup_step_5" = "Come back to %1$@";
|
||||
"screen_missing_key_backup_title" = "Enable your key storage before proceeding to %1$@";
|
||||
@@ -1256,6 +1290,10 @@
|
||||
"screen_room_change_role_section_users" = "Membres";
|
||||
"screen_room_change_role_unsaved_changes_description" = "Hi ha canvis sense desar.";
|
||||
"screen_room_change_role_unsaved_changes_title" = "Desar canvis?";
|
||||
"screen_room_confirm_removal_message" = "Are you sure you wish to remove this message?";
|
||||
"screen_room_confirm_removal_reason_label" = "Reason (optional)";
|
||||
"screen_room_confirm_removal_reason_placeholder" = "Enter…";
|
||||
"screen_room_confirm_removal_title" = "Confirm removal";
|
||||
"screen_room_details_add_topic_title" = "Afegeix tema";
|
||||
"screen_room_details_badge_encrypted" = "Xifrada";
|
||||
"screen_room_details_badge_not_encrypted" = "No xifrada";
|
||||
@@ -1301,6 +1339,7 @@
|
||||
"screen_room_invite_again_alert_message" = "Vols tornar-los a convidar-los?";
|
||||
"screen_room_invite_again_alert_title" = "No hi ha ningú més al xat";
|
||||
"screen_room_live_location_banner" = "Sharing live location";
|
||||
"screen_room_maximum_messages_selected" = "Maximum messages selected";
|
||||
"screen_room_member_details_block_alert_action" = "Bloqueja";
|
||||
"screen_room_member_details_block_alert_description" = "Els usuaris bloquejats no podran enviar-te missatges i tots els seus missatges s'amagaran. Pots desbloquejar-los en qualsevol moment.";
|
||||
"screen_room_member_details_block_user" = "Bloqueja usuari";
|
||||
@@ -1340,8 +1379,9 @@
|
||||
"screen_room_notification_settings_error_restoring_default" = "No s'ha pogut restaurar el mode predeterminat. Torna-ho a provar.";
|
||||
"screen_room_notification_settings_error_setting_mode" = "No s'ha pogut configurar el mode. Torna-ho a provar.";
|
||||
"screen_room_notification_settings_mentions_only_disclaimer" = "El servidor no admet aquesta opció en sales xifrades, no rebras notificacions en aquesta sala.";
|
||||
"screen_room_notification_settings_mode_all_messages" = "Tots els missatges";
|
||||
"screen_room_notification_settings_mode_mentions_and_keywords" = "Mencions y paraules clau (només)";
|
||||
"screen_room_notification_settings_mode_all_messages" = "All messages";
|
||||
"screen_room_notification_settings_mode_mentions_and_keywords" = "Mentions and replies only";
|
||||
"screen_room_notification_settings_mode_mute" = "Mute";
|
||||
"screen_room_notification_settings_room_custom_settings_title" = "En aquesta sala, notifica'm en";
|
||||
"screen_room_pinned_banner_indicator" = "%1$@ de %2$@";
|
||||
"screen_room_pinned_banner_indicator_description" = "%1$@ missatges fixats";
|
||||
@@ -1402,6 +1442,8 @@
|
||||
"screen_roomlist_filter_invites_empty_state_title" = "No tens cap invitació pendent.";
|
||||
"screen_roomlist_filter_low_priority" = "Prioritat baixa";
|
||||
"screen_roomlist_filter_low_priority_empty_state_title" = "You don’t have any low priority chats yet";
|
||||
"screen_roomlist_filter_mention" = "Mention";
|
||||
"screen_roomlist_filter_mention_empty_state_title" = "You don’t have any unread mentions";
|
||||
"screen_roomlist_filter_mixed_empty_state_subtitle" = "Pots desseleccionar els filtres per veure els altres xats";
|
||||
"screen_roomlist_filter_mixed_empty_state_title" = "Cap xats per a aquesta selecció";
|
||||
"screen_roomlist_filter_people" = "Persones";
|
||||
@@ -1488,6 +1530,8 @@
|
||||
"screen_session_verification_request_title" = "Verificació sol·licitada";
|
||||
"screen_session_verification_they_dont_match" = "No coincideixen";
|
||||
"screen_session_verification_they_match" = "Coincideixen";
|
||||
"screen_session_verification_unavailable_subtitle" = "Please use another device or recovery key.";
|
||||
"screen_session_verification_unavailable_title" = "Verification with this device is currently unavailable";
|
||||
"screen_session_verification_use_another_device_subtitle" = "Assegura't que tens l'aplicació oberta a l'altre dispositiu abans d'inicar la verificació des d'aquí.";
|
||||
"screen_session_verification_use_another_device_title" = "Obre l'aplicació en un altre dispositiu verificat";
|
||||
"screen_session_verification_user_initiator_subtitle" = "Per a més seguretat, verifica aquest usuari comparant un conjunt d'emoticones vostres dispositius. Fes-ho a través d'un mitjà de comunicació fiable, o en persona.";
|
||||
@@ -1500,6 +1544,14 @@
|
||||
"screen_session_verification_waiting_subtitle" = "Un cop acceptat, podràs continuar amb la verificació.";
|
||||
"screen_session_verification_waiting_to_accept_subtitle" = "Per continuar, accepta la sol·licitud per iniciar el procés de verificació a l'altra sessió.";
|
||||
"screen_session_verification_waiting_to_accept_title" = "Esperant que s'accepti la sol·licitud";
|
||||
"screen_settings_user_status_away" = "Away";
|
||||
"screen_settings_user_status_be_right_back" = "Be right back";
|
||||
"screen_settings_user_status_custom" = "Custom…";
|
||||
"screen_settings_user_status_custom_hint" = "Custom status…";
|
||||
"screen_settings_user_status_focus_time" = "Focus time";
|
||||
"screen_settings_user_status_in_a_meeting" = "In a meeting";
|
||||
"screen_settings_user_status_on_the_road" = "On the road";
|
||||
"screen_settings_user_status_placeholder" = "What's your status?";
|
||||
"screen_share_location_live_location_disclaimer_title" = "Your live location history will be stored in the room and visible to members after the session ends.";
|
||||
"screen_share_location_live_location_duration_picker_title" = "Choose how long to share your live location.";
|
||||
"screen_share_location_live_location_missing_permissions" = "You do not have permissions to share your live location in this room";
|
||||
@@ -1539,7 +1591,7 @@
|
||||
"screen_space_list_parent_space" = "%1$@ space";
|
||||
"screen_space_list_title" = "Spaces";
|
||||
"screen_space_menu_action_members" = "View members";
|
||||
"screen_space_remove_rooms_confirmation_content" = "Removing a room will not affect the room access. To change the access go to Room info > Privacy & security.";
|
||||
"screen_space_remove_rooms_confirmation_content" = "Removing a room will not affect the room access. To change the access go to Room info > Security & privacy.";
|
||||
"screen_space_remove_rooms_confirmation_title_ios" = "Remove rooms from %1$@?";
|
||||
"screen_space_settings_leave_space" = "Leave space";
|
||||
"screen_space_settings_roles_and_permissions" = "Rols i permisos";
|
||||
@@ -1690,6 +1742,7 @@
|
||||
"troubleshoot_notifications_test_push_loop_back_failure_2" = "Error: %1$@.";
|
||||
"troubleshoot_notifications_test_push_loop_back_failure_3" = "Error, no s'han pogut provar les notificacions push.";
|
||||
"troubleshoot_notifications_test_push_loop_back_failure_4" = "Error, s'ha acabat el temps d'espera de la notificació push.";
|
||||
"troubleshoot_notifications_test_push_loop_back_failure_rate_limit" = "Error: the push gateway is rate limiting this device, so notifications won't be reliable. Please set up a different push gateway.";
|
||||
"troubleshoot_notifications_test_push_loop_back_success" = "El bucle de notificacions push ha tardat %1$d ms.";
|
||||
"troubleshoot_notifications_test_push_loop_back_title" = "Prova el bucle de notificacions push";
|
||||
"troubleshoot_notifications_test_unified_push_description" = "Assegura't que hi hagi distribuïdors d'UnifiedPush disponibles.";
|
||||
|
||||
@@ -18,6 +18,22 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>a11y_gallery_more_media</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Gallery, %1$d more media</string>
|
||||
<key>other</key>
|
||||
<string>Gallery, %1$d more medias</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>a11y_polls_percent_of_total</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -50,6 +66,38 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>common_gallery_reply_attachments</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%1$d attachment…</string>
|
||||
<key>other</key>
|
||||
<string>%1$d attachments…</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>common_gallery_reply_media_items</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%1$d media item…</string>
|
||||
<key>other</key>
|
||||
<string>%1$d media items…</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>common_many_members</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -210,6 +258,22 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>notification_gallery_body</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Shared %1$d attachment</string>
|
||||
<key>other</key>
|
||||
<string>Shared %1$d attachments</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>notification_invitations</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -274,6 +338,22 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen.room.timeline_redacted_messages</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%1$d removed message</string>
|
||||
<key>other</key>
|
||||
<string>%1$d removed messages</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen_advanced_settings_live_location_update_distance</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -466,6 +546,22 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen_room_selection_count</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%1$d message selected</string>
|
||||
<key>other</key>
|
||||
<string>%1$d messages selected</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen_room_timeline_reaction_a11y</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -562,7 +658,7 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen_timeline_active_call_extra_joined_count</key>
|
||||
<key>screen_timeline_active_call_joined_count</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
@@ -571,9 +667,9 @@
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>+ %1$d joined</string>
|
||||
<string>%1$d joined</string>
|
||||
<key>other</key>
|
||||
<string>+ %1$d joined</string>
|
||||
<string>%1$d joined</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
|
||||
@@ -6,16 +6,23 @@
|
||||
"a11y_collapse_message_text_field" = "Minimalizovat textové pole zprávy";
|
||||
"a11y_create_poll_votes_allowed_decrease" = "Decrease votes allowed per person";
|
||||
"a11y_create_poll_votes_allowed_increase" = "Increase votes allowed per person";
|
||||
"a11y_custom_emoji" = "Custom emoji";
|
||||
"a11y_delete" = "Smazat";
|
||||
"a11y_duration" = "Duration: %1$@";
|
||||
"a11y_edit_avatar" = "Upravit avatar";
|
||||
"a11y_edit_room_address_hint" = "Úplná adresa bude %1$@";
|
||||
"a11y_expand_message_text_field" = "Rozbalit textové pole zprávy";
|
||||
"a11y_gallery_attachment" = "Gallery, attachment %1$d";
|
||||
"a11y_gallery_failed_scan" = "Gallery, failed scan %1$d";
|
||||
"a11y_gallery_image" = "Gallery, image %1$d";
|
||||
"a11y_gallery_scanning" = "Gallery, scanning %1$d";
|
||||
"a11y_gallery_video" = "Gallery, video %1$d";
|
||||
"a11y_hide_password" = "Skrýt heslo";
|
||||
"a11y_info" = "Informace";
|
||||
"a11y_join_call" = "Připojit se k hovoru";
|
||||
"a11y_jump_to_bottom" = "Přejít dolů";
|
||||
"a11y_jump_to_unread" = "Jump to unread";
|
||||
"a11y_jump_to_unread_messages" = "Jump to first unread message";
|
||||
"a11y_notifications_mentions_only" = "Pouze zmínky";
|
||||
"a11y_notifications_muted" = "Ztišeno";
|
||||
"a11y_notifications_new_mentions" = "Nové zmínky";
|
||||
@@ -50,6 +57,7 @@
|
||||
"a11y_start_call" = "Zahájit hovor";
|
||||
"a11y_start_video_call" = "Zahájit videohovor";
|
||||
"a11y_start_voice_call" = "Zahájit hlasový hovor";
|
||||
"a11y_status" = "Status";
|
||||
"a11y_tombstoned_room" = "Místnost s náhrobkem";
|
||||
"a11y_user_menu" = "Uživatelské menu";
|
||||
"a11y_video_preview" = "Video preview";
|
||||
@@ -135,6 +143,7 @@
|
||||
"action_manage_account_and_devices" = "Správa účtu a zařízení";
|
||||
"action_manage_devices" = "Spravovat zařízení";
|
||||
"action_manage_rooms" = "Spravovat místnosti";
|
||||
"action_mark_as_read" = "Mark as read";
|
||||
"action_message" = "Zpráva";
|
||||
"action_minimize" = "Minimalizovat";
|
||||
"action_next" = "Další";
|
||||
@@ -165,6 +174,7 @@
|
||||
"action_retry_decryption" = "Opakovat dešifrování";
|
||||
"action_save" = "Uložit";
|
||||
"action_search" = "Hledat";
|
||||
"action_select" = "Select";
|
||||
"action_select_all" = "Vybrat vše";
|
||||
"action_send" = "Odeslat";
|
||||
"action_send_edited_message" = "Odeslat upravenou zprávu";
|
||||
@@ -294,6 +304,7 @@
|
||||
"common_no_space_name" = "Žádný název prostoru";
|
||||
"common_not_encrypted" = "Nešifrováno";
|
||||
"common_offline" = "Offline";
|
||||
"common_on_a_call" = "On a call";
|
||||
"common_open_source_licenses" = "Licence s otevřeným zdrojovým kódem";
|
||||
"common_optic_id_ios" = "Optic ID";
|
||||
"common_or" = "nebo";
|
||||
@@ -410,7 +421,8 @@
|
||||
"confirm_recovery_key_banner_secondary_button_title" = "Zapomněli jste klíč pro obnovení?";
|
||||
"confirm_recovery_key_banner_title" = "Vaše úložiště klíčů není synchronizováno";
|
||||
"content_scanner_not_found" = "Download not available.";
|
||||
"content_scanner_not_found_title" = "File not found";
|
||||
"content_scanner_not_found_title" = "Something went wrong";
|
||||
"content_scanner_scanning" = "Scanning…";
|
||||
"content_scanner_unsafe_message" = "Preview and download have been disabled.";
|
||||
"content_scanner_unsafe_title" = "The file is not safe";
|
||||
"crash_detection_dialog_content" = "%1$@ havaroval při posledním použití. Chcete se s námi podělit o zprávu o selhání?";
|
||||
@@ -484,6 +496,11 @@
|
||||
"error_no_compatible_app_found" = "Nebyla nalezena žádná kompatibilní aplikace, která by tuto akci zpracovala.";
|
||||
"error_room_address_already_exists" = "Tato adresa místnosti již existuje, zkuste prosím upravit pole adresy místnosti nebo změnit název místnosti";
|
||||
"error_room_address_invalid_symbols" = "Některé znaky nejsou povoleny. Podporovány jsou pouze písmena, číslice a následující symboly ! $ & ‘ ( ) * + / ; = ? @ [ ] - . _";
|
||||
"error_sending_failure_invalid_mime_type" = "Invalid mime type: %@";
|
||||
"error_sending_failure_missing_media_content" = "Missing media content";
|
||||
"error_sending_failure_other" = "Error details: %@";
|
||||
"error_sending_failure_sending_from_unverified_device" = "Sending from unverified device";
|
||||
"error_sending_failure_unknown" = "Unknown error";
|
||||
"error_some_messages_have_not_been_sent" = "Některé zprávy nebyly odeslány";
|
||||
"error_unknown" = "Omlouváme se, došlo k chybě";
|
||||
"error.account_already_logged_in" = "Na tomto zařízení jste již přihlášeni jako %1$@.";
|
||||
@@ -513,6 +530,8 @@
|
||||
"notification_invitation_action_reject" = "Odmítnout";
|
||||
"notification_invite_body" = "Vás pozval(a) do chatu";
|
||||
"notification_invite_body_with_sender" = "%1$@ vás pozval(a) do chatu";
|
||||
"notification_knock_request_body" = "Requested to join";
|
||||
"notification_live_location_started_body" = "Started sharing their live location";
|
||||
"notification_mentioned_you_body" = "Zmínili vás: %1$@";
|
||||
"notification_new_messages" = "Nové zprávy";
|
||||
"notification_reaction_body" = "Reagoval(a) s %1$@";
|
||||
@@ -703,8 +722,16 @@
|
||||
"screen_change_server_error_unauthorized_homeserver_title" = "Poskytovatel účtu %1$@ není povolen.";
|
||||
"screen_change_server_form_header" = "Adresa URL domovského serveru";
|
||||
"screen_change_server_form_notice" = "Zadejte adresu domény.";
|
||||
"screen_change_server_navigation_title_login" = "Sign in";
|
||||
"screen_change_server_navigation_title_register" = "Create account";
|
||||
"screen_change_server_subtitle" = "Jaká je adresa vašeho serveru?";
|
||||
"screen_change_server_textfield_footer_login" = "If your account is provided by your company or a community, then change the account provider (example: companyname.com).";
|
||||
"screen_change_server_textfield_footer_register" = "Create an account on matrix.org for free. If you want to create an account with a different provider, then change it accordingly (example: communityname.org).";
|
||||
"screen_change_server_textfield_header" = "Account provider";
|
||||
"screen_change_server_textfield_placeholder" = "example.com";
|
||||
"screen_change_server_title" = "Vyberte váš server";
|
||||
"screen_change_server_title_login" = "Enter your account provider";
|
||||
"screen_change_server_title_register" = "Choose an account provider";
|
||||
"screen_chat_backup_key_backup_action_disable" = "Vypnout zálohování";
|
||||
"screen_chat_backup_key_backup_action_enable" = "Zapnout zálohování";
|
||||
"screen_chat_backup_key_backup_description" = "To vám umožní zobrazit historii chatu na všech nových zařízeních a je to nutné pro zálohování chatů a digitální identity. %1$@ .";
|
||||
@@ -924,6 +951,10 @@
|
||||
"screen_knock_requests_list_empty_state_title" = "Žádná čekající žádost o vstup";
|
||||
"screen_knock_requests_list_initial_loading_title" = "Načítání žádostí o vstup...";
|
||||
"screen_knock_requests_list_title" = "Žádosti o vstup";
|
||||
"screen_labs_enable_gallery" = "Gallery messages";
|
||||
"screen_labs_enable_gallery_description" = "Send multiple images or videos in one go. Stable on mobile, but not yet supported by web.";
|
||||
"screen_labs_enable_knocking" = "Ask to join";
|
||||
"screen_labs_enable_knocking_description" = "Users can request access to a room that is not open for anyone to join. Stable on mobile, web implementation exists but is experimental.";
|
||||
"screen_labs_enable_threads" = "Povolit odpovědi ve vlákně";
|
||||
"screen_labs_enable_threads_description" = "Aplikace se restartuje, aby se tato změna projevila.";
|
||||
"screen_labs_header_description" = "Vyzkoušejte naše nejnovější nápady, které jsou ve vývoji. Tyto funkce nejsou finalizované; mohou být nestabilní a mohou se změnit.";
|
||||
@@ -944,6 +975,7 @@
|
||||
"screen_link_new_device_desktop_step3" = "Naskenujte QR kód pomocí tohoto zařízení";
|
||||
"screen_link_new_device_desktop_submit" = "Připraveno ke skenování";
|
||||
"screen_link_new_device_desktop_title" = "Otevřete %1$@ na stolním počítači a získejte QR kód";
|
||||
"screen_link_new_device_desktop_warning" = "Only scan a QR code after following the steps above on your own device. Never scan a code sent by another person.";
|
||||
"screen_link_new_device_enter_number_error_numbers_do_not_match" = "Čísla se neshodují";
|
||||
"screen_link_new_device_enter_number_notice" = "Zadejte dvoumístný kód";
|
||||
"screen_link_new_device_enter_number_subtitle" = "Tím ověříte, zda je připojení k druhému zařízení bezpečné.";
|
||||
@@ -970,6 +1002,8 @@
|
||||
"screen_live_location_sheet_nobody_sharing" = "Nikdo nesdílí svou polohu";
|
||||
"screen_live_location_sheet_sharing_live_location" = "Sdílení aktuální polohy";
|
||||
"screen_live_location_sheet_title" = "Na mapě";
|
||||
"screen_local_network_opt_in_subtitle" = "Your homeserver is on your local network. To connect, %1$@ needs permission to reach devices on this network.";
|
||||
"screen_local_network_opt_in_title" = "Allow access to local network";
|
||||
"screen_login_error_deactivated_account" = "Tento účet byl smazán.";
|
||||
"screen_login_error_invalid_credentials" = "Nesprávné uživatelské jméno nebo heslo";
|
||||
"screen_login_error_invalid_user_id" = "Toto není platný identifikátor uživatele. Očekávaný formát: '@user:homeserver.org'";
|
||||
@@ -1256,6 +1290,10 @@
|
||||
"screen_room_change_role_section_users" = "Členové";
|
||||
"screen_room_change_role_unsaved_changes_description" = "Máte neuložené změny.";
|
||||
"screen_room_change_role_unsaved_changes_title" = "Uložit změny?";
|
||||
"screen_room_confirm_removal_message" = "Are you sure you wish to remove this message?";
|
||||
"screen_room_confirm_removal_reason_label" = "Reason (optional)";
|
||||
"screen_room_confirm_removal_reason_placeholder" = "Enter…";
|
||||
"screen_room_confirm_removal_title" = "Confirm removal";
|
||||
"screen_room_details_add_topic_title" = "Přidat téma";
|
||||
"screen_room_details_badge_encrypted" = "Šifrováno";
|
||||
"screen_room_details_badge_not_encrypted" = "Není šifrováno";
|
||||
@@ -1301,6 +1339,7 @@
|
||||
"screen_room_invite_again_alert_message" = "Chtěli byste je pozvat zpět?";
|
||||
"screen_room_invite_again_alert_title" = "V tomto chatu jste sami";
|
||||
"screen_room_live_location_banner" = "Sdílení aktuální polohy";
|
||||
"screen_room_maximum_messages_selected" = "Maximum messages selected";
|
||||
"screen_room_member_details_block_alert_action" = "Zablokovat";
|
||||
"screen_room_member_details_block_alert_description" = "Blokovaní uživatelé vám nebudou moci posílat zprávy a všechny jejich zprávy budou skryty. Můžete je kdykoli odblokovat.";
|
||||
"screen_room_member_details_block_user" = "Zablokovat uživatele";
|
||||
@@ -1342,6 +1381,7 @@
|
||||
"screen_room_notification_settings_mentions_only_disclaimer" = "Váš domovský server tuto možnost nepodporuje v šifrovaných místnostech, v této místnosti nebudete dostávat upozornění.";
|
||||
"screen_room_notification_settings_mode_all_messages" = "Všechny zprávy";
|
||||
"screen_room_notification_settings_mode_mentions_and_keywords" = "Pouze zmínky a klíčová slova";
|
||||
"screen_room_notification_settings_mode_mute" = "Mute";
|
||||
"screen_room_notification_settings_room_custom_settings_title" = "V této místnosti mě upozornit na";
|
||||
"screen_room_pinned_banner_indicator" = "%1$@ z %2$@";
|
||||
"screen_room_pinned_banner_indicator_description" = "%1$@ Připnuté zprávy";
|
||||
@@ -1402,6 +1442,8 @@
|
||||
"screen_roomlist_filter_invites_empty_state_title" = "Nemáte žádné nevyřízené pozvánky.";
|
||||
"screen_roomlist_filter_low_priority" = "Nízká priorita";
|
||||
"screen_roomlist_filter_low_priority_empty_state_title" = "Zatím nemáte žádné chaty s nízkou prioritou";
|
||||
"screen_roomlist_filter_mention" = "Mention";
|
||||
"screen_roomlist_filter_mention_empty_state_title" = "You don’t have any unread mentions";
|
||||
"screen_roomlist_filter_mixed_empty_state_subtitle" = "Můžete zrušit výběr filtrů, abyste viděli své další chaty";
|
||||
"screen_roomlist_filter_mixed_empty_state_title" = "Nemáte chaty pro tento výběr";
|
||||
"screen_roomlist_filter_people" = "Lidé";
|
||||
@@ -1488,6 +1530,8 @@
|
||||
"screen_session_verification_request_title" = "Požadováno ověření";
|
||||
"screen_session_verification_they_dont_match" = "Neshodují se";
|
||||
"screen_session_verification_they_match" = "Shodují se";
|
||||
"screen_session_verification_unavailable_subtitle" = "Please use another device or recovery key.";
|
||||
"screen_session_verification_unavailable_title" = "Verification with this device is currently unavailable";
|
||||
"screen_session_verification_use_another_device_subtitle" = "Před zahájením ověřování se ujistěte, že máte aplikaci otevřenou na druhém zařízení.";
|
||||
"screen_session_verification_use_another_device_title" = "Otevřete aplikaci na jiném ověřeném zařízení";
|
||||
"screen_session_verification_user_initiator_subtitle" = "Pro větší bezpečnost ověřte tohoto uživatele porovnáním sady emotikonů na svých zařízeních. Proveďte to pomocí důvěryhodného způsobu komunikace.";
|
||||
@@ -1500,6 +1544,14 @@
|
||||
"screen_session_verification_waiting_subtitle" = "Po přijetí budete moci pokračovat v ověřování.";
|
||||
"screen_session_verification_waiting_to_accept_subtitle" = "Pro pokračování přijměte požadavek na zahájení ověření v jiné relaci.";
|
||||
"screen_session_verification_waiting_to_accept_title" = "Čekání na přijetí žádosti";
|
||||
"screen_settings_user_status_away" = "Away";
|
||||
"screen_settings_user_status_be_right_back" = "Be right back";
|
||||
"screen_settings_user_status_custom" = "Custom…";
|
||||
"screen_settings_user_status_custom_hint" = "Custom status…";
|
||||
"screen_settings_user_status_focus_time" = "Focus time";
|
||||
"screen_settings_user_status_in_a_meeting" = "In a meeting";
|
||||
"screen_settings_user_status_on_the_road" = "On the road";
|
||||
"screen_settings_user_status_placeholder" = "What's your status?";
|
||||
"screen_share_location_live_location_disclaimer_title" = "Vaše historie aktuální polohy bude uložena v místnosti a bude viditelná pro členy i po skončení relace.";
|
||||
"screen_share_location_live_location_duration_picker_title" = "Zvolte, jak dlouho chcete sdílet svou aktuální polohu.";
|
||||
"screen_share_location_live_location_missing_permissions" = "Nemáte oprávnění sdílet svou aktuální polohu v této místnosti.";
|
||||
@@ -1690,6 +1742,7 @@
|
||||
"troubleshoot_notifications_test_push_loop_back_failure_2" = "Chyba: %1$@.";
|
||||
"troubleshoot_notifications_test_push_loop_back_failure_3" = "Chyba, nelze otestovat push.";
|
||||
"troubleshoot_notifications_test_push_loop_back_failure_4" = "Chyba, časový limit čekání na push.";
|
||||
"troubleshoot_notifications_test_push_loop_back_failure_rate_limit" = "Error: the push gateway is rate limiting this device, so notifications won't be reliable. Please set up a different push gateway.";
|
||||
"troubleshoot_notifications_test_push_loop_back_success" = "Push zpětná smyčka trvala %1$d ms.";
|
||||
"troubleshoot_notifications_test_push_loop_back_title" = "Otestovat push pomocí zpětného volání";
|
||||
"troubleshoot_notifications_test_unified_push_description" = "Ujistěte se, že jsou k dispozici distributoři UnifiedPush.";
|
||||
|
||||
@@ -20,6 +20,22 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>a11y_gallery_more_media</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Gallery, %1$d more media</string>
|
||||
<key>other</key>
|
||||
<string>Gallery, %1$d more medias</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>a11y_polls_percent_of_total</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -56,6 +72,38 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>common_gallery_reply_attachments</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%1$d attachment…</string>
|
||||
<key>other</key>
|
||||
<string>%1$d attachments…</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>common_gallery_reply_media_items</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%1$d media item…</string>
|
||||
<key>other</key>
|
||||
<string>%1$d media items…</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>common_many_members</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -232,6 +280,22 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>notification_gallery_body</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Shared %1$d attachment</string>
|
||||
<key>other</key>
|
||||
<string>Shared %1$d attachments</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>notification_invitations</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -304,6 +368,22 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen.room.timeline_redacted_messages</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%1$d removed message</string>
|
||||
<key>other</key>
|
||||
<string>%1$d removed messages</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen_advanced_settings_live_location_update_distance</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -516,6 +596,22 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen_room_selection_count</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%1$d message selected</string>
|
||||
<key>other</key>
|
||||
<string>%1$d messages selected</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen_room_timeline_reaction_a11y</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -624,7 +720,7 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen_timeline_active_call_extra_joined_count</key>
|
||||
<key>screen_timeline_active_call_joined_count</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
@@ -633,9 +729,9 @@
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>+ %1$d joined</string>
|
||||
<string>%1$d joined</string>
|
||||
<key>other</key>
|
||||
<string>+ %1$d joined</string>
|
||||
<string>%1$d joined</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"NSCameraUsageDescription" = "Er mwyn tynnu lluniau neu fideos a'u hanfon fel neges mae Elfen X angen mynediad i'r camera.";
|
||||
"NSFaceIDUsageDescription" = "Mae Face ID yn cael ei ddefnyddio i gael mynediad i'ch ap.";
|
||||
"NSLocationAlwaysAndWhenInUseUsageDescription" = "To share your live location, Element X needs location access when the app is in the background.";
|
||||
"NSLocationAlwaysAndWhenInUseUsageDescription" = "To share your location live in chats, location access is needed when the app is in the background.";
|
||||
"NSLocationWhenInUseUsageDescription" = "Caniatewch fynediad lleoliad fel y gall Elfen X rannu eich lleoliad.";
|
||||
"NSMicrophoneUsageDescription" = "I recordio ac anfon negeseuon gyda sain, mae angen i Elfen X gael mynediad i'r meicroffon.";
|
||||
"NSPhotoLibraryUsageDescription" = "Mae hyn yn caniatáu ichi gadw delweddau a fideos i'ch llyfrgell ffotograffau.";
|
||||
|
||||
@@ -6,16 +6,23 @@
|
||||
"a11y_collapse_message_text_field" = "Lleihau maes testun neges";
|
||||
"a11y_create_poll_votes_allowed_decrease" = "Decrease votes allowed per person";
|
||||
"a11y_create_poll_votes_allowed_increase" = "Increase votes allowed per person";
|
||||
"a11y_custom_emoji" = "Custom emoji";
|
||||
"a11y_delete" = "Dileu";
|
||||
"a11y_duration" = "Duration: %1$@";
|
||||
"a11y_edit_avatar" = "Golygu afatar";
|
||||
"a11y_edit_room_address_hint" = "Bydd y cyfeiriad llawn yn%1$@";
|
||||
"a11y_expand_message_text_field" = "Ehangu maes testun neges";
|
||||
"a11y_gallery_attachment" = "Gallery, attachment %1$d";
|
||||
"a11y_gallery_failed_scan" = "Gallery, failed scan %1$d";
|
||||
"a11y_gallery_image" = "Gallery, image %1$d";
|
||||
"a11y_gallery_scanning" = "Gallery, scanning %1$d";
|
||||
"a11y_gallery_video" = "Gallery, video %1$d";
|
||||
"a11y_hide_password" = "Cuddio cyfrinair";
|
||||
"a11y_info" = "Info";
|
||||
"a11y_join_call" = "Ymuno â galwad";
|
||||
"a11y_jump_to_bottom" = "Symud i'r gwaelod";
|
||||
"a11y_jump_to_unread" = "Jump to unread";
|
||||
"a11y_jump_to_unread_messages" = "Jump to first unread message";
|
||||
"a11y_notifications_mentions_only" = "Crybwylliadau'n unig";
|
||||
"a11y_notifications_muted" = "Wedi'i Dewi";
|
||||
"a11y_notifications_new_mentions" = "Crybwylliadau newydd";
|
||||
@@ -50,6 +57,7 @@
|
||||
"a11y_start_call" = "Cychwyn galwad";
|
||||
"a11y_start_video_call" = "Start a video call";
|
||||
"a11y_start_voice_call" = "Start a voice call";
|
||||
"a11y_status" = "Status";
|
||||
"a11y_tombstoned_room" = "Ystafell Tombstoned";
|
||||
"a11y_user_menu" = "Dewislen defnyddiwr";
|
||||
"a11y_video_preview" = "Video preview";
|
||||
@@ -135,6 +143,7 @@
|
||||
"action_manage_account_and_devices" = "Manage account & devices";
|
||||
"action_manage_devices" = "Rheoli dyfeisiau";
|
||||
"action_manage_rooms" = "Manage rooms";
|
||||
"action_mark_as_read" = "Mark as read";
|
||||
"action_message" = "Neges";
|
||||
"action_minimize" = "Minimise";
|
||||
"action_next" = "Nesaf";
|
||||
@@ -165,6 +174,7 @@
|
||||
"action_retry_decryption" = "Cynnig arall ar ddadgryptio";
|
||||
"action_save" = "Cadw";
|
||||
"action_search" = "Chwilio";
|
||||
"action_select" = "Select";
|
||||
"action_select_all" = "Dewis y cyfan";
|
||||
"action_send" = "Anfon";
|
||||
"action_send_edited_message" = "Anfon neges wedi'i golygu";
|
||||
@@ -294,6 +304,7 @@
|
||||
"common_no_space_name" = "Dim enw gofod";
|
||||
"common_not_encrypted" = "Heb ei amgryptio";
|
||||
"common_offline" = "All-lein";
|
||||
"common_on_a_call" = "On a call";
|
||||
"common_open_source_licenses" = "Trwyddedau cod agored";
|
||||
"common_optic_id_ios" = "ID optig";
|
||||
"common_or" = "neu";
|
||||
@@ -410,7 +421,8 @@
|
||||
"confirm_recovery_key_banner_secondary_button_title" = "Wedi anghofio'ch allwedd adfer?";
|
||||
"confirm_recovery_key_banner_title" = "Dyw eich allwedd storfa heb ei gydweddu";
|
||||
"content_scanner_not_found" = "Download not available.";
|
||||
"content_scanner_not_found_title" = "File not found";
|
||||
"content_scanner_not_found_title" = "Something went wrong";
|
||||
"content_scanner_scanning" = "Scanning…";
|
||||
"content_scanner_unsafe_message" = "Preview and download have been disabled.";
|
||||
"content_scanner_unsafe_title" = "The file is not safe";
|
||||
"crash_detection_dialog_content" = "Chwalodd %1$@ y tro diwethaf iddo gael ei ddefnyddio. Hoffech chi rannu adroddiad gwall gyda ni?";
|
||||
@@ -484,6 +496,11 @@
|
||||
"error_no_compatible_app_found" = "Heb ganfod ap cydnaws i drin y weithred hon.";
|
||||
"error_room_address_already_exists" = "Mae'r cyfeiriad ystafell hwn yn bodoli eisoes. Ceisiwch olygu'r maes cyfeiriad ystafell neu newid enw'r ystafell";
|
||||
"error_room_address_invalid_symbols" = "Dyw rhai nodau ddim yn cael eu caniatáu. Dim ond llythrennau, digidau a'r symbolau canlynol sy'n cael eu cefnogi ! $ & ‘ ( ) * + / ; = ? @ [ ] - . _";
|
||||
"error_sending_failure_invalid_mime_type" = "Invalid mime type: %@";
|
||||
"error_sending_failure_missing_media_content" = "Missing media content";
|
||||
"error_sending_failure_other" = "Error details: %@";
|
||||
"error_sending_failure_sending_from_unverified_device" = "Sending from unverified device";
|
||||
"error_sending_failure_unknown" = "Unknown error";
|
||||
"error_some_messages_have_not_been_sent" = "Nid yw rhai negeseuon wedi'u hanfon";
|
||||
"error_unknown" = "Ymddiheuriadau, mae gwall wedi digwydd";
|
||||
"error.account_already_logged_in" = "Rydych chi eisoes wedi mewngofnodi ar y ddyfais hon fel %1$@ .";
|
||||
@@ -513,6 +530,8 @@
|
||||
"notification_invitation_action_reject" = "Gwrthod";
|
||||
"notification_invite_body" = "Wedi eich gwahodd i sgwrsio";
|
||||
"notification_invite_body_with_sender" = "Mae %1$@ wedi eich gwahodd i sgwrsio";
|
||||
"notification_knock_request_body" = "Requested to join";
|
||||
"notification_live_location_started_body" = "Started sharing their live location";
|
||||
"notification_mentioned_you_body" = "Wedi eich crybwyll: %1$@";
|
||||
"notification_new_messages" = "Negeseuon Newydd";
|
||||
"notification_reaction_body" = "Wedi ymateb gyda %1$@";
|
||||
@@ -703,8 +722,16 @@
|
||||
"screen_change_server_error_unauthorized_homeserver_title" = "Dyw darparwr cyfrif %1$@ dddim yn cael ei ganiatáu.";
|
||||
"screen_change_server_form_header" = "URL y Gweinydd Cartref";
|
||||
"screen_change_server_form_notice" = "Rhowch gyfeiriad parth.";
|
||||
"screen_change_server_navigation_title_login" = "Sign in";
|
||||
"screen_change_server_navigation_title_register" = "Create account";
|
||||
"screen_change_server_subtitle" = "Beth yw cyfeiriad eich gweinydd?";
|
||||
"screen_change_server_textfield_footer_login" = "If your account is provided by your company or a community, then change the account provider (example: companyname.com).";
|
||||
"screen_change_server_textfield_footer_register" = "Create an account on matrix.org for free. If you want to create an account with a different provider, then change it accordingly (example: communityname.org).";
|
||||
"screen_change_server_textfield_header" = "Account provider";
|
||||
"screen_change_server_textfield_placeholder" = "example.com";
|
||||
"screen_change_server_title" = "Dewiswch eich gweinydd";
|
||||
"screen_change_server_title_login" = "Enter your account provider";
|
||||
"screen_change_server_title_register" = "Choose an account provider";
|
||||
"screen_chat_backup_key_backup_action_disable" = "Dileu storfa allweddi";
|
||||
"screen_chat_backup_key_backup_action_enable" = "Trowch y copi wrth gefn ymlaen";
|
||||
"screen_chat_backup_key_backup_description" = "Cadwch eich hunaniaeth cryptograffig a'ch allweddi neges yn ddiogel ar y gweinydd. Bydd hyn yn caniatáu ichi weld hanes eich neges ar unrhyw ddyfeisiau newydd. %1$@.";
|
||||
@@ -751,7 +778,7 @@
|
||||
"screen_create_room_private_option_description" = "Dim ond pobl wahoddwyd all gael mynediad i'r ystafell hon. Mae pob neges wedi'i hamgryptio o'r dechrau i'r diwedd.";
|
||||
"screen_create_room_private_option_title" = "Private";
|
||||
"screen_create_room_public_option_description" = "Gall unrhyw un ddod o hyd i'r ystafell hon.\nGallwch newid hyn unrhyw bryd yng ngosodiadau ystafell.";
|
||||
"screen_create_room_public_option_short_description" = "Anyone can join.";
|
||||
"screen_create_room_public_option_short_description" = "Anyone can join, including people outside your organisation.";
|
||||
"screen_create_room_public_option_title" = "Public";
|
||||
"screen_create_room_room_access_section_knocking_option_description" = "Gall unrhyw un ofyn am gael ymuno â'r ystafell ond bydd rhaid i weinyddwr neu gymedrolwr dderbyn y cais";
|
||||
"screen_create_room_room_access_section_knocking_option_title" = "Gofyn i gael ymuno";
|
||||
@@ -924,6 +951,10 @@
|
||||
"screen_knock_requests_list_empty_state_title" = "Dim cais i ymuno yn disgwyl";
|
||||
"screen_knock_requests_list_initial_loading_title" = "Yn llwytho ceisiadau i ymuno…";
|
||||
"screen_knock_requests_list_title" = "Ceisiadau i ymuno";
|
||||
"screen_labs_enable_gallery" = "Gallery messages";
|
||||
"screen_labs_enable_gallery_description" = "Send multiple images or videos in one go. Stable on mobile, but not yet supported by web.";
|
||||
"screen_labs_enable_knocking" = "Ask to join";
|
||||
"screen_labs_enable_knocking_description" = "Users can request access to a room that is not open for anyone to join. Stable on mobile, web implementation exists but is experimental.";
|
||||
"screen_labs_enable_threads" = "Enable thread replies";
|
||||
"screen_labs_enable_threads_description" = "The app will restart to apply this change.";
|
||||
"screen_labs_header_description" = "Try out our latest ideas in development. These features are not finalised; they may be unstable, may change.";
|
||||
@@ -932,11 +963,11 @@
|
||||
"screen_leave_space_choose_owners_action" = "Dewiswch Berchnogion";
|
||||
"screen_leave_space_last_admin_info" = "%1$@ (Gweinyddwr)";
|
||||
"screen_leave_space_subtitle" = "Dewiswch yr ystafelloedd yr hoffech chi eu gadael nad chi yw'r unig weinyddwr ar eu cyfer:";
|
||||
"screen_leave_space_subtitle_last_admin" = "You need to assign another admin for this space before you can leave.";
|
||||
"screen_leave_space_subtitle_last_admin" = "You need to assign another administrator for this space before you can leave.";
|
||||
"screen_leave_space_subtitle_last_owner" = "You are the only owner of %1$@. You need to transfer ownership to someone else before you leave.";
|
||||
"screen_leave_space_subtitle_only_last_admin" = "You will not be removed from the following room(s) because you're the only administrator:";
|
||||
"screen_leave_space_title" = "Gadael %1$@ ?";
|
||||
"screen_leave_space_title_last_admin" = "You are the only admin for %1$@";
|
||||
"screen_leave_space_title_last_admin" = "You are the only administrator for %1$@";
|
||||
"screen_leave_space_title_last_owner" = "Transfer ownership";
|
||||
"screen_link_new_device_authentication_reason_ios" = "Confirm it's you before linking a new device.";
|
||||
"screen_link_new_device_desktop_scanning_title" = "Sganiwch y cod QR";
|
||||
@@ -944,6 +975,7 @@
|
||||
"screen_link_new_device_desktop_step3" = "Sganiwch y cod QR gyda'r ddyfais hon";
|
||||
"screen_link_new_device_desktop_submit" = "Yn barod i sganio";
|
||||
"screen_link_new_device_desktop_title" = "Open %1$@ on a desktop computer to get the QR code";
|
||||
"screen_link_new_device_desktop_warning" = "Only scan a QR code after following the steps above on your own device. Never scan a code sent by another person.";
|
||||
"screen_link_new_device_enter_number_error_numbers_do_not_match" = "The numbers don’t match";
|
||||
"screen_link_new_device_enter_number_notice" = "Enter 2-digit code";
|
||||
"screen_link_new_device_enter_number_subtitle" = "This will verify that the connection to your other device is secure.";
|
||||
@@ -970,6 +1002,8 @@
|
||||
"screen_live_location_sheet_nobody_sharing" = "Nobody is sharing their location";
|
||||
"screen_live_location_sheet_sharing_live_location" = "Sharing live location";
|
||||
"screen_live_location_sheet_title" = "On the map";
|
||||
"screen_local_network_opt_in_subtitle" = "Your homeserver is on your local network. To connect, %1$@ needs permission to reach devices on this network.";
|
||||
"screen_local_network_opt_in_title" = "Allow access to local network";
|
||||
"screen_login_error_deactivated_account" = "Mae'r cyfrif hwn wedi'i gau.";
|
||||
"screen_login_error_invalid_credentials" = "Enw defnyddiwr a/neu gyfrinair anghywir";
|
||||
"screen_login_error_invalid_user_id" = "Nid yw hwn yn ddynodwr defnyddiwr dilys. Fformat disgwyliedig: ‘@user:homeserver.org’";
|
||||
@@ -1020,7 +1054,7 @@
|
||||
"screen_missing_key_backup_open_element_classic" = "Open Element Classic";
|
||||
"screen_missing_key_backup_step_1" = "Open Element Classic on your device";
|
||||
"screen_missing_key_backup_step_2_ios" = "Go to User settings > Security";
|
||||
"screen_missing_key_backup_step_3_ios" = "Scroll down to Secure Backup and tap on Set up";
|
||||
"screen_missing_key_backup_step_3_ios" = "Scroll down to Chat Backup and tap on Set up";
|
||||
"screen_missing_key_backup_step_4" = "Follow the instructions to enable your key storage";
|
||||
"screen_missing_key_backup_step_5" = "Come back to %1$@";
|
||||
"screen_missing_key_backup_title" = "Enable your key storage before proceeding to %1$@";
|
||||
@@ -1256,6 +1290,10 @@
|
||||
"screen_room_change_role_section_users" = "Aelodau";
|
||||
"screen_room_change_role_unsaved_changes_description" = "Mae gennych newidiadau heb eu cadw.";
|
||||
"screen_room_change_role_unsaved_changes_title" = "Cadw'r newidiadau?";
|
||||
"screen_room_confirm_removal_message" = "Are you sure you wish to remove this message?";
|
||||
"screen_room_confirm_removal_reason_label" = "Reason (optional)";
|
||||
"screen_room_confirm_removal_reason_placeholder" = "Enter…";
|
||||
"screen_room_confirm_removal_title" = "Confirm removal";
|
||||
"screen_room_details_add_topic_title" = "Ychwanegu pwnc";
|
||||
"screen_room_details_badge_encrypted" = "Wedi'i amgryptio";
|
||||
"screen_room_details_badge_not_encrypted" = "Heb ei amgryptio";
|
||||
@@ -1301,6 +1339,7 @@
|
||||
"screen_room_invite_again_alert_message" = "Hoffech chi eu gwahodd yn ôl?";
|
||||
"screen_room_invite_again_alert_title" = "Rydych chi ar eich pen eich hun yn y sgwrs hon";
|
||||
"screen_room_live_location_banner" = "Sharing live location";
|
||||
"screen_room_maximum_messages_selected" = "Maximum messages selected";
|
||||
"screen_room_member_details_block_alert_action" = "Rhwystro";
|
||||
"screen_room_member_details_block_alert_description" = "Fydd defnyddwyr sydd wedi'u rhwystro ddim yn gallu anfon negeseuon atoch a bydd eu holl negeseuon yn cael eu cuddio. Gallwch eu dadrwystro unrhyw bryd.";
|
||||
"screen_room_member_details_block_user" = "Rhwystro defnyddiwr";
|
||||
@@ -1341,7 +1380,8 @@
|
||||
"screen_room_notification_settings_error_setting_mode" = "Wedi methu gosod y modd, ceisiwch eto.";
|
||||
"screen_room_notification_settings_mentions_only_disclaimer" = "Nid yw eich gweinydd cartref yn cefnogi'r dewis hwn mewn ystafelloedd sydd wedi'u hamgryptio, chewch chi ddim eich hysbysu yn yr ystafell hon.";
|
||||
"screen_room_notification_settings_mode_all_messages" = "Pob neges";
|
||||
"screen_room_notification_settings_mode_mentions_and_keywords" = "Crybwylliadau ac Allweddeiriau'n unig";
|
||||
"screen_room_notification_settings_mode_mentions_and_keywords" = "Dim ond Crybwylliadau ac Allweddeiriau";
|
||||
"screen_room_notification_settings_mode_mute" = "Mute";
|
||||
"screen_room_notification_settings_room_custom_settings_title" = "Yn yr ystafell hon, rhowch wybod i mi am";
|
||||
"screen_room_pinned_banner_indicator" = "%1$@ o %2$@";
|
||||
"screen_room_pinned_banner_indicator_description" = "%1$@ Neges wedi'u pinio";
|
||||
@@ -1402,6 +1442,8 @@
|
||||
"screen_roomlist_filter_invites_empty_state_title" = "Does gennych chi ddim gwahoddiadau yn aros.";
|
||||
"screen_roomlist_filter_low_priority" = "Blaenoriaeth Isel";
|
||||
"screen_roomlist_filter_low_priority_empty_state_title" = "Does gennych chi ddim sgyrsiau blaenoriaeth isel eto";
|
||||
"screen_roomlist_filter_mention" = "Mention";
|
||||
"screen_roomlist_filter_mention_empty_state_title" = "You don’t have any unread mentions";
|
||||
"screen_roomlist_filter_mixed_empty_state_subtitle" = "Gallwch ddad-ddewis hidlwyr er mwyn gweld eich sgyrsiau eraill";
|
||||
"screen_roomlist_filter_mixed_empty_state_title" = "Does gennych chi ddim sgyrsiau ar gyfer y dewis hwn";
|
||||
"screen_roomlist_filter_people" = "Pobl";
|
||||
@@ -1488,6 +1530,8 @@
|
||||
"screen_session_verification_request_title" = "Gofynnwyd am ddilysiad";
|
||||
"screen_session_verification_they_dont_match" = "Dy'n nhw ddim yn cyfateb";
|
||||
"screen_session_verification_they_match" = "Maen nhw'n cyfateb";
|
||||
"screen_session_verification_unavailable_subtitle" = "Please use another device or recovery key.";
|
||||
"screen_session_verification_unavailable_title" = "Verification with this device is currently unavailable";
|
||||
"screen_session_verification_use_another_device_subtitle" = "Gwnewch yn siŵr fod gennych yr ap ar agor yn y ddyfais arall cyn dechrau dilysu o'r fan hon.";
|
||||
"screen_session_verification_use_another_device_title" = "Agorwch yr ap ar ddyfais arall sydd wedi'i gwirio";
|
||||
"screen_session_verification_user_initiator_subtitle" = "Er mwyn sicrhau diogelwch ychwanegol, gwiriwch y defnyddiwr hwn trwy gymharu set o emojis ar eich dyfeisiau. Gwnewch hyn trwy ddefnyddio ffordd ddibynadwy o gyfathrebu.";
|
||||
@@ -1500,6 +1544,14 @@
|
||||
"screen_session_verification_waiting_subtitle" = "Unwaith y byddwch wedi'ch derbyn, byddwch yn gallu parhau â'r dilysu.";
|
||||
"screen_session_verification_waiting_to_accept_subtitle" = "Derbyniwch y cais i gychwyn y broses ddilysu yn eich sesiwn arall i barhau.";
|
||||
"screen_session_verification_waiting_to_accept_title" = "Yn aros i dderbyn cais";
|
||||
"screen_settings_user_status_away" = "Away";
|
||||
"screen_settings_user_status_be_right_back" = "Be right back";
|
||||
"screen_settings_user_status_custom" = "Custom…";
|
||||
"screen_settings_user_status_custom_hint" = "Custom status…";
|
||||
"screen_settings_user_status_focus_time" = "Focus time";
|
||||
"screen_settings_user_status_in_a_meeting" = "In a meeting";
|
||||
"screen_settings_user_status_on_the_road" = "On the road";
|
||||
"screen_settings_user_status_placeholder" = "What's your status?";
|
||||
"screen_share_location_live_location_disclaimer_title" = "Your live location history will be stored in the room and visible to members after the session ends.";
|
||||
"screen_share_location_live_location_duration_picker_title" = "Choose how long to share your live location.";
|
||||
"screen_share_location_live_location_missing_permissions" = "You do not have permissions to share your live location in this room";
|
||||
@@ -1539,7 +1591,7 @@
|
||||
"screen_space_list_parent_space" = "Gofod %1$@";
|
||||
"screen_space_list_title" = "Gofodau";
|
||||
"screen_space_menu_action_members" = "View members";
|
||||
"screen_space_remove_rooms_confirmation_content" = "Removing a room will not affect the room access. To change the access go to Room info > Privacy & security.";
|
||||
"screen_space_remove_rooms_confirmation_content" = "Removing a room will not affect the room access. To change the access go to Room info > Security & privacy.";
|
||||
"screen_space_remove_rooms_confirmation_title_ios" = "Remove rooms from %1$@?";
|
||||
"screen_space_settings_leave_space" = "Gadael y gofod";
|
||||
"screen_space_settings_roles_and_permissions" = "Rolau a chaniatâd";
|
||||
@@ -1690,6 +1742,7 @@
|
||||
"troubleshoot_notifications_test_push_loop_back_failure_2" = "Gwall: %1$@.";
|
||||
"troubleshoot_notifications_test_push_loop_back_failure_3" = "Gwall, methu profi'r gwthio.";
|
||||
"troubleshoot_notifications_test_push_loop_back_failure_4" = "Gwall, terfyn amser wrth aros am y gwthio.";
|
||||
"troubleshoot_notifications_test_push_loop_back_failure_rate_limit" = "Error: the push gateway is rate limiting this device, so notifications won't be reliable. Please set up a different push gateway.";
|
||||
"troubleshoot_notifications_test_push_loop_back_success" = "Cymerodd dolen gwthio nôl %1$d ms.";
|
||||
"troubleshoot_notifications_test_push_loop_back_title" = "Prawf dolen gwthio'n ôl";
|
||||
"troubleshoot_notifications_test_unified_push_description" = "Sicrhewch fod dosbarthwyr UnifiedPush ar gael.";
|
||||
|
||||
@@ -26,6 +26,22 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>a11y_gallery_more_media</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Gallery, %1$d more media</string>
|
||||
<key>other</key>
|
||||
<string>Gallery, %1$d more medias</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>a11y_polls_percent_of_total</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -74,6 +90,38 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>common_gallery_reply_attachments</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%1$d attachment…</string>
|
||||
<key>other</key>
|
||||
<string>%1$d attachments…</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>common_gallery_reply_media_items</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%1$d media item…</string>
|
||||
<key>other</key>
|
||||
<string>%1$d media items…</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>common_many_members</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -298,6 +346,22 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>notification_gallery_body</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Shared %1$d attachment</string>
|
||||
<key>other</key>
|
||||
<string>Shared %1$d attachments</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>notification_invitations</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -394,6 +458,22 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen.room.timeline_redacted_messages</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%1$d removed message</string>
|
||||
<key>other</key>
|
||||
<string>%1$d removed messages</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen_advanced_settings_live_location_update_distance</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -634,6 +714,22 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen_room_selection_count</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%1$d message selected</string>
|
||||
<key>other</key>
|
||||
<string>%1$d messages selected</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen_room_timeline_reaction_a11y</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -770,7 +866,7 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen_timeline_active_call_extra_joined_count</key>
|
||||
<key>screen_timeline_active_call_joined_count</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
@@ -779,9 +875,9 @@
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>+ %1$d joined</string>
|
||||
<string>%1$d joined</string>
|
||||
<key>other</key>
|
||||
<string>+ %1$d joined</string>
|
||||
<string>%1$d joined</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
|
||||
@@ -6,16 +6,23 @@
|
||||
"a11y_collapse_message_text_field" = "Minimér tekstfeltet for beskeder";
|
||||
"a11y_create_poll_votes_allowed_decrease" = "Decrease votes allowed per person";
|
||||
"a11y_create_poll_votes_allowed_increase" = "Increase votes allowed per person";
|
||||
"a11y_custom_emoji" = "Custom emoji";
|
||||
"a11y_delete" = "Slet";
|
||||
"a11y_duration" = "Duration: %1$@";
|
||||
"a11y_edit_avatar" = "Redigér avatar";
|
||||
"a11y_edit_room_address_hint" = "Den fulde adresse vil være %1$@";
|
||||
"a11y_expand_message_text_field" = "Udvid tekstfeltet for beskeder";
|
||||
"a11y_gallery_attachment" = "Gallery, attachment %1$d";
|
||||
"a11y_gallery_failed_scan" = "Gallery, failed scan %1$d";
|
||||
"a11y_gallery_image" = "Gallery, image %1$d";
|
||||
"a11y_gallery_scanning" = "Gallery, scanning %1$d";
|
||||
"a11y_gallery_video" = "Gallery, video %1$d";
|
||||
"a11y_hide_password" = "Skjul adgangskode";
|
||||
"a11y_info" = "Info";
|
||||
"a11y_join_call" = "Deltag i opkald";
|
||||
"a11y_jump_to_bottom" = "Hop til bunden";
|
||||
"a11y_jump_to_unread" = "Jump to unread";
|
||||
"a11y_jump_to_unread_messages" = "Jump to first unread message";
|
||||
"a11y_notifications_mentions_only" = "Kun omtaler";
|
||||
"a11y_notifications_muted" = "Lyd slået fra";
|
||||
"a11y_notifications_new_mentions" = "Nye omtaler";
|
||||
@@ -50,6 +57,7 @@
|
||||
"a11y_start_call" = "Start et opkald";
|
||||
"a11y_start_video_call" = "Start et videoopkald";
|
||||
"a11y_start_voice_call" = "Start et taleopkald";
|
||||
"a11y_status" = "Status";
|
||||
"a11y_tombstoned_room" = "Deaktiveret rum";
|
||||
"a11y_user_menu" = "Brugermenu";
|
||||
"a11y_video_preview" = "Video preview";
|
||||
@@ -135,6 +143,7 @@
|
||||
"action_manage_account_and_devices" = "Administrer konto og enheder";
|
||||
"action_manage_devices" = "Administrer enheder";
|
||||
"action_manage_rooms" = "Administrer rum";
|
||||
"action_mark_as_read" = "Mark as read";
|
||||
"action_message" = "Besked";
|
||||
"action_minimize" = "Minimér";
|
||||
"action_next" = "Næste";
|
||||
@@ -165,6 +174,7 @@
|
||||
"action_retry_decryption" = "Prøv at dekryptere igen";
|
||||
"action_save" = "Gem";
|
||||
"action_search" = "Søg";
|
||||
"action_select" = "Select";
|
||||
"action_select_all" = "Vælg alle";
|
||||
"action_send" = "Send";
|
||||
"action_send_edited_message" = "Send redigeret besked";
|
||||
@@ -294,6 +304,7 @@
|
||||
"common_no_space_name" = "Intet klyngenavn";
|
||||
"common_not_encrypted" = "Ikke krypteret";
|
||||
"common_offline" = "Offline";
|
||||
"common_on_a_call" = "On a call";
|
||||
"common_open_source_licenses" = "Open Source-licenser";
|
||||
"common_optic_id_ios" = "Optisk ID";
|
||||
"common_or" = "eller";
|
||||
@@ -410,7 +421,8 @@
|
||||
"confirm_recovery_key_banner_secondary_button_title" = "Har du glemt din gendannelsesnøgle?";
|
||||
"confirm_recovery_key_banner_title" = "Dit nøglelager er ikke synkroniseret";
|
||||
"content_scanner_not_found" = "Download not available.";
|
||||
"content_scanner_not_found_title" = "File not found";
|
||||
"content_scanner_not_found_title" = "Something went wrong";
|
||||
"content_scanner_scanning" = "Scanning…";
|
||||
"content_scanner_unsafe_message" = "Preview and download have been disabled.";
|
||||
"content_scanner_unsafe_title" = "The file is not safe";
|
||||
"crash_detection_dialog_content" = "%1$@ crashede sidste gang den blev brugt. Vil du dele en ulykkesrapport med os?";
|
||||
@@ -484,6 +496,11 @@
|
||||
"error_no_compatible_app_found" = "Der blev ikke fundet nogen kompatibel app til at håndtere denne handling.";
|
||||
"error_room_address_already_exists" = "Denne rumadresse er allerede taget. Prøv at redigere rummets adressefelt eller at skifte rummets navn";
|
||||
"error_room_address_invalid_symbols" = "Nogle tegn er ikke tilladt. Kun bogstaver, cifre og følgende symboler understøttes! $ & '() * +/; =? @ [] - . _";
|
||||
"error_sending_failure_invalid_mime_type" = "Invalid mime type: %@";
|
||||
"error_sending_failure_missing_media_content" = "Missing media content";
|
||||
"error_sending_failure_other" = "Error details: %@";
|
||||
"error_sending_failure_sending_from_unverified_device" = "Sending from unverified device";
|
||||
"error_sending_failure_unknown" = "Unknown error";
|
||||
"error_some_messages_have_not_been_sent" = "Nogle beskeder er ikke blevet sendt";
|
||||
"error_unknown" = "Beklager, der opstod en fejl";
|
||||
"error.account_already_logged_in" = "Du er allerede logget ind på denne enhed som %1$@.";
|
||||
@@ -513,6 +530,8 @@
|
||||
"notification_invitation_action_reject" = "Afvis";
|
||||
"notification_invite_body" = "Inviterede dig til at samtale";
|
||||
"notification_invite_body_with_sender" = "%1$@ inviterede dig til at samtale";
|
||||
"notification_knock_request_body" = "Requested to join";
|
||||
"notification_live_location_started_body" = "Started sharing their live location";
|
||||
"notification_mentioned_you_body" = "Nævnte dig: %1$@";
|
||||
"notification_new_messages" = "Nye beskeder";
|
||||
"notification_reaction_body" = "Reagerede med%1$@";
|
||||
@@ -703,8 +722,16 @@
|
||||
"screen_change_server_error_unauthorized_homeserver_title" = "Kontoudbyder %1$@ er ikke tilladt.";
|
||||
"screen_change_server_form_header" = "URL-adressen på din hjemmeserver";
|
||||
"screen_change_server_form_notice" = "Indtast en domæneadresse.";
|
||||
"screen_change_server_navigation_title_login" = "Sign in";
|
||||
"screen_change_server_navigation_title_register" = "Create account";
|
||||
"screen_change_server_subtitle" = "Hvad er adressen på din server?";
|
||||
"screen_change_server_textfield_footer_login" = "If your account is provided by your company or a community, then change the account provider (example: companyname.com).";
|
||||
"screen_change_server_textfield_footer_register" = "Create an account on matrix.org for free. If you want to create an account with a different provider, then change it accordingly (example: communityname.org).";
|
||||
"screen_change_server_textfield_header" = "Account provider";
|
||||
"screen_change_server_textfield_placeholder" = "example.com";
|
||||
"screen_change_server_title" = "Vælg din server";
|
||||
"screen_change_server_title_login" = "Enter your account provider";
|
||||
"screen_change_server_title_register" = "Choose an account provider";
|
||||
"screen_chat_backup_key_backup_action_disable" = "Slet nøglelager";
|
||||
"screen_chat_backup_key_backup_action_enable" = "Aktivér sikkerhedskopiering";
|
||||
"screen_chat_backup_key_backup_description" = "Dette giver dig mulighed for at se din chathistorik på alle nye enheder og er påkrævet til sikkerhedskopiering af chats og digital identitet.%1$@ .";
|
||||
@@ -924,6 +951,10 @@
|
||||
"screen_knock_requests_list_empty_state_title" = "Ingen ventende anmodning om at deltage";
|
||||
"screen_knock_requests_list_initial_loading_title" = "Indlæser anmodninger om at deltage...";
|
||||
"screen_knock_requests_list_title" = "Anmodninger om at deltage";
|
||||
"screen_labs_enable_gallery" = "Gallery messages";
|
||||
"screen_labs_enable_gallery_description" = "Send multiple images or videos in one go. Stable on mobile, but not yet supported by web.";
|
||||
"screen_labs_enable_knocking" = "Ask to join";
|
||||
"screen_labs_enable_knocking_description" = "Users can request access to a room that is not open for anyone to join. Stable on mobile, web implementation exists but is experimental.";
|
||||
"screen_labs_enable_threads" = "Aktivér svar-tråde";
|
||||
"screen_labs_enable_threads_description" = "Appen genstarter for at anvende denne ændring.";
|
||||
"screen_labs_header_description" = "Prøv vores nyeste idéer under udvikling. Disse funktioner er ikke færdige; de kan være ustabile og kan ændre sig.";
|
||||
@@ -944,6 +975,7 @@
|
||||
"screen_link_new_device_desktop_step3" = "Scan QR-koden med denne enhed";
|
||||
"screen_link_new_device_desktop_submit" = "Klar til at scanne";
|
||||
"screen_link_new_device_desktop_title" = "Åbn %1$@ på en stationær computer for at få QR-koden";
|
||||
"screen_link_new_device_desktop_warning" = "Only scan a QR code after following the steps above on your own device. Never scan a code sent by another person.";
|
||||
"screen_link_new_device_enter_number_error_numbers_do_not_match" = "Tallene stemmer ikke overens";
|
||||
"screen_link_new_device_enter_number_notice" = "Indtast 2-cifret kode";
|
||||
"screen_link_new_device_enter_number_subtitle" = "Dette vil bekræfte, at forbindelsen til din anden enhed er sikker.";
|
||||
@@ -970,6 +1002,8 @@
|
||||
"screen_live_location_sheet_nobody_sharing" = "Ingen deler deres placering";
|
||||
"screen_live_location_sheet_sharing_live_location" = "Deler placering live";
|
||||
"screen_live_location_sheet_title" = "På kortet";
|
||||
"screen_local_network_opt_in_subtitle" = "Your homeserver is on your local network. To connect, %1$@ needs permission to reach devices on this network.";
|
||||
"screen_local_network_opt_in_title" = "Allow access to local network";
|
||||
"screen_login_error_deactivated_account" = "Denne konto er blevet slettet.";
|
||||
"screen_login_error_invalid_credentials" = "Forkert brugernavn og/eller adgangskode";
|
||||
"screen_login_error_invalid_user_id" = "Dette er ikke en gyldig brugeridentifikation. Forventet format: '@bruger:hjemmeserver.org'";
|
||||
@@ -1256,6 +1290,10 @@
|
||||
"screen_room_change_role_section_users" = "Medlemmer";
|
||||
"screen_room_change_role_unsaved_changes_description" = "Du har ændringer, der ikke er gemt.";
|
||||
"screen_room_change_role_unsaved_changes_title" = "Gem ændringer?";
|
||||
"screen_room_confirm_removal_message" = "Are you sure you wish to remove this message?";
|
||||
"screen_room_confirm_removal_reason_label" = "Reason (optional)";
|
||||
"screen_room_confirm_removal_reason_placeholder" = "Enter…";
|
||||
"screen_room_confirm_removal_title" = "Confirm removal";
|
||||
"screen_room_details_add_topic_title" = "Tilføj emne";
|
||||
"screen_room_details_badge_encrypted" = "Krypteret";
|
||||
"screen_room_details_badge_not_encrypted" = "Ikke krypteret";
|
||||
@@ -1301,6 +1339,7 @@
|
||||
"screen_room_invite_again_alert_message" = "Vil du invitere dem igen?";
|
||||
"screen_room_invite_again_alert_title" = "Du er alene i denne samtale";
|
||||
"screen_room_live_location_banner" = "Deler placering live";
|
||||
"screen_room_maximum_messages_selected" = "Maximum messages selected";
|
||||
"screen_room_member_details_block_alert_action" = "Bloker";
|
||||
"screen_room_member_details_block_alert_description" = "Blokerede brugere vil ikke være i stand til at sende dig beskeder, og alle deres beskeder vil blive skjult. Du kan fjerne blokeringen af dem når som helst.";
|
||||
"screen_room_member_details_block_user" = "Bloker bruger";
|
||||
@@ -1340,8 +1379,9 @@
|
||||
"screen_room_notification_settings_error_restoring_default" = "Gendannelse af standardtilstanden mislykkedes. Prøv igen.";
|
||||
"screen_room_notification_settings_error_setting_mode" = "Kunne ikke indstille tilstanden. Prøv igen.";
|
||||
"screen_room_notification_settings_mentions_only_disclaimer" = "Din hjemmeserver understøtter ikke denne indstilling i krypterede rum, du får ikke besked i dette rum.";
|
||||
"screen_room_notification_settings_mode_all_messages" = "Alle beskeder";
|
||||
"screen_room_notification_settings_mode_mentions_and_keywords" = "Kun omtaler og nøgleord";
|
||||
"screen_room_notification_settings_mode_all_messages" = "All messages";
|
||||
"screen_room_notification_settings_mode_mentions_and_keywords" = "Mentions and replies only";
|
||||
"screen_room_notification_settings_mode_mute" = "Mute";
|
||||
"screen_room_notification_settings_room_custom_settings_title" = "Giv mig besked i dette rum for";
|
||||
"screen_room_pinned_banner_indicator" = "%1$@ af %2$@";
|
||||
"screen_room_pinned_banner_indicator_description" = "%1$@ Fastgjorte beskeder";
|
||||
@@ -1402,6 +1442,8 @@
|
||||
"screen_roomlist_filter_invites_empty_state_title" = "Du har ingen afventende invitationer.";
|
||||
"screen_roomlist_filter_low_priority" = "Lav prioritet";
|
||||
"screen_roomlist_filter_low_priority_empty_state_title" = "Du har endnu ingen chats med lav prioritet";
|
||||
"screen_roomlist_filter_mention" = "Mention";
|
||||
"screen_roomlist_filter_mention_empty_state_title" = "You don’t have any unread mentions";
|
||||
"screen_roomlist_filter_mixed_empty_state_subtitle" = "Du kan fravælge filtre for at se dine andre samtaler";
|
||||
"screen_roomlist_filter_mixed_empty_state_title" = "Du har ingen samtaler til dette valg";
|
||||
"screen_roomlist_filter_people" = "Brugere";
|
||||
@@ -1488,6 +1530,8 @@
|
||||
"screen_session_verification_request_title" = "Anmodet om verifikation";
|
||||
"screen_session_verification_they_dont_match" = "De matcher ikke";
|
||||
"screen_session_verification_they_match" = "De matcher";
|
||||
"screen_session_verification_unavailable_subtitle" = "Please use another device or recovery key.";
|
||||
"screen_session_verification_unavailable_title" = "Verification with this device is currently unavailable";
|
||||
"screen_session_verification_use_another_device_subtitle" = "Sørg for, at du har appen åben på den anden enhed, før du starter verifikationen herfra.";
|
||||
"screen_session_verification_use_another_device_title" = "Åbn appen på en anden bekræftet enhed";
|
||||
"screen_session_verification_user_initiator_subtitle" = "For ekstra sikkerhed, verificér denne bruger ved at sammenligne et sæt emojier på jeres enheder. Gør dette ved at bruge en kommunikationsmetode i stoler på.";
|
||||
@@ -1500,6 +1544,14 @@
|
||||
"screen_session_verification_waiting_subtitle" = "Når du er blevet accepteret, kan du fortsætte med verifikationen.";
|
||||
"screen_session_verification_waiting_to_accept_subtitle" = "Accepter anmodningen om at starte bekræftelsesprocessen i din anden session for at fortsætte.";
|
||||
"screen_session_verification_waiting_to_accept_title" = "Venter på at acceptere anmodningen";
|
||||
"screen_settings_user_status_away" = "Away";
|
||||
"screen_settings_user_status_be_right_back" = "Be right back";
|
||||
"screen_settings_user_status_custom" = "Custom…";
|
||||
"screen_settings_user_status_custom_hint" = "Custom status…";
|
||||
"screen_settings_user_status_focus_time" = "Focus time";
|
||||
"screen_settings_user_status_in_a_meeting" = "In a meeting";
|
||||
"screen_settings_user_status_on_the_road" = "On the road";
|
||||
"screen_settings_user_status_placeholder" = "What's your status?";
|
||||
"screen_share_location_live_location_disclaimer_title" = "Din live-positionshistorik gemmes i rummet og er synlig for medlemmerne, når sessionen er afsluttet.";
|
||||
"screen_share_location_live_location_duration_picker_title" = "Vælg, hvor længe du vil dele din aktuelle position.";
|
||||
"screen_share_location_live_location_missing_permissions" = "You do not have permissions to share your live location in this room";
|
||||
@@ -1690,6 +1742,7 @@
|
||||
"troubleshoot_notifications_test_push_loop_back_failure_2" = "Fejl: %1$@.";
|
||||
"troubleshoot_notifications_test_push_loop_back_failure_3" = "Fejl, kan ikke teste push.";
|
||||
"troubleshoot_notifications_test_push_loop_back_failure_4" = "Fejl, timeout venter på push.";
|
||||
"troubleshoot_notifications_test_push_loop_back_failure_rate_limit" = "Error: the push gateway is rate limiting this device, so notifications won't be reliable. Please set up a different push gateway.";
|
||||
"troubleshoot_notifications_test_push_loop_back_success" = "Push loop back tog %1$d ms.";
|
||||
"troubleshoot_notifications_test_push_loop_back_title" = "Afprøv Push loop back";
|
||||
"troubleshoot_notifications_test_unified_push_description" = "Sørg for, at UnifiedPush-distributører er tilgængelige.";
|
||||
|
||||
@@ -18,6 +18,22 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>a11y_gallery_more_media</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Gallery, %1$d more media</string>
|
||||
<key>other</key>
|
||||
<string>Gallery, %1$d more medias</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>a11y_polls_percent_of_total</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -27,7 +43,7 @@
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%1$d% af de samlede stemmer</string>
|
||||
<string>%1$d%% af de samlede stemmer</string>
|
||||
<key>other</key>
|
||||
<string>%1$d procent af det samlede antal stemmer</string>
|
||||
</dict>
|
||||
@@ -50,6 +66,38 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>common_gallery_reply_attachments</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%1$d attachment…</string>
|
||||
<key>other</key>
|
||||
<string>%1$d attachments…</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>common_gallery_reply_media_items</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%1$d media item…</string>
|
||||
<key>other</key>
|
||||
<string>%1$d media items…</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>common_many_members</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -208,6 +256,22 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>notification_gallery_body</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Shared %1$d attachment</string>
|
||||
<key>other</key>
|
||||
<string>Shared %1$d attachments</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>notification_invitations</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -272,6 +336,22 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen.room.timeline_redacted_messages</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%1$d removed message</string>
|
||||
<key>other</key>
|
||||
<string>%1$d removed messages</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen_advanced_settings_live_location_update_distance</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -464,6 +544,22 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen_room_selection_count</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%1$d message selected</string>
|
||||
<key>other</key>
|
||||
<string>%1$d messages selected</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen_room_timeline_reaction_a11y</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
@@ -560,7 +656,7 @@
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
</dict>
|
||||
<key>screen_timeline_active_call_extra_joined_count</key>
|
||||
<key>screen_timeline_active_call_joined_count</key>
|
||||
<dict>
|
||||
<key>COUNT</key>
|
||||
<dict>
|
||||
@@ -569,9 +665,9 @@
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>+ %1$d joined</string>
|
||||
<string>%1$d joined</string>
|
||||
<key>other</key>
|
||||
<string>+ %1$d joined</string>
|
||||
<string>%1$d joined</string>
|
||||
</dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@COUNT@</string>
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// HealthChat fork strings. Not managed by Localazy — edit all three languages by hand.
|
||||
"common_academic_title" = "Titel";
|
||||
"common_address" = "Adresse";
|
||||
"common_business_email" = "E-Mail (geschäftlich)";
|
||||
"common_business_tel" = "Telefon (geschäftlich)";
|
||||
"common_city" = "Ort";
|
||||
"common_first_name" = "Vorname";
|
||||
"common_further_info" = "Weitere Infos / Qualifikationen";
|
||||
"common_house_number" = "Nr.";
|
||||
"common_last_name" = "Nachname";
|
||||
"common_postal_code" = "PLZ";
|
||||
"common_practice_name" = "Praxisname / Firmenname";
|
||||
"common_specialty" = "Fachgebiet";
|
||||
"common_street" = "Strasse";
|
||||
"common_website" = "Webseite";
|
||||
"screen_invite_member_email_placeholder" = "E-Mail-Adresse";
|
||||
"screen_invite_member_note_footer" = "Die persönliche Nachricht muss mindestens 10 Zeichen lang sein.";
|
||||
"screen_invite_member_note_placeholder" = "Persönliche Nachricht";
|
||||
"screen_invite_member_success" = "Einladung wurde versendet";
|
||||
"screen_invite_member_title" = "Mitglied einladen";
|
||||
"screen_member_directory_pending_approval" = "Ihr Konto wird derzeit geprüft. Sie erhalten Zugriff auf das Mitgliederverzeichnis, sobald Ihr Konto freigegeben wurde.";
|
||||
"screen_member_directory_search_placeholder" = "Name, Praxis, Ort oder Fachgebiet";
|
||||
"screen_member_directory_title" = "Mitglieder";
|
||||
"screen_profile_edit_section_address" = "Praxisadresse";
|
||||
"screen_profile_edit_section_contact" = "Kontaktdaten";
|
||||
"screen_profile_edit_section_personal" = "Persönliche Angaben";
|
||||
"screen_profile_edit_section_professional" = "Berufliche Angaben";
|
||||
@@ -1,6 +1,6 @@
|
||||
"NSCameraUsageDescription" = "Um Bilder oder Videos aufzunehmen und als Nachricht zu versenden, benötigt Element X Zugriff auf die Kamera.";
|
||||
"NSFaceIDUsageDescription" = "Face ID wird verwendet um die App zu entsperren.";
|
||||
"NSLocationAlwaysAndWhenInUseUsageDescription" = "Um deinen Live-Standort zu teilen, benötigt Element X Zugriff auf deinen Standort, während die App im Hintergrund läuft.";
|
||||
"NSLocationWhenInUseUsageDescription" = "Erlaube Element X den Zugriff auf deinen Standort, um den Standort zu teilen.";
|
||||
"NSFaceIDUsageDescription" = "Face ID wird verwendet, um den Zugriff auf dein Konto zu schützen.";
|
||||
"NSLocationAlwaysAndWhenInUseUsageDescription" = "Dein Standort wird auch im Hintergrund verwendet, wenn du ihn in einem Chat live teilst.";
|
||||
"NSLocationWhenInUseUsageDescription" = "Dein Standort wird verwendet, wenn du ihn selbst in einem Chat teilst oder Orte in deiner Nähe anzeigen möchtest.";
|
||||
"NSMicrophoneUsageDescription" = "Um Sprachnachrichten aufzunehmen und mit Element X zu versenden, wird der Zugriff auf das Mikrofon benötigt.";
|
||||
"NSPhotoLibraryUsageDescription" = "Damit kannst du Bilder und Videos in deiner Foto Galerie speichern.";
|
||||
|
||||