mirror of
https://github.com/vector-im/element-call.git
synced 2026-08-20 20:49:20 +00:00
Compare commits
144 Commits
fkwp/updat
...
robin/webc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f727b904b | ||
|
|
380880137e | ||
|
|
8828b705d9 | ||
|
|
b7e5b81dbf | ||
|
|
e12dfa9a9f | ||
|
|
48b4fd63fe | ||
|
|
f2b68e6dee | ||
|
|
128851263b | ||
|
|
679ff8c2af | ||
|
|
9dcaa60982 | ||
|
|
34a223f04b | ||
|
|
005402d8d1 | ||
|
|
76fb16dbfd | ||
|
|
1a3ac826b2 | ||
|
|
25afbf4303 | ||
|
|
9c65b40225 | ||
|
|
fb63e64eb4 | ||
|
|
8679b90bd7 | ||
|
|
14ff6dce93 | ||
|
|
08f034251c | ||
|
|
06e1a4eb1e | ||
|
|
aee30d8402 | ||
|
|
a4a6a16482 | ||
|
|
eeb3a1a991 | ||
|
|
c0c498aa04 | ||
|
|
9f5eae0ac1 | ||
|
|
f92c683bc1 | ||
|
|
dfb9eb4b1f | ||
|
|
fa0af6403e | ||
|
|
9df0f58117 | ||
|
|
0b82dcf701 | ||
|
|
8f1761442b | ||
|
|
7d0117903e | ||
|
|
cd9035b5fc | ||
|
|
02ce1f701a | ||
|
|
e88e0b1901 | ||
|
|
c91cc79162 | ||
|
|
edd8373649 | ||
|
|
31032994a5 | ||
|
|
984383b60d | ||
|
|
de4875ac7c | ||
|
|
9416c41d62 | ||
|
|
b61bed0197 | ||
|
|
8ad1d60975 | ||
|
|
1ae876de26 | ||
|
|
09177b90d3 | ||
|
|
dc5d1369bf | ||
|
|
a6696c2304 | ||
|
|
a1d6eef12a | ||
|
|
78a41c09de | ||
|
|
3fc4cc908e | ||
|
|
63ad4a3ad3 | ||
|
|
7142122a74 | ||
|
|
b7b3fde202 | ||
|
|
8fd99ed23e | ||
|
|
e751248fee | ||
|
|
3243afd061 | ||
|
|
733279f010 | ||
|
|
a5036ee291 | ||
|
|
2cf2e090f6 | ||
|
|
78a88a9e0b | ||
|
|
4694354f69 | ||
|
|
a839cde34f | ||
|
|
8b63813e51 | ||
|
|
e63aff3e9b | ||
|
|
d5407a4fde | ||
|
|
b813a3c95b | ||
|
|
0f69ace92a | ||
|
|
f5615f2e26 | ||
|
|
cb64c311c5 | ||
|
|
ee45e58903 | ||
|
|
4b247540ef | ||
|
|
fc281c516c | ||
|
|
8858e4003a | ||
|
|
58e542e15d | ||
|
|
770b94eb44 | ||
|
|
8c8a5e28a0 | ||
|
|
d0c76139a8 | ||
|
|
9c9d38cd95 | ||
|
|
13f12779dc | ||
|
|
c305fb8604 | ||
|
|
054d6a9e48 | ||
|
|
3c0d81844f | ||
|
|
1702b15abe | ||
|
|
e98b0ed1ed | ||
|
|
ba22be175d | ||
|
|
e166f36ab5 | ||
|
|
055f4d0193 | ||
|
|
7977101578 | ||
|
|
5267940a8a | ||
|
|
cb174aeaa6 | ||
|
|
d97332f47a | ||
|
|
6551ce8e18 | ||
|
|
3c5594b7e1 | ||
|
|
eb9593a4e5 | ||
|
|
078f36c14a | ||
|
|
7297dbcc00 | ||
|
|
ba382eef75 | ||
|
|
23b1a5fff5 | ||
|
|
95fed3fc2d | ||
|
|
6398fd2783 | ||
|
|
e8f0398f59 | ||
|
|
a7dc289b2d | ||
|
|
6884b19a73 | ||
|
|
75933a508c | ||
|
|
e5358e8609 | ||
|
|
bc0ea20343 | ||
|
|
00d724a3a9 | ||
|
|
4c4d01211c | ||
|
|
ba2e7a7462 | ||
|
|
38110749cd | ||
|
|
96ea920e98 | ||
|
|
bb0e1f38dc | ||
|
|
77ff3583b0 | ||
|
|
e0f4bf8eab | ||
|
|
7c985b0d9c | ||
|
|
7983adb98e | ||
|
|
6accf088bf | ||
|
|
3f48810034 | ||
|
|
843f081d78 | ||
|
|
f18ce5adf1 | ||
|
|
c860be73f6 | ||
|
|
5ead61d406 | ||
|
|
b6cc9c534b | ||
|
|
aa5cf2f591 | ||
|
|
18606462bb | ||
|
|
59bc73cedf | ||
|
|
b77c4afff2 | ||
|
|
574c89529a | ||
|
|
c6d48446f4 | ||
|
|
95c3ca8859 | ||
|
|
d179db1e8f | ||
|
|
9eae919050 | ||
|
|
7d8e9a7969 | ||
|
|
c2b6518027 | ||
|
|
a6745ef34a | ||
|
|
ae71c6e679 | ||
|
|
aade8f94a6 | ||
|
|
0be312a5e3 | ||
|
|
95bc7db28a | ||
|
|
d23beefb60 | ||
|
|
70ff435a8c | ||
|
|
140fe484d7 | ||
|
|
c798c79f41 |
@@ -1,10 +1,10 @@
|
||||
#!/usr/bin/sh
|
||||
|
||||
FILE=.links.disabled.yaml
|
||||
FILE=.links.temp-disabled.yaml
|
||||
if test -f "$FILE"; then
|
||||
# echo "$FILE exists. -> moving to .links.disabled.yaml"
|
||||
mv .links.disabled.yaml .links.yaml
|
||||
# echo "running yarn"
|
||||
# Only do the post-commit hook if the file was temp-disabled by the pre-commit hook.
|
||||
# Otherwise linking was actively (`yarn links:disable`) disabled and this hook should noop.
|
||||
mv .links.temp-disabled.yaml .links.yaml
|
||||
yarnLog=$(yarn)
|
||||
echo "[yarn-linker] The post-commit hook has re-enabled .links.yaml."
|
||||
exit 1
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
FILE=".links.yaml"
|
||||
if test -f "$FILE"; then
|
||||
# echo "$FILE exists. -> moving to .links.disabled.yaml"
|
||||
mv .links.yaml .links.disabled.yaml
|
||||
mv .links.yaml .links.temp-disabled.yaml
|
||||
# echo "running yarn"
|
||||
x=$(yarn)
|
||||
y=$(git add yarn.lock)
|
||||
|
||||
@@ -46,6 +46,8 @@ jobs:
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: ${{ inputs.docker_tags}}
|
||||
labels: |
|
||||
org.opencontainers.image.licenses=AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
|
||||
|
||||
14
.github/workflows/changelog-label.yml
vendored
Normal file
14
.github/workflows/changelog-label.yml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
name: PR changelog label
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [labeled, unlabeled, opened]
|
||||
jobs:
|
||||
pr-changelog-label:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: yogevbd/enforce-label-action@2.1.0
|
||||
with:
|
||||
REQUIRED_LABELS_ANY: "PR-Bug-Fix,PR-Documentation,PR-Task,PR-Feature,PR-Improvement,PR-Developer-Experience,dependencies"
|
||||
REQUIRED_LABELS_ANY_DESCRIPTION: "Select at least one 'PR-' label"
|
||||
BANNED_LABELS: "banned"
|
||||
115
.github/workflows/publish-embedded-packages.yaml
vendored
115
.github/workflows/publish-embedded-packages.yaml
vendored
@@ -11,19 +11,48 @@ on:
|
||||
push:
|
||||
branches: [livekit]
|
||||
|
||||
env:
|
||||
# We perform a dry run for all events except releases.
|
||||
# This is to help make sure that we notice if the packaging process has become
|
||||
# broken ahead of a release.
|
||||
DRY_RUN: ${{ github.event_name != 'release' }}
|
||||
# We should only use the hard coded test value for a dry run
|
||||
VERSION: ${{ github.event_name == 'release' && github.event.release.tag_name || 'v0.0.0-pre.0' }}
|
||||
|
||||
jobs:
|
||||
versioning:
|
||||
name: Versioning
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
DRY_RUN: ${{ steps.dry_run.outputs.DRY_RUN }}
|
||||
PREFIXED_VERSION: ${{ steps.prefixed_version.outputs.PREFIXED_VERSION }}
|
||||
UNPREFIXED_VERSION: ${{ steps.unprefixed_version.outputs.UNPREFIXED_VERSION }}
|
||||
TAG: ${{ steps.tag.outputs.TAG }}
|
||||
steps:
|
||||
- name: Calculate VERSION
|
||||
# We should only use the hard coded test value for a dry run
|
||||
run: echo "VERSION=${{ github.event_name == 'release' && github.event.release.tag_name || 'v0.0.0-pre.0' }}" >> "$GITHUB_ENV"
|
||||
- id: dry_run
|
||||
name: Set DRY_RUN
|
||||
# We perform a dry run for all events except releases.
|
||||
# This is to help make sure that we notice if the packaging process has become
|
||||
# broken ahead of a release.
|
||||
run: echo "DRY_RUN=${{ github.event_name != 'release' }}" >> "$GITHUB_OUTPUT"
|
||||
- id: prefixed_version
|
||||
name: Set PREFIXED_VERSION
|
||||
run: echo "PREFIXED_VERSION=${VERSION}" >> "$GITHUB_OUTPUT"
|
||||
- id: unprefixed_version
|
||||
name: Set UNPREFIXED_VERSION
|
||||
# This just strips the leading character
|
||||
run: echo "UNPREFIXED_VERSION=${VERSION:1}" >> "$GITHUB_OUTPUT"
|
||||
- id: tag
|
||||
# latest = a proper release
|
||||
# other = anything else
|
||||
name: Set tag
|
||||
run: |
|
||||
if [[ "${VERSION}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "TAG=latest" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "TAG=other" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
build_element_call:
|
||||
needs: versioning
|
||||
uses: ./.github/workflows/build-element-call.yaml
|
||||
with:
|
||||
vite_app_version: embedded-${{ github.event.release.tag_name || 'v0.0.0-pre.0' }} # Using ${{ env.VERSION }} here doesn't work
|
||||
vite_app_version: embedded-${{ needs.versioning.outputs.PREFIXED_VERSION }}
|
||||
package: embedded
|
||||
secrets:
|
||||
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
|
||||
@@ -32,7 +61,7 @@ jobs:
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
|
||||
publish_tarball:
|
||||
needs: build_element_call
|
||||
needs: [build_element_call, versioning]
|
||||
if: always()
|
||||
name: Publish tarball
|
||||
runs-on: ubuntu-latest
|
||||
@@ -40,7 +69,7 @@ jobs:
|
||||
contents: write # required to upload release asset
|
||||
steps:
|
||||
- name: Determine filename
|
||||
run: echo "FILENAME_PREFIX=element-call-embedded-${VERSION:1}" >> "$GITHUB_ENV"
|
||||
run: echo "FILENAME_PREFIX=element-call-embedded-${{ needs.versioning.outputs.UNPREFIXED_VERSION }}" >> "$GITHUB_ENV"
|
||||
- name: 📥 Download built element-call artifact
|
||||
uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4
|
||||
with:
|
||||
@@ -53,7 +82,7 @@ jobs:
|
||||
- name: Create Checksum
|
||||
run: find ${{ env.FILENAME_PREFIX }} -type f -print0 | sort -z | xargs -0 sha256sum | tee ${{ env.FILENAME_PREFIX }}.sha256
|
||||
- name: Upload
|
||||
if: ${{ env.DRY_RUN == 'false' }}
|
||||
if: ${{ needs.versioning.outputs.DRY_RUN == 'false' }}
|
||||
uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda # v2
|
||||
with:
|
||||
files: |
|
||||
@@ -61,10 +90,12 @@ jobs:
|
||||
${{ env.FILENAME_PREFIX }}.sha256
|
||||
|
||||
publish_npm:
|
||||
needs: build_element_call
|
||||
needs: [build_element_call, versioning]
|
||||
if: always()
|
||||
name: Publish NPM
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
ARTIFACT_VERSION: ${{ steps.artifact_version.outputs.ARTIFACT_VERSION }}
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write # required for the provenance flag on npm publish
|
||||
@@ -90,17 +121,23 @@ jobs:
|
||||
- name: Publish npm
|
||||
working-directory: embedded/web
|
||||
run: |
|
||||
npm version ${{ env.VERSION }} --no-git-tag-version
|
||||
npm version ${{ needs.versioning.outputs.PREFIXED_VERSION }} --no-git-tag-version
|
||||
echo "ARTIFACT_VERSION=$(jq '.version' --raw-output package.json)" >> "$GITHUB_ENV"
|
||||
npm publish --provenance --access public ${{ env.DRY_RUN == 'true' && '--dry-run' || '' }}
|
||||
npm publish --provenance --access public --tag ${{ needs.versioning.outputs.TAG }} ${{ needs.versioning.outputs.DRY_RUN == 'true' && '--dry-run' || '' }}
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_RELEASE_TOKEN }}
|
||||
|
||||
- id: artifact_version
|
||||
name: Output artifact version
|
||||
run: echo "ARTIFACT_VERSION=${{env.ARTIFACT_VERSION}}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
publish_android:
|
||||
needs: build_element_call
|
||||
needs: [build_element_call, versioning]
|
||||
if: always()
|
||||
name: Publish Android AAR
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
ARTIFACT_VERSION: ${{ steps.artifact_version.outputs.ARTIFACT_VERSION }}
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
@@ -122,7 +159,13 @@ jobs:
|
||||
java-version: "17"
|
||||
|
||||
- name: Get artifact version
|
||||
run: echo "ARTIFACT_VERSION=${VERSION:1}" >> "$GITHUB_ENV"
|
||||
# Anything that is not a final release will be tagged as a snapshot
|
||||
run: |
|
||||
if [[ "${{ needs.versioning.outputs.TAG }}" == "latest" ]]; then
|
||||
echo "ARTIFACT_VERSION=${{ needs.versioning.outputs.UNPREFIXED_VERSION }}" >> "$GITHUB_ENV"
|
||||
else
|
||||
echo "ARTIFACT_VERSION=${{ needs.versioning.outputs.UNPREFIXED_VERSION }}-SNAPSHOT" >> "$GITHUB_ENV"
|
||||
fi
|
||||
|
||||
- name: Set version string
|
||||
run: sed -i "s/0.0.0/${{ env.ARTIFACT_VERSION }}/g" embedded/android/lib/src/main/kotlin/io/element/android/call/embedded/Version.kt
|
||||
@@ -135,13 +178,19 @@ jobs:
|
||||
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_RELEASE_PASSWORD }}
|
||||
ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.GPG_SIGNING_KEY }}
|
||||
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.GPG_SIGNING_KEY_PASSWORD }}
|
||||
run: ./gradlew publishAndReleaseToMavenCentral --no-daemon ${{ env.DRY_RUN == 'true' && '--dry-run' || '' }}
|
||||
run: ./gradlew publishToMavenCentral --no-daemon ${{ needs.versioning.outputs.DRY_RUN == 'true' && '--dry-run' || '' }}
|
||||
|
||||
- id: artifact_version
|
||||
name: Output artifact version
|
||||
run: echo "ARTIFACT_VERSION=${{env.ARTIFACT_VERSION}}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
publish_ios:
|
||||
needs: build_element_call
|
||||
needs: [build_element_call, versioning]
|
||||
if: always()
|
||||
name: Publish SwiftPM Library
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
ARTIFACT_VERSION: ${{ steps.artifact_version.outputs.ARTIFACT_VERSION }}
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
@@ -169,7 +218,7 @@ jobs:
|
||||
run: rsync -a --delete --exclude .git element-call/embedded/ios/ element-call-swift
|
||||
|
||||
- name: Get artifact version
|
||||
run: echo "ARTIFACT_VERSION=${VERSION:1}" >> "$GITHUB_ENV"
|
||||
run: echo "ARTIFACT_VERSION=${{ needs.versioning.outputs.UNPREFIXED_VERSION }}" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Set version string
|
||||
run: sed -i "s/0.0.0/${{ env.ARTIFACT_VERSION }}/g" element-call-swift/Sources/EmbeddedElementCall/EmbeddedElementCall.swift
|
||||
@@ -184,27 +233,33 @@ jobs:
|
||||
git config --global user.email "ci@element.io"
|
||||
git config --global user.name "Element CI"
|
||||
git add -A
|
||||
git commit -am "Release ${{ env.VERSION }}"
|
||||
git commit -am "Release ${{ needs.versioning.outputs.PREFIXED_VERSION }}"
|
||||
git tag -a ${{ env.ARTIFACT_VERSION }} -m "${{ github.event.release.html_url }}"
|
||||
|
||||
- name: Push
|
||||
working-directory: element-call-swift
|
||||
run: |
|
||||
git push --tags ${{ env.DRY_RUN == 'true' && '--dry-run' || '' }}
|
||||
git push --tags ${{ needs.versioning.outputs.DRY_RUN == 'true' && '--dry-run' || '' }}
|
||||
|
||||
- id: artifact_version
|
||||
name: Output artifact version
|
||||
run: echo "ARTIFACT_VERSION=${{env.ARTIFACT_VERSION}}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
release_notes:
|
||||
needs: [publish_npm, publish_android, publish_ios]
|
||||
needs: [versioning, publish_npm, publish_android, publish_ios]
|
||||
if: always()
|
||||
name: Update release notes
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write # to update release notes
|
||||
steps:
|
||||
- name: Get artifact version
|
||||
run: echo "ARTIFACT_VERSION=${VERSION:1}" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Log versions
|
||||
run: |
|
||||
echo "NPM: ${{ needs.publish_npm.outputs.ARTIFACT_VERSION }}"
|
||||
echo "Android: ${{ needs.publish_android.outputs.ARTIFACT_VERSION }}"
|
||||
echo "iOS: ${{ needs.publish_ios.outputs.ARTIFACT_VERSION }}"
|
||||
- name: Add release notes
|
||||
if: ${{ env.DRY_RUN == 'false' }}
|
||||
if: ${{ needs.versioning.outputs.DRY_RUN == 'false' }}
|
||||
uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda # v2
|
||||
with:
|
||||
append_body: true
|
||||
@@ -218,19 +273,19 @@ jobs:
|
||||
### NPM
|
||||
|
||||
```
|
||||
npm install @element-hq/element-call-embedded@${{ env.ARTIFACT_VERSION }}
|
||||
npm install @element-hq/element-call-embedded@${{ needs.publish_npm.outputs.ARTIFACT_VERSION }}
|
||||
```
|
||||
|
||||
### Android AAR
|
||||
|
||||
```
|
||||
dependencies {
|
||||
implementation 'io.element.android:element-call-embedded:${{ env.ARTIFACT_VERSION }}'
|
||||
implementation 'io.element.android:element-call-embedded:${{ needs.publish_android.outputs.ARTIFACT_VERSION }}'
|
||||
}
|
||||
```
|
||||
|
||||
### SwiftPM
|
||||
|
||||
```
|
||||
.package(url: "https://github.com/element-hq/element-call-swift.git", from: "${{ env.ARTIFACT_VERSION }}")
|
||||
.package(url: "https://github.com/element-hq/element-call-swift.git", from: "${{ needs.publish_ios.outputs.ARTIFACT_VERSION }}")
|
||||
```
|
||||
|
||||
7
.github/workflows/publish.yaml
vendored
7
.github/workflows/publish.yaml
vendored
@@ -60,14 +60,13 @@ jobs:
|
||||
artifact_run_id: ${{ github.event.workflow_run.id || github.run_id }}
|
||||
docker_tags: |
|
||||
type=sha,format=short,event=branch
|
||||
type=semver,pattern=v{{version}}
|
||||
type=raw,value=${{ github.event.release.tag_name }}
|
||||
# Like before, using ${{ env.VERSION }} above doesn't work
|
||||
add_docker_release_note:
|
||||
needs: publish_docker
|
||||
name: Add docker release note
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Get artifact version
|
||||
run: echo "ARTIFACT_VERSION=${VERSION:1}" >> "$GITHUB_ENV"
|
||||
- name: Add release note
|
||||
uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda # v2
|
||||
with:
|
||||
@@ -79,5 +78,5 @@ jobs:
|
||||
The image provides a full build of Element Call that can be used both in standalone and as a widget (on a remote URL).
|
||||
|
||||
```
|
||||
docker pull ghcr.io/element-hq/element-call:${{ env.ARTIFACT_VERSION }}
|
||||
docker pull ghcr.io/element-hq/element-call:${{ env.VERSION }}
|
||||
```
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -21,6 +21,7 @@ yarn-error.log
|
||||
!/.yarn/versions
|
||||
/.links.yaml
|
||||
/.links.disabled.yaml
|
||||
/.links.temp-disabled.yaml
|
||||
|
||||
# Playwright
|
||||
/test-results/
|
||||
|
||||
31
README.md
31
README.md
@@ -192,11 +192,6 @@ To use it, create a local config by, e.g.,
|
||||
The `config.devenv.json` config should work with the backend development
|
||||
environment as outlined in the next section out of box.
|
||||
|
||||
> [!NOTE]
|
||||
> Be aware, that this `config.devenv.json` is exposing a deprecated fallback
|
||||
> LiveKit config key. If the homeserver advertises SFU backend via
|
||||
> `.well-known/matrix/client` this has precedence.
|
||||
|
||||
You're now ready to launch the development server:
|
||||
|
||||
```sh
|
||||
@@ -212,12 +207,20 @@ See also:
|
||||
A docker compose file `dev-backend-docker-compose.yml` is provided to start the
|
||||
whole stack of components which is required for a local development environment:
|
||||
|
||||
- Minimum Synapse Setup (servername: `synapse.localhost`)
|
||||
- LiveKit JWT Service (Note requires Federation API and hence a TLS reverse proxy)
|
||||
- Minimum TLS reverse proxy (servername: `synapse.localhost`) Note certificates
|
||||
are valid for at least 10 years from now
|
||||
- Minimum Synapse Setup (servername: `synapse.m.localhost`)
|
||||
- LiveKit Authorization Service (Note requires Federation API and hence a TLS reverse proxy)
|
||||
- Minimum LiveKit SFU Setup using dev defaults for config
|
||||
- Redis db for completeness
|
||||
- Minimum `localhost` Certificate Authority (CA) for Transport Layer Security (TLS)
|
||||
- Hostnames: `m.localhost`, `*.m.localhost`
|
||||
- Add [./backend/dev_tls_local-ca.crt](./backend/dev_tls_local-ca.crt) to your web browsers trusted
|
||||
certificates
|
||||
- Minimum TLS reverse proxy for
|
||||
- Synapse homeserver: `synapse.m.localhost`
|
||||
- MatrixRTC backend: `matrix-rtc.m.localhost`
|
||||
- Local Element Call development `call.m.localhost` via `yarn dev --host `
|
||||
- Element Web `app.m.localhost`
|
||||
- Note certificates will expire on Thu, 03 May 2035 10:32:02 GMT
|
||||
|
||||
These use a test 'secret' published in this repository, so this must be used
|
||||
only for local development and **_never be exposed to the public Internet._**
|
||||
@@ -230,6 +233,16 @@ yarn backend
|
||||
# podman-compose -f dev-backend-docker-compose.yml up
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> To ensure your local development frontend functions properly, you’ll need to
|
||||
> add certificate exceptions in your browser for `https://localhost:3000`,
|
||||
> `https://matrix-rtc.m.localhost/livekit/jwt/healthz` and
|
||||
> `https://synapse.m.localhost/.well-known/matrix/client`. This can be either
|
||||
> done by adding the minimum localhost CA
|
||||
> ([./backend/dev_tls_local-ca.crt](./backend/dev_tls_local-ca.crt)) to your web
|
||||
> browsers trusted certificates or by simply copying and pasting each URL into
|
||||
> your browser’s address bar and follow the prompts to add the exception.
|
||||
|
||||
### Playwright tests
|
||||
|
||||
Our Playwright tests run automatically as part of our CI along with our other
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
server_name: "synapse.localhost"
|
||||
public_baseurl: http://synapse.localhost:8008/
|
||||
server_name: "synapse.m.localhost"
|
||||
public_baseurl: https://synapse.m.localhost/
|
||||
|
||||
pid_file: /data/homeserver.pid
|
||||
|
||||
|
||||
155
backend/dev_nginx.conf
Normal file
155
backend/dev_nginx.conf
Normal file
@@ -0,0 +1,155 @@
|
||||
# Synapse reverse proxy including .well-known/matrix/client
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
listen 443 ssl;
|
||||
listen 8448 ssl;
|
||||
listen [::]:443 ssl;
|
||||
listen [::]:8448 ssl;
|
||||
server_name synapse.m.localhost;
|
||||
ssl_certificate /root/ssl/cert.pem;
|
||||
ssl_certificate_key /root/ssl/key.pem;
|
||||
|
||||
# well-known config adding rtc_foci backend
|
||||
# Note well-known is currently not effective due to:
|
||||
# https://spec.matrix.org/v1.12/client-server-api/#well-known-uri the spec
|
||||
# says it must be at https://$server_name/... (implied port 443) Hence, we
|
||||
# currently rely for local development environment on deprecated config.json
|
||||
# setting for livekit_service_url
|
||||
location /.well-known/matrix/client {
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
return 200 '{"m.homeserver": {"base_url": "https://synapse.m.localhost"}, "org.matrix.msc4143.rtc_foci": [{"type": "livekit", "livekit_service_url": "https://matrix-rtc.m.localhost/livekit/jwt"}]}';
|
||||
default_type application/json;
|
||||
}
|
||||
|
||||
# Reverse proxy for Matrix Synapse Homeserver
|
||||
# This is also required for development environment.
|
||||
# Reason: the lk-jwt-service uses the federation API for the openid token
|
||||
# verification, which requires TLS
|
||||
location / {
|
||||
proxy_pass "http://homeserver:8008";
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
|
||||
}
|
||||
|
||||
# MatrixRTC reverse proxy
|
||||
# - MatrixRTC Authorization Service
|
||||
# - LiveKit SFU websocket signaling connection
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl;
|
||||
listen 8448 ssl;
|
||||
listen [::]:8448 ssl;
|
||||
server_name matrix-rtc.m.localhost;
|
||||
ssl_certificate /root/ssl/cert.pem;
|
||||
ssl_certificate_key /root/ssl/key.pem;
|
||||
|
||||
|
||||
location ^~ /livekit/jwt/ {
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# JWT Service running at port 8080
|
||||
proxy_pass http://auth-server:8080/;
|
||||
}
|
||||
|
||||
location ^~ /livekit/sfu/ {
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
proxy_send_timeout 120;
|
||||
proxy_read_timeout 120;
|
||||
proxy_buffering off;
|
||||
|
||||
proxy_set_header Accept-Encoding gzip;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
# LiveKit SFU websocket connection running at port 7880
|
||||
proxy_pass http://livekit-sfu:7880/;
|
||||
}
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
|
||||
}
|
||||
|
||||
# Convenience reverse proxy for the call.m.localhost domain to yarn dev --host
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name call.m.localhost;
|
||||
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl;
|
||||
server_name call.m.localhost;
|
||||
ssl_certificate /root/ssl/cert.pem;
|
||||
ssl_certificate_key /root/ssl/key.pem;
|
||||
|
||||
|
||||
location ^~ / {
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
proxy_pass https://host.docker.internal:3000;
|
||||
proxy_ssl_verify off;
|
||||
|
||||
}
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
|
||||
}
|
||||
|
||||
# Convenience reverse proxy app.m.localhost for element web
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name app.m.localhost;
|
||||
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl;
|
||||
server_name app.m.localhost;
|
||||
ssl_certificate /root/ssl/cert.pem;
|
||||
ssl_certificate_key /root/ssl/key.pem;
|
||||
|
||||
|
||||
location ^~ / {
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
proxy_pass http://element-web:81;
|
||||
proxy_ssl_verify off;
|
||||
|
||||
}
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
|
||||
}
|
||||
19
backend/dev_tls_local-ca.crt
Normal file
19
backend/dev_tls_local-ca.crt
Normal file
@@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDGjCCAgKgAwIBAgIUGdiFHhH4KL2pqBjMQHQ+PVIkSV8wDQYJKoZIhvcNAQEL
|
||||
BQAwHjEcMBoGA1UEAwwTRWxlbWVudCBDYWxsIERldiBDQTAeFw0yNTA1MDUxMDMy
|
||||
MDJaFw0zNTA1MDMxMDMyMDJaMB4xHDAaBgNVBAMME0VsZW1lbnQgQ2FsbCBEZXYg
|
||||
Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA2y0hjmNn1vRsVSdy
|
||||
8IOfo8N1q9UgkhQWpGKXzPh+D5d1fnuJEmHIVwtDEtS/PwQ43LTmegChPtKH9jdT
|
||||
tG0IihW9Ja5YNG+9xAwaoA/sB3CGCBYsz+2/XjVUpXoBJXIPoFBWsn+K0oeFw9fw
|
||||
eRO1z9abM4cl+LjKzMNM8CCyu9uI1MaGjYez2YIWvG854VucLxX7HSlMJxZNWnie
|
||||
Ui7fMakuJhB2+aiIQjdKxy4E5RHNhzYG/LXhvP+wBYBDPNRsP3rtzEaE9HAveL9K
|
||||
FGqd3R4cBia6r1WIXmpAzyu5RGP5Eou0TZlGkal96/bF0I7q/pKlL23Jt1BLPiQU
|
||||
KGKrAgMBAAGjUDBOMB0GA1UdDgQWBBQJqBjMu61c1p24txw/y+kv3D+V6DAfBgNV
|
||||
HSMEGDAWgBQJqBjMu61c1p24txw/y+kv3D+V6DAMBgNVHRMEBTADAQH/MA0GCSqG
|
||||
SIb3DQEBCwUAA4IBAQB8m2YfFGLugNt5vAAOvNxVqDA8c72yCVYr3CBCpmTIEY5Z
|
||||
d3qVGhG9//ux6+J8ntkSwd9nV5GJyYXHukCG1VavnAWolWdNF/WAllf0jhLuz7kD
|
||||
/cJnuI1By4tBsBmSz851i6HJ4t5k99Be+6GQVzi0e7zzfxTHZE4xP2J6Ox8QbPsP
|
||||
n0m76nIp/WbWaJqzvIIjJhmUUPPv+4wN+eOArgjiGLzptM2qTtGZtd0c9nS5gvep
|
||||
+mEbSUN9zkhAroZf80wf+hEvy+fJ94VbZ9QjTzTg7odZLrsXGIe8DaG63EYRQ25b
|
||||
W5iYBAreln5fGSt7qHsGfqwZibTEk/Lx3dydO1Kg
|
||||
-----END CERTIFICATE-----
|
||||
28
backend/dev_tls_local-ca.key
Normal file
28
backend/dev_tls_local-ca.key
Normal file
@@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDA2y0hjmNn1vRs
|
||||
VSdy8IOfo8N1q9UgkhQWpGKXzPh+D5d1fnuJEmHIVwtDEtS/PwQ43LTmegChPtKH
|
||||
9jdTtG0IihW9Ja5YNG+9xAwaoA/sB3CGCBYsz+2/XjVUpXoBJXIPoFBWsn+K0oeF
|
||||
w9fweRO1z9abM4cl+LjKzMNM8CCyu9uI1MaGjYez2YIWvG854VucLxX7HSlMJxZN
|
||||
WnieUi7fMakuJhB2+aiIQjdKxy4E5RHNhzYG/LXhvP+wBYBDPNRsP3rtzEaE9HAv
|
||||
eL9KFGqd3R4cBia6r1WIXmpAzyu5RGP5Eou0TZlGkal96/bF0I7q/pKlL23Jt1BL
|
||||
PiQUKGKrAgMBAAECggEAAPX2kxi5AQ7ul82SzT1KgpSXyDHLdYaUyAoYnaX9RO+B
|
||||
8ylmpyeqygs4+KQS4EMJm9jpo85Oy37bIKdG3kljU6wQcKlL5Y+ZUOo1nzpV6fid
|
||||
hGVs6ts8VXw8KshKQ9AyccZ8L/pirUfgOffgTwfjY7/90zceAL/s98GuZWc62nkX
|
||||
55joQv/OikqYfAGP/U6Bp2Zyf23DwJB09Z3B6NnZj/ZyAbDrDEHuA15LhCOcCczp
|
||||
IU/mFEywBPHT9Tg4w4Beq78PeAETvku2UalYRLhP3RLlXr2oEbwUtINRVt2QjZ85
|
||||
Esps4uCqL/mgQluIebtudD9HL/YMlNPXue1mDXFxJQKBgQDgZZY4yJBcf488T1V6
|
||||
HNm06b/LvVGj253pKgw14hpY1xQu3Ymgzv1GEqzhSYdzxhpmj0tMUNHxAp+YdGQu
|
||||
SZ0wcPKhw0aYVkIjDRYDC3Wn5GJhyIEYHGYMo/n4l49UzHRBPOTDzp49DkHTKBgh
|
||||
XgIIazYT3CkjTIMRrkUv+qfIPQKBgQDcBGu/mqbjxs4sN3zqPS4aB21o6t6W0sXs
|
||||
ZP9w6RlTPQi5U2oRbftjZtYc0bbEgkMUImB1HwYPQT5pJ+MyC414xDvSc2exBr5d
|
||||
To6yyPIy78Tf5PHM12fpKV92nSvoz/pSjYcGxxDtKfPqu+t8mOJfjCV1lLLA+xuB
|
||||
DDaE4p8dBwKBgQCdAne6A5v/HMH8UQZeCxHJpESvKiiVnnU/UEx651nID7XvlNNX
|
||||
0X0mKqsMd4ZvW43ddSYan/JF0LAa3FW8jYWO/3jF9vzOWoysOdvNBZetgf/Uq5ao
|
||||
aDZ/YbzmVCXWD7jIbPMkjs3pqrAkL0mzDzQc7+dGviWKrV6IYIfIqnn7gQKBgDCz
|
||||
vdIk/qpO+JZrFfiX4Fucp0hhLTJ/p5ZDaRPqVVPKn+K+Jy2ChfIj8mNgvK9VEloj
|
||||
nexvGJ1J2PHYBX+vdPp1nbRhHWPfVUY8PHQw7QP/dToGaMvqJrNDGEGeWvjnCMc7
|
||||
UtdaO1H0Rm0AegkTopB56lTTvJnhO95eALd7nrMDAoGAEPdzJtWoKafp49svhSj0
|
||||
hiXQv2SPBwVUN4LZ4SOWiXUcmYYm80aNpYKLkBxYjrfqFWhE7NUHLGp8YorQWKY2
|
||||
acD9AReHk/xku0ABy6jeYmSCmCxASxst5liKD+l12sk0gB0rk5MBxB4Uu1MIbQZ2
|
||||
aCASX3AVD2/XyC2MKkzc8Eg=
|
||||
-----END PRIVATE KEY-----
|
||||
21
backend/dev_tls_m.localhost.crt
Normal file
21
backend/dev_tls_m.localhost.crt
Normal file
@@ -0,0 +1,21 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDZzCCAk+gAwIBAgIUXizLjwkdqepX0bh0K3abeJxj68IwDQYJKoZIhvcNAQEL
|
||||
BQAwHjEcMBoGA1UEAwwTRWxlbWVudCBDYWxsIERldiBDQTAeFw0yNTA1MDUxMzU5
|
||||
MTFaFw0zNTA1MDMxMzU5MTFaMBgxFjAUBgNVBAMMDSoubS5sb2NhbGhvc3QwggEi
|
||||
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrzGSScSgaQuZdELGFYiLiYRwr
|
||||
LKyUdNr0rsPcOo0bvbeZ3zQMeUMRNlA69zGFdarumiDRXUoAmZI39WmH95aX3d+A
|
||||
U7EFnWev7xpWSVhSYj8T0d4rke8HjGk3LpaffJ93tbJuagBIH1ouuN6AOdzWs8hp
|
||||
RYIomWleEeeuVnnfaMwaXOdc+ihJJ6wzm2hwQSfdpjZPWBDd/DFft1ZXxIZOCjDs
|
||||
rEIiI7uU8iZPLB3QEM/tgxSSAOxrcKvQvxZokk+FD7aMJFP71IfieLCEzMTP1VXa
|
||||
tP7UTAKAqB2NyDJ8m3IHbOINiqcdFvFR3R1D9bXOYE4oRynNvYZrQUGnL2RtAgMB
|
||||
AAGjgaIwgZ8wHwYDVR0jBBgwFoAUCagYzLutXNaduLccP8vpL9w/legwCQYDVR0T
|
||||
BAIwADALBgNVHQ8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwMAYDVR0RBCkw
|
||||
J4IJbG9jYWxob3N0ggttLmxvY2FsaG9zdIINKi5tLmxvY2FsaG9zdDAdBgNVHQ4E
|
||||
FgQUfdh1p52ZgWyZcBgBXGwKi4EnUE0wDQYJKoZIhvcNAQELBQADggEBAKrHEuB6
|
||||
33j8+EwSHw3zrvt/DRXK2BDHI1Ir9JcztSunaKAjZXVvf/dvZp0Xs1dEdJIdnv6G
|
||||
iZYhBbOqDqpQZbf2h/h0kuu5yZSBUdnQXnYNxlhp2UaC/UEgw5iZT/p1rm7RjVie
|
||||
y4Dp2WytV5iZOLmLj6xDvd3DXazgJPWIRX8p8qJZbKTkwCjTr7nDIj8jjG1sVFf7
|
||||
1RJBO5/6WSnImrpDmlLUrvjiKvbxcdseDJyBOhTwdRdSk4S2M+s5tR5j2I1gXLOq
|
||||
J5ioN76+SCrTY0K0WKRy9oOXWO1/X3+VYcekp+0F3SGkd5w17jylCv1XIGHAdEsQ
|
||||
v2z2/aMI/7sAD2Q=
|
||||
-----END CERTIFICATE-----
|
||||
28
backend/dev_tls_m.localhost.key
Normal file
28
backend/dev_tls_m.localhost.key
Normal file
@@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCrzGSScSgaQuZd
|
||||
ELGFYiLiYRwrLKyUdNr0rsPcOo0bvbeZ3zQMeUMRNlA69zGFdarumiDRXUoAmZI3
|
||||
9WmH95aX3d+AU7EFnWev7xpWSVhSYj8T0d4rke8HjGk3LpaffJ93tbJuagBIH1ou
|
||||
uN6AOdzWs8hpRYIomWleEeeuVnnfaMwaXOdc+ihJJ6wzm2hwQSfdpjZPWBDd/DFf
|
||||
t1ZXxIZOCjDsrEIiI7uU8iZPLB3QEM/tgxSSAOxrcKvQvxZokk+FD7aMJFP71Ifi
|
||||
eLCEzMTP1VXatP7UTAKAqB2NyDJ8m3IHbOINiqcdFvFR3R1D9bXOYE4oRynNvYZr
|
||||
QUGnL2RtAgMBAAECggEAJaFQii8U/KOYt9vXNoMnZvSkaeSQLLhn2V6Kciu1CtWE
|
||||
aMTWLsFE6nk+G5xXkYcTmM3T0GghtH3u5CjyI6EcsEkeEorCZJt0wbmayDmqiekR
|
||||
LfMzOdHuTHX5+edPgMGYYG1BFyRKyYFsjH1b5zRFZhXdGQnrl5760GsVlz9D1KZQ
|
||||
iHcT+q1S2tmZeoUukQnADENKXUMCyTGM5FCddgNtsWnGDsTDayh7hUdvDkB+mW4G
|
||||
lSp+BZuc3PCwpbD6qkXvfugWs6CUAAtXoV3ceWgxQ+TEnNlwxaG1AyugfgNUBolk
|
||||
8xgeZt4r5QId03jsHDf7hpBAofcaCd5EMIIQYFvWoQKBgQDlbAvAzEFPTZZn2nRV
|
||||
Xagw4xjqVc1LLEKLCWq0N5rEkwn0h90Dz5N7/3NuonP/sIDsDHCbyiOYBI1Ck6Xi
|
||||
0WuB+OyKDh+xeF2mekN9G9ywPahdK5lT/TVsxXFyZlwtVv1x/6KBO4yv5URizxqU
|
||||
gyAPDDxfD/KcNjkOBaodWEwQGQKBgQC/s2gPDBtQkjLwkHXchBomLww5eLlVrac1
|
||||
WK4UX6uSdOgrjJ375OOgMTxe8NVZdOuAKytGXRWDwgH3nVWvuZhe7dGlX3JMuSer
|
||||
e9VwDpBESrvqcR4ruL6wm8wej6BXyjH0wD3FHb0S5HfuBDxTn+4bDwrbRzOUMNgy
|
||||
lSppuflxdQKBgQDiZcIfazFT8evn5nMAvuC4BZNTxIJHmZC9JfjPiUPIkpWzYtOe
|
||||
7BvNtKOT3Op9uw8uYYRKqKqBXJSNy6ha8XCXHS9HeXKbLn20SFkLQBCDNwVLlDfF
|
||||
40zyXtF6JDr4XyzSb4NM5pgKCER5AYloXxGm59s3sEQpFXUuOjbKqJS/GQKBgAoI
|
||||
c7vF4HAZFr1sch62cz/oWnVvkhOf4Q5zs7ixQSOLJtOQqnwSgK9TpFs7s47ZBbJR
|
||||
kBRAru2Ua9Hv1Bo8VnMxczV6h1roneDlvEf/GyHX33nnrbKQGrrXjJlU3wl5NaAf
|
||||
p5v3cHvapUQ5yIZ/6lBUOzc6xMJOxCHxmKSr7Rg5AoGAbEE4lt6Xh2dnBPJ81eNI
|
||||
IDrw/3ITY53qAY4Bx88CByIFuu8CEUdUZprh98jSl6ic1tMinZfUhRMwABLrUD51
|
||||
DGst8iGLPD9u83iMcUHI/L+p7AbxrKLvWXZrF5UZm440c9mSWqfhPaTBosPtNDsG
|
||||
LfETwH1flKXMTXd2xA9RTE4=
|
||||
-----END PRIVATE KEY-----
|
||||
38
backend/dev_tls_setup
Normal file
38
backend/dev_tls_setup
Normal file
@@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Step 1: Create a Root CA key and cert
|
||||
openssl genrsa -out dev_tls_local-ca.key 2048
|
||||
openssl req -x509 -new -nodes \
|
||||
-days 3650 \
|
||||
-subj "/CN=Element Call Dev CA" \
|
||||
-key dev_tls_local-ca.key \
|
||||
-out dev_tls_local-ca.crt \
|
||||
-sha256 -addext "basicConstraints=CA:TRUE"
|
||||
|
||||
# Step 2: Create a private key and CSR for *.m.localhost
|
||||
openssl req -new -nodes -newkey rsa:2048 \
|
||||
-keyout dev_tls_m.localhost.key \
|
||||
-out dev_tls_m.localhost.csr \
|
||||
-subj "/CN=*.m.localhost"
|
||||
|
||||
# Step 3: Sign the CSR with your CA
|
||||
openssl x509 \
|
||||
-req -in dev_tls_m.localhost.csr \
|
||||
-CA dev_tls_local-ca.crt -CAkey dev_tls_local-ca.key \
|
||||
-CAcreateserial \
|
||||
-out dev_tls_m.localhost.crt \
|
||||
-days 3650 \
|
||||
-sha256 \
|
||||
-extfile <( cat <<EOF
|
||||
authorityKeyIdentifier=keyid,issuer
|
||||
basicConstraints=CA:FALSE
|
||||
keyUsage = digitalSignature, keyEncipherment
|
||||
extendedKeyUsage = serverAuth
|
||||
subjectAltName = @alt_names
|
||||
|
||||
[alt_names]
|
||||
DNS.1 = localhost
|
||||
DNS.2 = m.localhost
|
||||
DNS.3 = *.m.localhost
|
||||
EOF
|
||||
)
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"default_server_config": {
|
||||
"m.homeserver": {
|
||||
"base_url": "http://synapse.localhost:8008",
|
||||
"server_name": "synapse.localhost"
|
||||
"base_url": "https://synapse.m.localhost",
|
||||
"server_name": "synapse.m.localhost"
|
||||
}
|
||||
},
|
||||
"disable_custom_urls": false,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
server_name: "synapse.localhost"
|
||||
public_baseurl: http://synapse.localhost:8008/
|
||||
server_name: "synapse.m.localhost"
|
||||
public_baseurl: https://synapse.m.localhost/
|
||||
|
||||
pid_file: /data/homeserver.pid
|
||||
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDtzCCAp+gAwIBAgIUCmJjl3HAeLmrPwRg+/OzikW6peQwDQYJKoZIhvcNAQEL
|
||||
BQAwazELMAkGA1UEBhMCR0IxDzANBgNVBAgMBkxvbmRvbjEPMA0GA1UEBwwGTG9u
|
||||
ZG9uMQ4wDAYDVQQKDAVBbHJvczEWMBQGA1UECwwNSVQgRGVwYXJ0bWVudDESMBAG
|
||||
A1UEAwwJbG9jYWxob3N0MB4XDTI0MTEwNDIxNDcwMFoXDTM0MTEwMjIxNDcwMFow
|
||||
azELMAkGA1UEBhMCR0IxDzANBgNVBAgMBkxvbmRvbjEPMA0GA1UEBwwGTG9uZG9u
|
||||
MQ4wDAYDVQQKDAVBbHJvczEWMBQGA1UECwwNSVQgRGVwYXJ0bWVudDESMBAGA1UE
|
||||
AwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs368
|
||||
ExLSudP8luNoY5UfaPqBSVJUPYBi+JGyd36tyN75p5OI7xSfHTttQxuD4KrExBFP
|
||||
C8mAhE1eoZPBVBOZJ4FYWBJfMaQnCjeqU+laP36td65kSJYbUYlKYH1WpxEpCdgx
|
||||
wWOKkP/kPX5YXbYqODx9aBJXgoT3yAJW7AniIoL+eLFnS9Xo86TPqCDBTJU9ocwK
|
||||
gPIDLhDv60724rhZT1kbGp7ECqRovndoDTQjuws2D3yNMfQ+4rrQGPXHGmP5PcaR
|
||||
0R7uueB+6APyC7MJbuhbxxg/+DFHrRi3lJsgwxuh2hi/+vWw8zgKlgYIwHFA9X0l
|
||||
cX0UlQdENMH3bgcGIwIDAQABo1MwUTAdBgNVHQ4EFgQUUFGxw7zoiHXGwRqtagjZ
|
||||
RPYc85cwHwYDVR0jBBgwFoAUUFGxw7zoiHXGwRqtagjZRPYc85cwDwYDVR0TAQH/
|
||||
BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEALokb1z2lu3qW141b2wm14ilZQKCZ
|
||||
reNNuUR95Uom96FXPH4QVEH+mYTXXJ5UrfNhQYKQFpdE+5S4HL/UqEOxtWvbAHpK
|
||||
nsLQ62J8m+0+uwiJGqeQpWr03KJgXDAVE9X3XwMlp/+buxSLhc+GIHWuXW56itV2
|
||||
jiZJYjhO5SnhhgTWNoVZk93qXuuWEN0yacw7c3Fr1IvFYYYWufbXTk70dbZihPDK
|
||||
VD141o8tpp6FerSKHNYDqkVFDyTz3DVOhQQJ59zfMre7bFr+PpTTl4vIuGzXEY+E
|
||||
HPjUSlOzwkCoh5fu7Fs3qG55rJt8akhTEoKpiBTaLucgAjVWNHeci1+Yxg==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,28 +0,0 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCzfrwTEtK50/yW
|
||||
42hjlR9o+oFJUlQ9gGL4kbJ3fq3I3vmnk4jvFJ8dO21DG4PgqsTEEU8LyYCETV6h
|
||||
k8FUE5kngVhYEl8xpCcKN6pT6Vo/fq13rmRIlhtRiUpgfVanESkJ2DHBY4qQ/+Q9
|
||||
flhdtio4PH1oEleChPfIAlbsCeIigv54sWdL1ejzpM+oIMFMlT2hzAqA8gMuEO/r
|
||||
TvbiuFlPWRsansQKpGi+d2gNNCO7CzYPfI0x9D7iutAY9ccaY/k9xpHRHu654H7o
|
||||
A/ILswlu6FvHGD/4MUetGLeUmyDDG6HaGL/69bDzOAqWBgjAcUD1fSVxfRSVB0Q0
|
||||
wfduBwYjAgMBAAECggEACTqdSExxzJ+LX5ARFaWyOBSWly2GKqSyR14+aInOklhx
|
||||
9QgkmfOxJrCf3TvJ8RWhXloW0Aqr8qGDxG0Ixgjn7rG7gskXCey1xn8MNppLS0kj
|
||||
ztaG+NB3AR89ABm8XdoHsSY45geh3/Ni9I0i1VardGQafUJhgNLTZqjwIodzkBtJ
|
||||
S/bi4uFk1lGNfuvWQvWqzGXUvd1l1YupV6iA4GfhXlUvrSBZwftLBD6xEvQaSqsA
|
||||
pHvBxTfMXG4RMAkNPDIElkuQ8++CGi1gIRkJfmrv4OgbbitteMnxqqqGYV0zSNCg
|
||||
R/5FG6umIV7lDLBHZCSCk7wmfmq2UUvzhHThHy4yMQKBgQDu4TwFJCIcVIj7Wj4r
|
||||
DUBFvz6Lgbltqb+YAMUBtpiDcAQxDJWmedh6dK04ts5CFAFRlRjjuz2uFn7qlVBm
|
||||
uye9R7tL+tOv5viqDXU78a4snFywoXub6yzpbxrW8B4W1pdIUvQmhwCcDwvO1V24
|
||||
7Vj2vxcM5I9dsk1aCQSi3VY5yQKBgQDAW/VoTRwhU6OUc6sji5Z5dnkMjkP6NZK9
|
||||
CSrTWLAMGaLPY+g6fFS7JMNSvfWm/okypD6rcN7p0cxMK3mfFKmMiyPRde0wdrci
|
||||
sGFjGxM/2d2D7KTMC9iMYwA0K17UIna+UiYPfhR/muIg/dCyjlkKDFs9Z4jk//r1
|
||||
91bmznt2iwKBgFdiYXhn/Wprqih4nKFXGZnqGdEixVhObl4GegrkZuo+AeqHdf8O
|
||||
N5ikMfG7PbyCYPEdH5u/FRMn+4mI0X6jHChroyJqQSHp1jEu9yHUiSicknOyvusM
|
||||
nsNN932FHRyxp2m3nsSxQhHUlzc0ajKJ8K9iu+XlfmSCIzW6cs25Nh+xAoGBAJro
|
||||
M0wIdPPdsCj3sUVRvx8XqknTM6kGhaIYBNXoYPWNm5BaC4U15OJEq8sxUOdnqcMP
|
||||
g6x6m/k+S8C3bh0O/a9Bydl/l0BlCfw0gGjYP/s2ju4Tn272xy/e9iYNGzPIgUmp
|
||||
TB9D0GwmpZ4d6HgyrD+sTbm4bATGpCp6QhBjDggbAoGBAJVMMtZ4pF8D6mLMRZGR
|
||||
pQjNPy+MH13XYmDRc/BSF8KJ4yKk3tohr9LSXzxR0SEB43NoL1bHkucZrNjGyL8x
|
||||
jktnwkoIs96kO2mPrl1TqWkXs5RjGkkSTbAJovIcvkRU31SWap/WzN2kHpmRVcQc
|
||||
KEFKXT5fUYZCLLWxhgZFlGPp
|
||||
-----END PRIVATE KEY-----
|
||||
@@ -1,40 +0,0 @@
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
listen 443 ssl;
|
||||
listen 8448 ssl;
|
||||
listen [::]:443 ssl;
|
||||
listen [::]:8448 ssl;
|
||||
server_name synapse.localhost;
|
||||
ssl_certificate /root/ssl/cert.pem;
|
||||
ssl_certificate_key /root/ssl/key.pem;
|
||||
|
||||
# well-known config adding rtc_foci backend
|
||||
# Note well-known is currently not effective due to:
|
||||
# https://spec.matrix.org/v1.12/client-server-api/#well-known-uri the spec
|
||||
# says it must be at https://$server_name/... (implied port 443) Hence, we
|
||||
# currently rely for local development environment on deprecated config.json
|
||||
# setting for livekit_service_url
|
||||
location /.well-known/matrix/client {
|
||||
return 200 '{"m.homeserver": {"base_url": "http://synapse.localhost:8008"}, "org.matrix.msc4143.rtc_foci": [{"type": "livekit", "livekit_service_url": "http://localhost:8080"}]}';
|
||||
default_type application/json;
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
}
|
||||
|
||||
# Reverse proxy for Matrix Synapse Homeserver
|
||||
# This is also required for development environment.
|
||||
# Reason: the lk-jwt-service uses the federation API for the openid token
|
||||
# verification, which requires TLS
|
||||
location / {
|
||||
proxy_pass "http://homeserver:8008";
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
|
||||
}
|
||||
@@ -1,13 +1,10 @@
|
||||
{
|
||||
"default_server_config": {
|
||||
"m.homeserver": {
|
||||
"base_url": "http://synapse.localhost:8008",
|
||||
"server_name": "synapse.localhost"
|
||||
"base_url": "https://synapse.m.localhost",
|
||||
"server_name": "synapse.m.localhost"
|
||||
}
|
||||
},
|
||||
"livekit": {
|
||||
"livekit_service_url": "http://localhost:8009"
|
||||
},
|
||||
"features": {
|
||||
"feature_use_device_session_member_events": true
|
||||
},
|
||||
|
||||
@@ -7,7 +7,7 @@ services:
|
||||
hostname: auth-server
|
||||
environment:
|
||||
- LK_JWT_PORT=8080
|
||||
- LIVEKIT_URL=ws://localhost:7880
|
||||
- LIVEKIT_URL=wss://matrix-rtc.m.localhost/livekit/sfu
|
||||
- LIVEKIT_KEY=devkey
|
||||
- LIVEKIT_SECRET=secret
|
||||
# If the configured homeserver runs on localhost, it'll probably be using
|
||||
@@ -18,12 +18,13 @@ services:
|
||||
condition: on-failure
|
||||
ports:
|
||||
# HOST_PORT:CONTAINER_PORT
|
||||
- 8009:8080
|
||||
- 8080:8080
|
||||
networks:
|
||||
- ecbackend
|
||||
|
||||
livekit:
|
||||
image: livekit/livekit-server:latest
|
||||
hostname: livekit-sfu
|
||||
command: --dev --config /etc/livekit.yaml
|
||||
restart: unless-stopped
|
||||
# The SFU seems to work far more reliably when we let it share the host
|
||||
@@ -81,17 +82,22 @@ services:
|
||||
- ecbackend
|
||||
|
||||
nginx:
|
||||
# openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout tls_localhost_key.pem -out tls_localhost_cert.pem -subj "/C=GB/ST=London/L=London/O=Alros/OU=IT Department/CN=localhost"
|
||||
hostname: synapse.localhost
|
||||
# see backend/dev_tls_setup for how to generate the tls certs
|
||||
hostname: synapse.m.localhost
|
||||
image: nginx:latest
|
||||
volumes:
|
||||
- ./backend/tls_localhost_nginx.conf:/etc/nginx/conf.d/default.conf:Z
|
||||
- ./backend/tls_localhost_key.pem:/root/ssl/key.pem:Z
|
||||
- ./backend/tls_localhost_cert.pem:/root/ssl/cert.pem:Z
|
||||
- ./backend/dev_nginx.conf:/etc/nginx/conf.d/default.conf:Z
|
||||
- ./backend/dev_tls_m.localhost.key:/root/ssl/key.pem:Z
|
||||
- ./backend/dev_tls_m.localhost.crt:/root/ssl/cert.pem:Z
|
||||
ports:
|
||||
# HOST_PORT:CONTAINER_PORT
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "8008:80"
|
||||
- "4443:443"
|
||||
- "8448:8448"
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
depends_on:
|
||||
- synapse
|
||||
networks:
|
||||
|
||||
@@ -55,13 +55,19 @@ rc_message:
|
||||
# Note key sharing events are bursty
|
||||
per_second: 0.5
|
||||
burst_count: 30
|
||||
|
||||
rc_delayed_event_mgmt:
|
||||
# This needs to match at least the heart-beat frequency plus a bit of headroom
|
||||
# Currently the heart-beat is every 5 seconds which translates into a rate of 0.2s
|
||||
rc_delayed_event_mgmt:
|
||||
per_second: 1
|
||||
burst_count: 20
|
||||
```
|
||||
|
||||
As a prerequisite for the
|
||||
[Matrix LiveKit JWT auth service](https://github.com/element-hq/lk-jwt-service)
|
||||
make sure that your Synapse server has either a `federation` or `openid`
|
||||
[listener configured](https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html#listeners).
|
||||
|
||||
### MatrixRTC Backend
|
||||
|
||||
In order to **guarantee smooth operation** of Element Call MatrixRTC backend is
|
||||
@@ -87,7 +93,7 @@ the example above, this results in:
|
||||
|
||||
Using Nginx, you can achieve this by:
|
||||
|
||||
```jsonc
|
||||
```nginx configuration file
|
||||
server {
|
||||
...
|
||||
location ^~ /livekit/jwt/ {
|
||||
@@ -147,6 +153,17 @@ server {
|
||||
]
|
||||
```
|
||||
|
||||
Make sure this file is served with the correct MIME type (`application/json`).
|
||||
Additionally, ensure the appropriate CORS headers are set to allow web clients
|
||||
to access it across origins. For more details, refer to the
|
||||
[Matrix Client-Server API: 2. Web Browser Clients](https://spec.matrix.org/latest/client-server-api/#web-browser-clients).
|
||||
|
||||
```
|
||||
Access-Control-Allow-Origin: *
|
||||
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
|
||||
Access-Control-Allow-Headers: X-Requested-With, Content-Type, Authorization
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> Most `org.matrix.msc4143.rtc_foci` configurations will only have one entry in
|
||||
> the array
|
||||
@@ -186,7 +203,7 @@ Because Element Call uses client-side routing, your server must be able to route
|
||||
any requests to non-existing paths back to `/index.html`. For example, in Nginx
|
||||
you can achieve this with the `try_files` directive:
|
||||
|
||||
```jsonc
|
||||
```nginx configuration file
|
||||
server {
|
||||
...
|
||||
location / {
|
||||
@@ -223,3 +240,30 @@ federation, so as to prevent spam registrations (if you keep registrations open)
|
||||
and to ensure Element Call continues to work in case any user decides to log in
|
||||
to their Element Call account using the standard Element app and joins normal
|
||||
rooms that Element Call cannot handle.
|
||||
|
||||
# 📚 Community Guides & How-Tos
|
||||
|
||||
Looking for real-world tips, tutorials, and experiences from the community?
|
||||
Below is a collection of blog posts, walkthroughs, and how-tos created by other
|
||||
self-hosters and developers working with Element Call.
|
||||
|
||||
> [!NOTE]
|
||||
> These resources are community-created and may reflect different setups or
|
||||
> versions. Use them alongside the official documentation for best results.
|
||||
|
||||
## 🌐 Blog Posts & Articles
|
||||
|
||||
- [How to resolve stuck MatrixRTC calls](https://sspaeth.de/2025/02/how-to-resolve-stuck-matrixrtc-calls/)
|
||||
|
||||
## 🛠️ How-Tos & Tutorials
|
||||
|
||||
- [MatrixRTC aka Element-call setup (Geek warning)](https://sspaeth.de/2024/11/sfu/)
|
||||
- [MatrixRTC with Synology Container Manager (Docker)](https://ztfr.de/matrixrtc-with-synology-container-manager-docker/)
|
||||
- [Encrypted & Scalable Video Calls: How to deploy an Element Call backend with Synapse Using Docker-Compose](https://willlewis.co.uk/blog/posts/deploy-element-call-backend-with-synapse-and-docker-compose/)
|
||||
- [Element Call einrichten: Verschlüsselte Videoanrufe mit Element X und Matrix Synapse](https://www.cleveradmin.de/blog/2025/04/matrixrtc-element-call-backend-einrichten/)
|
||||
|
||||
## 🤝 Want to Contribute?
|
||||
|
||||
Have a guide or blog post you'd like to share? Open a
|
||||
[PR](https://github.com/element-hq/element-call/pulls) to add it here, or drop a
|
||||
link in the [#webrtc:matrix.org](https://matrix.to/#/#webrtc:matrix.org) room.
|
||||
|
||||
@@ -27,7 +27,7 @@ android {
|
||||
}
|
||||
|
||||
mavenPublishing {
|
||||
publishToMavenCentral(SonatypeHost.S01)
|
||||
publishToMavenCentral(SonatypeHost.S01, automaticRelease = true)
|
||||
|
||||
signAllPublications()
|
||||
|
||||
|
||||
4
knip.ts
4
knip.ts
@@ -27,6 +27,10 @@ export default {
|
||||
// then Knip will flag it as a false positive
|
||||
// https://github.com/webpro-nl/knip/issues/766
|
||||
"@vector-im/compound-web",
|
||||
// We need this so that TypeScript is happy with @livekit/track-processors.
|
||||
// This might be a bug in the LiveKit repo but for now we fix it on the
|
||||
// Element Call side.
|
||||
"@types/dom-mediacapture-transform",
|
||||
"matrix-widget-api",
|
||||
],
|
||||
ignoreExportsUsedInFile: true,
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
},
|
||||
"action": {
|
||||
"close": "Затвори",
|
||||
"copy_link": "Копиране на връзката",
|
||||
"go": "Напред",
|
||||
"invite": "Покана",
|
||||
"no": "Не",
|
||||
"register": "Регистрация",
|
||||
"remove": "Премахни",
|
||||
|
||||
@@ -4,40 +4,139 @@
|
||||
},
|
||||
"action": {
|
||||
"close": "Zavřít",
|
||||
"go": "Pokračovat",
|
||||
"copy_link": "Kopírovat odkaz",
|
||||
"edit": "Upravit",
|
||||
"go": "Přejít",
|
||||
"invite": "Pozvat",
|
||||
"lower_hand": "Snížení ruky",
|
||||
"no": "Ne",
|
||||
"pick_reaction": "Vybrat reakci",
|
||||
"raise_hand": "Zvednutí ruky",
|
||||
"register": "Registrace",
|
||||
"remove": "Odstranit",
|
||||
"show_less": "Zobrazit méně",
|
||||
"show_more": "Zobrazit více",
|
||||
"sign_in": "Přihlásit se",
|
||||
"sign_out": "Odhlásit se"
|
||||
"sign_out": "Odhlásit se",
|
||||
"submit": "Odeslat",
|
||||
"upload_file": "Nahrát soubor"
|
||||
},
|
||||
"analytics_notice": "Účastí v této beta verzi souhlasíte se shromažďováním anonymních údajů, které používáme ke zlepšování produktu. Více informací o tom, které údaje sledujeme, najdete v našich <2>Zásadách ochrany osobních údajů</2> a <6>Zásadách používání souborů cookie</6>.",
|
||||
"app_selection_modal": {
|
||||
"continue_in_browser": "Pokračovat v prohlížeči",
|
||||
"open_in_app": "Otevřít v aplikaci",
|
||||
"text": "Jste připraveni se připojit?",
|
||||
"title": "Vybrat aplikaci"
|
||||
},
|
||||
"call_ended_view": {
|
||||
"create_account_button": "Vytvořit účet",
|
||||
"create_account_prompt": "<0>Proč neskončit nastavením hesla, abyste mohli účet použít znovu?</0><1>Budete si moci nechat své jméno a nastavit si avatar pro budoucí hovory </1>",
|
||||
"not_now_button": "Teď ne, vrátit se na domovskou obrazovku"
|
||||
"feedback_done": "<0>Děkujeme za vaši zpětnou vazbu! </0>",
|
||||
"feedback_prompt": "<0>Rádi si vyslechneme vaši zpětnou vazbu, abychom mohli vaše prostředí vylepšit. </0>",
|
||||
"headline": "{{displayName}}, váš hovor skončil.",
|
||||
"not_now_button": "Teď ne, vrátit se na domovskou obrazovku",
|
||||
"reconnect_button": "Znovu připojit",
|
||||
"survey_prompt": "Jak to probíhalo?"
|
||||
},
|
||||
"call_name": "Název hovoru",
|
||||
"common": {
|
||||
"analytics": "Analytika",
|
||||
"audio": "Zvuk",
|
||||
"avatar": "Avatar",
|
||||
"back": "Zpět",
|
||||
"display_name": "Zobrazované jméno",
|
||||
"encrypted": "Šifrováno",
|
||||
"home": "Domov",
|
||||
"loading": "Načítání…",
|
||||
"next": "Další",
|
||||
"options": "Možnosti",
|
||||
"password": "Heslo",
|
||||
"preferences": "Předvolby",
|
||||
"profile": "Profil",
|
||||
"reaction": "Reakce",
|
||||
"reactions": "Reakce",
|
||||
"settings": "Nastavení",
|
||||
"username": "Uživatelské jméno"
|
||||
"unencrypted": "Nešifrováno",
|
||||
"username": "Uživatelské jméno",
|
||||
"video": "Video"
|
||||
},
|
||||
"developer_mode": {
|
||||
"crypto_version": "Kryptografická verze: {{version}}",
|
||||
"debug_tile_layout_label": "Ladění rozložení dlaždic",
|
||||
"device_id": "ID zařízení: {{id}}",
|
||||
"duplicate_tiles_label": "Počet dalších kopií dlaždic na účastníka",
|
||||
"environment_variables": "Proměnné prostředí",
|
||||
"hostname": "Název hostitele: {{hostname}}",
|
||||
"livekit_server_info": "Informace o serveru LiveKit",
|
||||
"livekit_sfu": "LiveKit SFU: {{url}}",
|
||||
"matrix_id": "Matrix ID: {{id}}",
|
||||
"show_connection_stats": "Zobrazit statistiky připojení",
|
||||
"show_non_member_tiles": "Zobrazit dlaždice pro nečlenská média",
|
||||
"url_params": "Parametry URL",
|
||||
"use_new_membership_manager": "Použijte novou implementaci volání MembershipManager"
|
||||
},
|
||||
"disconnected_banner": "Připojení k serveru bylo ztraceno.",
|
||||
"error": {
|
||||
"call_is_not_supported": "Volání není podporováno",
|
||||
"call_not_found": "Volání nebylo nalezeno",
|
||||
"call_not_found_description": "<0>Zdá se, že tento odkaz nepatří k žádnému existujícímu volání. Zkontrolujte, zda máte správný odkaz, nebo <1>vytvořte nový</1>.</0>",
|
||||
"connection_lost": "Spojení ztraceno",
|
||||
"connection_lost_description": "Hovor byl přerušen.",
|
||||
"e2ee_unsupported": "Nekompatibilní prohlížeč",
|
||||
"e2ee_unsupported_description": "Váš webový prohlížeč nepodporuje šifrované hovory. Mezi podporované prohlížeče patří Chrome, Safari a Firefox 117+.",
|
||||
"generic": "Něco se pokazilo.",
|
||||
"generic_description": "Odeslání protokolů ladění nám pomůže vystopovat problém.",
|
||||
"insufficient_capacity": "Nedostatečná kapacita",
|
||||
"insufficient_capacity_description": "Server dosáhl své maximální kapacity a v tuto chvíli se nemůžete připojit k hovoru. Zkuste to později nebo se obraťte na správce serveru, pokud problém přetrvává.",
|
||||
"matrix_rtc_focus_missing": "Server není nakonfigurován pro práci s {{brand}}. Obraťte se na správce serveru (Doména: {{domain}}, Kód chyby: {{ errorCode }}).",
|
||||
"open_elsewhere": "Otevřeno na jiné kartě",
|
||||
"open_elsewhere_description": "{{brand}} byl otevřen v jiné záložce. Pokud to nezní správně, zkuste stránku znovu načíst.",
|
||||
"unexpected_ec_error": "Došlo k neočekávané chybě (<0>Error Code:</0> <1>{{ errorCode }}</1>). Obraťte se prosím na správce serveru."
|
||||
},
|
||||
"group_call_loader": {
|
||||
"banned_body": "Byl jste vykázán z místnosti.",
|
||||
"banned_heading": "Zabanován",
|
||||
"call_ended_body": "Byl jste vyřazen z hovoru.",
|
||||
"call_ended_heading": "Hovor ukončen",
|
||||
"knock_reject_body": "Vaše žádost o připojení byla zamítnuta.",
|
||||
"knock_reject_heading": "Přístup odepřen",
|
||||
"reason": "Důvod"
|
||||
},
|
||||
"hangup_button_label": "Ukončit hovor",
|
||||
"header_label": "Domov Element Call",
|
||||
"header_participants_label": "Účastníci",
|
||||
"invite_modal": {
|
||||
"link_copied_toast": "Odkaz zkopírován do schránky",
|
||||
"title": "Pozvat na tento hovor"
|
||||
},
|
||||
"join_existing_call_modal": {
|
||||
"join_button": "Ano, připojit se",
|
||||
"text": "Tento hovor již existuje, chcete se připojit?",
|
||||
"title": "Připojit se k existujícimu hovoru?"
|
||||
},
|
||||
"layout_grid_label": "Mřížka",
|
||||
"layout_spotlight_label": "Soustředěný mód",
|
||||
"lobby": {
|
||||
"join_button": "Připojit se k hovoru"
|
||||
"ask_to_join": "Žádost o připojení k hovoru",
|
||||
"join_as_guest": "Připojte se jako host",
|
||||
"join_button": "Připojit se k hovoru",
|
||||
"leave_button": "Zpět na poslední",
|
||||
"waiting_for_invite": "Žádost odeslána! Čekáme na povolení k připojení..."
|
||||
},
|
||||
"log_in": "Přihlášení",
|
||||
"logging_in": "Přihlašování se…",
|
||||
"login_auth_links": "<0>Vytvořit účet</0> Or <2>Jako host</2>",
|
||||
"login_auth_links_prompt": "Ještě nejste zaregistrováni?",
|
||||
"login_subheading": "Chcete-li pokračovat na Element",
|
||||
"login_title": "Přihlášení",
|
||||
"microphone_off": "Mikrofon vypnutý",
|
||||
"microphone_on": "Mikrofon zapnutý",
|
||||
"mute_microphone_button_label": "Ztlumit mikrofon",
|
||||
"participant_count_one": "{{count, number}}",
|
||||
"participant_count_few": "{{count, number}}",
|
||||
"participant_count_other": "{{count, number}}",
|
||||
"qr_code": "QR kód",
|
||||
"rageshake_button_error_caption": "Znovu zkusit odeslat protokoly",
|
||||
"rageshake_request_modal": {
|
||||
"body": "Jiný uživatel v tomto hovoru má problémy. Abychom mohli diagnostikovat problém, rádi bychom shromáždili protokoly ladění.",
|
||||
"title": "Žádost o protokoly ladění"
|
||||
@@ -45,22 +144,79 @@
|
||||
"rageshake_send_logs": "Poslat ladící záznam",
|
||||
"rageshake_sending": "Posílání…",
|
||||
"rageshake_sending_logs": "Posílání ladícího záznamu…",
|
||||
"rageshake_sent": "Díky!",
|
||||
"recaptcha_dismissed": "Recaptcha byla zamítnuta",
|
||||
"recaptcha_not_loaded": "Recaptcha se nenačetla",
|
||||
"recaptcha_ssla_caption": "Tato stránka je chráněna ReCAPTCHA a platí zde <2>Ochrana osobních údajů</2> a <6>Podmínky služby</6> od Google.<9></9>Kliknutím na \"Registrovat\" souhlasíte s naší <12>Licenční smlouvou na software a služby (SSLA)</12>",
|
||||
"register": {
|
||||
"passwords_must_match": "Hesla se musí shodovat",
|
||||
"registering": "Registrování…"
|
||||
},
|
||||
"register_auth_links": "<0>Už máte účet?</0><1><0>Přihlásit se</0> Or <2>Jako host</2></1>",
|
||||
"register_confirm_password_label": "Potvrdit heslo",
|
||||
"register_heading": "Vytvořte si účet",
|
||||
"return_home_button": "Vrátit se na domácí obrazovku",
|
||||
"room_auth_view_continue_button": "Pokračovat",
|
||||
"room_auth_view_ssla_caption": "Kliknutím na „Připojit se k hovoru nyní“ souhlasíte s naší <2>Licenční smlouvou o softwaru a službách (SSLA) </2>",
|
||||
"screenshare_button_label": "Sdílet obrazovku",
|
||||
"settings": {
|
||||
"audio_tab": {
|
||||
"effect_volume_description": "Upravit hlasitost přehrávání reakcí a efektů zvednutých rukou.",
|
||||
"effect_volume_label": "Hlasitost zvukového efektu"
|
||||
},
|
||||
"developer_tab_title": "Vývojář",
|
||||
"devices": {
|
||||
"camera": "Fotoaparát",
|
||||
"camera_numbered": "Fotoaparát {{n}}",
|
||||
"default": "Výchozí",
|
||||
"default_named": "Výchozí <2> ({{name}}) </2>",
|
||||
"microphone": "Mikrofon",
|
||||
"microphone_numbered": "Mikrofon {{n}}",
|
||||
"speaker": "Reproduktor",
|
||||
"speaker_numbered": "Reproduktor {{n}}"
|
||||
},
|
||||
"feedback_tab_body": "Pokud se potýkáte s problémy nebo byste nám jen chtěli poskytnout zpětnou vazbu, pošlete nám prosím krátký popis níže.",
|
||||
"feedback_tab_description_label": "Vaše zpětná vazba",
|
||||
"feedback_tab_h4": "Dát feedback",
|
||||
"feedback_tab_send_logs_label": "Zahrnout ladící záznamy"
|
||||
"feedback_tab_send_logs_label": "Zahrnout ladící záznamy",
|
||||
"feedback_tab_thank_you": "Děkujeme, obdrželi jsme vaši zpětnou vazbu!",
|
||||
"feedback_tab_title": "Zpětná vazba",
|
||||
"opt_in_description": "<0></0><1></1>Souhlas můžete odvolat zrušením zaškrtnutí tohoto políčka. Pokud jste právě v hovoru, toto nastavení se projeví po jeho skončení.",
|
||||
"preferences_tab": {
|
||||
"developer_mode_label": "Vývojářský režim",
|
||||
"developer_mode_label_description": "Povolte vývojářský režim a zobrazte kartu nastavení vývojáře.",
|
||||
"introduction": "Zde můžete nakonfigurovat další možnosti pro lepší zážitek.",
|
||||
"reactions_play_sound_description": "Přehrát zvukový efekt, když někdo odešle reakci do hovoru.",
|
||||
"reactions_play_sound_label": "Přehrát reakční zvuky",
|
||||
"reactions_show_description": "Zobrazit animaci, když někdo pošle reakci.",
|
||||
"reactions_show_label": "Zobrazit reakce",
|
||||
"show_hand_raised_timer_description": "Zobrazit časovač, když účastník zvedne ruku",
|
||||
"show_hand_raised_timer_label": "Zobrazit dobu trvání zvednutí ruky"
|
||||
}
|
||||
},
|
||||
"star_rating_input_label_one": "{{count}} hvězdička",
|
||||
"star_rating_input_label_few": "{{count}} hvězdičky",
|
||||
"star_rating_input_label_other": "{{count}} hvězdiček",
|
||||
"start_new_call": "Zahájit nový hovor",
|
||||
"start_video_button_label": "Spustit video",
|
||||
"stop_screenshare_button_label": "Sdílení obrazovky",
|
||||
"stop_video_button_label": "Zastavit video",
|
||||
"submitting": "Odeslání...",
|
||||
"switch_camera": "Přepnout kameru",
|
||||
"unauthenticated_view_body": "Nejste registrovaní? <2>Vytvořit účet</2>",
|
||||
"unauthenticated_view_login_button": "Přihlásit se ke svému účtu",
|
||||
"version": "Verze: {{version}}"
|
||||
"unauthenticated_view_ssla_caption": "Kliknutím na tlačítko \"Přejít\" souhlasíte s naší <2>Licenční smlouvou na software a služby (SSLA)</2>",
|
||||
"unmute_microphone_button_label": "Zrušit ztlumení mikrofonu",
|
||||
"version": "{{productName}}verze: {{version}}",
|
||||
"video_tile": {
|
||||
"always_show": "Vždy zobrazit",
|
||||
"camera_starting": "Načítání videa...",
|
||||
"change_fit_contain": "Přizpůsobit rámu",
|
||||
"collapse": "Sbalit",
|
||||
"expand": "Rozbalit",
|
||||
"mute_for_me": "Pro mě ztlumit",
|
||||
"muted_for_me": "Pro mě ztlumené",
|
||||
"volume": "Hlasitost",
|
||||
"waiting_for_media": "Čekání na média..."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,8 @@
|
||||
"show_connection_stats": "Show connection statistics",
|
||||
"show_non_member_tiles": "Show tiles for non-member media",
|
||||
"url_params": "URL parameters",
|
||||
"use_new_membership_manager": "Use the new implementation of the call MembershipManager"
|
||||
"use_new_membership_manager": "Use the new implementation of the call MembershipManager",
|
||||
"use_to_device_key_transport": "Use to device key transport. This will fallback to room key transport when another call member sent a room key"
|
||||
},
|
||||
"disconnected_banner": "Connectivity to the server has been lost.",
|
||||
"error": {
|
||||
@@ -163,6 +164,9 @@
|
||||
"effect_volume_description": "Adjust the volume at which reactions and hand raised effects play.",
|
||||
"effect_volume_label": "Sound effect volume"
|
||||
},
|
||||
"background_blur_header": "Background",
|
||||
"background_blur_label": "Blur the background of the video",
|
||||
"blur_not_supported_by_browser": "(Background blur is not supported by this device.)",
|
||||
"developer_tab_title": "Developer",
|
||||
"devices": {
|
||||
"camera": "Camera",
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
},
|
||||
"action": {
|
||||
"close": "Cerrar",
|
||||
"copy_link": "Copiar vínculo",
|
||||
"go": "Comenzar",
|
||||
"invite": "Invitar",
|
||||
"no": "No",
|
||||
"register": "Registrarse",
|
||||
"remove": "Eliminar",
|
||||
"sign_in": "Iniciar sesión",
|
||||
@@ -12,6 +15,12 @@
|
||||
"submit": "Enviar"
|
||||
},
|
||||
"analytics_notice": "Al participar en esta beta, consientes a la recogida de datos anónimos, los cuales usaremos para mejorar el producto. Puedes encontrar más información sobre que datos recogemos en nuestra <2>Política de privacidad</2> y en nuestra <5>Política sobre Cookies</5>.",
|
||||
"app_selection_modal": {
|
||||
"continue_in_browser": "Continuar en el navegador",
|
||||
"open_in_app": "Abrir en la aplicación",
|
||||
"text": "¿Listo para unirte?",
|
||||
"title": "Selecciona aplicación"
|
||||
},
|
||||
"call_ended_view": {
|
||||
"create_account_button": "Crear cuenta",
|
||||
"create_account_prompt": "<0>¿Por qué no mantienes tu cuenta estableciendo una contraseña?</0><1>Podrás mantener tu nombre y establecer un avatar para usarlo en futuras llamadas</1>",
|
||||
|
||||
@@ -5,16 +5,23 @@
|
||||
"action": {
|
||||
"close": "Sulge",
|
||||
"copy_link": "Kopeeri link",
|
||||
"edit": "Muuda",
|
||||
"go": "Jätka",
|
||||
"invite": "Kutsu",
|
||||
"lower_hand": "Lase käsi alla",
|
||||
"no": "Ei",
|
||||
"pick_reaction": "Vali reaktsioon",
|
||||
"raise_hand": "Anna käega märku",
|
||||
"register": "Registreeru",
|
||||
"remove": "Eemalda",
|
||||
"show_less": "Näita vähem",
|
||||
"show_more": "Näita rohkem",
|
||||
"sign_in": "Logi sisse",
|
||||
"sign_out": "Logi välja",
|
||||
"submit": "Saada"
|
||||
"submit": "Saada",
|
||||
"upload_file": "Laadi fail üles"
|
||||
},
|
||||
"analytics_notice": "Nõustudes selle beetaversiooni kasutamisega sa nõustud ka toote arendamiseks kasutatavate anonüümsete andmete kogumisega. Täpsemat teavet kogutavate andmete kohta leiad meie <2>Privaatsuspoliitikast</2> ja meie <5>Küpsiste kasutamise reeglitest</5>.",
|
||||
"analytics_notice": "Nõustudes selle beetaversiooni kasutamisega, sa nõustud ka toote arendamiseks kasutatavate anonüümsete andmete kogumisega. Täpsemat teavet kogutavate andmete kohta leiad meie <2>Privaatsuspoliitikast</2> ja meie <6>Küpsiste kasutamise reeglitest</6>.",
|
||||
"app_selection_modal": {
|
||||
"continue_in_browser": "Jätka veebibrauseris",
|
||||
"open_in_app": "Ava rakenduses",
|
||||
@@ -33,20 +40,70 @@
|
||||
},
|
||||
"call_name": "Kõne nimi",
|
||||
"common": {
|
||||
"analytics": "Analüütika",
|
||||
"audio": "Heli",
|
||||
"avatar": "Tunnuspilt",
|
||||
"back": "Tagasi",
|
||||
"display_name": "Kuvatav nimi",
|
||||
"encrypted": "Krüptitud",
|
||||
"home": "Avavaatesse",
|
||||
"home": "Kodu",
|
||||
"loading": "Laadimine …",
|
||||
"next": "Edasi",
|
||||
"options": "Valikud",
|
||||
"password": "Salasõna",
|
||||
"preferences": "Eelistused",
|
||||
"profile": "Profiil",
|
||||
"reaction": "Reaktsioon",
|
||||
"reactions": "Reageerimised",
|
||||
"settings": "Seadistused",
|
||||
"unencrypted": "Krüptimata",
|
||||
"username": "Kasutajanimi"
|
||||
"username": "Kasutajanimi",
|
||||
"video": "Video"
|
||||
},
|
||||
"developer_mode": {
|
||||
"crypto_version": "Krüptoteekide versioon: {{version}}",
|
||||
"debug_tile_layout_label": "Meediapaanide paigutus",
|
||||
"device_id": "Seadme tunnus: {{id}}",
|
||||
"duplicate_tiles_label": "Täiendavaid vaadete koopiaid osaleja kohta",
|
||||
"environment_variables": "Keskkonnamuutujad",
|
||||
"hostname": "Hosti nimi: {{hostname}}",
|
||||
"livekit_server_info": "LiveKiti serveri teave",
|
||||
"livekit_sfu": "LiveKit SFU: {{url}}",
|
||||
"matrix_id": "Matrixi kasutajatunnus: {{id}}",
|
||||
"show_connection_stats": "Näita ühenduse statistikat",
|
||||
"show_non_member_tiles": "Näita ka mitteseotud meedia paane",
|
||||
"url_params": "Võrguaadressi parameetrid",
|
||||
"use_new_membership_manager": "Kasuta kõne liikmelisuse halduri (MembershipManager) uut implementatsiooni"
|
||||
},
|
||||
"disconnected_banner": "Võrguühendus serveriga on katkenud.",
|
||||
"error": {
|
||||
"call_is_not_supported": "Kõne pole toetatud",
|
||||
"call_not_found": "Kõnet ei leidu",
|
||||
"call_not_found_description": "<0>See link ei tundu olema seotud ühegi olemasoleva kõnega. Kontrolli, et sul on õige link või <1>loo uus</1>.</0>",
|
||||
"connection_lost": "Ühendus on katkenud",
|
||||
"connection_lost_description": "Sinu ühendus selle kõnega on katkenud.",
|
||||
"e2ee_unsupported": "Mitteühilduv brauser",
|
||||
"e2ee_unsupported_description": "Sinu veebibrauser ei toeta krüptitud kõnesid. Toimivad veebibrauserid on Chrome, Safari, ja Firefox 117+.",
|
||||
"generic": "Midagi läks valesti",
|
||||
"generic_description": "Silumis- ja vealogide saatmine võib aidata meid vea põhjuseni jõuda.",
|
||||
"insufficient_capacity": "Mittepiisav jõudlus",
|
||||
"insufficient_capacity_description": "Serveri jõudluse ülempiir on hetkel ületatud ja sa ei saa hetkel selle kõnega liituda. Proovi hiljem uuesti või kui probleem kestab kauem, siis võta ühendust serveri haldajaga.",
|
||||
"matrix_rtc_focus_missing": "See server pole seadistatud töötama rakendusega {{brand}}. Palun võta ühendust serveri halduriga (domeen: {{domain}}, veakood: {{ errorCode }}).",
|
||||
"open_elsewhere": "Avatud teisel vahekaardil",
|
||||
"open_elsewhere_description": "{{brand}} on avatud teisel vahekaardil. Kui see ei tundu olema õige, proovi selle lehe uuesti laadimist.",
|
||||
"unexpected_ec_error": "Tekkis ootamatu viga (<0>Veakood:</0> <1>{{ errorCode }}</1>). Palun võta ühendust serveri haldajaga."
|
||||
},
|
||||
"group_call_loader": {
|
||||
"banned_body": "Sa oled saanud selles jututoas suhtluskeelu",
|
||||
"banned_heading": "Suhtluskeeld",
|
||||
"call_ended_body": "Sa oled sellest kõnest eemaldatud.",
|
||||
"call_ended_heading": "Kõne lõppes",
|
||||
"knock_reject_body": "Jututoa liikmed ei nõustunud sinu liitumispalvega.",
|
||||
"knock_reject_heading": "Liitumine pole lubatud",
|
||||
"reason": "Põhjus"
|
||||
},
|
||||
"hangup_button_label": "Lõpeta kõne",
|
||||
"header_label": "Avaleht: Element Call",
|
||||
"header_participants_label": "Osalejad",
|
||||
"invite_modal": {
|
||||
"link_copied_toast": "Link on kopeeritud lõikelauale",
|
||||
@@ -60,15 +117,24 @@
|
||||
"layout_grid_label": "Ruudustik",
|
||||
"layout_spotlight_label": "Rambivalgus",
|
||||
"lobby": {
|
||||
"join_button": "Kõnega liitumine",
|
||||
"leave_button": "Tagasi hiljutiste kõnede juurde"
|
||||
"ask_to_join": "Küsi võimalust liituda kõnega",
|
||||
"join_as_guest": "Liitu külalisena",
|
||||
"join_button": "Liitu kõnega",
|
||||
"leave_button": "Tagasi hiljutiste kõnede juurde",
|
||||
"waiting_for_invite": "Päring on saadetud"
|
||||
},
|
||||
"logging_in": "Sisselogimine …",
|
||||
"login_auth_links": "<0>Loo konto</0> Või <2>Sisene külalisena</2>",
|
||||
"log_in": "Logi sisse",
|
||||
"logging_in": "Logime sisse…",
|
||||
"login_auth_links": "<0>Loo konto</0> või <2>Sisene külalisena</2>",
|
||||
"login_auth_links_prompt": "Sa pole veel registreerunud?",
|
||||
"login_subheading": "Jätka rakenduses Element",
|
||||
"login_title": "Sisselogimine",
|
||||
"microphone_off": "Mikrofon ei tööta",
|
||||
"microphone_on": "Mikrofon töötab",
|
||||
"mute_microphone_button_label": "Summuta mikrofon",
|
||||
"participant_count_one": "{{count, number}}",
|
||||
"participant_count_other": "{{count, number}}",
|
||||
"qr_code": "QR-kood",
|
||||
"rageshake_button_error_caption": "Proovi uuesti logisid saata",
|
||||
"rageshake_request_modal": {
|
||||
"body": "Ühel teisel selles kõnes osalejal on lahenduse kasutamisel tekkinud probleem ning selle põhjuse leidmiseks me sooviksime koguda silumislogisid.",
|
||||
@@ -80,33 +146,75 @@
|
||||
"rageshake_sent": "Tänud!",
|
||||
"recaptcha_dismissed": "Robotilõks on vahele jäetud",
|
||||
"recaptcha_not_loaded": "Robotilõks pole laetud",
|
||||
"recaptcha_ssla_caption": "Selle saidi kaitsmiseks on kasutusel ReCAPTCHA ning rakenduvad Google'i <2>Privaatusreeglid</2> ja <6>Kasutustingimused</6>.<9></9>Klõpsides „Registreeru“ nõustud sa meie <12>Tarkvara ja teenuste litsentseerimise lepinguga (Software and Services License Agreement - SSLA)</12>",
|
||||
"register": {
|
||||
"passwords_must_match": "Salasõnad ei klapi",
|
||||
"registering": "Registreerimine…"
|
||||
},
|
||||
"register_auth_links": "<0>On sul juba konto?</0><1><0>Logi sisse</0> Või <2>Logi sisse külalisena</2></1>",
|
||||
"register_auth_links": "<0>On sul juba konto?</0><1><0>Logi sisse</0> või <2>Logi sisse külalisena</2></1>",
|
||||
"register_confirm_password_label": "Kinnita salasõna",
|
||||
"register_heading": "Loo omale konto",
|
||||
"return_home_button": "Tagasi avalehele",
|
||||
"room_auth_view_continue_button": "Jätka",
|
||||
"room_auth_view_ssla_caption": "Klõpsides „Liitu kõnega“ nõustud sa meie <2>Tarkvara ja teenuste litsentseerimise lepinguga (Software and Services License Agreement - SSLA)</2>",
|
||||
"screenshare_button_label": "Jaga ekraani",
|
||||
"settings": {
|
||||
"audio_tab": {
|
||||
"effect_volume_description": "Häälesta helivaljust, mida kasutatakse käe tõstmisel ja regeerimisel",
|
||||
"effect_volume_label": "Efektide helivajlus"
|
||||
},
|
||||
"developer_tab_title": "Arendaja",
|
||||
"devices": {
|
||||
"camera": "Kaamera",
|
||||
"camera_numbered": "Kaamera {{n}}",
|
||||
"default": "Vaikimisi",
|
||||
"default_named": "Vaikimisi <2>({{name}})</2>",
|
||||
"microphone": "Mikrofon",
|
||||
"microphone_numbered": "Mikrofon {{n}}",
|
||||
"speaker": "Kõlar",
|
||||
"speaker_numbered": "Kõlar {{n}}"
|
||||
},
|
||||
"feedback_tab_body": "Kui selle rakenduse kasutamisel tekib sul probleeme või lihtsalt soovid oma arvamust avaldada, siis palun täida alljärgnev lühike kirjeldus.",
|
||||
"feedback_tab_description_label": "Sinu tagasiside",
|
||||
"feedback_tab_h4": "Jaga tagasisidet",
|
||||
"feedback_tab_send_logs_label": "Lisa veatuvastuslogid",
|
||||
"feedback_tab_thank_you": "Tänud, me oleme sinu tagasiside kätte saanud!",
|
||||
"feedback_tab_title": "Tagasiside",
|
||||
"opt_in_description": "<0></0><1></1>Sa võid selle valiku eelmaldamisega alati oma nõusoleku tagasi võtta. Kui sul parasjagu on kõne pooleli, siis seadistuste muudatus jõustub pärast kõne lõppu."
|
||||
"opt_in_description": "<0></0><1></1>Sa võid selle valiku eelmaldamisega alati oma nõusoleku tagasi võtta. Kui sul parasjagu on kõne pooleli, siis seadistuste muudatus jõustub pärast kõne lõppu.",
|
||||
"preferences_tab": {
|
||||
"developer_mode_label": "Arendajate režiim",
|
||||
"developer_mode_label_description": "Kasuta arendusrežiimi ja näita asjakohaseid seadistusi.",
|
||||
"introduction": "Parema kasutuskogemuse nimel saad siin seadistada täiendavaid eelistusi.",
|
||||
"reactions_play_sound_description": "Kui keegi lisab käimasolevale kõnele reaktsiooni, siis täienda seda heliefektiga.",
|
||||
"reactions_play_sound_label": "Lisa reageerimistele heli",
|
||||
"reactions_show_description": "Näita reageerimisi",
|
||||
"reactions_show_label": "Kui keegi reageerib, siis näita seda animatsioonina",
|
||||
"show_hand_raised_timer_description": "Kui osaleja annab käetõstmisega märku, siis kuva ka kestuse taimer",
|
||||
"show_hand_raised_timer_label": "Näita käega märkuandmise kestust"
|
||||
}
|
||||
},
|
||||
"star_rating_input_label_one": "{{count}} tärni",
|
||||
"star_rating_input_label_one": "{{count}} tärn",
|
||||
"star_rating_input_label_other": "{{count}} tärni",
|
||||
"start_new_call": "Algata uus kõne",
|
||||
"start_video_button_label": "Lülita videovoog sisse",
|
||||
"stop_screenshare_button_label": "Ekraanivaade on jagamisel",
|
||||
"stop_video_button_label": "Peata videovoog",
|
||||
"submitting": "Saadan…",
|
||||
"switch_camera": "Vaheta kaamerat",
|
||||
"unauthenticated_view_body": "Sa pole veel registreerunud? <2>Loo kasutajakonto</2>",
|
||||
"unauthenticated_view_login_button": "Logi oma kontosse sisse",
|
||||
"unauthenticated_view_ssla_caption": "Klõpsides „Jätka“ nõustud sa meie <2>Tarkvara ja teenuste litsentseerimise lepinguga (Software and Services License Agreement - SSLA)</2>",
|
||||
"unmute_microphone_button_label": "Lülita mikrofon sisse",
|
||||
"version": "Versioon: {{version}}"
|
||||
"version": "{{productName}}, versioon: {{version}}",
|
||||
"video_tile": {
|
||||
"always_show": "Näita alati",
|
||||
"camera_starting": "Video on laadimisel...",
|
||||
"change_fit_contain": "Mahuta aknasse",
|
||||
"collapse": "Näita vähem",
|
||||
"expand": "Näita rohkem",
|
||||
"mute_for_me": "Summuta minu jaoks",
|
||||
"muted_for_me": "Minule summutatud",
|
||||
"volume": "Helivaljus",
|
||||
"waiting_for_media": "Ootame kuni meedia on olemas..."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,13 +5,21 @@
|
||||
"action": {
|
||||
"close": "Chiudi",
|
||||
"copy_link": "Copia collegamento",
|
||||
"edit": "Modifica",
|
||||
"go": "Vai",
|
||||
"invite": "Invita",
|
||||
"lower_hand": "Abbassa la mano",
|
||||
"no": "No",
|
||||
"pick_reaction": "Scegli una reazione",
|
||||
"raise_hand": "Alza la mano",
|
||||
"register": "Registra",
|
||||
"remove": "Rimuovi",
|
||||
"show_less": "Mostra meno",
|
||||
"show_more": "Mostra altro",
|
||||
"sign_in": "Accedi",
|
||||
"sign_out": "Disconnetti",
|
||||
"submit": "Invia"
|
||||
"submit": "Invia",
|
||||
"upload_file": "Carica file"
|
||||
},
|
||||
"analytics_notice": "Partecipando a questa beta, acconsenti alla raccolta di dati anonimi che usiamo per migliorare il prodotto. Puoi trovare più informazioni su quali dati monitoriamo nella nostra <2>informativa sulla privacy</2> e nell'<5>informativa sui cookie</5>.",
|
||||
"app_selection_modal": {
|
||||
@@ -32,16 +40,66 @@
|
||||
},
|
||||
"call_name": "Nome della chiamata",
|
||||
"common": {
|
||||
"analytics": "Statistiche",
|
||||
"audio": "Audio",
|
||||
"avatar": "Avatar",
|
||||
"back": "Indietro",
|
||||
"display_name": "Il tuo nome",
|
||||
"encrypted": "Cifrata",
|
||||
"home": "Pagina iniziale",
|
||||
"loading": "Caricamento…",
|
||||
"next": "Avanti",
|
||||
"options": "Opzioni",
|
||||
"password": "Password",
|
||||
"preferences": "Preferenze",
|
||||
"profile": "Profilo",
|
||||
"reaction": "Reazione",
|
||||
"reactions": "Reazioni",
|
||||
"settings": "Impostazioni",
|
||||
"unencrypted": "Non cifrata",
|
||||
"username": "Nome utente"
|
||||
"username": "Nome utente",
|
||||
"video": "Video"
|
||||
},
|
||||
"developer_mode": {
|
||||
"crypto_version": "Versione crittografica: {{version}}",
|
||||
"debug_tile_layout_label": "Debug della disposizione dei riquadri",
|
||||
"device_id": "ID dispositivo: {{id}}",
|
||||
"duplicate_tiles_label": "Numero di copie di riquadri aggiuntivi per partecipante",
|
||||
"hostname": "Nome host: {{hostname}}",
|
||||
"livekit_server_info": "Informazioni sul server LiveKit",
|
||||
"livekit_sfu": "SFU LiveKit: {{url}}",
|
||||
"matrix_id": "ID Matrix: {{id}}",
|
||||
"show_connection_stats": "Mostra le statistiche di connessione",
|
||||
"show_non_member_tiles": "Mostra i riquadri per i file multimediali non-membri",
|
||||
"use_new_membership_manager": "Usa la nuova implementazione della chiamata MembershipManager"
|
||||
},
|
||||
"disconnected_banner": "La connessione al server è stata persa.",
|
||||
"error": {
|
||||
"call_is_not_supported": "La chiamata non è supportata",
|
||||
"call_not_found": "Chiamata non trovata",
|
||||
"call_not_found_description": "<0>Quel link non sembra appartenere a nessuna chiamata esistente. Controlla di avere il link giusto, oppure <1> creane uno nuovo</1> .</0>",
|
||||
"connection_lost": "Connessione persa",
|
||||
"connection_lost_description": "Sei stato disconnesso dalla chiamata.",
|
||||
"e2ee_unsupported": "Browser incompatibile",
|
||||
"e2ee_unsupported_description": "Il tuo browser non supporta le chiamate crittografate. I browser supportati sono Chrome, Safari e Firefox 117+.",
|
||||
"generic": "Qualcosa è andato storto",
|
||||
"generic_description": "L'invio dei registri di debug ci aiuterà a rintracciare il problema.",
|
||||
"insufficient_capacity": "Capacità insufficiente",
|
||||
"insufficient_capacity_description": "Il server ha raggiunto la capacità massima e non è possibile partecipare alla chiamata in questo momento. Riprova più tardi o contatta l'amministratore del server se il problema persiste.",
|
||||
"matrix_rtc_focus_missing": "Il server non è configurato per funzionare con {{brand}}. Contatta l'amministratore del tuo server (Dominio: {{domain}}, codice di errore: {{ errorCode }}).",
|
||||
"open_elsewhere": "Aperto in un'altra scheda",
|
||||
"open_elsewhere_description": "{{brand}} è stato aperto in un'altra scheda. Se non ti sembra corretto, prova a ricaricare la pagina.",
|
||||
"unexpected_ec_error": "Si è verificato un errore imprevisto (<0>Codice errore:</0> <1>{{ errorCode }}</1>). Contatta l'amministratore del tuo server."
|
||||
},
|
||||
"group_call_loader": {
|
||||
"banned_body": "Sei stato bandito dalla stanza.",
|
||||
"banned_heading": "Bandito",
|
||||
"call_ended_body": "Sei stato rimosso dalla chiamata.",
|
||||
"call_ended_heading": "Chiamata terminata",
|
||||
"knock_reject_body": "I membri della stanza hanno rifiutato la tua richiesta di partecipazione.",
|
||||
"knock_reject_heading": "Partecipazione non consentita",
|
||||
"reason": "Motivo"
|
||||
},
|
||||
"hangup_button_label": "Termina chiamata",
|
||||
"header_label": "Inizio di Element Call",
|
||||
"header_participants_label": "Partecipanti",
|
||||
@@ -57,15 +115,24 @@
|
||||
"layout_grid_label": "Griglia",
|
||||
"layout_spotlight_label": "In primo piano",
|
||||
"lobby": {
|
||||
"ask_to_join": "Chiedi di partecipare alla chiamata",
|
||||
"join_as_guest": "Partecipa come ospite",
|
||||
"join_button": "Entra in chiamata",
|
||||
"leave_button": "Torna ai recenti"
|
||||
"leave_button": "Torna ai recenti",
|
||||
"waiting_for_invite": "Richiesta inviata"
|
||||
},
|
||||
"log_in": "Accedi",
|
||||
"logging_in": "Accesso…",
|
||||
"login_auth_links": "<0>Crea un profilo</0> o <2>Accedi come ospite</2>",
|
||||
"login_auth_links_prompt": "Non sei ancora registrato?",
|
||||
"login_subheading": "Per continuare su Element",
|
||||
"login_title": "Accedi",
|
||||
"microphone_off": "Microfono spento",
|
||||
"microphone_on": "Microfono acceso",
|
||||
"mute_microphone_button_label": "Spegni il microfono",
|
||||
"participant_count_one": "{{count, number}}",
|
||||
"participant_count_other": "{{count, number}}",
|
||||
"qr_code": "Codice QR",
|
||||
"rageshake_button_error_caption": "Riprova l'invio dei registri",
|
||||
"rageshake_request_modal": {
|
||||
"body": "Un altro utente in questa chiamata sta avendo problemi. Per diagnosticare meglio questi problemi, vorremmo raccogliere un registro di debug.",
|
||||
@@ -83,16 +150,44 @@
|
||||
},
|
||||
"register_auth_links": "<0>Hai già un profilo?</0><1><0>Accedi</0> o <2>Accedi come ospite</2></1>",
|
||||
"register_confirm_password_label": "Conferma password",
|
||||
"register_heading": "Crea il tuo account",
|
||||
"return_home_button": "Torna alla schermata di iniziale",
|
||||
"room_auth_view_continue_button": "Continua",
|
||||
"screenshare_button_label": "Condividi schermo",
|
||||
"settings": {
|
||||
"audio_tab": {
|
||||
"effect_volume_description": "Regola il volume delle reazioni e degli effetti di alzata di mani.",
|
||||
"effect_volume_label": "Volume degli effetti sonori"
|
||||
},
|
||||
"developer_tab_title": "Sviluppatore",
|
||||
"devices": {
|
||||
"camera": "Fotocamera",
|
||||
"camera_numbered": "Fotocamera {{n}}",
|
||||
"default": "Predefinito",
|
||||
"default_named": "Predefinito <2>({{name}})</2>",
|
||||
"microphone": "Microfono",
|
||||
"microphone_numbered": "Microfono {{n}}",
|
||||
"speaker": "Altoparlante",
|
||||
"speaker_numbered": "Altoparlante {{n}}"
|
||||
},
|
||||
"feedback_tab_body": "Se stai riscontrando problemi o semplicemente vuoi dare un'opinione, inviaci una breve descrizione qua sotto.",
|
||||
"feedback_tab_description_label": "Il tuo commento",
|
||||
"feedback_tab_h4": "Invia commento",
|
||||
"feedback_tab_send_logs_label": "Includi registri di debug",
|
||||
"feedback_tab_thank_you": "Grazie, abbiamo ricevuto il tuo commento!",
|
||||
"opt_in_description": "<0></0><1></1>Puoi revocare il consenso deselezionando questa casella. Se attualmente sei in una chiamata, avrà effetto al termine di essa."
|
||||
"feedback_tab_title": "Commenti",
|
||||
"opt_in_description": "<0></0><1></1>Puoi revocare il consenso deselezionando questa casella. Se attualmente sei in una chiamata, avrà effetto al termine di essa.",
|
||||
"preferences_tab": {
|
||||
"developer_mode_label": "Modalità sviluppatore",
|
||||
"developer_mode_label_description": "Attiva la modalità sviluppatore e mostra la scheda di impostazioni sviluppatore.",
|
||||
"introduction": "Qui puoi configurare opzioni extra per un'esperienza migliore.",
|
||||
"reactions_play_sound_description": "Riprodurre un effetto sonoro quando qualcuno invia una reazione in una chiamata.",
|
||||
"reactions_play_sound_label": "Riproduci suoni di reazione",
|
||||
"reactions_show_description": "Mostra un'animazione quando qualcuno invia una reazione.",
|
||||
"reactions_show_label": "Mostra reazioni",
|
||||
"show_hand_raised_timer_description": "Mostra un contatore quando un partecipante alza la mano",
|
||||
"show_hand_raised_timer_label": "Mostra la durata dell'alzata di mano"
|
||||
}
|
||||
},
|
||||
"star_rating_input_label_one": "{{count}} stelle",
|
||||
"star_rating_input_label_other": "{{count}} stelle",
|
||||
@@ -101,8 +196,20 @@
|
||||
"stop_screenshare_button_label": "Condivisione schermo",
|
||||
"stop_video_button_label": "Ferma video",
|
||||
"submitting": "Invio…",
|
||||
"switch_camera": "Cambia fotocamera",
|
||||
"unauthenticated_view_body": "Non hai ancora un profilo? <2>Creane uno</2>",
|
||||
"unauthenticated_view_login_button": "Accedi al tuo profilo",
|
||||
"unmute_microphone_button_label": "Riaccendi il microfono",
|
||||
"version": "Versione: {{version}}"
|
||||
"version": "Versione: {{version}}",
|
||||
"video_tile": {
|
||||
"always_show": "Mostra sempre",
|
||||
"camera_starting": "Caricamento del video...",
|
||||
"change_fit_contain": "Adatta al frame",
|
||||
"collapse": "Riduci",
|
||||
"expand": "Espandi",
|
||||
"mute_for_me": "Disattiva l'audio per me",
|
||||
"muted_for_me": "Muto per me",
|
||||
"volume": "Volume",
|
||||
"waiting_for_media": "In attesa dei media..."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,61 +4,120 @@
|
||||
},
|
||||
"action": {
|
||||
"close": "閉じる",
|
||||
"copy_link": "リンクをコピー",
|
||||
"go": "続行",
|
||||
"invite": "招待",
|
||||
"no": "いいえ",
|
||||
"register": "登録",
|
||||
"remove": "削除",
|
||||
"sign_in": "サインイン",
|
||||
"sign_out": "サインアウト"
|
||||
"sign_out": "サインアウト",
|
||||
"submit": "送信"
|
||||
},
|
||||
"analytics_notice": "ベータ版への参加と同時に、製品の改善のために匿名データを収集することに同意したことになります。追跡するデータの詳細については、<2>プライバシーポリシー</2>と<6>クッキーポリシー</6>をご確認下さい。",
|
||||
"app_selection_modal": {
|
||||
"continue_in_browser": "ブラウザで続行",
|
||||
"open_in_app": "アプリで開く",
|
||||
"text": "準備完了?",
|
||||
"title": "アプリを選択"
|
||||
},
|
||||
"call_ended_view": {
|
||||
"create_account_button": "アカウントを作成"
|
||||
"create_account_button": "アカウントを作成",
|
||||
"create_account_prompt": "<0>パスワードを設定してアカウント設定を保持してみませんか?</0><1>名前とアバターの設定を次の通話に利用する事ができます。</1>",
|
||||
"feedback_done": "<0>フィードバックありがとうございます!</0>",
|
||||
"feedback_prompt": "<0>品質向上のため、皆様のフィードバックをお待ちしております。</0>",
|
||||
"headline": "{{displayName}} さんの通話は終了しました。",
|
||||
"not_now_button": "終了せずホーム画面に戻る",
|
||||
"reconnect_button": "再接続",
|
||||
"survey_prompt": "通話はどうでしたか?"
|
||||
},
|
||||
"call_name": "通話名",
|
||||
"common": {
|
||||
"analytics": "分析",
|
||||
"audio": "音声",
|
||||
"avatar": "アバター",
|
||||
"display_name": "表示名",
|
||||
"encrypted": "暗号化済み",
|
||||
"home": "ホーム",
|
||||
"loading": "読み込んでいます…",
|
||||
"options": "オプション",
|
||||
"password": "パスワード",
|
||||
"profile": "プロフィール",
|
||||
"settings": "設定",
|
||||
"unencrypted": "暗号化されていません",
|
||||
"username": "ユーザー名",
|
||||
"video": "ビデオ"
|
||||
},
|
||||
"disconnected_banner": "サーバーへの接続が失われました。",
|
||||
"hangup_button_label": "通話終了",
|
||||
"header_label": "Element Call ホーム",
|
||||
"header_participants_label": "参加者",
|
||||
"invite_modal": {
|
||||
"link_copied_toast": "リンクがクリップボードにコピーされました",
|
||||
"title": "この通話に招待する"
|
||||
},
|
||||
"join_existing_call_modal": {
|
||||
"join_button": "はい、通話に参加",
|
||||
"text": "この通話は既に存在します。参加しますか?",
|
||||
"title": "既存の通話に参加しますか?"
|
||||
},
|
||||
"layout_grid_label": "グリッド",
|
||||
"layout_spotlight_label": "スポットライト",
|
||||
"lobby": {
|
||||
"join_button": "通話に参加"
|
||||
"join_button": "通話に参加",
|
||||
"leave_button": "最近に戻る"
|
||||
},
|
||||
"log_in": "ログイン",
|
||||
"logging_in": "ログインしています…",
|
||||
"login_auth_links": "<0>アカウントを作成</0>または<2>ゲストとしてアクセス</2>",
|
||||
"login_auth_links_prompt": "登録はまだですか?",
|
||||
"login_subheading": "Element を続けるには",
|
||||
"login_title": "ログイン",
|
||||
"microphone_off": "マイクオフ",
|
||||
"microphone_on": "マイクオン",
|
||||
"mute_microphone_button_label": "ミュート",
|
||||
"rageshake_button_error_caption": "ログ送信の再試行",
|
||||
"rageshake_request_modal": {
|
||||
"body": "この通話に参加している別のユーザーに問題が発生しています。この問題のより良い診断のため、デバッグ ログを収集したいと考えています。",
|
||||
"title": "デバッグログを要求"
|
||||
},
|
||||
"rageshake_send_logs": "デバッグログを送信",
|
||||
"rageshake_sending": "送信しています…",
|
||||
"rageshake_sending_logs": "デバッグログを送信しています…",
|
||||
"rageshake_sent": "ありがとうございます!",
|
||||
"recaptcha_dismissed": "Recaptcha は却下されました",
|
||||
"recaptcha_not_loaded": "Recaptcha が読み込まれませんでした",
|
||||
"register": {
|
||||
"passwords_must_match": "パスワードが一致する必要があります",
|
||||
"registering": "登録しています…"
|
||||
},
|
||||
"register_auth_links": "<0>既にアカウントをお持ちですか?</0><1><0>ログイン</0>または<2>ゲストとしてアクセス</2></1>",
|
||||
"register_confirm_password_label": "パスワードを確認",
|
||||
"register_heading": "アカウントを作成",
|
||||
"return_home_button": "ホーム画面に戻る",
|
||||
"screenshare_button_label": "画面共有",
|
||||
"settings": {
|
||||
"developer_tab_title": "開発者",
|
||||
"feedback_tab_body": "問題が発生している場合、もしくはフィードバックを提供したい場合は、以下に簡単な説明を入力してお送りください。",
|
||||
"feedback_tab_description_label": "フィードバック",
|
||||
"feedback_tab_h4": "フィードバックを送信",
|
||||
"feedback_tab_send_logs_label": "デバッグログを含める"
|
||||
"feedback_tab_send_logs_label": "デバッグログを含める",
|
||||
"feedback_tab_thank_you": "ありがとうございます。フィードバックを受け取りました!",
|
||||
"feedback_tab_title": "フィードバック",
|
||||
"opt_in_description": "<0></0><1></1>このボックスのチェックを外すと同意を取り消すことができます。現在通話中の場合、この変更は通話終了後に有効になります。"
|
||||
},
|
||||
"start_new_call": "新しい通話を開始",
|
||||
"start_video_button_label": "ビデオを開始",
|
||||
"stop_screenshare_button_label": "共有画面",
|
||||
"stop_video_button_label": "ビデオを停止",
|
||||
"submitting": "送信中…",
|
||||
"unauthenticated_view_body": "アカウントがありませんか? <2>アカウントを作成</2>",
|
||||
"unauthenticated_view_login_button": "アカウントにログイン",
|
||||
"version": "バージョン:{{version}}"
|
||||
"unmute_microphone_button_label": "マイクのミュート解除",
|
||||
"version": "バージョン:{{version}}",
|
||||
"video_tile": {
|
||||
"change_fit_contain": "フレームに合わせる",
|
||||
"mute_for_me": "ミュートする",
|
||||
"volume": "ボリューム"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,14 +5,21 @@
|
||||
"action": {
|
||||
"close": "Zamknij",
|
||||
"copy_link": "Kopiuj link",
|
||||
"edit": "Edytuj",
|
||||
"go": "Przejdź",
|
||||
"invite": "Zaproś",
|
||||
"lower_hand": "Opuść rękę",
|
||||
"no": "Nie",
|
||||
"pick_reaction": "Wybierz reakcję",
|
||||
"raise_hand": "Podnieś rękę",
|
||||
"register": "Zarejestruj",
|
||||
"remove": "Usuń",
|
||||
"show_less": "Pokaż mniej",
|
||||
"show_more": "Pokaż więcej",
|
||||
"sign_in": "Zaloguj się",
|
||||
"sign_out": "Wyloguj się",
|
||||
"submit": "Wyślij"
|
||||
"submit": "Wyślij",
|
||||
"upload_file": "Prześlij plik"
|
||||
},
|
||||
"analytics_notice": "Uczestnicząc w tej becie, upoważniasz nas do zbierania anonimowych danych, które wykorzystamy do ulepszenia produktu. Dowiedz się więcej na temat danych, które zbieramy w naszej <2>Polityce prywatności</2> i <5>Polityce ciasteczek</5>.",
|
||||
"app_selection_modal": {
|
||||
@@ -33,20 +40,68 @@
|
||||
},
|
||||
"call_name": "Nazwa połączenia",
|
||||
"common": {
|
||||
"analytics": "Dane analityczne",
|
||||
"audio": "Dźwięk",
|
||||
"avatar": "Awatar",
|
||||
"back": "Wstecz",
|
||||
"display_name": "Nazwa wyświetlana",
|
||||
"encrypted": "Szyfrowane",
|
||||
"home": "Strona domowa",
|
||||
"loading": "Ładowanie…",
|
||||
"next": "Dalej",
|
||||
"options": "Opcje",
|
||||
"password": "Hasło",
|
||||
"preferences": "Preferencje",
|
||||
"profile": "Profil",
|
||||
"reaction": "Reakcja",
|
||||
"reactions": "Reakcje",
|
||||
"settings": "Ustawienia",
|
||||
"unencrypted": "Nie szyfrowane",
|
||||
"username": "Nazwa użytkownika",
|
||||
"video": "Wideo"
|
||||
},
|
||||
"developer_mode": {
|
||||
"crypto_version": "Wersja krypto: {{version}}",
|
||||
"debug_tile_layout_label": "Układ kafelków Debug",
|
||||
"device_id": "ID urządzenia: {{id}}",
|
||||
"duplicate_tiles_label": "Liczba dodatkowych kopii kafelków na uczestnika",
|
||||
"environment_variables": "Zmienne środowiskowe",
|
||||
"hostname": "Nazwa hosta: {{hostname}}",
|
||||
"livekit_server_info": "Informacje serwera LiveKit",
|
||||
"livekit_sfu": "LiveKit SFU: {{url}}",
|
||||
"matrix_id": "ID Matrix: {{id}}",
|
||||
"show_connection_stats": "Pokaż statystyki połączenia",
|
||||
"show_non_member_tiles": "Pokaż kafelki dla mediów, które nie są od członków",
|
||||
"url_params": "Parametry URL",
|
||||
"use_new_membership_manager": "Użyj nowej implementacji połączenia MembershipManager"
|
||||
},
|
||||
"disconnected_banner": "Utracono połączenie z serwerem.",
|
||||
"error": {
|
||||
"call_is_not_supported": "Połączenie nie jest obsługiwane",
|
||||
"call_not_found": "Nie znaleziono połączenia",
|
||||
"call_not_found_description": "<0>Wygląda na to, że ten link nie należy do żadnego istniejącego połączenia. Sprawdź, czy posiadasz prawidłowy link lub <1>utwórz nowy</1>.</0>",
|
||||
"connection_lost": "Utracono połączenie",
|
||||
"connection_lost_description": "Zostałeś rozłączony z rozmowy.",
|
||||
"e2ee_unsupported": "Niekompatybilna przeglądarka",
|
||||
"e2ee_unsupported_description": "Twoja przeglądarka nie wspiera szyfrowanych połączeń. Obsługiwane przeglądarki obejmują Chrome, Safari i Firefox 117+.",
|
||||
"generic": "Coś poszło nie tak",
|
||||
"generic_description": "Wysłanie dziennika debug, pozwoli nam namierzyć problem.",
|
||||
"insufficient_capacity": "Za mało miejsca",
|
||||
"insufficient_capacity_description": "Serwer osiągnął maksymalną pojemność, przez co nie możesz dołączyć do połączenia. Spróbuj ponownie później lub skontaktuj się z administratorem serwera, jeśli problem nie zniknie.",
|
||||
"matrix_rtc_focus_missing": "Serwer nie jest skonfigurowany do pracy z {{brand}}. Prosimy o kontakt z administratorem serwera (Domena: {{domain}}, Kod błędu: {{ errorCode }}).",
|
||||
"open_elsewhere": "Otwarto w innej karcie",
|
||||
"open_elsewhere_description": "{{brand}} został otwarty w innej karcie. Jeśli tak nie jest, spróbuj odświeżyć stronę.",
|
||||
"unexpected_ec_error": "Wystąpił nieoczekiwany błąd (<0>Kod błędu:</0> <1>{{ errorCode }}</1>). Skontaktuj się z administratorem serwera."
|
||||
},
|
||||
"group_call_loader": {
|
||||
"banned_body": "Zostałeś zbanowany z pokoju.",
|
||||
"banned_heading": "Zbanowany",
|
||||
"call_ended_body": "Zostałeś usunięty z rozmowy.",
|
||||
"call_ended_heading": "Połączenie zakończone",
|
||||
"knock_reject_body": "Członkowie pokoju odrzucili Twoją prośbę o dołączenie.",
|
||||
"knock_reject_heading": "Nie możesz dołączyć",
|
||||
"reason": "Powód: {{reason}}"
|
||||
},
|
||||
"hangup_button_label": "Zakończ połączenie",
|
||||
"header_label": "Strona główna Element Call",
|
||||
"header_participants_label": "Uczestnicy",
|
||||
@@ -62,15 +117,25 @@
|
||||
"layout_grid_label": "Siatka",
|
||||
"layout_spotlight_label": "Centrum uwagi",
|
||||
"lobby": {
|
||||
"ask_to_join": "Poproś o dołączenie do rozmowy",
|
||||
"join_as_guest": "Dołącz jako gość",
|
||||
"join_button": "Dołącz do połączenia",
|
||||
"leave_button": "Wróć do ostatnie"
|
||||
"leave_button": "Wróć do ostatnie",
|
||||
"waiting_for_invite": "Żądanie wysłane"
|
||||
},
|
||||
"log_in": "Zaloguj",
|
||||
"logging_in": "Logowanie…",
|
||||
"login_auth_links": "<0>Utwórz konto</0> lub <2>Dołącz jako gość</2>",
|
||||
"login_auth_links_prompt": "Nie masz konta?",
|
||||
"login_subheading": "Aby przejść do Element",
|
||||
"login_title": "Zaloguj się",
|
||||
"microphone_off": "Mikrofon wyłączony",
|
||||
"microphone_on": "Mikrofon włączony",
|
||||
"mute_microphone_button_label": "Wycisz mikrofon",
|
||||
"participant_count_one": "{{count, number}}",
|
||||
"participant_count_few": "{{count, number}}",
|
||||
"participant_count_many": "{{count, number}}",
|
||||
"qr_code": "Kod QR",
|
||||
"rageshake_button_error_caption": "Wyślij logi ponownie",
|
||||
"rageshake_request_modal": {
|
||||
"body": "Inny użytkownik w tym połączeniu napotkał problem. Aby lepiej zdiagnozować tę usterkę, chcielibyśmy zebrać dzienniki debugowania.",
|
||||
@@ -82,23 +147,52 @@
|
||||
"rageshake_sent": "Dziękujemy!",
|
||||
"recaptcha_dismissed": "Recaptcha odrzucona",
|
||||
"recaptcha_not_loaded": "Recaptcha nie została załadowana",
|
||||
"recaptcha_ssla_caption": "Ta strona jest chroniona przez reCAPTCHA i obowiązują <2> Polityka prywatności Google </2> i <6>Warunki korzystania z usługi</6>. <9></9>Klikając „Zarejestruj się”, wyrażasz zgodę na naszą <12>umowę licencyjną oprogramowania i usług (SSLA)</12>",
|
||||
"register": {
|
||||
"passwords_must_match": "Hasła muszą pasować",
|
||||
"registering": "Rejestrowanie…"
|
||||
},
|
||||
"register_auth_links": "<0>Masz już konto?</0><1><0>Zaloguj się</0> lub <2>Dołącz jako gość</2></1>",
|
||||
"register_confirm_password_label": "Potwierdź hasło",
|
||||
"register_heading": "Utwórz konto",
|
||||
"return_home_button": "Powróć do strony głównej",
|
||||
"room_auth_view_continue_button": "Kontynuuj",
|
||||
"room_auth_view_ssla_caption": "Klikając \"Dołącz teraz do połączenia\", wyrażasz zgodę na naszą <2>Umowę licencyjną oprogramowania i usług (SSLA)</2>",
|
||||
"screenshare_button_label": "Udostępnij ekran",
|
||||
"settings": {
|
||||
"audio_tab": {
|
||||
"effect_volume_description": "Dostosuj głośność, z jaką odtwarzane są efekty reakcji i podniesionej ręki",
|
||||
"effect_volume_label": "Głośność efektu dźwiękowego"
|
||||
},
|
||||
"developer_tab_title": "Programista",
|
||||
"devices": {
|
||||
"camera": "Kamera",
|
||||
"camera_numbered": "Kamera {{n}}",
|
||||
"default": "Domyślne",
|
||||
"default_named": "Domyślne <2>({{name}})</2>",
|
||||
"microphone": "Mikrofon",
|
||||
"microphone_numbered": "Mikrofon {{n}}",
|
||||
"speaker": "Głośnik",
|
||||
"speaker_numbered": "Głośnik {{n}}"
|
||||
},
|
||||
"feedback_tab_body": "Jeśli posiadasz problemy lub chciałbyś zgłosić swoją opinię, wyślij nam krótki opis.",
|
||||
"feedback_tab_description_label": "Twoje opinie",
|
||||
"feedback_tab_h4": "Prześlij opinię",
|
||||
"feedback_tab_send_logs_label": "Dołącz dzienniki debugowania",
|
||||
"feedback_tab_thank_you": "Dziękujemy, otrzymaliśmy Twoją opinię!",
|
||||
"feedback_tab_title": "Opinia użytkownika",
|
||||
"opt_in_description": "<0></0><1></1>Możesz wycofać swoją zgodę poprzez odznaczenie tego pola. Jeśli już jesteś w trakcie rozmowy, opcja zostanie zastosowana po jej zakończeniu."
|
||||
"opt_in_description": "<0></0><1></1>Możesz wycofać swoją zgodę poprzez odznaczenie tego pola. Jeśli już jesteś w trakcie rozmowy, opcja zostanie zastosowana po jej zakończeniu.",
|
||||
"preferences_tab": {
|
||||
"developer_mode_label": "Tryb programisty",
|
||||
"developer_mode_label_description": "Włącz tryb programisty i wyświetl kartę ustawień programisty.",
|
||||
"introduction": "Tutaj możesz skonfigurować dodatkowe opcje dla lepszych doświadczeń.",
|
||||
"reactions_play_sound_description": "Odtwórz efekt dźwiękowy, gdy ktoś wyślę reakcję w trakcie połączenia.",
|
||||
"reactions_play_sound_label": "Odtwórz dźwięki reakcji",
|
||||
"reactions_show_description": "Odtwórz animację, gdy ktoś wyślę reakcję.",
|
||||
"reactions_show_label": "Pokaż reakcje",
|
||||
"show_hand_raised_timer_description": "Pokaż licznik, gdy uczestnik podniesie rękę",
|
||||
"show_hand_raised_timer_label": "Pokaż czas po podniesieniu ręki"
|
||||
}
|
||||
},
|
||||
"star_rating_input_label_one": "{{count}} gwiazdki",
|
||||
"star_rating_input_label_other": "{{count}} gwiazdki",
|
||||
@@ -107,8 +201,21 @@
|
||||
"stop_screenshare_button_label": "Udostępnianie ekranu",
|
||||
"stop_video_button_label": "Zakończ wideo",
|
||||
"submitting": "Wysyłanie…",
|
||||
"switch_camera": "Przełącz kamerę",
|
||||
"unauthenticated_view_body": "Nie masz konta? <2>Utwórz je</2>",
|
||||
"unauthenticated_view_login_button": "Zaloguj się do swojego konta",
|
||||
"unauthenticated_view_ssla_caption": "Klikając \"Przejdź\", wyrażasz zgodę na naszą <2>Umowę licencyjną oprogramowania i usług (SSLA)</2>",
|
||||
"unmute_microphone_button_label": "Odcisz mikrofon",
|
||||
"version": "Wersja: {{version}}"
|
||||
"version": "Wersja: {{version}}",
|
||||
"video_tile": {
|
||||
"always_show": "Zawsze pokazuj",
|
||||
"camera_starting": "Wczytywanie wideo...",
|
||||
"change_fit_contain": "Dopasuj do obramowania",
|
||||
"collapse": "Zwiń",
|
||||
"expand": "Rozwiń",
|
||||
"mute_for_me": "Wycisz dla mnie",
|
||||
"muted_for_me": "Wyciszone dla mnie",
|
||||
"volume": "Głośność",
|
||||
"waiting_for_media": "Oczekiwanie na media..."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,10 +143,13 @@
|
||||
"feedback_tab_title": "Feedback",
|
||||
"opt_in_description": "<0></0><1></1>Puteți retrage consimțământul debifând această casetă. Dacă sunteți în prezent la un apel, această setare va intra în vigoare la sfârșitul apelului.",
|
||||
"preferences_tab": {
|
||||
"introduction": "Aici puteți configura opțiuni suplimentare pentru o experiență îmbunătățită.",
|
||||
"reactions_play_sound_description": "Redați un efect sonor atunci când cineva trimite o reacție la un apel.",
|
||||
"reactions_play_sound_label": "Redați sunete de reacție",
|
||||
"reactions_show_description": "Afișați o animație atunci când cineva trimite o reacție.",
|
||||
"reactions_show_label": "Afișați reacțiile"
|
||||
"reactions_show_label": "Afișați reacțiile",
|
||||
"show_hand_raised_timer_description": "Afișați un cronometru atunci când un participant ridică mâna.",
|
||||
"show_hand_raised_timer_label": "Afișați durata ridicării mâinii"
|
||||
}
|
||||
},
|
||||
"start_new_call": "Începe un nou apel",
|
||||
|
||||
@@ -4,15 +4,30 @@
|
||||
},
|
||||
"action": {
|
||||
"close": "Закрыть",
|
||||
"copy_link": "Скопировать ссылку",
|
||||
"edit": "Редактировать",
|
||||
"go": "Далее",
|
||||
"invite": "Пригласить",
|
||||
"lower_hand": "Опустить руку",
|
||||
"no": "Нет",
|
||||
"pick_reaction": "Выберите реакцию",
|
||||
"raise_hand": "Поднять руку",
|
||||
"register": "Зарегистрироваться",
|
||||
"remove": "Удалить",
|
||||
"show_less": "Показать меньше",
|
||||
"show_more": "Показать больше",
|
||||
"sign_in": "Войти",
|
||||
"sign_out": "Выйти",
|
||||
"submit": "Отправить"
|
||||
"submit": "Отправить",
|
||||
"upload_file": "Загрузить файл"
|
||||
},
|
||||
"analytics_notice": "Участвуя в этой бета-версии, вы соглашаетесь на сбор анонимных данных, которые мы используем для улучшения продукта. Более подробную информацию о том, какие данные мы отслеживаем, вы можете найти в нашей <2> Политике конфиденциальности</2> и нашей <5> Политике использования файлов cookie</5>.",
|
||||
"app_selection_modal": {
|
||||
"continue_in_browser": "Продолжить в браузере",
|
||||
"open_in_app": "Открыть в приложении",
|
||||
"text": "Готовы присоединиться?",
|
||||
"title": "Выбрать приложение"
|
||||
},
|
||||
"call_ended_view": {
|
||||
"create_account_button": "Создать аккаунт",
|
||||
"create_account_prompt": "<0>Почему бы не задать пароль, тем самым сохранив аккаунт?</0><1>Так вы можете оставить своё имя и задать аватар для будущих звонков.</1>",
|
||||
@@ -20,33 +35,106 @@
|
||||
"feedback_prompt": "<0>Мы будем рады видеть ваши отзывы, чтобы мы могли улучшить ваш опыт.</0>",
|
||||
"headline": "{{displayName}}, ваш звонок окончен.",
|
||||
"not_now_button": "Не сейчас, вернуться в Начало",
|
||||
"reconnect_button": "Переподключиться",
|
||||
"survey_prompt": "Как всё прошло?"
|
||||
},
|
||||
"call_name": "Название звонка",
|
||||
"common": {
|
||||
"analytics": "Аналитика",
|
||||
"audio": "Аудио",
|
||||
"avatar": "Аватар",
|
||||
"back": "Назад",
|
||||
"display_name": "Видимое имя",
|
||||
"encrypted": "Зашифровано",
|
||||
"home": "Начало",
|
||||
"loading": "Загрузка…",
|
||||
"next": "Далее",
|
||||
"options": "Параметры",
|
||||
"password": "Пароль",
|
||||
"preferences": "Настройки",
|
||||
"profile": "Профиль",
|
||||
"reaction": "Реакция",
|
||||
"reactions": "Реакции",
|
||||
"settings": "Настройки",
|
||||
"unencrypted": "Не зашифровано",
|
||||
"username": "Имя пользователя",
|
||||
"video": "Видео"
|
||||
},
|
||||
"developer_mode": {
|
||||
"crypto_version": "Версия криптографии: {{version}}",
|
||||
"debug_tile_layout_label": "Отладка расположения плиток",
|
||||
"device_id": "Идентификатор устройства: {{id}}",
|
||||
"duplicate_tiles_label": "Количество дополнительных копий плиток на участника",
|
||||
"hostname": "Имя хоста: {{hostname}}",
|
||||
"livekit_server_info": "Информация о сервере LiveKit",
|
||||
"livekit_sfu": "LiveKit SFU: {{url}}",
|
||||
"matrix_id": "Matrix ID: {{id}}",
|
||||
"show_connection_stats": "Показать статистику подключений",
|
||||
"show_non_member_tiles": "Показать плитки для медиафайлов, не являющихся участниками",
|
||||
"use_new_membership_manager": "Используйте новую реализацию вызова MembershipManager"
|
||||
},
|
||||
"disconnected_banner": "Связь с сервером была потеряна.",
|
||||
"error": {
|
||||
"call_is_not_supported": "Вызов не поддерживается",
|
||||
"call_not_found": "Звонок не найден",
|
||||
"call_not_found_description": "<0>Эта ссылка, похоже, не принадлежит ни к одному существующему звонку. Убедитесь, что у вас есть нужная ссылка, или <1>создайте новую</1>.</0>",
|
||||
"connection_lost": "Соединение потеряно",
|
||||
"connection_lost_description": "Вы были отключены от звонка.",
|
||||
"e2ee_unsupported": "Несовместимый браузер",
|
||||
"e2ee_unsupported_description": "Ваш веб-браузер не поддерживает зашифрованные звонки. Поддерживаются следующие браузеры: Chrome, Safari и Firefox 117+.",
|
||||
"generic": "Произошла ошибка",
|
||||
"generic_description": "Отправка журналов отладки поможет нам отследить проблему.",
|
||||
"insufficient_capacity": "Недостаточная пропускная способность",
|
||||
"insufficient_capacity_description": "Сервер достиг максимальной пропускной способности, и вы не можете присоединиться к звонку в данный момент. Повторите попытку позже или обратитесь к администратору сервера, если проблема сохраняется.",
|
||||
"matrix_rtc_focus_missing": "Сервер не настроен для работы с {{brand}}. Пожалуйста, свяжитесь с администратором вашего сервера (Домен: {{domain}}, Код ошибки: {{ errorCode }}).",
|
||||
"open_elsewhere": "Открыто в другой вкладке",
|
||||
"open_elsewhere_description": "{{brand}} был открыт в другой вкладке. Если это неверно, попробуйте перезагрузить страницу.",
|
||||
"unexpected_ec_error": "Произошла непредвиденная ошибка (<0> Код ошибки:</0><1>{{ errorCode }}</1> ). Обратитесь к администратору вашего сервера."
|
||||
},
|
||||
"group_call_loader": {
|
||||
"banned_body": "Вас заблокировали в этой комнате",
|
||||
"banned_heading": "Заблокирован",
|
||||
"call_ended_body": "Вы были удалены из звонка.",
|
||||
"call_ended_heading": "Вызов завершен",
|
||||
"knock_reject_body": "Участники комнаты отклонили ваш запрос на присоединение.",
|
||||
"knock_reject_heading": "Не разрешено присоединиться",
|
||||
"reason": "Причина"
|
||||
},
|
||||
"hangup_button_label": "Завершить звонок",
|
||||
"header_label": "Главная Element Call",
|
||||
"header_participants_label": "Участники",
|
||||
"invite_modal": {
|
||||
"link_copied_toast": "Ссылка скопирована в буфер обмена",
|
||||
"title": "Пригласить в этот звонок"
|
||||
},
|
||||
"join_existing_call_modal": {
|
||||
"join_button": "Да, присоединиться",
|
||||
"text": "Этот звонок уже существует, хотите присоединиться?",
|
||||
"title": "Присоединиться к существующему звонку?"
|
||||
},
|
||||
"layout_grid_label": "Сетка",
|
||||
"layout_spotlight_label": "Внимание",
|
||||
"lobby": {
|
||||
"join_button": "Присоединиться"
|
||||
"ask_to_join": "Запрос на подключение к звонку",
|
||||
"join_as_guest": "Присоединиться в качестве гостя",
|
||||
"join_button": "Присоединиться",
|
||||
"leave_button": "Вернуться к списку недавних",
|
||||
"waiting_for_invite": "Запрос отправлен"
|
||||
},
|
||||
"log_in": "Войти",
|
||||
"logging_in": "Вход…",
|
||||
"login_auth_links": "<0>Создать аккаунт</0> или <2>Зайти как гость</2>",
|
||||
"login_auth_links_prompt": "Еще не зарегистрированы?",
|
||||
"login_subheading": "Продолжить в Element",
|
||||
"login_title": "Вход",
|
||||
"microphone_off": "Микрофон выключен",
|
||||
"microphone_on": "Микрофон включен",
|
||||
"mute_microphone_button_label": "Отключить микрофон",
|
||||
"participant_count_one": "{{count, number}}",
|
||||
"participant_count_few": "{{count, number}}",
|
||||
"participant_count_many": "{{count, number}}",
|
||||
"qr_code": "QR код",
|
||||
"rageshake_button_error_caption": "Повторить отправку журналов",
|
||||
"rageshake_request_modal": {
|
||||
"body": "У одного из участников звонка есть неполадки. Чтобы лучше диагностировать похожие проблемы, нам нужен журнал отладки.",
|
||||
"title": "Запрос журнала отладки"
|
||||
@@ -54,6 +142,7 @@
|
||||
"rageshake_send_logs": "Отправить журнал отладки",
|
||||
"rageshake_sending": "Отправка…",
|
||||
"rageshake_sending_logs": "Отправка журнала отладки…",
|
||||
"rageshake_sent": "Спасибо!",
|
||||
"recaptcha_dismissed": "Проверка не пройдена",
|
||||
"recaptcha_not_loaded": "Невозможно начать проверку",
|
||||
"register": {
|
||||
@@ -62,22 +151,66 @@
|
||||
},
|
||||
"register_auth_links": "<0>Уже есть аккаунт?</0><1><0>Войти с ним</0> или <2>Зайти как гость</2></1>",
|
||||
"register_confirm_password_label": "Подтвердите пароль",
|
||||
"register_heading": "Создать учетную запись",
|
||||
"return_home_button": "Вернуться в Начало",
|
||||
"room_auth_view_continue_button": "Продолжить",
|
||||
"screenshare_button_label": "Поделиться экраном",
|
||||
"settings": {
|
||||
"audio_tab": {
|
||||
"effect_volume_description": "Отрегулируйте громкость воспроизведения реакций и эффектов поднятия руки.",
|
||||
"effect_volume_label": "Громкость звукового эффекта"
|
||||
},
|
||||
"developer_tab_title": "Разработчику",
|
||||
"devices": {
|
||||
"camera": "Камера",
|
||||
"camera_numbered": "Камера {{n}}",
|
||||
"default": "По умолчанию",
|
||||
"default_named": "По умолчанию <2>({{name}})</2>",
|
||||
"microphone": "Микрофон",
|
||||
"microphone_numbered": "Микрофон {{n}}",
|
||||
"speaker": "Динамик",
|
||||
"speaker_numbered": "Динамик {{n}}"
|
||||
},
|
||||
"feedback_tab_body": "Если у вас возникли проблемы или вы просто хотите оставить отзыв, отправьте нам краткое описание ниже.",
|
||||
"feedback_tab_description_label": "Ваш отзыв",
|
||||
"feedback_tab_h4": "Отправить отзыв",
|
||||
"feedback_tab_send_logs_label": "Приложить журнал отладки",
|
||||
"feedback_tab_thank_you": "Спасибо. Мы получили ваш отзыв!",
|
||||
"feedback_tab_title": "Отзыв",
|
||||
"opt_in_description": "<0></0><1></1>Вы можете отозвать согласие, сняв этот флажок. Если вы в данный момент находитесь в разговоре, эта настройка вступит в силу по окончании разговора."
|
||||
"opt_in_description": "<0></0><1></1>Вы можете отозвать согласие, сняв этот флажок. Если вы в данный момент находитесь в разговоре, эта настройка вступит в силу по окончании разговора.",
|
||||
"preferences_tab": {
|
||||
"developer_mode_label": "Режим разработчика",
|
||||
"developer_mode_label_description": "Включить режим разработчика и показать настройки.",
|
||||
"introduction": "Здесь вы можете настроить дополнительные параметры для улучшения качества работы.",
|
||||
"reactions_play_sound_description": "Воспроизведите звуковой эффект, когда кто-либо отреагирует на звонок.",
|
||||
"reactions_play_sound_label": "Воспроизводить звуки реакции",
|
||||
"reactions_show_description": "Показать реакции",
|
||||
"reactions_show_label": "Показывать анимацию, когда кто-либо отправляет реакцию.",
|
||||
"show_hand_raised_timer_description": "Показывать таймер, когда участник поднимает руку",
|
||||
"show_hand_raised_timer_label": "Показать продолжительность поднятия руки"
|
||||
}
|
||||
},
|
||||
"star_rating_input_label_one": "{{count}} отмечен",
|
||||
"star_rating_input_label_other": "{{count}} отмеченных",
|
||||
"start_new_call": "Начать новый звонок",
|
||||
"start_video_button_label": "Начать видео",
|
||||
"stop_screenshare_button_label": "Демонстрация экрана",
|
||||
"stop_video_button_label": "Остановить видео",
|
||||
"submitting": "Отправляем…",
|
||||
"switch_camera": "Переключить камеру",
|
||||
"unauthenticated_view_body": "Ещё не зарегистрированы? <2>Создайте аккаунт</2>",
|
||||
"unauthenticated_view_login_button": "Войдите в свой аккаунт",
|
||||
"version": "Версия: {{version}}"
|
||||
"unmute_microphone_button_label": "Включить микрофон",
|
||||
"version": "Версия: {{version}}",
|
||||
"video_tile": {
|
||||
"always_show": "Показывать всегда",
|
||||
"camera_starting": "Загрузка видео...",
|
||||
"change_fit_contain": "По размеру окна",
|
||||
"collapse": "Свернуть",
|
||||
"expand": "Развернуть",
|
||||
"mute_for_me": "Заглушить звук для меня",
|
||||
"muted_for_me": "Приглушить для меня",
|
||||
"volume": "Громкость",
|
||||
"waiting_for_media": "В ожидании медиа..."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,14 +5,21 @@
|
||||
"action": {
|
||||
"close": "Zatvoriť",
|
||||
"copy_link": "Kopírovať odkaz",
|
||||
"edit": "Upraviť",
|
||||
"go": "Prejsť",
|
||||
"invite": "Pozvať",
|
||||
"lower_hand": "Dať dole ruku",
|
||||
"no": "Nie",
|
||||
"pick_reaction": "Vybrať reakciu",
|
||||
"raise_hand": "Zdvihnúť ruku",
|
||||
"register": "Registrovať sa",
|
||||
"remove": "Odstrániť",
|
||||
"show_less": "Zobraziť menej",
|
||||
"show_more": "Zobraziť viac",
|
||||
"sign_in": "Prihlásiť sa",
|
||||
"sign_out": "Odhlásiť sa",
|
||||
"submit": "Odoslať"
|
||||
"submit": "Odoslať",
|
||||
"upload_file": "Nahrať súbor"
|
||||
},
|
||||
"analytics_notice": "Účasťou v tejto beta verzii súhlasíte so zhromažďovaním anonymných údajov, ktoré použijeme na zlepšenie produktu. Viac informácií o tom, ktoré údaje sledujeme, nájdete v našich <2>Zásadách ochrany osobných údajov</2> a <5>Zásadách používania súborov cookie</5>.",
|
||||
"app_selection_modal": {
|
||||
@@ -33,18 +40,66 @@
|
||||
},
|
||||
"call_name": "Názov hovoru",
|
||||
"common": {
|
||||
"analytics": "Analytika",
|
||||
"audio": "Zvuk",
|
||||
"avatar": "Obrázok",
|
||||
"back": "Späť",
|
||||
"display_name": "Zobrazované meno",
|
||||
"encrypted": "Šifrované",
|
||||
"home": "Domov",
|
||||
"loading": "Načítanie…",
|
||||
"next": "Ďalej",
|
||||
"options": "Možnosti",
|
||||
"password": "Heslo",
|
||||
"preferences": "Predvoľby",
|
||||
"profile": "Profil",
|
||||
"reaction": "Reakcia",
|
||||
"reactions": "Reakcie",
|
||||
"settings": "Nastavenia",
|
||||
"unencrypted": "Nie je zašifrované",
|
||||
"username": "Meno používateľa"
|
||||
"username": "Meno používateľa",
|
||||
"video": "Video"
|
||||
},
|
||||
"developer_mode": {
|
||||
"crypto_version": "Krypto verzia: {{version}}",
|
||||
"debug_tile_layout_label": "Ladenie rozloženia dlaždíc",
|
||||
"device_id": "ID zariadenia: {{id}}",
|
||||
"duplicate_tiles_label": "Počet ďalších kópií dlaždíc na účastníka",
|
||||
"hostname": "Názov hostiteľa: {{hostname}}",
|
||||
"livekit_server_info": "Informácie o serveri LiveKit",
|
||||
"livekit_sfu": "LiveKit SFU: {{url}}",
|
||||
"matrix_id": "Matrix ID: {{id}}",
|
||||
"show_connection_stats": "Zobraziť štatistiky pripojenia",
|
||||
"show_non_member_tiles": "Zobraziť dlaždice pre nečlenské médiá",
|
||||
"use_new_membership_manager": "Použiť novú implementáciu hovoru MembershipManager"
|
||||
},
|
||||
"disconnected_banner": "Spojenie so serverom sa stratilo.",
|
||||
"error": {
|
||||
"call_is_not_supported": "Hovor nie je podporovaný",
|
||||
"call_not_found": "Hovor nebol nájdený",
|
||||
"call_not_found_description": "<0>Zdá sa, že tento odkaz nepatrí k žiadnemu existujúcemu hovoru. Skontrolujte, či máte správny odkaz, alebo <1> vytvorte nový</1>. </0>",
|
||||
"connection_lost": "Strata spojenia",
|
||||
"connection_lost_description": "Boli ste odpojení od hovoru.",
|
||||
"e2ee_unsupported": "Nekompatibilný prehliadač",
|
||||
"e2ee_unsupported_description": "Váš webový prehliadač nepodporuje šifrované hovory. Medzi podporované prehliadače patria Chrome, Safari a Firefox 117+.",
|
||||
"generic": "Niečo sa pokazilo",
|
||||
"generic_description": "Odoslanie záznamov ladenia nám pomôže nájsť problém.",
|
||||
"insufficient_capacity": "Nedostatočná kapacita",
|
||||
"insufficient_capacity_description": "Server dosiahol svoju maximálnu kapacitu a momentálne sa nemôžete pripojiť k hovoru. Skúste to znova neskôr alebo kontaktujte správcu servera, ak problém pretrváva.",
|
||||
"matrix_rtc_focus_missing": "Server nie je nakonfigurovaný na prácu s aplikáciou {{brand}}. Kontaktujte správcu svojho servera (Doména:{{domain}}, Kód chyby:{{ errorCode }}).",
|
||||
"open_elsewhere": "Otvorené na inej karte",
|
||||
"open_elsewhere_description": "Aplikácia {{brand}} bola otvorená na inej karte. Ak sa vám to nezdá, skúste znovu načítať stránku.",
|
||||
"unexpected_ec_error": "Vyskytla sa neočakávaná chyba (<0>Kód chyby:</0> <1>{{ errorCode }}</1>). Kontaktujte prosím správcu vášho servera."
|
||||
},
|
||||
"group_call_loader": {
|
||||
"banned_body": "Dostali ste zákaz vstupu do miestnosti.",
|
||||
"banned_heading": "Zakázané",
|
||||
"call_ended_body": "Boli ste odstránení z hovoru.",
|
||||
"call_ended_heading": "Hovor bol ukončený",
|
||||
"knock_reject_body": "Členovia miestnosti odmietli vašu žiadosť o pripojenie.",
|
||||
"knock_reject_heading": "Nie je povolené pripojiť sa",
|
||||
"reason": "Dôvod"
|
||||
},
|
||||
"hangup_button_label": "Ukončiť hovor",
|
||||
"header_label": "Domov Element Call",
|
||||
"header_participants_label": "Účastníci",
|
||||
@@ -60,15 +115,25 @@
|
||||
"layout_grid_label": "Sieť",
|
||||
"layout_spotlight_label": "Stredobod",
|
||||
"lobby": {
|
||||
"ask_to_join": "Požiadať o pripojenie k hovoru",
|
||||
"join_as_guest": "Pripojiť sa ako hosť",
|
||||
"join_button": "Pripojiť sa k hovoru",
|
||||
"leave_button": "Späť k nedávnym"
|
||||
"leave_button": "Späť k nedávnym",
|
||||
"waiting_for_invite": "Žiadosť odoslaná"
|
||||
},
|
||||
"log_in": "Prihlásiť sa",
|
||||
"logging_in": "Prihlasovanie…",
|
||||
"login_auth_links": "<0>Vytvoriť konto</0> Alebo <2>Prihlásiť sa ako hosť</2>",
|
||||
"login_auth_links_prompt": "Nie ste ešte zaregistrovaní?",
|
||||
"login_subheading": "Ak chcete pokračovať na Element",
|
||||
"login_title": "Prihlásiť sa",
|
||||
"microphone_off": "Mikrofón vypnutý",
|
||||
"microphone_on": "Mikrofón zapnutý",
|
||||
"mute_microphone_button_label": "Stlmiť mikrofón",
|
||||
"participant_count_one": "{{count, number}}",
|
||||
"participant_count_few": "{{count, number}}",
|
||||
"participant_count_other": "{{count, number}}",
|
||||
"qr_code": "QR kód",
|
||||
"rageshake_button_error_caption": "Opakovať odoslanie záznamov",
|
||||
"rageshake_request_modal": {
|
||||
"body": "Ďalší používateľ v tomto hovore má problém. Aby sme mohli lepšie diagnostikovať tieto problémy, chceli by sme získať záznam o ladení.",
|
||||
@@ -86,17 +151,44 @@
|
||||
},
|
||||
"register_auth_links": "<0>Už máte konto?</0><1><0>Prihláste sa</0> Alebo <2>Prihlásiť sa ako hosť</2></1>",
|
||||
"register_confirm_password_label": "Potvrdiť heslo",
|
||||
"register_heading": "Vytvorte si účet",
|
||||
"return_home_button": "Návrat na domovskú obrazovku",
|
||||
"room_auth_view_continue_button": "Pokračovať",
|
||||
"screenshare_button_label": "Zdieľať obrazovku",
|
||||
"settings": {
|
||||
"audio_tab": {
|
||||
"effect_volume_description": "Upraviť hlasitosť, pri ktorej sa prehrávajú reakcie a efekty zdvihnutia ruky.",
|
||||
"effect_volume_label": "Hlasitosť zvukového efektu"
|
||||
},
|
||||
"developer_tab_title": "Vývojár",
|
||||
"devices": {
|
||||
"camera": "Kamera",
|
||||
"camera_numbered": "Kamera {{n}}",
|
||||
"default": "Predvolené",
|
||||
"default_named": "Predvolené <2>({{name}})</2>",
|
||||
"microphone": "Mikrofón",
|
||||
"microphone_numbered": "Mikrofón {{n}}",
|
||||
"speaker": "Reproduktor",
|
||||
"speaker_numbered": "Reproduktor {{n}}"
|
||||
},
|
||||
"feedback_tab_body": "Ak máte problémy alebo jednoducho chcete poskytnúť spätnú väzbu, pošlite nám krátky popis nižšie.",
|
||||
"feedback_tab_description_label": "Vaša spätná väzba",
|
||||
"feedback_tab_h4": "Odoslať spätnú väzbu",
|
||||
"feedback_tab_send_logs_label": "Zahrnúť záznamy o ladení",
|
||||
"feedback_tab_thank_you": "Ďakujeme, dostali sme vašu spätnú väzbu!",
|
||||
"feedback_tab_title": "Spätná väzba",
|
||||
"opt_in_description": "<0></0><1></1>Súhlas môžete odvolať zrušením označenia tohto políčka. Ak práve prebieha hovor, toto nastavenie nadobudne platnosť po skončení hovoru."
|
||||
"opt_in_description": "<0></0><1></1>Súhlas môžete odvolať zrušením označenia tohto políčka. Ak práve prebieha hovor, toto nastavenie nadobudne platnosť po skončení hovoru.",
|
||||
"preferences_tab": {
|
||||
"developer_mode_label": "Režim vývojára",
|
||||
"developer_mode_label_description": "Povoliť režim vývojára a zobraziť kartu Nastavenia vývojára.",
|
||||
"introduction": "Tu môžete nastaviť ďalšie možnosti pre lepší zážitok.",
|
||||
"reactions_play_sound_description": "Prehrať zvukový efekt, keď niekto odošle reakciu na hovor.",
|
||||
"reactions_play_sound_label": "Prehrať zvuky reakcie",
|
||||
"reactions_show_description": "Zobraziť animáciu, keď niekto odošle reakciu.",
|
||||
"reactions_show_label": "Zobraziť reakcie",
|
||||
"show_hand_raised_timer_description": "Zobraziť časovač, keď účastník zdvihne ruku",
|
||||
"show_hand_raised_timer_label": "Zobraziť trvanie zdvihnutia ruky"
|
||||
}
|
||||
},
|
||||
"star_rating_input_label_one": "{{count}} hviezdička",
|
||||
"star_rating_input_label_other": "{{count}} hviezdičiek",
|
||||
@@ -105,8 +197,20 @@
|
||||
"stop_screenshare_button_label": "Zdieľanie obrazovky",
|
||||
"stop_video_button_label": "Zastaviť video",
|
||||
"submitting": "Odosielanie…",
|
||||
"switch_camera": "Prepnúť fotoaparát",
|
||||
"unauthenticated_view_body": "Ešte nie ste zaregistrovaný? <2>Vytvorte si účet</2>",
|
||||
"unauthenticated_view_login_button": "Prihláste sa do svojho konta",
|
||||
"unmute_microphone_button_label": "Zrušiť stlmenie mikrofónu",
|
||||
"version": "Verzia: {{version}}"
|
||||
"version": "Verzia: {{version}}",
|
||||
"video_tile": {
|
||||
"always_show": "Vždy zobraziť",
|
||||
"camera_starting": "Načítavanie videa...",
|
||||
"change_fit_contain": "Orezať na mieru",
|
||||
"collapse": "Zbaliť",
|
||||
"expand": "Rozbaliť",
|
||||
"mute_for_me": "Pre mňa stlmiť",
|
||||
"muted_for_me": "Pre mňa stlmené",
|
||||
"volume": "Hlasitosť",
|
||||
"waiting_for_media": "Čaká sa na médiá..."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,220 @@
|
||||
{
|
||||
"a11y": {
|
||||
"user_menu": "Användarmeny"
|
||||
},
|
||||
"action": {
|
||||
"close": "Stäng",
|
||||
"copy_link": "Kopiera länk",
|
||||
"edit": "Redigera",
|
||||
"go": "Gå",
|
||||
"invite": "Bjud in",
|
||||
"lower_hand": "Sänk handen",
|
||||
"no": "Nej",
|
||||
"pick_reaction": "Välj reaktion",
|
||||
"raise_hand": "Räck upp handen",
|
||||
"register": "Registrera",
|
||||
"remove": "Ta bort",
|
||||
"show_less": "Visa mindre",
|
||||
"show_more": "Visa mer",
|
||||
"sign_in": "Logga in",
|
||||
"sign_out": "Logga ut",
|
||||
"submit": "Skicka",
|
||||
"upload_file": "Ladda upp fil"
|
||||
},
|
||||
"analytics_notice": "Genom att delta i denna beta samtycker du till insamling av anonyma uppgifter, som vi använder för att förbättra produkten. Du kan hitta mer information om vilka data vi spårar i vår <2>integritetspolicy</2> och vår <5>cookiepolicy</5>.",
|
||||
"app_selection_modal": {
|
||||
"continue_in_browser": "Fortsätt i webbläsaren",
|
||||
"open_in_app": "Öppna i appen",
|
||||
"text": "Är du redo att gå med?",
|
||||
"title": "Välj app"
|
||||
},
|
||||
"call_ended_view": {
|
||||
"headline": "{{displayName}}, ditt samtal har avslutats."
|
||||
"create_account_button": "Skapa konto",
|
||||
"create_account_prompt": "<0>Varför inte avsluta genom att skapa ett lösenord för att behålla ditt konto?</0><1>Du kommer att kunna behålla ditt namn och ställa in en avatar för användning vid framtida samtal</1>",
|
||||
"feedback_done": "<0>Tack för din feedback! </0>",
|
||||
"feedback_prompt": "<0>Vi vill gärna höra din feedback så att vi kan förbättra din upplevelse. </0>",
|
||||
"headline": "{{displayName}}, ditt samtal har avslutats.",
|
||||
"not_now_button": "Inte nu, återgå till startskärmen",
|
||||
"reconnect_button": "Återanslut",
|
||||
"survey_prompt": "Hur gick det?"
|
||||
},
|
||||
"call_name": "Namn på samtal",
|
||||
"common": {
|
||||
"analytics": "Analysdata",
|
||||
"audio": "Ljud",
|
||||
"avatar": "Avatar",
|
||||
"back": "Tillbaka",
|
||||
"display_name": "Visningsnamn",
|
||||
"encrypted": "Krypterad",
|
||||
"home": "Hem",
|
||||
"loading": "Laddar …",
|
||||
"next": "Nästa",
|
||||
"options": "Alternativ",
|
||||
"password": "Lösenord",
|
||||
"preferences": "Alternativ",
|
||||
"profile": "Profil",
|
||||
"reaction": "Reaktion",
|
||||
"reactions": "Reaktioner",
|
||||
"settings": "Inställningar",
|
||||
"unencrypted": "Inte krypterad",
|
||||
"username": "Användarnamn",
|
||||
"video": "Video"
|
||||
},
|
||||
"developer_mode": {
|
||||
"crypto_version": "Kryptoversion: {{version}}",
|
||||
"debug_tile_layout_label": "Felsök panelarrangemang",
|
||||
"device_id": "Enhets-ID: {{id}}",
|
||||
"duplicate_tiles_label": "Antal ytterligare panelkopior per deltagare",
|
||||
"environment_variables": "Miljövariabler",
|
||||
"hostname": "Värdnamn: {{hostname}}",
|
||||
"livekit_server_info": "LiveKit-serverinfo",
|
||||
"livekit_sfu": "LiveKit SFU: {{url}}",
|
||||
"matrix_id": "Matrix-ID: {{id}}",
|
||||
"show_connection_stats": "Visa anslutningsstatistik",
|
||||
"show_non_member_tiles": "Visa paneler för media som inte är medlemmar",
|
||||
"url_params": "URL-parametrar",
|
||||
"use_new_membership_manager": "Använd den nya implementeringen av samtals-MembershipManager"
|
||||
},
|
||||
"disconnected_banner": "Anslutningen till servern har brutits.",
|
||||
"error": {
|
||||
"call_is_not_supported": "Call stöds inte",
|
||||
"call_not_found": "Samtal hittades inte",
|
||||
"call_not_found_description": "<0>Den länken verkar inte tillhöra något befintligt samtal. Kontrollera att du har rätt länk, eller <1>skapa en ny</1>.</0>",
|
||||
"connection_lost": "Anslutning förlorad",
|
||||
"connection_lost_description": "Du kopplades bort från samtalet.",
|
||||
"e2ee_unsupported": "Inkompatibel webbläsare",
|
||||
"e2ee_unsupported_description": "Din webbläsare stöder inte krypterade samtal. Webbläsare som stöds inkluderar Chrome, Safari och Firefox 117+.",
|
||||
"generic": "Något gick fel",
|
||||
"generic_description": "Att skicka felsökningsloggar hjälper oss att spåra problemet.",
|
||||
"insufficient_capacity": "Otillräcklig kapacitet",
|
||||
"insufficient_capacity_description": "Servern har nått sin maximala kapacitet och du kan inte gå med i samtalet just nu. Försök igen senare, eller kontakta serveradministratören om problemet kvarstår.",
|
||||
"matrix_rtc_focus_missing": "Servern är inte konfigurerad för att fungera med {{brand}}. Vänligen kontakta serveradministratören (Domän: {{domain}}, Felkod: {{ errorCode }}).",
|
||||
"open_elsewhere": "Öppnades i en annan flik",
|
||||
"open_elsewhere_description": "{{brand}} har öppnats i en annan flik. Om det inte låter rätt, pröva att ladda om sidan.",
|
||||
"unexpected_ec_error": "Ett oväntat fel inträffade (<0>Felkod:</0> <1>{{ errorCode }}</1>). Kontakta din serveradministratör."
|
||||
},
|
||||
"group_call_loader": {
|
||||
"banned_body": "Du har bannats från rummet.",
|
||||
"banned_heading": "Bannad",
|
||||
"call_ended_body": "Du har har tagits bort från samtalet.",
|
||||
"call_ended_heading": "Samtal avslutat",
|
||||
"knock_reject_body": "Rumsmedlemmarna avslog din begäran om att gå med.",
|
||||
"knock_reject_heading": "Inte tillåten att gå med",
|
||||
"reason": "Anledning"
|
||||
},
|
||||
"hangup_button_label": "Avsluta samtal",
|
||||
"header_label": "Element Call Hem",
|
||||
"header_participants_label": "Deltagare",
|
||||
"invite_modal": {
|
||||
"link_copied_toast": "Länk kopierad till klippbordet",
|
||||
"title": "Bjud in till det här samtalet"
|
||||
},
|
||||
"join_existing_call_modal": {
|
||||
"join_button": "Ja, gå med i samtal",
|
||||
"text": "Det här samtalet finns redan, vill du gå med?",
|
||||
"title": "Gå med i befintligt samtal?"
|
||||
},
|
||||
"layout_grid_label": "Rutnät",
|
||||
"layout_spotlight_label": "Spotlight",
|
||||
"lobby": {
|
||||
"ask_to_join": "Be om att delta i samtalet",
|
||||
"join_as_guest": "Gå med som gäst",
|
||||
"join_button": "Anslut till samtal",
|
||||
"leave_button": "Tillbaka till senaste",
|
||||
"waiting_for_invite": "Begäran skickad"
|
||||
},
|
||||
"log_in": "Logga in",
|
||||
"logging_in": "Loggar in …",
|
||||
"login_auth_links": "<0>Skapa ett konto</0> eller <2>Kom åt som gäst</2>",
|
||||
"login_auth_links_prompt": "Inte registrerad än?",
|
||||
"login_subheading": "För att fortsätta till Element",
|
||||
"login_title": "Logga in",
|
||||
"microphone_off": "Mikrofon av",
|
||||
"microphone_on": "Mikrofon på",
|
||||
"mute_microphone_button_label": "Tysta mikrofonen",
|
||||
"participant_count_one": "{{count, number}}",
|
||||
"participant_count_other": "{{count, number}}",
|
||||
"qr_code": "QR-kod",
|
||||
"rageshake_button_error_caption": "Försök att skicka loggar igen",
|
||||
"rageshake_request_modal": {
|
||||
"body": "En annan användare i det här samtalet har ett problem. För att bättre kunna diagnostisera dessa problem vill vi samla in en felsökningslogg.",
|
||||
"title": "Begäran om felsökningslogg"
|
||||
},
|
||||
"rageshake_send_logs": "Skicka felsökningsloggar",
|
||||
"rageshake_sending": "Skickar …",
|
||||
"rageshake_sending_logs": "Skickar felsökningsloggar …",
|
||||
"rageshake_sent": "Tack!",
|
||||
"recaptcha_dismissed": "Recaptcha avvisad",
|
||||
"recaptcha_not_loaded": "Recaptcha laddades inte",
|
||||
"recaptcha_ssla_caption": "Denna webbplats skyddas av ReCAPTCHA och Googles <2>sekretesspolicy</2> och <6>användarvillkor</6> gäller.<9></9>Genom att klicka på ”Registrera” godkänner du vårt <12>licensavtal för programvara och tjänster</12>",
|
||||
"register": {
|
||||
"passwords_must_match": "Lösenorden måste överensstämma",
|
||||
"registering": "Registrerar …"
|
||||
},
|
||||
"register_auth_links": "<0>Har du redan ett konto?</0><1><0>Logga in</0> eller <2>kom åt som en gäst</2></1>",
|
||||
"register_confirm_password_label": "Bekräfta lösenord",
|
||||
"register_heading": "Skapa ditt konto",
|
||||
"return_home_button": "Återgå till startskärmen",
|
||||
"room_auth_view_continue_button": "Fortsätt",
|
||||
"room_auth_view_ssla_caption": "Genom att klicka på ”Anslut till samtal nu” godkänner du vårt <2>licensavtal för programvara och tjänster</2>",
|
||||
"screenshare_button_label": "Dela skärm",
|
||||
"settings": {
|
||||
"audio_tab": {
|
||||
"effect_volume_description": "Justera volymen vid vilken reaktioner och handuppräckningseffekter spelas",
|
||||
"effect_volume_label": "Ljudeffektsvolym"
|
||||
},
|
||||
"developer_tab_title": "Utvecklare",
|
||||
"devices": {
|
||||
"camera": "Kamera",
|
||||
"camera_numbered": "Kamera {{n}}",
|
||||
"default": "Förval",
|
||||
"default_named": "Förval <2>({{name}})</2>",
|
||||
"microphone": "Mikrofon",
|
||||
"microphone_numbered": "Mikrofon {{n}}",
|
||||
"speaker": "Högtalare",
|
||||
"speaker_numbered": "Högtalare {{n}}"
|
||||
},
|
||||
"feedback_tab_body": "Om du har problem eller bara vill ge lite återkoppling, skicka oss en kort beskrivning nedan.",
|
||||
"feedback_tab_description_label": "Din återkoppling",
|
||||
"feedback_tab_h4": "Skicka återkoppling",
|
||||
"feedback_tab_send_logs_label": "Inkludera felsökningsloggar",
|
||||
"feedback_tab_thank_you": "Tack, vi har tagit emot din återkoppling!",
|
||||
"feedback_tab_title": "Återkoppling",
|
||||
"opt_in_description": "<0></0><1></1>Du kan återkalla ditt samtycke genom att avmarkera den här rutan. Om du för närvarande är i ett samtal träder den här inställningen i kraft vid slutet av samtalet.",
|
||||
"preferences_tab": {
|
||||
"developer_mode_label": "Utvecklarläge",
|
||||
"developer_mode_label_description": "Aktivera utvecklarläger och visa fliken utvecklarinställningar.",
|
||||
"introduction": "Här kan du konfigurera extra alternativ för en förbättrad upplevelse.",
|
||||
"reactions_play_sound_description": "Spela en ljudeffekt när någon skickar in en reaktion i ett samtal.",
|
||||
"reactions_play_sound_label": "Spela reaktionsljud",
|
||||
"reactions_show_description": "Visa en animering när någon skickar en reaktion.",
|
||||
"reactions_show_label": "Visa reaktioner",
|
||||
"show_hand_raised_timer_description": "Visa en timer när en deltagare räcker upp handen",
|
||||
"show_hand_raised_timer_label": "Visa varaktighet för handuppräckning"
|
||||
}
|
||||
},
|
||||
"star_rating_input_label_one": "{{count}} stjärna",
|
||||
"star_rating_input_label_other": "{{count}} stjärnor"
|
||||
"star_rating_input_label_other": "{{count}} stjärnor",
|
||||
"start_new_call": "Starta ett nytt samtal",
|
||||
"start_video_button_label": "Starta video",
|
||||
"stop_screenshare_button_label": "Delar skärm",
|
||||
"stop_video_button_label": "Stoppa video",
|
||||
"submitting": "Skickar …",
|
||||
"switch_camera": "Byt kamera",
|
||||
"unauthenticated_view_body": "Inte registrerad än? <2>Skapa ett konto</2>",
|
||||
"unauthenticated_view_login_button": "Logga in på ditt konto",
|
||||
"unauthenticated_view_ssla_caption": "Genom att klicka på ”Kör” godkänner du vårt <2>licensavtal för programvara och tjänster</2>",
|
||||
"unmute_microphone_button_label": "Sluta tysta mikrofonen",
|
||||
"version": "Version: {{version}}",
|
||||
"video_tile": {
|
||||
"always_show": "Visa alltid",
|
||||
"camera_starting": "Video laddar …",
|
||||
"change_fit_contain": "Anpassa till ram",
|
||||
"collapse": "Kollapsa",
|
||||
"expand": "Expandera",
|
||||
"mute_for_me": "Tysta för mig",
|
||||
"muted_for_me": "Tystad för mig",
|
||||
"volume": "Volym",
|
||||
"waiting_for_media": "Väntar på media …"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,42 +1,141 @@
|
||||
{
|
||||
"a11y": {
|
||||
"user_menu": "Kullanıcı menüsü"
|
||||
},
|
||||
"action": {
|
||||
"close": "Kapat",
|
||||
"copy_link": "Bağlantıyı kopyala",
|
||||
"edit": "Düzenle",
|
||||
"go": "Git",
|
||||
"invite": "Davet et",
|
||||
"lower_hand": "Elini indir",
|
||||
"no": "Hayır",
|
||||
"pick_reaction": "Tepki seç",
|
||||
"raise_hand": "Elini kaldır",
|
||||
"register": "Kaydol",
|
||||
"remove": "Çıkar",
|
||||
"show_less": "Daha az göster",
|
||||
"show_more": "Daha fazla göster",
|
||||
"sign_in": "Gir",
|
||||
"sign_out": "Çık"
|
||||
"sign_out": "Çık",
|
||||
"submit": "Gönder",
|
||||
"upload_file": "Dosya Yükle"
|
||||
},
|
||||
"analytics_notice": "Bu beta sürümüne katılarak, ürünü geliştirmek için kullandığımız anonim verilerin toplanmasına izin vermiş olursunuz. Hangi verileri izlediğimiz hakkında daha fazla bilgiyi <2>Gizlilik Politikamızda</2> ve <6>Çerez Politikamızda bulabilirsiniz</6>..",
|
||||
"app_selection_modal": {
|
||||
"continue_in_browser": "Tarayıcıda devam et",
|
||||
"open_in_app": "Uygulamada aç",
|
||||
"text": "Katılmaya hazır mısınız?",
|
||||
"title": "Uygulama seçin"
|
||||
},
|
||||
"call_ended_view": {
|
||||
"create_account_button": "Hesap aç",
|
||||
"create_account_prompt": "<0>Hesabınızı tutmak için niye bir parola açmıyorsunuz?</0><1>Böylece ileriki aramalarda adınızı ve avatarınızı kullanabileceksiniz</1>",
|
||||
"not_now_button": "Şimdi değil, ev ekranına dön"
|
||||
"feedback_done": "<0>Geri bildiriminiz için teşekkürler!</0>",
|
||||
"feedback_prompt": "<0>Deneyiminizi geliştirebilmemiz için geri bildirimlerinizi duymak isteriz.</0>",
|
||||
"headline": "{{displayName}}, çağrınız sona erdi.",
|
||||
"not_now_button": "Şimdi değil, ev ekranına dön",
|
||||
"reconnect_button": "Yeniden bağlan",
|
||||
"survey_prompt": "Nasıl geçti?"
|
||||
},
|
||||
"call_name": "Aramanın adı",
|
||||
"common": {
|
||||
"analytics": "Analiz",
|
||||
"audio": "Ses",
|
||||
"avatar": "Avatar",
|
||||
"back": "Geri",
|
||||
"display_name": "Ekran adı",
|
||||
"encrypted": "Şifrelenmiş",
|
||||
"home": "Ev",
|
||||
"loading": "Yükleniyor…",
|
||||
"next": "İleri",
|
||||
"options": "Seçenekler",
|
||||
"password": "Parola",
|
||||
"settings": "Ayarlar"
|
||||
"preferences": "Tercihler",
|
||||
"profile": "Profil",
|
||||
"reaction": "Tepki",
|
||||
"reactions": "Tepkiler",
|
||||
"settings": "Ayarlar",
|
||||
"unencrypted": "Şifrelenmemiş",
|
||||
"username": "Kullanıcı adı",
|
||||
"video": "Video"
|
||||
},
|
||||
"developer_mode": {
|
||||
"crypto_version": "Şifreleme sürümü: {{version}}",
|
||||
"debug_tile_layout_label": "Hata ayıklama döşeme düzeni",
|
||||
"device_id": "Cihaz Kimliği: {{id}}",
|
||||
"duplicate_tiles_label": "Katılımcı başına ek döşeme sayısı",
|
||||
"hostname": "Sunucu adı: {{hostname}}",
|
||||
"livekit_server_info": "LiveKit Sunucu Bilgisi",
|
||||
"livekit_sfu": "LiveKit SFU: {{url}}",
|
||||
"matrix_id": "Matrix Kimliği: {{id}}",
|
||||
"show_connection_stats": "Bağlantı istatistiklerini göster",
|
||||
"show_non_member_tiles": "Üye olmayan kullanıcılar için ortam döşemelerini göster"
|
||||
},
|
||||
"disconnected_banner": "Sunucuyla bağlantı kesildi.",
|
||||
"error": {
|
||||
"call_not_found": "Çağrı bulunamadı",
|
||||
"call_not_found_description": "<0>Bu bağlantı mevcut herhangi bir çağrıya ait görünmüyor. Doğru bağlantıya sahip olduğunuzu kontrol edin veya <1> yeni bir bağlantı oluşturun</1>. </0>",
|
||||
"connection_lost": "Bağlantı kesildi",
|
||||
"connection_lost_description": "Çağrıdan bağlantınız kesildi.",
|
||||
"e2ee_unsupported": "Uyumsuz Tarayıcı",
|
||||
"e2ee_unsupported_description": "İnternet tarayıcınız şifreli aramaları desteklemiyor. Desteklenen tarayıcılar arasında Chrome, Safari ve Firefox 117+ bulunur.",
|
||||
"generic": "Bir şeyler ters gitti",
|
||||
"generic_description": "Hata ayıklama günlüklerini göndermeniz sorunu tespit etmemizde yardımcı olacaktır.",
|
||||
"open_elsewhere": "Başka bir sekmede açıldı",
|
||||
"open_elsewhere_description": "{{brand}} başka bir sekmede açıldı. Bu doğru değilse, sayfayı yeniden yüklemeyi deneyin."
|
||||
},
|
||||
"group_call_loader": {
|
||||
"banned_body": "Odaya girmeniz yasaklandı.",
|
||||
"banned_heading": "Yasaklandı",
|
||||
"call_ended_body": "Aramadan çıkarıldınız.",
|
||||
"call_ended_heading": "Arama sonlandırıldı",
|
||||
"knock_reject_body": "Katılma isteğiniz reddedildi.",
|
||||
"knock_reject_heading": "Erişim reddedildi",
|
||||
"reason": "Neden: {{reason}}"
|
||||
},
|
||||
"hangup_button_label": "Aramayı sonlandır",
|
||||
"header_label": "Element Call Ana Sayfa",
|
||||
"header_participants_label": "Katılımcılar",
|
||||
"invite_modal": {
|
||||
"link_copied_toast": "Bağlantı panoya kopyalandı",
|
||||
"title": "Bu görüşmeye davet edin"
|
||||
},
|
||||
"join_existing_call_modal": {
|
||||
"join_button": "Evet, aramaya katıl",
|
||||
"text": "Bu arama zaten var, katılmak ister misiniz?",
|
||||
"title": "Mevcut aramaya katıl?"
|
||||
},
|
||||
"layout_grid_label": "Izgara",
|
||||
"layout_spotlight_label": "İlgi Odağı",
|
||||
"lobby": {
|
||||
"join_button": "Aramaya katıl"
|
||||
"ask_to_join": "Aramaya katılma isteği gönder",
|
||||
"join_as_guest": "Misafir olarak katıl",
|
||||
"join_button": "Aramaya katıl",
|
||||
"leave_button": "Son aramalara dön",
|
||||
"waiting_for_invite": "İstek gönderildi! Katılmak için izin verilmesi bekleniyor…"
|
||||
},
|
||||
"log_in": "Giriş yap",
|
||||
"logging_in": "Giriliyor…",
|
||||
"login_auth_links": "<0>Hesap oluştur</0> yahut <2>Konuk olarak gir</2>",
|
||||
"login_auth_links_prompt": "Henüz kaydolmadınız mı?",
|
||||
"login_subheading": "Element'e devam etmek için",
|
||||
"login_title": "Gir",
|
||||
"microphone_off": "Mikrofon kapalı",
|
||||
"microphone_on": "Mikrofon açık",
|
||||
"mute_microphone_button_label": "Mikrofonu sessize al",
|
||||
"participant_count_one": "{{count, number}}",
|
||||
"participant_count_other": "{{count, number}}",
|
||||
"qr_code": "QR Kodu",
|
||||
"rageshake_button_error_caption": "Günlükleri göndermeyi yeniden dene",
|
||||
"rageshake_request_modal": {
|
||||
"body": "Bu aramadaki başka bir kullanıcı sorun yaşıyor. Sorunu daha iyi çözebilmemiz için hata ayıklama kütüğünü almak isteriz.",
|
||||
"title": "Hata ayıklama kütük istemi"
|
||||
},
|
||||
"rageshake_send_logs": "Hata ayıklama kütüğünü gönder",
|
||||
"rageshake_sending": "Gönderiliyor…",
|
||||
"rageshake_sending_logs": "Hata ayıklama günlükleri gönderiliyor...",
|
||||
"rageshake_sent": "Teşekkürler!",
|
||||
"recaptcha_dismissed": "reCAPTCHA atlandı",
|
||||
"recaptcha_not_loaded": "reCAPTCHA yüklenmedi",
|
||||
"register": {
|
||||
@@ -45,13 +144,66 @@
|
||||
},
|
||||
"register_auth_links": "<0>Mevcut hesabınız mı var?</0><1><0>Gir</0> yahut <2>Konuk girişi</2></1>",
|
||||
"register_confirm_password_label": "Parolayı tekrar edin",
|
||||
"register_heading": "Hesabınızı Oluşturun",
|
||||
"return_home_button": "Ev ekranına geri dön",
|
||||
"room_auth_view_continue_button": "Devam et",
|
||||
"screenshare_button_label": "Ekran paylaş",
|
||||
"settings": {
|
||||
"audio_tab": {
|
||||
"effect_volume_description": "Tepkilerin ve el kaldırmaların çaldığı ses düzeyini ayarlayın.",
|
||||
"effect_volume_label": "Ses efekti sesi"
|
||||
},
|
||||
"developer_tab_title": "Geliştirici",
|
||||
"devices": {
|
||||
"camera": "Kamera",
|
||||
"camera_numbered": "Kamera {{n}}",
|
||||
"default": "Varsayılan",
|
||||
"default_named": "Varsayılan <2>({{name}})</2>",
|
||||
"microphone": "Mikrofon",
|
||||
"microphone_numbered": "Mikrofon {{n}}",
|
||||
"speaker": "Hoparlör",
|
||||
"speaker_numbered": "Hoparlör {{n}}"
|
||||
},
|
||||
"feedback_tab_body": "Sorun yaşıyorsanız veya yalnızca geri bildirimde bulunmak istiyorsanız, lütfen bize aşağıdan kısa bir açıklama gönderin.",
|
||||
"feedback_tab_description_label": "Görüşleriniz",
|
||||
"feedback_tab_h4": "Geri bildirim ver",
|
||||
"feedback_tab_send_logs_label": "Hata ayıklama kütüğünü dahil et"
|
||||
"feedback_tab_send_logs_label": "Hata ayıklama kütüğünü dahil et",
|
||||
"feedback_tab_thank_you": "Teşekkürler, geri bildiriminizi aldık!",
|
||||
"feedback_tab_title": "Geri Bildirim",
|
||||
"opt_in_description": "<0></0><1></1>Bu kutunun işaretini kaldırarak onayınızı geri çekebilirsiniz. Şu anda bir aramadaysanız, bu ayar aramanın sonunda geçerli olacaktır.",
|
||||
"preferences_tab": {
|
||||
"developer_mode_label": "Geliştirici modu",
|
||||
"developer_mode_label_description": "Geliştirici modunu etkinleştir ve geliştirici ayarları sekmesini göster.",
|
||||
"introduction": "Burada daha iyi bir deneyim için ek seçenekleri yapılandırabilirsiniz.",
|
||||
"reactions_play_sound_description": "Birisi aramada tepki gönderdiğinde ses efekti çal.",
|
||||
"reactions_play_sound_label": "Tepki seslerini çal",
|
||||
"reactions_show_description": "Biri tepki gönderdiğinde animasyon göster.",
|
||||
"reactions_show_label": "Tepkileri göster",
|
||||
"show_hand_raised_timer_description": "Bir katılımcı elini kaldırdığında bir zamanlayıcı göster",
|
||||
"show_hand_raised_timer_label": "El kaldırma süresini göster"
|
||||
}
|
||||
},
|
||||
"star_rating_input_label_one": "{{count}} yıldız",
|
||||
"star_rating_input_label_other": "{{count}} yıldız",
|
||||
"start_new_call": "Yeni arama başlat",
|
||||
"start_video_button_label": "Videoy paylaşımı Başlat",
|
||||
"stop_screenshare_button_label": "Ekran paylaşılıyor",
|
||||
"stop_video_button_label": "Video paylaşımını durdur",
|
||||
"submitting": "Gönderiliyor...",
|
||||
"switch_camera": "Kamerayı değiştir",
|
||||
"unauthenticated_view_body": "Kaydolmadınız mı? <2>Hesap açın</2>",
|
||||
"unauthenticated_view_login_button": "Hesabınıza girin"
|
||||
"unauthenticated_view_login_button": "Hesabınıza girin",
|
||||
"unmute_microphone_button_label": "Mikrofonun sesini aç",
|
||||
"version": "{{productName}} sürüm: {{version}}",
|
||||
"video_tile": {
|
||||
"always_show": "Her zaman göster",
|
||||
"camera_starting": "Video paylaşımı başlatılıyor...",
|
||||
"change_fit_contain": "Çerçeveye sığdır",
|
||||
"collapse": "Daralt",
|
||||
"expand": "Genişlet",
|
||||
"mute_for_me": "Benim için sessize al",
|
||||
"muted_for_me": "Benim için susturulanlar",
|
||||
"volume": "Ses",
|
||||
"waiting_for_media": "Ortam bekleniyor..."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,14 +5,21 @@
|
||||
"action": {
|
||||
"close": "Закрити",
|
||||
"copy_link": "Скопіювати посилання",
|
||||
"edit": "Редагувати",
|
||||
"go": "Далі",
|
||||
"invite": "Запросити",
|
||||
"lower_hand": "Опустити руку",
|
||||
"no": "Ні",
|
||||
"pick_reaction": "Виберіть реакцію",
|
||||
"raise_hand": "Підняти руку",
|
||||
"register": "Зареєструватися",
|
||||
"remove": "Вилучити",
|
||||
"show_less": "Показувати менше",
|
||||
"show_more": "Показати більше",
|
||||
"sign_in": "Увійти",
|
||||
"sign_out": "Вийти",
|
||||
"submit": "Надіслати"
|
||||
"submit": "Надіслати",
|
||||
"upload_file": "Завантажити файл"
|
||||
},
|
||||
"analytics_notice": "Користуючись дочасним доступом, ви даєте згоду на збір анонімних даних, які ми використовуємо для вдосконалення продукту. Ви можете знайти більше інформації про те, які дані ми відстежуємо в нашій <2>Політиці Приватності</2> і нашій <5>Політиці про куки</5>.",
|
||||
"app_selection_modal": {
|
||||
@@ -33,20 +40,68 @@
|
||||
},
|
||||
"call_name": "Назва виклику",
|
||||
"common": {
|
||||
"analytics": "Аналітика",
|
||||
"audio": "Звук",
|
||||
"avatar": "Аватар",
|
||||
"back": "Назад",
|
||||
"display_name": "Псевдонім",
|
||||
"encrypted": "Зашифровано",
|
||||
"home": "Домівка",
|
||||
"loading": "Завантаження…",
|
||||
"next": "Далі",
|
||||
"options": "Налаштування",
|
||||
"password": "Пароль",
|
||||
"preferences": "Уподобання",
|
||||
"profile": "Профіль",
|
||||
"reaction": "Реакція",
|
||||
"reactions": "Реакції",
|
||||
"settings": "Налаштування",
|
||||
"unencrypted": "Не зашифровано",
|
||||
"username": "Ім'я користувача",
|
||||
"video": "Відео"
|
||||
},
|
||||
"developer_mode": {
|
||||
"crypto_version": "Крипто-версія: {{version}}",
|
||||
"debug_tile_layout_label": "Налагоджування макету плиток",
|
||||
"device_id": "ID пристрою: {{id}}",
|
||||
"duplicate_tiles_label": "Кількість додаткових копій плиток на одного учасника",
|
||||
"environment_variables": "Змінні середовища",
|
||||
"hostname": "Ім'я хоста: {{hostname}}",
|
||||
"livekit_server_info": "Інформація про сервер LiveKit",
|
||||
"livekit_sfu": "LiveKit SFU: {{url}}",
|
||||
"matrix_id": "Matrix ID: {{id}}",
|
||||
"show_connection_stats": "Показувати статистику підключення",
|
||||
"show_non_member_tiles": "Показувати плитки для медіа, які не є учасниками",
|
||||
"url_params": "Параметри URL",
|
||||
"use_new_membership_manager": "Використовуйте нову реалізацію виклику MembershipManager"
|
||||
},
|
||||
"disconnected_banner": "Втрачено зв'язок з сервером.",
|
||||
"error": {
|
||||
"call_is_not_supported": "Виклик не підтримується",
|
||||
"call_not_found": "Виклик не знайдено",
|
||||
"call_not_found_description": "<0>Схоже, що це посилання не належить до жодного існуючого дзвінка. Перевірте, чи посилання правильне, або <1> створіть нове</1>. </0>",
|
||||
"connection_lost": "Зв'язок втрачено",
|
||||
"connection_lost_description": "Вас було відключено від дзвінка.",
|
||||
"e2ee_unsupported": "Несумісний браузер",
|
||||
"e2ee_unsupported_description": "Ваш веб-браузер не підтримує зашифровані дзвінки. Підтримувані браузери включають Chrome, Safari та Firefox 117+.",
|
||||
"generic": "Щось пішло не так",
|
||||
"generic_description": "Надсилання журналів налагодження допоможе нам відстежити проблему.",
|
||||
"insufficient_capacity": "Недостатньо обсягу",
|
||||
"insufficient_capacity_description": "Сервер досяг максимального обсягу, і ви на разі не можете приєднатися до виклику. Спробуйте пізніше або зверніться до адміністратора сервера, якщо проблема не зникне.",
|
||||
"matrix_rtc_focus_missing": "Сервер не налаштований щоб працювати з {{brand}}. Будь ласка, зв'яжіться з адміністратором сервера (Домен: {{domain}}, Код помилки: {{ errorCode }}).",
|
||||
"open_elsewhere": "Відкрито в іншій вкладці",
|
||||
"open_elsewhere_description": "{{brand}} було відкрито в іншій вкладці. Якщо це звучить неправильно, спробуйте перезавантажити сторінку.",
|
||||
"unexpected_ec_error": "Сталася несподівана помилка (<0>Код помилки: </0> <1> {{ errorCode }}</1>). Будь ласка, зв'яжіться з адміністратором сервера."
|
||||
},
|
||||
"group_call_loader": {
|
||||
"banned_body": "Вас було забанено в цій кімнаті.",
|
||||
"banned_heading": "Забанено",
|
||||
"call_ended_body": "Вас вилучено з виклику.",
|
||||
"call_ended_heading": "Виклик завершено",
|
||||
"knock_reject_body": "Ваш запит на приєднання було відхилено.",
|
||||
"knock_reject_heading": "Доступ заборонено",
|
||||
"reason": "Причина: {{reason}}"
|
||||
},
|
||||
"hangup_button_label": "Завершити виклик",
|
||||
"header_label": "Домівка Element Call",
|
||||
"header_participants_label": "Учасники",
|
||||
@@ -62,15 +117,25 @@
|
||||
"layout_grid_label": "Сітка",
|
||||
"layout_spotlight_label": "У центрі уваги",
|
||||
"lobby": {
|
||||
"ask_to_join": "Запит на приєднання до виклику",
|
||||
"join_as_guest": "Приєднатись як гість",
|
||||
"join_button": "Приєднатися до виклику",
|
||||
"leave_button": "Повернутися до недавніх"
|
||||
"leave_button": "Повернутися до недавніх",
|
||||
"waiting_for_invite": "Запит надіслано! Чекаємо дозволу на приєднання..."
|
||||
},
|
||||
"log_in": "Увійти",
|
||||
"logging_in": "Вхід…",
|
||||
"login_auth_links": "<0>Створити обліковий запис</0> або <2>Отримати доступ як гість</2>",
|
||||
"login_auth_links_prompt": "Ще не зареєстровані?",
|
||||
"login_subheading": "Продовжити в Element",
|
||||
"login_title": "Увійти",
|
||||
"microphone_off": "Мікрофон вимкнено",
|
||||
"microphone_on": "Мікрофон увімкнено",
|
||||
"mute_microphone_button_label": "Вимкнути мікрофон",
|
||||
"participant_count_one": "{{count, number}}",
|
||||
"participant_count_few": "{{count, number}}",
|
||||
"participant_count_many": "{{count, number}}",
|
||||
"qr_code": "QR-код",
|
||||
"rageshake_button_error_caption": "Повторити надсилання журналів",
|
||||
"rageshake_request_modal": {
|
||||
"body": "Інший користувач у цьому виклику має проблему. Щоб краще визначити ці проблеми, ми хотіли б зібрати журнал налагодження.",
|
||||
@@ -82,23 +147,52 @@
|
||||
"rageshake_sent": "Дякуємо!",
|
||||
"recaptcha_dismissed": "Recaptcha не пройдено",
|
||||
"recaptcha_not_loaded": "Recaptcha не завантажено",
|
||||
"recaptcha_ssla_caption": "Цей сайт захищений ReCAPTCHA та Google<2>Політикою конфіденційності</2> і <6>Умови обслуговування</6> застосовуються.<9></9> Натискаючи «Зареєструватися», ви погоджуєтеся з нашою<12> Ліцензійна угодою про програмне забезпечення та послуги (SSLA)</12>",
|
||||
"register": {
|
||||
"passwords_must_match": "Паролі відрізняються",
|
||||
"registering": "Реєстрація…"
|
||||
},
|
||||
"register_auth_links": "<0>Уже маєте обліковий запис?</0><1><0>Увійти</0> Or <2>Отримати доступ як гість</2></1>",
|
||||
"register_confirm_password_label": "Підтвердити пароль",
|
||||
"register_heading": "Створити свій акаунт",
|
||||
"return_home_button": "Повернутися на екран домівки",
|
||||
"room_auth_view_continue_button": "Продовжити",
|
||||
"room_auth_view_ssla_caption": "Натиснувши «Приєднатися до виклику зараз», ви погоджуєтеся з нашою <2>Ліцензійною угодою на програмне забезпечення та послуги (SSLA) </2>",
|
||||
"screenshare_button_label": "Поділитися екраном",
|
||||
"settings": {
|
||||
"audio_tab": {
|
||||
"effect_volume_description": "Змінити гучність реакцій і ефекту підіймання руки.",
|
||||
"effect_volume_label": "Гучність звукових ефектів"
|
||||
},
|
||||
"developer_tab_title": "Розробнику",
|
||||
"devices": {
|
||||
"camera": "Камера",
|
||||
"camera_numbered": "Камера {{n}}",
|
||||
"default": "За замовчуванням",
|
||||
"default_named": "За замовчуванням <2> ({{name}}) </2>",
|
||||
"microphone": "Мікрофон",
|
||||
"microphone_numbered": "Мікрофон {{n}}",
|
||||
"speaker": "Динамік",
|
||||
"speaker_numbered": "Динамік {{n}}"
|
||||
},
|
||||
"feedback_tab_body": "Якщо у вас виникли проблеми або ви просто хочете залишити відгук, надішліть нам короткий опис нижче.",
|
||||
"feedback_tab_description_label": "Ваш відгук",
|
||||
"feedback_tab_h4": "Надіслати відгук",
|
||||
"feedback_tab_send_logs_label": "Долучити журнали налагодження",
|
||||
"feedback_tab_thank_you": "Дякуємо, ми отримали ваш відгук!",
|
||||
"feedback_tab_title": "Відгук",
|
||||
"opt_in_description": "<0></0><1></1>Ви можете відкликати згоду, прибравши цей прапорець. Якщо ви зараз розмовляєте, це налаштування застосується після завершення виклику."
|
||||
"opt_in_description": "<0></0><1></1>Ви можете відкликати згоду, прибравши цей прапорець. Якщо ви зараз розмовляєте, це налаштування застосується після завершення виклику.",
|
||||
"preferences_tab": {
|
||||
"developer_mode_label": "Режим розробника",
|
||||
"developer_mode_label_description": "Увімкнути режим розробника та показати вкладку налаштувань розробника.",
|
||||
"introduction": "Тут ви можете налаштувати додаткові параметри для кращого досвіду.",
|
||||
"reactions_play_sound_description": "Відтворювати звуковий ефект, коли хтось надсилає реакцію у виклик.",
|
||||
"reactions_play_sound_label": "Відтворювати звуки реакції",
|
||||
"reactions_show_description": "Показувати анімацію, коли хтось надсилає реакцію.",
|
||||
"reactions_show_label": "Показувати реакції",
|
||||
"show_hand_raised_timer_description": "Показувати таймер, коли учасник піднімає руку",
|
||||
"show_hand_raised_timer_label": "Показувати тривалість підняття руки"
|
||||
}
|
||||
},
|
||||
"star_rating_input_label_one": "{{count}} зірок",
|
||||
"star_rating_input_label_other": "{{count}} зірок",
|
||||
@@ -107,8 +201,21 @@
|
||||
"stop_screenshare_button_label": "Презентація екрана",
|
||||
"stop_video_button_label": "Зупинити відео",
|
||||
"submitting": "Надсилання…",
|
||||
"switch_camera": "Переключити камеру",
|
||||
"unauthenticated_view_body": "Ще не зареєстровані? <2>Створіть обліковий запис</2>",
|
||||
"unauthenticated_view_login_button": "Увійдіть до свого облікового запису",
|
||||
"unauthenticated_view_ssla_caption": "Натискаючи \"Перейти\", ви погоджуєтеся з нашою <2>Ліцензійною угодою на програмне забезпечення та послуги (SSLA) </2>",
|
||||
"unmute_microphone_button_label": "Увімкнути мікрофон",
|
||||
"version": "Версія: {{version}}"
|
||||
"version": "Версія: {{version}}",
|
||||
"video_tile": {
|
||||
"always_show": "Показувати завжди",
|
||||
"camera_starting": "Завантаження відео...",
|
||||
"change_fit_contain": "Допасувати до рамки",
|
||||
"collapse": "Згорнути",
|
||||
"expand": "Розгорнути",
|
||||
"mute_for_me": "Вимкнути звук для мене",
|
||||
"muted_for_me": "Вимкнено звук для мене",
|
||||
"volume": "Гучність",
|
||||
"waiting_for_media": "Очікування медіа..."
|
||||
}
|
||||
}
|
||||
|
||||
17
package.json
17
package.json
@@ -40,6 +40,8 @@
|
||||
"@livekit/components-core": "^0.12.0",
|
||||
"@livekit/components-react": "^2.0.0",
|
||||
"@livekit/protocol": "^1.33.0",
|
||||
"@livekit/track-processors": "^0.5.5",
|
||||
"@mediapipe/tasks-vision": "^0.10.18",
|
||||
"@opentelemetry/api": "^1.4.0",
|
||||
"@opentelemetry/core": "^1.25.1",
|
||||
"@opentelemetry/exporter-trace-otlp-http": "^0.57.0",
|
||||
@@ -47,7 +49,7 @@
|
||||
"@opentelemetry/sdk-trace-base": "^1.25.1",
|
||||
"@opentelemetry/sdk-trace-web": "^1.9.1",
|
||||
"@opentelemetry/semantic-conventions": "^1.25.1",
|
||||
"@playwright/test": "^1.51.0",
|
||||
"@playwright/test": "^1.52.0",
|
||||
"@radix-ui/react-dialog": "^1.0.4",
|
||||
"@radix-ui/react-slider": "^1.1.2",
|
||||
"@radix-ui/react-visually-hidden": "^1.0.3",
|
||||
@@ -60,6 +62,7 @@
|
||||
"@testing-library/react": "^16.0.0",
|
||||
"@testing-library/user-event": "^14.5.1",
|
||||
"@types/content-type": "^1.1.5",
|
||||
"@types/dom-mediacapture-transform": "^0.1.11",
|
||||
"@types/grecaptcha": "^3.0.9",
|
||||
"@types/jsdom": "^21.1.7",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
@@ -70,12 +73,11 @@
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@types/sdp-transform": "^2.4.5",
|
||||
"@types/uuid": "10",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.31.0",
|
||||
"@typescript-eslint/parser": "^8.31.0",
|
||||
"@use-gesture/react": "^10.2.11",
|
||||
"@vector-im/compound-design-tokens": "^3.0.0",
|
||||
"@vector-im/compound-web": "^7.2.0",
|
||||
"@vitejs/plugin-basic-ssl": "^1.0.1",
|
||||
"@vitejs/plugin-react": "^4.0.1",
|
||||
"@vitest/coverage-v8": "^3.0.0",
|
||||
"babel-plugin-transform-vite-meta-env": "^1.0.3",
|
||||
@@ -97,10 +99,10 @@
|
||||
"i18next-parser": "^9.1.0",
|
||||
"jsdom": "^26.0.0",
|
||||
"knip": "^5.27.2",
|
||||
"livekit-client": "2.9.1",
|
||||
"livekit-client": "^2.11.3",
|
||||
"lodash-es": "^4.17.21",
|
||||
"loglevel": "^1.9.1",
|
||||
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#8395919f0fd1af7cab1e793d736f2cdf18ef7686",
|
||||
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#19b1b901f575755d29d1fe03ca48cbf7c1cae05c",
|
||||
"matrix-widget-api": "1.11.0",
|
||||
"normalize.css": "^8.0.1",
|
||||
"observable-hooks": "^4.2.3",
|
||||
@@ -118,7 +120,7 @@
|
||||
"react-use-measure": "^2.1.1",
|
||||
"rxjs": "^7.8.1",
|
||||
"sass": "^1.42.1",
|
||||
"typescript": "^5.1.6",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint-language-service": "^5.0.5",
|
||||
"unique-names-generator": "^4.6.0",
|
||||
"vaul": "^1.0.0",
|
||||
@@ -131,6 +133,7 @@
|
||||
},
|
||||
"resolutions": {
|
||||
"@livekit/components-core/rxjs": "^7.8.1",
|
||||
"@livekit/track-processors/@mediapipe/tasks-vision": "^0.10.18",
|
||||
"matrix-widget-api": "1.11.0"
|
||||
},
|
||||
"packageManager": "yarn@4.7.0"
|
||||
|
||||
4
playwright-backend-docker-compose.override.yml
Normal file
4
playwright-backend-docker-compose.override.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
services:
|
||||
synapse:
|
||||
volumes:
|
||||
- ./backend/playwright_homeserver.yaml:/data/cfg/homeserver.yaml:Z
|
||||
@@ -1,97 +1,2 @@
|
||||
networks:
|
||||
ecbackend:
|
||||
|
||||
services:
|
||||
auth-service:
|
||||
image: ghcr.io/element-hq/lk-jwt-service:latest-ci
|
||||
hostname: auth-server
|
||||
environment:
|
||||
- LK_JWT_PORT=8080
|
||||
- LIVEKIT_URL=ws://localhost:7880
|
||||
- LIVEKIT_KEY=devkey
|
||||
- LIVEKIT_SECRET=secret
|
||||
# If the configured homeserver runs on localhost, it'll probably be using
|
||||
# a self-signed certificate
|
||||
- LIVEKIT_INSECURE_SKIP_VERIFY_TLS=YES_I_KNOW_WHAT_I_AM_DOING
|
||||
deploy:
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
ports:
|
||||
# HOST_PORT:CONTAINER_PORT
|
||||
- 8009:8080
|
||||
networks:
|
||||
- ecbackend
|
||||
|
||||
livekit:
|
||||
image: livekit/livekit-server:latest
|
||||
command: --dev --config /etc/livekit.yaml
|
||||
restart: unless-stopped
|
||||
# The SFU seems to work far more reliably when we let it share the host
|
||||
# network rather than opening specific ports (but why?? we're not missing
|
||||
# any…)
|
||||
ports:
|
||||
# HOST_PORT:CONTAINER_PORT
|
||||
- 7880:7880/tcp
|
||||
- 7881:7881/tcp
|
||||
- 7882:7882/tcp
|
||||
- 50100-50200:50100-50200/udp
|
||||
volumes:
|
||||
- ./backend/dev_livekit.yaml:/etc/livekit.yaml:Z
|
||||
networks:
|
||||
- ecbackend
|
||||
|
||||
redis:
|
||||
image: redis:6-alpine
|
||||
command: redis-server /etc/redis.conf
|
||||
ports:
|
||||
# HOST_PORT:CONTAINER_PORT
|
||||
- 6379:6379
|
||||
volumes:
|
||||
- ./backend/redis.conf:/etc/redis.conf:Z
|
||||
networks:
|
||||
- ecbackend
|
||||
|
||||
element-web:
|
||||
image: ghcr.io/element-hq/element-web:develop
|
||||
volumes:
|
||||
- ./backend/ew.test.config.json:/app/config.json
|
||||
environment:
|
||||
ELEMENT_WEB_PORT: 81
|
||||
ports:
|
||||
- "8081:81"
|
||||
networks:
|
||||
- ecbackend
|
||||
|
||||
synapse:
|
||||
hostname: homeserver
|
||||
image: docker.io/matrixdotorg/synapse:latest
|
||||
environment:
|
||||
- SYNAPSE_CONFIG_PATH=/data/cfg/homeserver.yaml
|
||||
# Needed for rootless podman-compose such that the uid/gid mapping does
|
||||
# fit local user uid. If the container runs as root (uid 0) it is fine as
|
||||
# it actually maps to your non-root user on the host (e.g. 1000).
|
||||
# Otherwise uid mapping will not match your non-root user.
|
||||
- UID=0
|
||||
- GID=0
|
||||
volumes:
|
||||
- ./backend/synapse_tmp:/data:Z
|
||||
- ./backend/playwright_homeserver.yaml:/data/cfg/homeserver.yaml:Z
|
||||
networks:
|
||||
- ecbackend
|
||||
|
||||
nginx:
|
||||
# openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout tls_localhost_key.pem -out tls_localhost_cert.pem -subj "/C=GB/ST=London/L=London/O=Alros/OU=IT Department/CN=localhost"
|
||||
hostname: synapse.localhost
|
||||
image: nginx:latest
|
||||
volumes:
|
||||
- ./backend/tls_localhost_nginx.conf:/etc/nginx/conf.d/default.conf:Z
|
||||
- ./backend/tls_localhost_key.pem:/root/ssl/key.pem:Z
|
||||
- ./backend/tls_localhost_cert.pem:/root/ssl/cert.pem:Z
|
||||
ports:
|
||||
# HOST_PORT:CONTAINER_PORT
|
||||
- "8008:80"
|
||||
- "4443:443"
|
||||
depends_on:
|
||||
- synapse
|
||||
networks:
|
||||
- ecbackend
|
||||
include:
|
||||
- dev-backend-docker-compose.yml
|
||||
|
||||
@@ -154,8 +154,13 @@ export const widgetTest = test.extend<MyFixtures>({
|
||||
ewPage1.getByRole("heading", { name: "Invite to Welcome Room" }),
|
||||
).toBeVisible();
|
||||
|
||||
await ewPage1.getByRole("textbox").fill(whistlerMxId);
|
||||
await ewPage1.getByRole("textbox").click();
|
||||
// To get the invite textbox we need to specifically select within the
|
||||
// dialog, since there is another textbox in the background (the message
|
||||
// composer). In theory the composer shouldn't be visible to Playwright at
|
||||
// all because the invite dialog has trapped focus, but the focus trap
|
||||
// doesn't quite work right on Firefox.
|
||||
await ewPage1.getByRole("dialog").getByRole("textbox").fill(whistlerMxId);
|
||||
await ewPage1.getByRole("dialog").getByRole("textbox").click();
|
||||
await ewPage1.getByRole("button", { name: "Invite" }).click();
|
||||
|
||||
// Accept the invite
|
||||
|
||||
@@ -48,6 +48,14 @@
|
||||
"groupName": "Vaul",
|
||||
"matchDepNames": ["vaul"],
|
||||
"prHeader": "Please review modals on mobile for visual regressions."
|
||||
},
|
||||
{
|
||||
"groupName": "embedded package dependencies",
|
||||
"matchFileNames": ["embedded/**/*"]
|
||||
},
|
||||
{
|
||||
"groupName": "Yarn",
|
||||
"matchDepNames": ["yarn"]
|
||||
}
|
||||
],
|
||||
"semanticCommits": "disabled",
|
||||
|
||||
35
src/App.tsx
35
src/App.tsx
@@ -22,6 +22,7 @@ import { Initializer } from "./initializer";
|
||||
import { MediaDevicesProvider } from "./livekit/MediaDevicesContext";
|
||||
import { widget } from "./widget";
|
||||
import { useTheme } from "./useTheme";
|
||||
import { ProcessorProvider } from "./livekit/TrackProcessorContext";
|
||||
|
||||
const SentryRoute = Sentry.withSentryReactRouterV7Routing(Route);
|
||||
|
||||
@@ -72,22 +73,24 @@ export const App: FC = () => {
|
||||
<Suspense fallback={null}>
|
||||
<ClientProvider>
|
||||
<MediaDevicesProvider>
|
||||
<Sentry.ErrorBoundary
|
||||
fallback={(error) => (
|
||||
<ErrorPage error={error} widget={widget} />
|
||||
)}
|
||||
>
|
||||
<DisconnectedBanner />
|
||||
<Routes>
|
||||
<SentryRoute path="/" element={<HomePage />} />
|
||||
<SentryRoute path="/login" element={<LoginPage />} />
|
||||
<SentryRoute
|
||||
path="/register"
|
||||
element={<RegisterPage />}
|
||||
/>
|
||||
<SentryRoute path="*" element={<RoomPage />} />
|
||||
</Routes>
|
||||
</Sentry.ErrorBoundary>
|
||||
<ProcessorProvider>
|
||||
<Sentry.ErrorBoundary
|
||||
fallback={(error) => (
|
||||
<ErrorPage error={error} widget={widget} />
|
||||
)}
|
||||
>
|
||||
<DisconnectedBanner />
|
||||
<Routes>
|
||||
<SentryRoute path="/" element={<HomePage />} />
|
||||
<SentryRoute path="/login" element={<LoginPage />} />
|
||||
<SentryRoute
|
||||
path="/register"
|
||||
element={<RegisterPage />}
|
||||
/>
|
||||
<SentryRoute path="*" element={<RoomPage />} />
|
||||
</Routes>
|
||||
</Sentry.ErrorBoundary>
|
||||
</ProcessorProvider>
|
||||
</MediaDevicesProvider>
|
||||
</ClientProvider>
|
||||
</Suspense>
|
||||
|
||||
@@ -16,7 +16,7 @@ export class MatrixKeyProvider extends BaseKeyProvider {
|
||||
private rtcSession?: MatrixRTCSession;
|
||||
|
||||
public constructor() {
|
||||
super({ ratchetWindowSize: 0, keyringSize: 256 });
|
||||
super({ ratchetWindowSize: 10, keyringSize: 256 });
|
||||
}
|
||||
|
||||
public setRTCSession(rtcSession: MatrixRTCSession): void {
|
||||
|
||||
@@ -136,6 +136,11 @@ export class Initializer {
|
||||
lookup: () => getUrlParams().lang ?? undefined,
|
||||
});
|
||||
|
||||
// Synchronise the HTML lang attribute with the i18next language
|
||||
i18n.on("languageChanged", (lng) => {
|
||||
document.documentElement.lang = lng;
|
||||
});
|
||||
|
||||
await i18n
|
||||
.use(Backend)
|
||||
.use(languageDetector)
|
||||
|
||||
80
src/livekit/BlurBackgroundTransformer.ts
Normal file
80
src/livekit/BlurBackgroundTransformer.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
Copyright 2024-2025 New Vector Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
import {
|
||||
BackgroundTransformer,
|
||||
VideoTransformer,
|
||||
type VideoTransformerInitOptions,
|
||||
} from "@livekit/track-processors";
|
||||
import { ImageSegmenter } from "@mediapipe/tasks-vision";
|
||||
|
||||
import modelAssetPath from "../mediapipe/imageSegmenter/selfie_segmenter.tflite?url";
|
||||
|
||||
interface WasmFileset {
|
||||
/** The path to the Wasm loader script. */
|
||||
wasmLoaderPath: string;
|
||||
/** The path to the Wasm binary. */
|
||||
wasmBinaryPath: string;
|
||||
}
|
||||
|
||||
// The MediaPipe package, by default, ships some alternative versions of the
|
||||
// WASM files which avoid SIMD for compatibility with older browsers. But SIMD
|
||||
// in WASM is actually fine by our support policy, so we include just the SIMD
|
||||
// versions.
|
||||
// It's really not ideal that we have to reference these internal files from
|
||||
// MediaPipe and depend on node_modules having this specific structure. It's
|
||||
// easy to see this breaking if our dependencies changed and MediaPipe were
|
||||
// no longer hoisted, or if we switched to another dependency loader such as
|
||||
// Yarn PnP.
|
||||
// https://github.com/google-ai-edge/mediapipe/issues/5961
|
||||
const wasmFileset: WasmFileset = {
|
||||
wasmLoaderPath: new URL(
|
||||
"../../node_modules/@mediapipe/tasks-vision/wasm/vision_wasm_internal.js",
|
||||
import.meta.url,
|
||||
).href,
|
||||
wasmBinaryPath: new URL(
|
||||
"../../node_modules/@mediapipe/tasks-vision/wasm/vision_wasm_internal.wasm",
|
||||
import.meta.url,
|
||||
).href,
|
||||
};
|
||||
|
||||
/**
|
||||
* Track processor that applies effects such as blurring to a user's background.
|
||||
*
|
||||
* This is just like LiveKit's prebuilt BackgroundTransformer except that it
|
||||
* loads the segmentation models from our own bundle rather than as an external
|
||||
* resource fetched from the public internet.
|
||||
*/
|
||||
export class BlurBackgroundTransformer extends BackgroundTransformer {
|
||||
public async init({
|
||||
outputCanvas,
|
||||
inputElement: inputVideo,
|
||||
}: VideoTransformerInitOptions): Promise<void> {
|
||||
// Call super.super.init() since we're totally replacing the init method of
|
||||
// BackgroundTransformer here, rather than extending it
|
||||
await VideoTransformer.prototype.init.call(this, {
|
||||
outputCanvas,
|
||||
inputElement: inputVideo,
|
||||
});
|
||||
|
||||
this.imageSegmenter = await ImageSegmenter.createFromOptions(wasmFileset, {
|
||||
baseOptions: {
|
||||
modelAssetPath,
|
||||
delegate: "GPU",
|
||||
...this.options.segmenterOptions,
|
||||
},
|
||||
canvas: this.canvas,
|
||||
runningMode: "VIDEO",
|
||||
outputCategoryMask: true,
|
||||
outputConfidenceMasks: false,
|
||||
});
|
||||
|
||||
if (this.options.blurRadius) {
|
||||
this.gl?.setBlurRadius(this.options.blurRadius);
|
||||
}
|
||||
}
|
||||
}
|
||||
84
src/livekit/TrackProcessorContext.tsx
Normal file
84
src/livekit/TrackProcessorContext.tsx
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
import {
|
||||
ProcessorWrapper,
|
||||
supportsBackgroundProcessors,
|
||||
type BackgroundOptions,
|
||||
} from "@livekit/track-processors";
|
||||
import { createContext, type FC, useContext, useEffect, useMemo } from "react";
|
||||
import { type LocalVideoTrack } from "livekit-client";
|
||||
|
||||
import {
|
||||
backgroundBlur as backgroundBlurSettings,
|
||||
useSetting,
|
||||
} from "../settings/settings";
|
||||
import { BlurBackgroundTransformer } from "./BlurBackgroundTransformer";
|
||||
|
||||
type ProcessorState = {
|
||||
supported: boolean | undefined;
|
||||
processor: undefined | ProcessorWrapper<BackgroundOptions>;
|
||||
};
|
||||
|
||||
const ProcessorContext = createContext<ProcessorState | undefined>(undefined);
|
||||
|
||||
export function useTrackProcessor(): ProcessorState {
|
||||
const state = useContext(ProcessorContext);
|
||||
if (state === undefined)
|
||||
throw new Error(
|
||||
"useTrackProcessor must be used within a ProcessorProvider",
|
||||
);
|
||||
return state;
|
||||
}
|
||||
|
||||
export const useTrackProcessorSync = (
|
||||
videoTrack: LocalVideoTrack | null,
|
||||
): void => {
|
||||
const { processor } = useTrackProcessor();
|
||||
useEffect(() => {
|
||||
if (!videoTrack) return;
|
||||
if (processor && !videoTrack.getProcessor()) {
|
||||
void videoTrack.setProcessor(processor);
|
||||
}
|
||||
if (!processor && videoTrack.getProcessor()) {
|
||||
void videoTrack.stopProcessor();
|
||||
}
|
||||
}, [processor, videoTrack]);
|
||||
};
|
||||
|
||||
interface Props {
|
||||
children: JSX.Element;
|
||||
}
|
||||
|
||||
export const ProcessorProvider: FC<Props> = ({ children }) => {
|
||||
// The setting the user wants to have
|
||||
const [blurActivated] = useSetting(backgroundBlurSettings);
|
||||
const supported = useMemo(() => supportsBackgroundProcessors(), []);
|
||||
const blur = useMemo(
|
||||
() =>
|
||||
new ProcessorWrapper(
|
||||
new BlurBackgroundTransformer({ blurRadius: 15 }),
|
||||
"background-blur",
|
||||
),
|
||||
[],
|
||||
);
|
||||
|
||||
// This is the actual state exposed through the context
|
||||
const processorState = useMemo(
|
||||
() => ({
|
||||
supported,
|
||||
processor: supported && blurActivated ? blur : undefined,
|
||||
}),
|
||||
[supported, blurActivated, blur],
|
||||
);
|
||||
|
||||
return (
|
||||
<ProcessorContext.Provider value={processorState}>
|
||||
{children}
|
||||
</ProcessorContext.Provider>
|
||||
);
|
||||
};
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
ConnectionState,
|
||||
type E2EEManagerOptions,
|
||||
ExternalE2EEKeyProvider,
|
||||
LocalVideoTrack,
|
||||
Room,
|
||||
type RoomOptions,
|
||||
Track,
|
||||
@@ -17,6 +18,8 @@ import { useEffect, useMemo, useRef } from "react";
|
||||
import E2EEWorker from "livekit-client/e2ee-worker?worker";
|
||||
import { logger } from "matrix-js-sdk/lib/logger";
|
||||
import { type MatrixRTCSession } from "matrix-js-sdk/lib/matrixrtc";
|
||||
import { useObservable, useObservableEagerState } from "observable-hooks";
|
||||
import { map } from "rxjs";
|
||||
|
||||
import { defaultLiveKitOptions } from "./options";
|
||||
import { type SFUConfig } from "./openIDSFU";
|
||||
@@ -33,6 +36,12 @@ import {
|
||||
import { MatrixKeyProvider } from "../e2ee/matrixKeyProvider";
|
||||
import { E2eeType } from "../e2ee/e2eeType";
|
||||
import { type EncryptionSystem } from "../e2ee/sharedKeyManagement";
|
||||
import {
|
||||
useTrackProcessor,
|
||||
useTrackProcessorSync,
|
||||
} from "./TrackProcessorContext";
|
||||
import { useInitial } from "../useInitial";
|
||||
import { observeTrackReference$ } from "../state/MediaViewModel";
|
||||
|
||||
interface UseLivekitResult {
|
||||
livekitRoom?: Room;
|
||||
@@ -49,11 +58,14 @@ export function useLiveKit(
|
||||
if (e2eeSystem.kind === E2eeType.NONE) return undefined;
|
||||
|
||||
if (e2eeSystem.kind === E2eeType.PER_PARTICIPANT) {
|
||||
logger.info("Created MatrixKeyProvider (per participant)");
|
||||
return {
|
||||
keyProvider: new MatrixKeyProvider(),
|
||||
worker: new E2EEWorker(),
|
||||
};
|
||||
} else if (e2eeSystem.kind === E2eeType.SHARED_KEY && e2eeSystem.secret) {
|
||||
logger.info("Created ExternalE2EEKeyProvider (shared key)");
|
||||
|
||||
return {
|
||||
keyProvider: new ExternalE2EEKeyProvider(),
|
||||
worker: new E2EEWorker(),
|
||||
@@ -79,12 +91,15 @@ export function useLiveKit(
|
||||
const devices = useMediaDevices();
|
||||
const initialDevices = useRef<MediaDevices>(devices);
|
||||
|
||||
const { processor } = useTrackProcessor();
|
||||
const initialProcessor = useInitial(() => processor);
|
||||
const roomOptions = useMemo(
|
||||
(): RoomOptions => ({
|
||||
...defaultLiveKitOptions,
|
||||
videoCaptureDefaults: {
|
||||
...defaultLiveKitOptions.videoCaptureDefaults,
|
||||
deviceId: initialDevices.current.videoInput.selectedId,
|
||||
processor: initialProcessor,
|
||||
},
|
||||
audioCaptureDefaults: {
|
||||
...defaultLiveKitOptions.audioCaptureDefaults,
|
||||
@@ -95,7 +110,7 @@ export function useLiveKit(
|
||||
},
|
||||
e2ee: e2eeOptions,
|
||||
}),
|
||||
[e2eeOptions],
|
||||
[e2eeOptions, initialProcessor],
|
||||
);
|
||||
|
||||
// Store if audio/video are currently updating. If to prohibit unnecessary calls
|
||||
@@ -120,6 +135,25 @@ export function useLiveKit(
|
||||
return r;
|
||||
}, [roomOptions, e2eeSystem]);
|
||||
|
||||
// Sync the requested track processors with LiveKit
|
||||
useTrackProcessorSync(
|
||||
useObservableEagerState(
|
||||
useObservable(
|
||||
(room$) =>
|
||||
observeTrackReference$(
|
||||
room$.pipe(map(([room]) => room.localParticipant)),
|
||||
Track.Source.Camera,
|
||||
).pipe(
|
||||
map((trackRef) => {
|
||||
const track = trackRef?.publication?.track;
|
||||
return track instanceof LocalVideoTrack ? track : null;
|
||||
}),
|
||||
),
|
||||
[room],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
const connectionState = useECConnectionState(
|
||||
{
|
||||
deviceId: initialDevices.current.audioInput.selectedId,
|
||||
@@ -195,6 +229,7 @@ export function useLiveKit(
|
||||
audioMuteUpdating.current = true;
|
||||
trackPublication = await participant.setMicrophoneEnabled(
|
||||
buttonEnabled.current.audio,
|
||||
room.options.audioCaptureDefaults,
|
||||
);
|
||||
audioMuteUpdating.current = false;
|
||||
break;
|
||||
@@ -202,6 +237,7 @@ export function useLiveKit(
|
||||
videoMuteUpdating.current = true;
|
||||
trackPublication = await participant.setCameraEnabled(
|
||||
buttonEnabled.current.video,
|
||||
room.options.videoCaptureDefaults,
|
||||
);
|
||||
videoMuteUpdating.current = false;
|
||||
break;
|
||||
|
||||
5
src/mediapipe/imageSegmenter/README.md
Normal file
5
src/mediapipe/imageSegmenter/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Google AI Edge MediaPipe Selfie Segmentation
|
||||
|
||||
- See: https://ai.google.dev/edge/mediapipe/solutions/vision/image_segmenter
|
||||
- Latest: https://storage.googleapis.com/mediapipe-models/image_segmenter/selfie_segmenter/float16/latest/selfie_segmenter.tflite
|
||||
- License: Apache 2.0 as per https://storage.googleapis.com/mediapipe-assets/Model%20Card%20MediaPipe%20Selfie%20Segmentation.pdf
|
||||
BIN
src/mediapipe/imageSegmenter/selfie_segmenter.tflite
Normal file
BIN
src/mediapipe/imageSegmenter/selfie_segmenter.tflite
Normal file
Binary file not shown.
@@ -38,6 +38,7 @@ import { GroupCallView } from "./GroupCallView";
|
||||
import { type WidgetHelpers } from "../widget";
|
||||
import { LazyEventEmitter } from "../LazyEventEmitter";
|
||||
import { MatrixRTCFocusMissingError } from "../utils/errors";
|
||||
import { ProcessorProvider } from "../livekit/TrackProcessorContext";
|
||||
|
||||
vi.mock("../soundUtils");
|
||||
vi.mock("../useAudioContext");
|
||||
@@ -46,6 +47,13 @@ vi.mock("react-use-measure", () => ({
|
||||
default: (): [() => void, object] => [(): void => {}, {}],
|
||||
}));
|
||||
|
||||
vi.hoisted(
|
||||
() =>
|
||||
(global.ImageData = class MockImageData {
|
||||
public data: number[] = [];
|
||||
} as unknown as typeof ImageData),
|
||||
);
|
||||
|
||||
const enterRTCSession = vi.hoisted(() => vi.fn(async () => Promise.resolve()));
|
||||
const leaveRTCSession = vi.hoisted(() =>
|
||||
vi.fn(
|
||||
@@ -137,18 +145,20 @@ function createGroupCallView(
|
||||
const { getByText } = render(
|
||||
<BrowserRouter>
|
||||
<TooltipProvider>
|
||||
<GroupCallView
|
||||
client={client}
|
||||
isPasswordlessUser={false}
|
||||
confineToRoom={false}
|
||||
preload={false}
|
||||
skipLobby={false}
|
||||
hideHeader={true}
|
||||
rtcSession={rtcSession as unknown as MatrixRTCSession}
|
||||
isJoined={joined}
|
||||
muteStates={muteState}
|
||||
widget={widget}
|
||||
/>
|
||||
<ProcessorProvider>
|
||||
<GroupCallView
|
||||
client={client}
|
||||
isPasswordlessUser={false}
|
||||
confineToRoom={false}
|
||||
preload={false}
|
||||
skipLobby={false}
|
||||
hideHeader={true}
|
||||
rtcSession={rtcSession as unknown as MatrixRTCSession}
|
||||
isJoined={joined}
|
||||
muteStates={muteState}
|
||||
widget={widget}
|
||||
/>
|
||||
</ProcessorProvider>
|
||||
</TooltipProvider>
|
||||
</BrowserRouter>,
|
||||
);
|
||||
|
||||
@@ -62,6 +62,7 @@ import {
|
||||
} from "../utils/errors.ts";
|
||||
import { GroupCallErrorBoundary } from "./GroupCallErrorBoundary.tsx";
|
||||
import {
|
||||
useExperimentalToDeviceTransportSetting,
|
||||
useNewMembershipManagerSetting as useNewMembershipManagerSetting,
|
||||
useSetting,
|
||||
} from "../settings/settings";
|
||||
@@ -151,6 +152,9 @@ export const GroupCallView: FC<Props> = ({
|
||||
const { perParticipantE2EE, returnToLobby } = useUrlParams();
|
||||
const e2eeSystem = useRoomEncryptionSystem(room.roomId);
|
||||
const [useNewMembershipManager] = useSetting(useNewMembershipManagerSetting);
|
||||
const [useExperimentalToDeviceTransport] = useSetting(
|
||||
useExperimentalToDeviceTransportSetting,
|
||||
);
|
||||
|
||||
usePageTitle(roomName);
|
||||
|
||||
@@ -178,16 +182,13 @@ export const GroupCallView: FC<Props> = ({
|
||||
const latestMuteStates = useLatest(muteStates);
|
||||
|
||||
const enterRTCSessionOrError = useCallback(
|
||||
async (
|
||||
rtcSession: MatrixRTCSession,
|
||||
perParticipantE2EE: boolean,
|
||||
newMembershipManager: boolean,
|
||||
): Promise<void> => {
|
||||
async (rtcSession: MatrixRTCSession): Promise<void> => {
|
||||
try {
|
||||
await enterRTCSession(
|
||||
rtcSession,
|
||||
perParticipantE2EE,
|
||||
newMembershipManager,
|
||||
useNewMembershipManager,
|
||||
useExperimentalToDeviceTransport,
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof ElementCallError) {
|
||||
@@ -201,7 +202,11 @@ export const GroupCallView: FC<Props> = ({
|
||||
}
|
||||
}
|
||||
},
|
||||
[setExternalError],
|
||||
[
|
||||
perParticipantE2EE,
|
||||
useExperimentalToDeviceTransport,
|
||||
useNewMembershipManager,
|
||||
],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -253,11 +258,7 @@ export const GroupCallView: FC<Props> = ({
|
||||
await defaultDeviceSetup(
|
||||
ev.detail.data as unknown as JoinCallData,
|
||||
);
|
||||
await enterRTCSessionOrError(
|
||||
rtcSession,
|
||||
perParticipantE2EE,
|
||||
useNewMembershipManager,
|
||||
);
|
||||
await enterRTCSessionOrError(rtcSession);
|
||||
widget.api.transport.reply(ev.detail, {});
|
||||
})().catch((e) => {
|
||||
logger.error("Error joining RTC session", e);
|
||||
@@ -270,21 +271,13 @@ export const GroupCallView: FC<Props> = ({
|
||||
} else {
|
||||
// No lobby and no preload: we enter the rtc session right away
|
||||
(async (): Promise<void> => {
|
||||
await enterRTCSessionOrError(
|
||||
rtcSession,
|
||||
perParticipantE2EE,
|
||||
useNewMembershipManager,
|
||||
);
|
||||
await enterRTCSessionOrError(rtcSession);
|
||||
})().catch((e) => {
|
||||
logger.error("Error joining RTC session", e);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
void enterRTCSessionOrError(
|
||||
rtcSession,
|
||||
perParticipantE2EE,
|
||||
useNewMembershipManager,
|
||||
);
|
||||
void enterRTCSessionOrError(rtcSession);
|
||||
}
|
||||
}
|
||||
}, [
|
||||
@@ -407,13 +400,7 @@ export const GroupCallView: FC<Props> = ({
|
||||
client={client}
|
||||
matrixInfo={matrixInfo}
|
||||
muteStates={muteStates}
|
||||
onEnter={() =>
|
||||
void enterRTCSessionOrError(
|
||||
rtcSession,
|
||||
perParticipantE2EE,
|
||||
useNewMembershipManager,
|
||||
)
|
||||
}
|
||||
onEnter={() => void enterRTCSessionOrError(rtcSession)}
|
||||
confineToRoom={confineToRoom}
|
||||
hideHeader={hideHeader}
|
||||
participantCount={participantCount}
|
||||
@@ -491,11 +478,7 @@ export const GroupCallView: FC<Props> = ({
|
||||
recoveryActionHandler={(action) => {
|
||||
if (action == "reconnect") {
|
||||
setLeft(false);
|
||||
enterRTCSessionOrError(
|
||||
rtcSession,
|
||||
perParticipantE2EE,
|
||||
useNewMembershipManager,
|
||||
).catch((e) => {
|
||||
enterRTCSessionOrError(rtcSession).catch((e) => {
|
||||
logger.error("Error re-entering RTC session", e);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
RoomContext,
|
||||
useLocalParticipant,
|
||||
} from "@livekit/components-react";
|
||||
import { Text } from "@vector-im/compound-web";
|
||||
import { ConnectionState, type Room } from "livekit-client";
|
||||
import { type MatrixClient } from "matrix-js-sdk";
|
||||
import {
|
||||
@@ -31,6 +32,7 @@ import classNames from "classnames";
|
||||
import { BehaviorSubject, map } from "rxjs";
|
||||
import { useObservable, useObservableEagerState } from "observable-hooks";
|
||||
import { logger } from "matrix-js-sdk/lib/logger";
|
||||
import { RoomAndToDeviceEvents } from "matrix-js-sdk/lib/matrixrtc/RoomAndToDeviceKeyTransport";
|
||||
|
||||
import LogoMark from "../icons/LogoMark.svg?react";
|
||||
import LogoType from "../icons/LogoType.svg?react";
|
||||
@@ -94,10 +96,12 @@ import { ReactionsOverlay } from "./ReactionsOverlay";
|
||||
import { CallEventAudioRenderer } from "./CallEventAudioRenderer";
|
||||
import {
|
||||
debugTileLayout as debugTileLayoutSetting,
|
||||
useExperimentalToDeviceTransportSetting,
|
||||
useSetting,
|
||||
} from "../settings/settings";
|
||||
import { ReactionsReader } from "../reactions/ReactionsReader";
|
||||
import { ConnectionLostError } from "../utils/errors.ts";
|
||||
import { useTypedEventEmitter } from "../useEvents.ts";
|
||||
|
||||
const canScreenshare = "getDisplayMedia" in (navigator.mediaDevices ?? {});
|
||||
|
||||
@@ -216,6 +220,21 @@ export const InCallView: FC<InCallViewProps> = ({
|
||||
room: livekitRoom,
|
||||
});
|
||||
|
||||
const [toDeviceEncryptionSetting] = useSetting(
|
||||
useExperimentalToDeviceTransportSetting,
|
||||
);
|
||||
const [showToDeviceEncryption, setShowToDeviceEncryption] = useState(
|
||||
() => toDeviceEncryptionSetting,
|
||||
);
|
||||
useEffect(() => {
|
||||
setShowToDeviceEncryption(toDeviceEncryptionSetting);
|
||||
}, [toDeviceEncryptionSetting]);
|
||||
useTypedEventEmitter(
|
||||
rtcSession,
|
||||
RoomAndToDeviceEvents.EnabledTransportsChanged,
|
||||
(enabled) => setShowToDeviceEncryption(enabled.to_device),
|
||||
);
|
||||
|
||||
const toggleMicrophone = useCallback(
|
||||
() => muteStates.audio.setEnabled?.((e) => !e),
|
||||
[muteStates],
|
||||
@@ -662,6 +681,18 @@ export const InCallView: FC<InCallViewProps> = ({
|
||||
</RightNav>
|
||||
</Header>
|
||||
))}
|
||||
{
|
||||
// TODO: remove this once we remove the developer flag gets removed and we have shipped to
|
||||
// device transport as the default.
|
||||
showToDeviceEncryption && (
|
||||
<Text
|
||||
style={{ height: 0, zIndex: 1, alignSelf: "center", margin: 0 }}
|
||||
size="sm"
|
||||
>
|
||||
using to Device key transport
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
<RoomAudioRenderer />
|
||||
{renderContent()}
|
||||
<CallEventAudioRenderer vm={vm} />
|
||||
|
||||
@@ -12,7 +12,11 @@ import { Button } from "@vector-im/compound-web";
|
||||
import classNames from "classnames";
|
||||
import { logger } from "matrix-js-sdk/lib/logger";
|
||||
import { usePreviewTracks } from "@livekit/components-react";
|
||||
import { type LocalVideoTrack, Track } from "livekit-client";
|
||||
import {
|
||||
type CreateLocalTracksOptions,
|
||||
type LocalVideoTrack,
|
||||
Track,
|
||||
} from "livekit-client";
|
||||
import { useObservable } from "observable-hooks";
|
||||
import { map } from "rxjs";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
@@ -36,7 +40,11 @@ import { E2eeType } from "../e2ee/e2eeType";
|
||||
import { Link } from "../button/Link";
|
||||
import { useMediaDevices } from "../livekit/MediaDevicesContext";
|
||||
import { useInitial } from "../useInitial";
|
||||
import { useSwitchCamera } from "./useSwitchCamera";
|
||||
import { useSwitchCamera as useShowSwitchCamera } from "./useSwitchCamera";
|
||||
import {
|
||||
useTrackProcessor,
|
||||
useTrackProcessorSync,
|
||||
} from "../livekit/TrackProcessorContext";
|
||||
import { usePageTitle } from "../usePageTitle";
|
||||
|
||||
interface Props {
|
||||
@@ -112,7 +120,10 @@ export const LobbyView: FC<Props> = ({
|
||||
muteStates.audio.enabled && { deviceId: devices.audioInput.selectedId },
|
||||
);
|
||||
|
||||
const localTrackOptions = useMemo(
|
||||
const { processor } = useTrackProcessor();
|
||||
|
||||
const initialProcessor = useInitial(() => processor);
|
||||
const localTrackOptions = useMemo<CreateLocalTracksOptions>(
|
||||
() => ({
|
||||
// The only reason we request audio here is to get the audio permission
|
||||
// request over with at the same time. But changing the audio settings
|
||||
@@ -123,12 +134,14 @@ export const LobbyView: FC<Props> = ({
|
||||
audio: Object.assign({}, initialAudioOptions),
|
||||
video: muteStates.video.enabled && {
|
||||
deviceId: devices.videoInput.selectedId,
|
||||
processor: initialProcessor,
|
||||
},
|
||||
}),
|
||||
[
|
||||
initialAudioOptions,
|
||||
devices.videoInput.selectedId,
|
||||
muteStates.video.enabled,
|
||||
devices.videoInput.selectedId,
|
||||
initialProcessor,
|
||||
],
|
||||
);
|
||||
|
||||
@@ -149,8 +162,8 @@ export const LobbyView: FC<Props> = ({
|
||||
null) as LocalVideoTrack | null,
|
||||
[tracks],
|
||||
);
|
||||
|
||||
const switchCamera = useSwitchCamera(
|
||||
useTrackProcessorSync(videoTrack);
|
||||
const showSwitchCamera = useShowSwitchCamera(
|
||||
useObservable(
|
||||
(inputs$) => inputs$.pipe(map(([video]) => video)),
|
||||
[videoTrack],
|
||||
@@ -212,7 +225,9 @@ export const LobbyView: FC<Props> = ({
|
||||
onClick={onVideoPress}
|
||||
disabled={muteStates.video.setEnabled === null}
|
||||
/>
|
||||
{switchCamera && <SwitchCameraButton onClick={switchCamera} />}
|
||||
{showSwitchCamera && (
|
||||
<SwitchCameraButton onClick={showSwitchCamera} />
|
||||
)}
|
||||
<SettingsButton onClick={openSettings} />
|
||||
{!confineToRoom && <EndCallButton onClick={onLeaveClick} />}
|
||||
</div>
|
||||
|
||||
@@ -112,6 +112,7 @@ test("It joins the correct Session", async () => {
|
||||
manageMediaKeys: false,
|
||||
useLegacyMemberEvents: false,
|
||||
useNewMembershipManager: true,
|
||||
useExperimentalToDeviceTransport: false,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -98,6 +98,7 @@ export async function enterRTCSession(
|
||||
rtcSession: MatrixRTCSession,
|
||||
encryptMedia: boolean,
|
||||
useNewMembershipManager = true,
|
||||
useExperimentalToDeviceTransport = false,
|
||||
): Promise<void> {
|
||||
PosthogAnalytics.instance.eventCallEnded.cacheStartCall(new Date());
|
||||
PosthogAnalytics.instance.eventCallStarted.track(rtcSession.room.roomId);
|
||||
@@ -125,6 +126,7 @@ export async function enterRTCSession(
|
||||
membershipKeepAlivePeriod:
|
||||
matrixRtcSessionConfig?.membership_keep_alive_period,
|
||||
makeKeyDelay: matrixRtcSessionConfig?.key_rotation_on_leave_delay,
|
||||
useExperimentalToDeviceTransport,
|
||||
},
|
||||
);
|
||||
if (widget) {
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
showNonMemberTiles as showNonMemberTilesSetting,
|
||||
showConnectionStats as showConnectionStatsSetting,
|
||||
useNewMembershipManagerSetting,
|
||||
useExperimentalToDeviceTransportSetting,
|
||||
} from "./settings";
|
||||
import type { MatrixClient } from "matrix-js-sdk";
|
||||
import type { Room as LivekitRoom } from "livekit-client";
|
||||
@@ -44,6 +45,10 @@ export const DeveloperSettingsTab: FC<Props> = ({ client, livekitRoom }) => {
|
||||
useNewMembershipManagerSetting,
|
||||
);
|
||||
|
||||
const [
|
||||
useExperimentalToDeviceTransport,
|
||||
setUseExperimentalToDeviceTransport,
|
||||
] = useSetting(useExperimentalToDeviceTransportSetting);
|
||||
const urlParams = useUrlParams();
|
||||
|
||||
const sfuUrl = useMemo((): URL | null => {
|
||||
@@ -156,6 +161,20 @@ export const DeveloperSettingsTab: FC<Props> = ({ client, livekitRoom }) => {
|
||||
)}
|
||||
/>
|
||||
</FieldRow>
|
||||
<FieldRow>
|
||||
<InputField
|
||||
id="useToDeviceKeyTransport"
|
||||
type="checkbox"
|
||||
label={t("developer_mode.use_to_device_key_transport")}
|
||||
checked={!!useExperimentalToDeviceTransport}
|
||||
onChange={useCallback(
|
||||
(event: ChangeEvent<HTMLInputElement>): void => {
|
||||
setUseExperimentalToDeviceTransport(event.target.checked);
|
||||
},
|
||||
[setUseExperimentalToDeviceTransport],
|
||||
)}
|
||||
/>
|
||||
</FieldRow>
|
||||
{livekitRoom ? (
|
||||
<>
|
||||
<p>
|
||||
|
||||
@@ -5,10 +5,10 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { type FC, useState } from "react";
|
||||
import { type FC, type ReactNode, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { type MatrixClient } from "matrix-js-sdk";
|
||||
import { Root as Form } from "@vector-im/compound-web";
|
||||
import { Root as Form, Separator } from "@vector-im/compound-web";
|
||||
import { type Room as LivekitRoom } from "livekit-client";
|
||||
|
||||
import { Modal } from "../Modal";
|
||||
@@ -24,12 +24,15 @@ import { widget } from "../widget";
|
||||
import {
|
||||
useSetting,
|
||||
soundEffectVolumeSetting,
|
||||
backgroundBlur as backgroundBlurSetting,
|
||||
developerMode,
|
||||
} from "./settings";
|
||||
import { PreferencesSettingsTab } from "./PreferencesSettingsTab";
|
||||
import { Slider } from "../Slider";
|
||||
import { DeviceSelection } from "./DeviceSelection";
|
||||
import { useTrackProcessor } from "../livekit/TrackProcessorContext";
|
||||
import { DeveloperSettingsTab } from "./DeveloperSettingsTab";
|
||||
import { FieldRow, InputField } from "../input/Input";
|
||||
import { useSubmitRageshake } from "./submit-rageshake";
|
||||
|
||||
type SettingsTab =
|
||||
@@ -64,6 +67,33 @@ export const SettingsModal: FC<Props> = ({
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
// Generate a `Checkbox` input to turn blur on or off.
|
||||
const BlurCheckbox: React.FC = (): ReactNode => {
|
||||
const { supported } = useTrackProcessor();
|
||||
|
||||
const [blurActive, setBlurActive] = useSetting(backgroundBlurSetting);
|
||||
|
||||
return (
|
||||
<>
|
||||
<h4>{t("settings.background_blur_header")}</h4>
|
||||
|
||||
<FieldRow>
|
||||
<InputField
|
||||
id="activateBackgroundBlur"
|
||||
label={t("settings.background_blur_label")}
|
||||
description={
|
||||
supported ? "" : t("settings.blur_not_supported_by_browser")
|
||||
}
|
||||
type="checkbox"
|
||||
checked={!!blurActive}
|
||||
onChange={(b): void => setBlurActive(b.target.checked)}
|
||||
disabled={!supported}
|
||||
/>
|
||||
</FieldRow>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const devices = useMediaDevices();
|
||||
useMediaDeviceNames(devices, open);
|
||||
const [soundVolume, setSoundVolume] = useSetting(soundEffectVolumeSetting);
|
||||
@@ -113,13 +143,17 @@ export const SettingsModal: FC<Props> = ({
|
||||
key: "video",
|
||||
name: t("common.video"),
|
||||
content: (
|
||||
<Form>
|
||||
<DeviceSelection
|
||||
devices={devices.videoInput}
|
||||
title={t("settings.devices.camera")}
|
||||
numberedLabel={(n) => t("settings.devices.camera_numbered", { n })}
|
||||
/>
|
||||
</Form>
|
||||
<>
|
||||
<Form>
|
||||
<DeviceSelection
|
||||
devices={devices.videoInput}
|
||||
title={t("settings.devices.camera")}
|
||||
numberedLabel={(n) => t("settings.devices.camera_numbered", { n })}
|
||||
/>
|
||||
</Form>
|
||||
<Separator />
|
||||
<BlurCheckbox />
|
||||
</>
|
||||
),
|
||||
};
|
||||
|
||||
|
||||
@@ -473,11 +473,6 @@ export async function init(): Promise<void> {
|
||||
|
||||
// configure loglevel based loggers:
|
||||
setLogExtension(logger, global.mx_rage_logger.log);
|
||||
// these are the child/prefixed loggers we want to capture from js-sdk
|
||||
// there doesn't seem to be an easy way to capture all children
|
||||
["MatrixRTCSession", "MatrixRTCSessionManager"].forEach((loggerName) => {
|
||||
setLogExtension(logger.getChild(loggerName), global.mx_rage_logger.log);
|
||||
});
|
||||
|
||||
// intercept console logging so that we can get matrix_sdk logs:
|
||||
// this is nasty, but no logging hooks are provided
|
||||
|
||||
@@ -96,6 +96,8 @@ export const videoInput = new Setting<string | undefined>(
|
||||
undefined,
|
||||
);
|
||||
|
||||
export const backgroundBlur = new Setting<boolean>("background-blur", false);
|
||||
|
||||
export const showHandRaisedTimer = new Setting<boolean>(
|
||||
"hand-raised-show-timer",
|
||||
false,
|
||||
@@ -117,4 +119,10 @@ export const useNewMembershipManagerSetting = new Setting<boolean>(
|
||||
"new-membership-manager",
|
||||
true,
|
||||
);
|
||||
|
||||
export const useExperimentalToDeviceTransportSetting = new Setting<boolean>(
|
||||
"experimental-to-device-transport",
|
||||
true,
|
||||
);
|
||||
|
||||
export const alwaysShowSelf = new Setting<boolean>("always-show-self", true);
|
||||
|
||||
@@ -337,7 +337,7 @@ export function getRelativeRoomUrl(
|
||||
}
|
||||
|
||||
/**
|
||||
* Perfom a network operation with retries on ConnectionError.
|
||||
* Perform a network operation with retries on ConnectionError.
|
||||
* If the error is not retryable, or the max number of retries is reached, the error is rethrown.
|
||||
* Supports handling of matrix quotas.
|
||||
*/
|
||||
|
||||
@@ -5,13 +5,14 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { defineConfig, loadEnv } from "vite";
|
||||
import { defineConfig, loadEnv, searchForWorkspaceRoot } from "vite";
|
||||
import svgrPlugin from "vite-plugin-svgr";
|
||||
import { createHtmlPlugin } from "vite-plugin-html";
|
||||
import { codecovVitePlugin } from "@codecov/vite-plugin";
|
||||
import { sentryVitePlugin } from "@sentry/vite-plugin";
|
||||
import react from "@vitejs/plugin-react";
|
||||
import basicSsl from "@vitejs/plugin-basic-ssl";
|
||||
import { realpathSync } from "fs";
|
||||
import * as fs from "node:fs";
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig(({ mode, packageType }) => {
|
||||
@@ -23,7 +24,6 @@ export default defineConfig(({ mode, packageType }) => {
|
||||
process.env.VITE_PACKAGE = packageType ?? "full";
|
||||
const plugins = [
|
||||
react(),
|
||||
basicSsl(),
|
||||
svgrPlugin({
|
||||
svgrOptions: {
|
||||
// This enables ref forwarding on SVGR components, which is needed, for
|
||||
@@ -64,9 +64,29 @@ export default defineConfig(({ mode, packageType }) => {
|
||||
);
|
||||
}
|
||||
|
||||
// The crypto WASM module is imported dynamically. Since it's common
|
||||
// for developers to use a linked copy of matrix-js-sdk or Rust
|
||||
// crypto (which could reside anywhere on their file system), Vite
|
||||
// needs to be told to recognize it as a legitimate file access.
|
||||
const allow = [searchForWorkspaceRoot(process.cwd())];
|
||||
for (const path of [
|
||||
"node_modules/matrix-js-sdk/node_modules/@matrix-org/matrix-sdk-crypto-wasm",
|
||||
"node_modules/@matrix-org/matrix-sdk-crypto-wasm",
|
||||
]) {
|
||||
try {
|
||||
allow.push(realpathSync(path));
|
||||
} catch {}
|
||||
}
|
||||
console.log("Allowed vite paths:", allow);
|
||||
|
||||
return {
|
||||
server: {
|
||||
port: 3000,
|
||||
fs: { allow },
|
||||
https: {
|
||||
key: fs.readFileSync("./backend/dev_tls_m.localhost.key"),
|
||||
cert: fs.readFileSync("./backend/dev_tls_m.localhost.crt"),
|
||||
},
|
||||
},
|
||||
build: {
|
||||
sourcemap: true,
|
||||
|
||||
262
yarn.lock
262
yarn.lock
@@ -2527,21 +2527,23 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@livekit/protocol@npm:1.33.0":
|
||||
version: 1.33.0
|
||||
resolution: "@livekit/protocol@npm:1.33.0"
|
||||
"@livekit/protocol@npm:1.36.1, @livekit/protocol@npm:^1.33.0":
|
||||
version: 1.36.1
|
||||
resolution: "@livekit/protocol@npm:1.36.1"
|
||||
dependencies:
|
||||
"@bufbuild/protobuf": "npm:^1.10.0"
|
||||
checksum: 10c0/5eced9581c4af7fd67e65e93a40a389202b8a9031b4e76d7709d5c1e35ae5816c11a7b9265d6b9cf8b19c3b4077dbdd2a17275a29e98f9ec785232c4750d8ded
|
||||
checksum: 10c0/bb2e56785c542446bef3e2f2fd20b33d01db43b786be87ccb834feee8a664fd32c8231e249b4e1915d7a8eda13af0d59eea479fa710327079a1a370daf05c42e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@livekit/protocol@npm:^1.33.0":
|
||||
version: 1.34.0
|
||||
resolution: "@livekit/protocol@npm:1.34.0"
|
||||
"@livekit/track-processors@npm:^0.5.5":
|
||||
version: 0.5.5
|
||||
resolution: "@livekit/track-processors@npm:0.5.5"
|
||||
dependencies:
|
||||
"@bufbuild/protobuf": "npm:^1.10.0"
|
||||
checksum: 10c0/f6c8ad1fe5da151e2fc103118e61c5110df32088e13a03a30dd2de9cce401e9c99eed3cc61324272a8a2fef1c001bb4d215b2a9479774f493b6a301f547f01e5
|
||||
"@mediapipe/tasks-vision": "npm:0.10.14"
|
||||
peerDependencies:
|
||||
livekit-client: ^1.12.0 || ^2.1.0
|
||||
checksum: 10c0/b86737c4ce6b93c714dfc814c997d07f1d40b0869b5e269b28e00034a3c06da811d9117c4914d8a2706ac760be31f2e9d0705108c07b29f4bbb4626dcd41ed64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -2559,6 +2561,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mediapipe/tasks-vision@npm:^0.10.18":
|
||||
version: 0.10.21
|
||||
resolution: "@mediapipe/tasks-vision@npm:0.10.21"
|
||||
checksum: 10c0/11b2bdf98b8cb6e044f2a954e7c8393169e62c86ff49b3d0b61c3b327d18e1ccd47a187999b023bad48380c9da41bfa66eb165301c80da07746390482cb18a19
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@nodelib/fs.scandir@npm:2.1.5":
|
||||
version: 2.1.5
|
||||
resolution: "@nodelib/fs.scandir@npm:2.1.5"
|
||||
@@ -3054,14 +3063,14 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@playwright/test@npm:^1.51.0":
|
||||
version: 1.51.0
|
||||
resolution: "@playwright/test@npm:1.51.0"
|
||||
"@playwright/test@npm:^1.52.0":
|
||||
version: 1.52.0
|
||||
resolution: "@playwright/test@npm:1.52.0"
|
||||
dependencies:
|
||||
playwright: "npm:1.51.0"
|
||||
playwright: "npm:1.52.0"
|
||||
bin:
|
||||
playwright: cli.js
|
||||
checksum: 10c0/ae83dd2c3a32133de58f44a9dbcd73a8059155ebd8acc736ba8bd0a7ca99b194afe2e8f5a500861d18b1c8f06b4e4ea8de4a2402297c59053d4becc404b47e0a
|
||||
checksum: 10c0/1c428b421593eb4f79b7c99783a389c3ab3526c9051ec772749f4fca61414dfa9f2344eba846faac5f238084aa96c836364a91d81d3034ac54924f239a93e247
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -4612,6 +4621,22 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/dom-mediacapture-transform@npm:^0.1.11":
|
||||
version: 0.1.11
|
||||
resolution: "@types/dom-mediacapture-transform@npm:0.1.11"
|
||||
dependencies:
|
||||
"@types/dom-webcodecs": "npm:*"
|
||||
checksum: 10c0/19c76d54cf31aa2a925011fc5f973dff9a10bdecfdf2285e5e568e61850a0fa2b8c9f1807a1462cbefd57ec26d32eeaa9c359117aca9d9fe7f0d6f2fff33f51e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/dom-webcodecs@npm:*":
|
||||
version: 0.1.15
|
||||
resolution: "@types/dom-webcodecs@npm:0.1.15"
|
||||
checksum: 10c0/1407f0352156c99c9b4378fb4c0c799b061520d031903a7f359ad09a6f706cc1fd56bafb272bb1a3decffcb32e54a51d2f07442eb72622464a950cff7f9e8862
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/estree@npm:1.0.6, @types/estree@npm:^1.0.0":
|
||||
version: 1.0.6
|
||||
resolution: "@types/estree@npm:1.0.6"
|
||||
@@ -4806,15 +4831,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/eslint-plugin@npm:^8.0.0":
|
||||
version: 8.25.0
|
||||
resolution: "@typescript-eslint/eslint-plugin@npm:8.25.0"
|
||||
"@typescript-eslint/eslint-plugin@npm:^8.31.0":
|
||||
version: 8.31.0
|
||||
resolution: "@typescript-eslint/eslint-plugin@npm:8.31.0"
|
||||
dependencies:
|
||||
"@eslint-community/regexpp": "npm:^4.10.0"
|
||||
"@typescript-eslint/scope-manager": "npm:8.25.0"
|
||||
"@typescript-eslint/type-utils": "npm:8.25.0"
|
||||
"@typescript-eslint/utils": "npm:8.25.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.25.0"
|
||||
"@typescript-eslint/scope-manager": "npm:8.31.0"
|
||||
"@typescript-eslint/type-utils": "npm:8.31.0"
|
||||
"@typescript-eslint/utils": "npm:8.31.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.31.0"
|
||||
graphemer: "npm:^1.4.0"
|
||||
ignore: "npm:^5.3.1"
|
||||
natural-compare: "npm:^1.4.0"
|
||||
@@ -4822,8 +4847,8 @@ __metadata:
|
||||
peerDependencies:
|
||||
"@typescript-eslint/parser": ^8.0.0 || ^8.0.0-alpha.0
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <5.8.0"
|
||||
checksum: 10c0/11d63850f5f03b29cd31166f8da111788dc74e46877c2e16a5c488d6c4aa4b6c68c0857b9a396ad920aa7f0f3e7166f4faecbb194c19cd2bb9d3f687c5d2b292
|
||||
typescript: ">=4.8.4 <5.9.0"
|
||||
checksum: 10c0/7d78e0cdcc967742752d49d2d38986ee38d0b7ca64af247e5fe0816cea9ae5f1bfa5c126154acc0846af515c4fb1c52c96926ee25c73b4c3f7e6fd73cb6d2b0e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -4838,19 +4863,19 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/parser@npm:^8.0.0":
|
||||
version: 8.25.0
|
||||
resolution: "@typescript-eslint/parser@npm:8.25.0"
|
||||
"@typescript-eslint/parser@npm:^8.31.0":
|
||||
version: 8.31.0
|
||||
resolution: "@typescript-eslint/parser@npm:8.31.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/scope-manager": "npm:8.25.0"
|
||||
"@typescript-eslint/types": "npm:8.25.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.25.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.25.0"
|
||||
"@typescript-eslint/scope-manager": "npm:8.31.0"
|
||||
"@typescript-eslint/types": "npm:8.31.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.31.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.31.0"
|
||||
debug: "npm:^4.3.4"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <5.8.0"
|
||||
checksum: 10c0/9a54539ba297791f23093ff42a885cc57d36b26205d7a390e114d1f01cc584ce91ac6ead01819daa46b48f873cac6c829fcf399a436610bdbfa98e5cd78148a2
|
||||
typescript: ">=4.8.4 <5.9.0"
|
||||
checksum: 10c0/9bd903b3ea4e24bfeb444d7a5c2ed82e591ef5cffc0874c609de854c05d34935cd85543e66678ecdb8e0e3eae2cda2df5c1ba66eb72010632cb9f8779031d56d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -4874,18 +4899,28 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/type-utils@npm:8.25.0":
|
||||
version: 8.25.0
|
||||
resolution: "@typescript-eslint/type-utils@npm:8.25.0"
|
||||
"@typescript-eslint/scope-manager@npm:8.31.0":
|
||||
version: 8.31.0
|
||||
resolution: "@typescript-eslint/scope-manager@npm:8.31.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/typescript-estree": "npm:8.25.0"
|
||||
"@typescript-eslint/utils": "npm:8.25.0"
|
||||
"@typescript-eslint/types": "npm:8.31.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.31.0"
|
||||
checksum: 10c0/eae758a24cc578fa351b8bf0c30c50de384292c0b05a58762f9b632d65a009bd5d902d806eccb6b678cc0b09686289fb4f1fd67da7f12d59ad43ff033b35cc4f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/type-utils@npm:8.31.0":
|
||||
version: 8.31.0
|
||||
resolution: "@typescript-eslint/type-utils@npm:8.31.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/typescript-estree": "npm:8.31.0"
|
||||
"@typescript-eslint/utils": "npm:8.31.0"
|
||||
debug: "npm:^4.3.4"
|
||||
ts-api-utils: "npm:^2.0.1"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <5.8.0"
|
||||
checksum: 10c0/b7477a2d239cfd337f7d28641666763cf680a43a8d377a09dc42415f715670d35fbb4e772e103dfe8cd620c377e66bce740106bb3983ee65a739c28fab7325d1
|
||||
typescript: ">=4.8.4 <5.9.0"
|
||||
checksum: 10c0/f6938413a583430468b259f6823bb2ab1b5cd77cd6d4e21e1803df70e329046b9579aed5bdc9bdcf4046c8091615a911ac3990859db78d00210bb867915ba37f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -4903,6 +4938,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/types@npm:8.31.0":
|
||||
version: 8.31.0
|
||||
resolution: "@typescript-eslint/types@npm:8.31.0"
|
||||
checksum: 10c0/04130a30aac477d36d6a155399b27773457aeb9b485ef8fb56fee05725b6e36768c9fac7e4d1f073fd16988de0eb7dffc743c3f834ae907cf918cabb075e5cd8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/typescript-estree@npm:5.62.0":
|
||||
version: 5.62.0
|
||||
resolution: "@typescript-eslint/typescript-estree@npm:5.62.0"
|
||||
@@ -4939,6 +4981,24 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/typescript-estree@npm:8.31.0":
|
||||
version: 8.31.0
|
||||
resolution: "@typescript-eslint/typescript-estree@npm:8.31.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": "npm:8.31.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.31.0"
|
||||
debug: "npm:^4.3.4"
|
||||
fast-glob: "npm:^3.3.2"
|
||||
is-glob: "npm:^4.0.3"
|
||||
minimatch: "npm:^9.0.4"
|
||||
semver: "npm:^7.6.0"
|
||||
ts-api-utils: "npm:^2.0.1"
|
||||
peerDependencies:
|
||||
typescript: ">=4.8.4 <5.9.0"
|
||||
checksum: 10c0/0ec074b2b9c49f80fafea716aa0cc4b05085e65730a3ef7c7d2d39db1657a40b38abe83f22bbe15ac4f6fdf576692f47d2d057347242e6cef5be81d070f55064
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/utils@npm:5.62.0":
|
||||
version: 5.62.0
|
||||
resolution: "@typescript-eslint/utils@npm:5.62.0"
|
||||
@@ -4957,7 +5017,22 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/utils@npm:8.25.0, @typescript-eslint/utils@npm:^8.13.0":
|
||||
"@typescript-eslint/utils@npm:8.31.0":
|
||||
version: 8.31.0
|
||||
resolution: "@typescript-eslint/utils@npm:8.31.0"
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils": "npm:^4.4.0"
|
||||
"@typescript-eslint/scope-manager": "npm:8.31.0"
|
||||
"@typescript-eslint/types": "npm:8.31.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.31.0"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <5.9.0"
|
||||
checksum: 10c0/1fd4f62e16a44a5be2de501f70ba4b2d64479e014370bde7bbc6de6897cf1699766a8b7be4deb9b0328e74c2b4171839336ede4e3c60fec6ac8378b623a75275
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/utils@npm:^8.13.0":
|
||||
version: 8.25.0
|
||||
resolution: "@typescript-eslint/utils@npm:8.25.0"
|
||||
dependencies:
|
||||
@@ -4992,6 +5067,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/visitor-keys@npm:8.31.0":
|
||||
version: 8.31.0
|
||||
resolution: "@typescript-eslint/visitor-keys@npm:8.31.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": "npm:8.31.0"
|
||||
eslint-visitor-keys: "npm:^4.2.0"
|
||||
checksum: 10c0/e41e2a9e287d11232cda6126377d1df4de69c6e9dc2a14058819cff15280ec654a3877886a6806728196f299766cfbb0b299eb021c2ce168eb15dff5eb07b51b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@ungap/structured-clone@npm:^1.2.0":
|
||||
version: 1.2.0
|
||||
resolution: "@ungap/structured-clone@npm:1.2.0"
|
||||
@@ -5058,15 +5143,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitejs/plugin-basic-ssl@npm:^1.0.1":
|
||||
version: 1.2.0
|
||||
resolution: "@vitejs/plugin-basic-ssl@npm:1.2.0"
|
||||
peerDependencies:
|
||||
vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0
|
||||
checksum: 10c0/0d360fcca01f91ade6e451edbea09a107ff9e95cd3c3766c7a069d1a168709df92d96c0bd1eccc66e2739a153e07c75a45321ec487450c0da942606200d8441d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitejs/plugin-react@npm:^4.0.1":
|
||||
version: 4.3.4
|
||||
resolution: "@vitejs/plugin-react@npm:4.3.4"
|
||||
@@ -6862,6 +6938,8 @@ __metadata:
|
||||
"@livekit/components-core": "npm:^0.12.0"
|
||||
"@livekit/components-react": "npm:^2.0.0"
|
||||
"@livekit/protocol": "npm:^1.33.0"
|
||||
"@livekit/track-processors": "npm:^0.5.5"
|
||||
"@mediapipe/tasks-vision": "npm:^0.10.18"
|
||||
"@opentelemetry/api": "npm:^1.4.0"
|
||||
"@opentelemetry/core": "npm:^1.25.1"
|
||||
"@opentelemetry/exporter-trace-otlp-http": "npm:^0.57.0"
|
||||
@@ -6869,7 +6947,7 @@ __metadata:
|
||||
"@opentelemetry/sdk-trace-base": "npm:^1.25.1"
|
||||
"@opentelemetry/sdk-trace-web": "npm:^1.9.1"
|
||||
"@opentelemetry/semantic-conventions": "npm:^1.25.1"
|
||||
"@playwright/test": "npm:^1.51.0"
|
||||
"@playwright/test": "npm:^1.52.0"
|
||||
"@radix-ui/react-dialog": "npm:^1.0.4"
|
||||
"@radix-ui/react-slider": "npm:^1.1.2"
|
||||
"@radix-ui/react-visually-hidden": "npm:^1.0.3"
|
||||
@@ -6882,6 +6960,7 @@ __metadata:
|
||||
"@testing-library/react": "npm:^16.0.0"
|
||||
"@testing-library/user-event": "npm:^14.5.1"
|
||||
"@types/content-type": "npm:^1.1.5"
|
||||
"@types/dom-mediacapture-transform": "npm:^0.1.11"
|
||||
"@types/grecaptcha": "npm:^3.0.9"
|
||||
"@types/jsdom": "npm:^21.1.7"
|
||||
"@types/lodash-es": "npm:^4.17.12"
|
||||
@@ -6892,12 +6971,11 @@ __metadata:
|
||||
"@types/react-dom": "npm:^18.3.0"
|
||||
"@types/sdp-transform": "npm:^2.4.5"
|
||||
"@types/uuid": "npm:10"
|
||||
"@typescript-eslint/eslint-plugin": "npm:^8.0.0"
|
||||
"@typescript-eslint/parser": "npm:^8.0.0"
|
||||
"@typescript-eslint/eslint-plugin": "npm:^8.31.0"
|
||||
"@typescript-eslint/parser": "npm:^8.31.0"
|
||||
"@use-gesture/react": "npm:^10.2.11"
|
||||
"@vector-im/compound-design-tokens": "npm:^3.0.0"
|
||||
"@vector-im/compound-web": "npm:^7.2.0"
|
||||
"@vitejs/plugin-basic-ssl": "npm:^1.0.1"
|
||||
"@vitejs/plugin-react": "npm:^4.0.1"
|
||||
"@vitest/coverage-v8": "npm:^3.0.0"
|
||||
babel-plugin-transform-vite-meta-env: "npm:^1.0.3"
|
||||
@@ -6919,10 +6997,10 @@ __metadata:
|
||||
i18next-parser: "npm:^9.1.0"
|
||||
jsdom: "npm:^26.0.0"
|
||||
knip: "npm:^5.27.2"
|
||||
livekit-client: "npm:2.9.1"
|
||||
livekit-client: "npm:^2.11.3"
|
||||
lodash-es: "npm:^4.17.21"
|
||||
loglevel: "npm:^1.9.1"
|
||||
matrix-js-sdk: "github:matrix-org/matrix-js-sdk#8395919f0fd1af7cab1e793d736f2cdf18ef7686"
|
||||
matrix-js-sdk: "github:matrix-org/matrix-js-sdk#19b1b901f575755d29d1fe03ca48cbf7c1cae05c"
|
||||
matrix-widget-api: "npm:1.11.0"
|
||||
normalize.css: "npm:^8.0.1"
|
||||
observable-hooks: "npm:^4.2.3"
|
||||
@@ -6940,7 +7018,7 @@ __metadata:
|
||||
react-use-measure: "npm:^2.1.1"
|
||||
rxjs: "npm:^7.8.1"
|
||||
sass: "npm:^1.42.1"
|
||||
typescript: "npm:^5.1.6"
|
||||
typescript: "npm:^5.8.3"
|
||||
typescript-eslint-language-service: "npm:^5.0.5"
|
||||
unique-names-generator: "npm:^4.6.0"
|
||||
vaul: "npm:^1.0.0"
|
||||
@@ -9289,20 +9367,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"livekit-client@npm:2.9.1":
|
||||
version: 2.9.1
|
||||
resolution: "livekit-client@npm:2.9.1"
|
||||
"livekit-client@npm:^2.11.3":
|
||||
version: 2.11.3
|
||||
resolution: "livekit-client@npm:2.11.3"
|
||||
dependencies:
|
||||
"@livekit/mutex": "npm:1.1.1"
|
||||
"@livekit/protocol": "npm:1.33.0"
|
||||
"@livekit/protocol": "npm:1.36.1"
|
||||
events: "npm:^3.3.0"
|
||||
loglevel: "npm:^1.8.0"
|
||||
sdp-transform: "npm:^2.14.1"
|
||||
loglevel: "npm:^1.9.2"
|
||||
sdp-transform: "npm:^2.15.0"
|
||||
ts-debounce: "npm:^4.0.0"
|
||||
tslib: "npm:2.8.1"
|
||||
typed-emitter: "npm:^2.1.0"
|
||||
webrtc-adapter: "npm:^9.0.0"
|
||||
checksum: 10c0/06c4bcfe22c2629bd3e2a7fdf5d104425ed9c781d77a39fd61940d30a85dff0b9e3364b0ad8e584a8dc2d885f625532dd6ec151f5c8a4ecfb16cdcf2718e817f
|
||||
webrtc-adapter: "npm:^9.0.1"
|
||||
checksum: 10c0/d56444f31c107b46ccd5532038ac77bd21038042910619008267c17894f1d3f054262ae2354d89df6fe0ba325aba01909b0612ad4c290906487c40d91641f6e4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -9359,7 +9437,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"loglevel@npm:^1.7.1, loglevel@npm:^1.8.0, loglevel@npm:^1.9.1":
|
||||
"loglevel@npm:^1.9.1, loglevel@npm:^1.9.2":
|
||||
version: 1.9.2
|
||||
resolution: "loglevel@npm:1.9.2"
|
||||
checksum: 10c0/1e317fa4648fe0b4a4cffef6de037340592cee8547b07d4ce97a487abe9153e704b98451100c799b032c72bb89c9366d71c9fb8192ada8703269263ae77acdc7
|
||||
@@ -9513,9 +9591,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"matrix-js-sdk@github:matrix-org/matrix-js-sdk#8395919f0fd1af7cab1e793d736f2cdf18ef7686":
|
||||
version: 37.1.0
|
||||
resolution: "matrix-js-sdk@https://github.com/matrix-org/matrix-js-sdk.git#commit=8395919f0fd1af7cab1e793d736f2cdf18ef7686"
|
||||
"matrix-js-sdk@github:matrix-org/matrix-js-sdk#19b1b901f575755d29d1fe03ca48cbf7c1cae05c":
|
||||
version: 37.4.0
|
||||
resolution: "matrix-js-sdk@https://github.com/matrix-org/matrix-js-sdk.git#commit=19b1b901f575755d29d1fe03ca48cbf7c1cae05c"
|
||||
dependencies:
|
||||
"@babel/runtime": "npm:^7.12.5"
|
||||
"@matrix-org/matrix-sdk-crypto-wasm": "npm:^14.0.1"
|
||||
@@ -9524,7 +9602,7 @@ __metadata:
|
||||
bs58: "npm:^6.0.0"
|
||||
content-type: "npm:^1.0.4"
|
||||
jwt-decode: "npm:^4.0.0"
|
||||
loglevel: "npm:^1.7.1"
|
||||
loglevel: "npm:^1.9.2"
|
||||
matrix-events-sdk: "npm:0.0.1"
|
||||
matrix-widget-api: "npm:^1.10.0"
|
||||
oidc-client-ts: "npm:^3.0.1"
|
||||
@@ -9532,7 +9610,7 @@ __metadata:
|
||||
sdp-transform: "npm:^2.14.1"
|
||||
unhomoglyph: "npm:^1.0.6"
|
||||
uuid: "npm:11"
|
||||
checksum: 10c0/a0eb3be822e07cfe53965f6ca4f0c3cdf8ba3728d03a15f2322a463a7543206583e0c2f34d6b6d45089ce36eec60d77d9e90eb0635d3c65a343f77728908fe57
|
||||
checksum: 10c0/68a30a113059ba052b2e66502abcd9805f9a18a1bfd1d209203d728b36508af257a57e6248fb237c7018c81bfbe1ec78fa17aea8968c8af0729ea935398dcf8b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -10304,27 +10382,27 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"playwright-core@npm:1.51.0":
|
||||
version: 1.51.0
|
||||
resolution: "playwright-core@npm:1.51.0"
|
||||
"playwright-core@npm:1.52.0":
|
||||
version: 1.52.0
|
||||
resolution: "playwright-core@npm:1.52.0"
|
||||
bin:
|
||||
playwright-core: cli.js
|
||||
checksum: 10c0/8f5de23088c5e97c00327f356b17e0223181e921baf99f4e38d9a3b18d0693db288f8b5389e96d0cb4a1b55f03870f140dd7346128a0c02ce36d11eb92153841
|
||||
checksum: 10c0/640945507e6ca2144e9f596b2a6ecac042c2fd3683ff99e6271e9a7b38f3602d415f282609d569456f66680aab8b3c5bb1b257d8fb63a7fc0ed648261110421f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"playwright@npm:1.51.0":
|
||||
version: 1.51.0
|
||||
resolution: "playwright@npm:1.51.0"
|
||||
"playwright@npm:1.52.0":
|
||||
version: 1.52.0
|
||||
resolution: "playwright@npm:1.52.0"
|
||||
dependencies:
|
||||
fsevents: "npm:2.3.2"
|
||||
playwright-core: "npm:1.51.0"
|
||||
playwright-core: "npm:1.52.0"
|
||||
dependenciesMeta:
|
||||
fsevents:
|
||||
optional: true
|
||||
bin:
|
||||
playwright: cli.js
|
||||
checksum: 10c0/e8509ea500e03e8051fd243f2347ac3196ff8dde4c20ae3aba4cf723e2b647a0158d209fba062995dab90590229a483d723562cf1ea8b2fc11698617027416fd
|
||||
checksum: 10c0/2c6edf1e15e59bbaf77f3fa0fe0ac975793c17cff835d9c8b8bc6395a3b6f1c01898b3058ab37891b2e4d424bcc8f1b4844fe70d943e0143d239d7451408c579
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -11710,7 +11788,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"sdp-transform@npm:^2.14.1":
|
||||
"sdp-transform@npm:^2.14.1, sdp-transform@npm:^2.15.0":
|
||||
version: 2.15.0
|
||||
resolution: "sdp-transform@npm:2.15.0"
|
||||
bin:
|
||||
@@ -12681,13 +12759,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"typescript@npm:^5.1.6":
|
||||
version: 5.7.3
|
||||
resolution: "typescript@npm:5.7.3"
|
||||
"typescript@npm:^5.8.3":
|
||||
version: 5.8.3
|
||||
resolution: "typescript@npm:5.8.3"
|
||||
bin:
|
||||
tsc: bin/tsc
|
||||
tsserver: bin/tsserver
|
||||
checksum: 10c0/b7580d716cf1824736cc6e628ab4cd8b51877408ba2be0869d2866da35ef8366dd6ae9eb9d0851470a39be17cbd61df1126f9e211d8799d764ea7431d5435afa
|
||||
checksum: 10c0/5f8bb01196e542e64d44db3d16ee0e4063ce4f3e3966df6005f2588e86d91c03e1fb131c2581baf0fb65ee79669eea6e161cd448178986587e9f6844446dbb48
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -12701,13 +12779,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"typescript@patch:typescript@npm%3A^5.1.6#optional!builtin<compat/typescript>":
|
||||
version: 5.7.3
|
||||
resolution: "typescript@patch:typescript@npm%3A5.7.3#optional!builtin<compat/typescript>::version=5.7.3&hash=5786d5"
|
||||
"typescript@patch:typescript@npm%3A^5.8.3#optional!builtin<compat/typescript>":
|
||||
version: 5.8.3
|
||||
resolution: "typescript@patch:typescript@npm%3A5.8.3#optional!builtin<compat/typescript>::version=5.8.3&hash=5786d5"
|
||||
bin:
|
||||
tsc: bin/tsc
|
||||
tsserver: bin/tsserver
|
||||
checksum: 10c0/6fd7e0ed3bf23a81246878c613423730c40e8bdbfec4c6e4d7bf1b847cbb39076e56ad5f50aa9d7ebd89877999abaee216002d3f2818885e41c907caaa192cc4
|
||||
checksum: 10c0/39117e346ff8ebd87ae1510b3a77d5d92dae5a89bde588c747d25da5c146603a99c8ee588c7ef80faaf123d89ed46f6dbd918d534d641083177d5fac38b8a1cb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -13101,8 +13179,8 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"vite@npm:^5.0.0 || ^6.0.0, vite@npm:^6.0.0":
|
||||
version: 6.2.4
|
||||
resolution: "vite@npm:6.2.4"
|
||||
version: 6.2.6
|
||||
resolution: "vite@npm:6.2.6"
|
||||
dependencies:
|
||||
esbuild: "npm:^0.25.0"
|
||||
fsevents: "npm:~2.3.3"
|
||||
@@ -13148,7 +13226,7 @@ __metadata:
|
||||
optional: true
|
||||
bin:
|
||||
vite: bin/vite.js
|
||||
checksum: 10c0/5a011ee5cce91de023a22564a314f04bf64d0d02b420d92c3d539d10257448d60e98e52b491404656426fba4a50dc25f107282540d7388fc5303dc441280155e
|
||||
checksum: 10c0/68a2ed3e61bdd654c59b817b4f3203065241c66d1739faa707499130f3007bc3a666c7a8320a4198e275e62b5e4d34d9b78a6533f69e321d366e76f5093b2071
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -13298,7 +13376,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"webrtc-adapter@npm:^9.0.0":
|
||||
"webrtc-adapter@npm:^9.0.1":
|
||||
version: 9.0.1
|
||||
resolution: "webrtc-adapter@npm:9.0.1"
|
||||
dependencies:
|
||||
|
||||
Reference in New Issue
Block a user