diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 561b95c360..9fa794a134 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,7 +1,7 @@ # To get started with Dependabot version updates, you'll need to specify which # package ecosystems to update and where the package manifests are located. # Please see the documentation for all configuration options: -# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates version: 2 updates: @@ -15,7 +15,7 @@ updates: reviewers: - "vector-im/element-android-reviewers" ignore: - - dependency-name: "*github-script*" + - dependency-name: "*" # Updates for Gradle dependencies used in the app - package-ecosystem: gradle directory: "/" @@ -25,5 +25,6 @@ updates: open-pull-requests-limit: 0 reviewers: - "vector-im/element-android-reviewers" - ignore: - - dependency-name: com.google.zxing:core + allow: + - dependency-name: "io.element.android:wysiwyg" + - dependency-name: "org.matrix.rustcomponents:crypto-android" diff --git a/.github/workflows/triage-incoming.yml b/.github/workflows/triage-incoming.yml index 56bad8a2d7..4f9c239429 100644 --- a/.github/workflows/triage-incoming.yml +++ b/.github/workflows/triage-incoming.yml @@ -15,3 +15,11 @@ jobs: project: Issue triage column: Incoming repo-token: ${{ secrets.ELEMENT_BOT_TOKEN }} + + triage-new-issues: + runs-on: ubuntu-latest + steps: + - uses: actions/add-to-project@main + with: + project-url: https://github.com/orgs/vector-im/projects/91 + github-token: ${{ secrets.ELEMENT_BOT_TOKEN }} diff --git a/ELEMENT_CHANGES.md b/ELEMENT_CHANGES.md index 39ea3f1477..53ddf8a4ef 100644 --- a/ELEMENT_CHANGES.md +++ b/ELEMENT_CHANGES.md @@ -1,3 +1,39 @@ +Changes in Element v1.6.5 (2023-07-25) +====================================== + +Bugfixes 🐛 +---------- + - Fix several crashes observed when the device cannot reach the homeserver ([#8578](https://github.com/vector-im/element-android/issues/8578)) + +Other changes +------------- + - Update MSC3912 implementation: Redaction of related events ([#8481](https://github.com/vector-im/element-android/issues/8481)) + - Include some source code in our project to remove our dependency to artifact hosted by bintray (Jcenter). ([#8556](https://github.com/vector-im/element-android/issues/8556)) + + +Changes in Element v1.6.3 (2023-06-27) +====================================== + +Features ✨ +---------- + - **Element Android is now using the Crypto Rust SDK**. Migration of user's data should be done at first launch after application upgrade. ([#8390](https://github.com/vector-im/element-android/issues/8390)) + - [Rich text editor] Add mentions and slash commands ([#8440](https://github.com/vector-im/element-android/issues/8440)) + +Bugfixes 🐛 +---------- + - Update rich text editor library to support pasting of images. ([#8270](https://github.com/vector-im/element-android/issues/8270)) + - Fix | Got asked twice about verification #8353 (and other verification banners problems) ([#8353](https://github.com/vector-im/element-android/issues/8353)) + - Prompt the user when the invited MatrixId is not recognized ([#8468](https://github.com/vector-im/element-android/issues/8468)) + - The correct title and options are now displayed When a poll that was edited is ended. ([#8471](https://github.com/vector-im/element-android/issues/8471)) + - In some conditions the room shield is not refreshed correctly ([#8507](https://github.com/vector-im/element-android/issues/8507)) + - Fix crypto config fallback key sharing strategy ([#8541](https://github.com/vector-im/element-android/issues/8541)) + +Other changes +------------- + - MSC3987 implementation: the 'dont_notify' action for a push_rule is now deprecated and replaced by an empty action list. ([#8503](https://github.com/vector-im/element-android/issues/8503)) + - Update crypto rust sdk version to 0.3.10 ([#8554](https://github.com/vector-im/element-android/issues/8554)) + + Changes in Element v1.6.2 (2023-06-02) ====================================== diff --git a/TCHAP_CHANGES.md b/TCHAP_CHANGES.md index bcb4f0748b..6a81e3b8eb 100644 --- a/TCHAP_CHANGES.md +++ b/TCHAP_CHANGES.md @@ -1,3 +1,22 @@ +Changes in Tchap 2.9.3 (2023-09-14) +=================================== + +Improvements 🙌 +-------------- + - Le message d'erreur de connexion affiche un lien vers la page de status des services ([#955](https://github.com/tchapgouv/tchap-android/issues/955)) + - Rebase against Element-Android v1.6.5 ([#966](https://github.com/tchapgouv/tchap-android/issues/966)) + +Bugfixes 🐛 +---------- + - Problème d'invitation : IdentityServerUrl comporte un "/" terminal en fin d'URL qui pose problème ([#949](https://github.com/tchapgouv/tchap-android/issues/949)) + - Crash avec erreur "Max number of dynamic shortcuts exceeded" ([#964](https://github.com/tchapgouv/tchap-android/issues/964)) + - La recherche ne fonctionne pas. Le serveur d'identité n'est pas configuré ([#965](https://github.com/tchapgouv/tchap-android/issues/965)) + +Other changes +------------- + - Update appname in crash logs ([#969](https://github.com/tchapgouv/tchap-android/issues/969)) + + Changes in Tchap 2.9.2 (2023-09-01) =================================== diff --git a/build.gradle b/build.gradle index 186db39277..4aa75e62b6 100644 --- a/build.gradle +++ b/build.gradle @@ -112,16 +112,6 @@ allprojects { groups.google.group.each { includeGroup it } } } - //noinspection JcenterRepositoryObsolete - // Do not use `jcenter`, it prevents Dependabot from working properly - maven { - url 'https://jcenter.bintray.com' - content { - groups.jcenter.regex.each { includeGroupByRegex it } - groups.jcenter.group.each { includeGroup it } - } - } - maven { url 'https://s01.oss.sonatype.org/content/repositories/snapshots' content { @@ -129,7 +119,6 @@ allprojects { groups.mavenSnapshots.group.each { includeGroup it } } } - } tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { diff --git a/dependencies.gradle b/dependencies.gradle index f4d32c4894..355f5de661 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -101,7 +101,7 @@ ext.libs = [ ], element : [ 'opusencoder' : "io.element.android:opusencoder:1.1.0", - 'wysiwyg' : "io.element.android:wysiwyg:2.2.1" + 'wysiwyg' : "io.element.android:wysiwyg:2.2.2" ], squareup : [ 'moshi' : "com.squareup.moshi:moshi:$moshi", @@ -172,6 +172,7 @@ ext.libs = [ 'kluent' : "org.amshove.kluent:kluent-android:1.73", 'timberJunitRule' : "net.lachlanmckee:timber-junit-rule:1.0.1", 'junit' : "junit:junit:4.13.2", + 'robolectric' : "org.robolectric:robolectric:4.9", ] ] diff --git a/dependencies_groups.gradle b/dependencies_groups.gradle index 6292b5d231..c023eab2eb 100644 --- a/dependencies_groups.gradle +++ b/dependencies_groups.gradle @@ -115,6 +115,7 @@ ext.groups = [ 'com.linkedin.dexmaker', 'com.mapbox.mapboxsdk', 'com.nulab-inc', + 'com.otaliastudios', 'com.otaliastudios.opengl', 'com.parse.bolts', 'com.pinterest', @@ -189,6 +190,7 @@ ext.groups = [ 'org.codehaus.groovy', 'org.codehaus.mojo', 'org.codehaus.woodstox', + 'org.conscrypt', 'org.eclipse.ee4j', 'org.ec4j.core', 'org.freemarker', @@ -221,6 +223,7 @@ ext.groups = [ 'org.ow2.asm', 'org.ow2.asm', 'org.reactivestreams', + 'org.robolectric', 'org.slf4j', 'org.sonatype.oss', 'org.testng', @@ -232,18 +235,4 @@ ext.groups = [ 'xml-apis', ] ], - jcenter : [ - regex: [ - ], - group: [ - 'com.amulyakhare', - 'com.otaliastudios', - 'com.yqritc', - // https://github.com/cmelchior/realmfieldnameshelper/issues/42 - 'dk.ilios', - 'im.dlg', - 'me.dm7.barcodescanner', - 'me.gujun.android', - ] - ] ] diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40106000.txt b/fastlane/metadata/android/cs-CZ/changelogs/40106000.txt new file mode 100644 index 0000000000..797d2af0ae --- /dev/null +++ b/fastlane/metadata/android/cs-CZ/changelogs/40106000.txt @@ -0,0 +1,2 @@ +Hlavní změny v této verzi: Element Android nyní používá Crypto Rust SDK. +Úplný seznam změn: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40106010.txt b/fastlane/metadata/android/cs-CZ/changelogs/40106010.txt new file mode 100644 index 0000000000..797d2af0ae --- /dev/null +++ b/fastlane/metadata/android/cs-CZ/changelogs/40106010.txt @@ -0,0 +1,2 @@ +Hlavní změny v této verzi: Element Android nyní používá Crypto Rust SDK. +Úplný seznam změn: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/cs-CZ/changelogs/40106020.txt b/fastlane/metadata/android/cs-CZ/changelogs/40106020.txt new file mode 100644 index 0000000000..797d2af0ae --- /dev/null +++ b/fastlane/metadata/android/cs-CZ/changelogs/40106020.txt @@ -0,0 +1,2 @@ +Hlavní změny v této verzi: Element Android nyní používá Crypto Rust SDK. +Úplný seznam změn: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/de-DE/changelogs/40106000.txt b/fastlane/metadata/android/de-DE/changelogs/40106000.txt new file mode 100644 index 0000000000..80ee810eec --- /dev/null +++ b/fastlane/metadata/android/de-DE/changelogs/40106000.txt @@ -0,0 +1,2 @@ +Die wichtigsten Änderungen in dieser Version: Element Android nutzt nun das Crypto-Rust-SDK. +Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/de-DE/changelogs/40106010.txt b/fastlane/metadata/android/de-DE/changelogs/40106010.txt new file mode 100644 index 0000000000..80ee810eec --- /dev/null +++ b/fastlane/metadata/android/de-DE/changelogs/40106010.txt @@ -0,0 +1,2 @@ +Die wichtigsten Änderungen in dieser Version: Element Android nutzt nun das Crypto-Rust-SDK. +Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/de-DE/changelogs/40106020.txt b/fastlane/metadata/android/de-DE/changelogs/40106020.txt new file mode 100644 index 0000000000..80ee810eec --- /dev/null +++ b/fastlane/metadata/android/de-DE/changelogs/40106020.txt @@ -0,0 +1,2 @@ +Die wichtigsten Änderungen in dieser Version: Element Android nutzt nun das Crypto-Rust-SDK. +Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/en-US/changelogs/40106030.txt b/fastlane/metadata/android/en-US/changelogs/40106030.txt new file mode 100644 index 0000000000..badf979955 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/40106030.txt @@ -0,0 +1,2 @@ +Main changes in this version: Element Android is now using the Crypto Rust SDK. +Full changelog: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/en-US/changelogs/40106050.txt b/fastlane/metadata/android/en-US/changelogs/40106050.txt new file mode 100644 index 0000000000..49eb8e5d5e --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/40106050.txt @@ -0,0 +1,2 @@ +Main changes in this version: corrective release. +Full changelog: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/et/changelogs/40106000.txt b/fastlane/metadata/android/et/changelogs/40106000.txt new file mode 100644 index 0000000000..233a4a0cdd --- /dev/null +++ b/fastlane/metadata/android/et/changelogs/40106000.txt @@ -0,0 +1,2 @@ +Põhilised muutused selles versioonis: Element Android krüptoteekideks on nüüd Crypto Rust SDK. +Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/et/changelogs/40106010.txt b/fastlane/metadata/android/et/changelogs/40106010.txt new file mode 100644 index 0000000000..233a4a0cdd --- /dev/null +++ b/fastlane/metadata/android/et/changelogs/40106010.txt @@ -0,0 +1,2 @@ +Põhilised muutused selles versioonis: Element Android krüptoteekideks on nüüd Crypto Rust SDK. +Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/et/changelogs/40106020.txt b/fastlane/metadata/android/et/changelogs/40106020.txt new file mode 100644 index 0000000000..233a4a0cdd --- /dev/null +++ b/fastlane/metadata/android/et/changelogs/40106020.txt @@ -0,0 +1,2 @@ +Põhilised muutused selles versioonis: Element Android krüptoteekideks on nüüd Crypto Rust SDK. +Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/fa/changelogs/40106000.txt b/fastlane/metadata/android/fa/changelogs/40106000.txt new file mode 100644 index 0000000000..1482b03042 --- /dev/null +++ b/fastlane/metadata/android/fa/changelogs/40106000.txt @@ -0,0 +1,2 @@ +تغییرات عمده در این نگارش: المنت اندروید اکنون از SDK راست Crypto استفاده می‌کند. +گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/fa/changelogs/40106010.txt b/fastlane/metadata/android/fa/changelogs/40106010.txt new file mode 100644 index 0000000000..1482b03042 --- /dev/null +++ b/fastlane/metadata/android/fa/changelogs/40106010.txt @@ -0,0 +1,2 @@ +تغییرات عمده در این نگارش: المنت اندروید اکنون از SDK راست Crypto استفاده می‌کند. +گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/fa/changelogs/40106020.txt b/fastlane/metadata/android/fa/changelogs/40106020.txt new file mode 100644 index 0000000000..1482b03042 --- /dev/null +++ b/fastlane/metadata/android/fa/changelogs/40106020.txt @@ -0,0 +1,2 @@ +تغییرات عمده در این نگارش: المنت اندروید اکنون از SDK راست Crypto استفاده می‌کند. +گزارش دگرگونی کامل: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/fr-FR/changelogs/40106000.txt b/fastlane/metadata/android/fr-FR/changelogs/40106000.txt new file mode 100644 index 0000000000..7e04ed8f3c --- /dev/null +++ b/fastlane/metadata/android/fr-FR/changelogs/40106000.txt @@ -0,0 +1,2 @@ +Principaux changements pour cette version : Element Android utilise désormais le SDK cryptographique en Rust. +Intégralité des changements : https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/fr-FR/changelogs/40106010.txt b/fastlane/metadata/android/fr-FR/changelogs/40106010.txt new file mode 100644 index 0000000000..7e04ed8f3c --- /dev/null +++ b/fastlane/metadata/android/fr-FR/changelogs/40106010.txt @@ -0,0 +1,2 @@ +Principaux changements pour cette version : Element Android utilise désormais le SDK cryptographique en Rust. +Intégralité des changements : https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/fr-FR/changelogs/40106020.txt b/fastlane/metadata/android/fr-FR/changelogs/40106020.txt new file mode 100644 index 0000000000..7e04ed8f3c --- /dev/null +++ b/fastlane/metadata/android/fr-FR/changelogs/40106020.txt @@ -0,0 +1,2 @@ +Principaux changements pour cette version : Element Android utilise désormais le SDK cryptographique en Rust. +Intégralité des changements : https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/hy/short_description.txt b/fastlane/metadata/android/hy/short_description.txt new file mode 100644 index 0000000000..3b02739117 --- /dev/null +++ b/fastlane/metadata/android/hy/short_description.txt @@ -0,0 +1 @@ +Խմբային մեսինջեր - գաղտնագրված շփում, խմբային չատեր և վիդեո զանգեր diff --git a/fastlane/metadata/android/hy/title.txt b/fastlane/metadata/android/hy/title.txt new file mode 100644 index 0000000000..2f3fd83a51 --- /dev/null +++ b/fastlane/metadata/android/hy/title.txt @@ -0,0 +1 @@ +Element - Անվտանգ Մեսինջեր diff --git a/fastlane/metadata/android/id/changelogs/40106000.txt b/fastlane/metadata/android/id/changelogs/40106000.txt new file mode 100644 index 0000000000..b69e7fc7b9 --- /dev/null +++ b/fastlane/metadata/android/id/changelogs/40106000.txt @@ -0,0 +1,2 @@ +Perubahan utama dalam versi ini: Element Android sekarang menggunakan SDK Kripto Rust. +Catatan perubahan lanjutan: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/id/changelogs/40106010.txt b/fastlane/metadata/android/id/changelogs/40106010.txt new file mode 100644 index 0000000000..b69e7fc7b9 --- /dev/null +++ b/fastlane/metadata/android/id/changelogs/40106010.txt @@ -0,0 +1,2 @@ +Perubahan utama dalam versi ini: Element Android sekarang menggunakan SDK Kripto Rust. +Catatan perubahan lanjutan: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/id/changelogs/40106020.txt b/fastlane/metadata/android/id/changelogs/40106020.txt new file mode 100644 index 0000000000..b69e7fc7b9 --- /dev/null +++ b/fastlane/metadata/android/id/changelogs/40106020.txt @@ -0,0 +1,2 @@ +Perubahan utama dalam versi ini: Element Android sekarang menggunakan SDK Kripto Rust. +Catatan perubahan lanjutan: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/it-IT/changelogs/40106000.txt b/fastlane/metadata/android/it-IT/changelogs/40106000.txt new file mode 100644 index 0000000000..2e8ef554e1 --- /dev/null +++ b/fastlane/metadata/android/it-IT/changelogs/40106000.txt @@ -0,0 +1,2 @@ +Modifiche principali in questa versione: Element Android ora utilizza l'SDK Rust Crypto. +Cronologia completa: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/it-IT/changelogs/40106010.txt b/fastlane/metadata/android/it-IT/changelogs/40106010.txt new file mode 100644 index 0000000000..2e8ef554e1 --- /dev/null +++ b/fastlane/metadata/android/it-IT/changelogs/40106010.txt @@ -0,0 +1,2 @@ +Modifiche principali in questa versione: Element Android ora utilizza l'SDK Rust Crypto. +Cronologia completa: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/it-IT/changelogs/40106020.txt b/fastlane/metadata/android/it-IT/changelogs/40106020.txt new file mode 100644 index 0000000000..2e8ef554e1 --- /dev/null +++ b/fastlane/metadata/android/it-IT/changelogs/40106020.txt @@ -0,0 +1,2 @@ +Modifiche principali in questa versione: Element Android ora utilizza l'SDK Rust Crypto. +Cronologia completa: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/nb/short_description.txt b/fastlane/metadata/android/nb/short_description.txt index b7cad4c849..ebe1e02ede 100644 --- a/fastlane/metadata/android/nb/short_description.txt +++ b/fastlane/metadata/android/nb/short_description.txt @@ -1 +1 @@ -Sikker desentralisert chat & VoIP. Beskytt dataene dine fra tredjeparter. +Gruppe-meldingsapp - krypterte meldinger, gruppechat og videosamtaler diff --git a/fastlane/metadata/android/nb/title.txt b/fastlane/metadata/android/nb/title.txt index aacee5be54..fff0c3fe11 100644 --- a/fastlane/metadata/android/nb/title.txt +++ b/fastlane/metadata/android/nb/title.txt @@ -1 +1 @@ -Element (tidligere Riot.im) +Element - Sikker Meldingsapp diff --git a/fastlane/metadata/android/pl-PL/changelogs/40106000.txt b/fastlane/metadata/android/pl-PL/changelogs/40106000.txt new file mode 100644 index 0000000000..c91b48c168 --- /dev/null +++ b/fastlane/metadata/android/pl-PL/changelogs/40106000.txt @@ -0,0 +1,2 @@ +Główne zmiany w tej wersji: Element Android teraz korzysta z Crypto Rust SDK. +Pełna lista zmian: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/pl-PL/changelogs/40106010.txt b/fastlane/metadata/android/pl-PL/changelogs/40106010.txt new file mode 100644 index 0000000000..c91b48c168 --- /dev/null +++ b/fastlane/metadata/android/pl-PL/changelogs/40106010.txt @@ -0,0 +1,2 @@ +Główne zmiany w tej wersji: Element Android teraz korzysta z Crypto Rust SDK. +Pełna lista zmian: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/pl-PL/changelogs/40106020.txt b/fastlane/metadata/android/pl-PL/changelogs/40106020.txt new file mode 100644 index 0000000000..c91b48c168 --- /dev/null +++ b/fastlane/metadata/android/pl-PL/changelogs/40106020.txt @@ -0,0 +1,2 @@ +Główne zmiany w tej wersji: Element Android teraz korzysta z Crypto Rust SDK. +Pełna lista zmian: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/ru-RU/changelogs/40106020.txt b/fastlane/metadata/android/ru-RU/changelogs/40106020.txt new file mode 100644 index 0000000000..11550d3bb1 --- /dev/null +++ b/fastlane/metadata/android/ru-RU/changelogs/40106020.txt @@ -0,0 +1,2 @@ +Главные изменения этой версии: Element для Android теперь использует Crypto Rust SDK. +Полный список изменений: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/sk/changelogs/40106000.txt b/fastlane/metadata/android/sk/changelogs/40106000.txt new file mode 100644 index 0000000000..bb76d77ad5 --- /dev/null +++ b/fastlane/metadata/android/sk/changelogs/40106000.txt @@ -0,0 +1,2 @@ +Hlavné zmeny v tejto verzii: Element Android teraz používa Crypto Rust SDK. +Úplný zoznam zmien: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/sk/changelogs/40106010.txt b/fastlane/metadata/android/sk/changelogs/40106010.txt new file mode 100644 index 0000000000..bb76d77ad5 --- /dev/null +++ b/fastlane/metadata/android/sk/changelogs/40106010.txt @@ -0,0 +1,2 @@ +Hlavné zmeny v tejto verzii: Element Android teraz používa Crypto Rust SDK. +Úplný zoznam zmien: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/sk/changelogs/40106020.txt b/fastlane/metadata/android/sk/changelogs/40106020.txt new file mode 100644 index 0000000000..bb76d77ad5 --- /dev/null +++ b/fastlane/metadata/android/sk/changelogs/40106020.txt @@ -0,0 +1,2 @@ +Hlavné zmeny v tejto verzii: Element Android teraz používa Crypto Rust SDK. +Úplný zoznam zmien: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/sq/changelogs/40106000.txt b/fastlane/metadata/android/sq/changelogs/40106000.txt new file mode 100644 index 0000000000..5b8003c310 --- /dev/null +++ b/fastlane/metadata/android/sq/changelogs/40106000.txt @@ -0,0 +1,2 @@ +Ndryshimet kryesore në këtë version: Element Android tani përdor Crypto Rust SDK. +Regjistër i plotë ndryshimesh: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/sq/changelogs/40106010.txt b/fastlane/metadata/android/sq/changelogs/40106010.txt new file mode 100644 index 0000000000..0c2470c653 --- /dev/null +++ b/fastlane/metadata/android/sq/changelogs/40106010.txt @@ -0,0 +1,2 @@ +Ndryshimet kryesore në këtë version: Element Android tanimë përdor SDK Rust Fshehtëzimesh. +Regjistër i plotë ndryshimesh: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/sq/changelogs/40106020.txt b/fastlane/metadata/android/sq/changelogs/40106020.txt new file mode 100644 index 0000000000..0cb7a00683 --- /dev/null +++ b/fastlane/metadata/android/sq/changelogs/40106020.txt @@ -0,0 +1,2 @@ +Ndryshimet kryesore në këtë version: Element Android tanimë përdor SDK Rust për Kripto. +Regjistër i plotë ndryshimesh: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/sv-SE/changelogs/40106000.txt b/fastlane/metadata/android/sv-SE/changelogs/40106000.txt new file mode 100644 index 0000000000..215691cf4b --- /dev/null +++ b/fastlane/metadata/android/sv-SE/changelogs/40106000.txt @@ -0,0 +1,2 @@ +Huvudsakliga ändringar i den här versionen: Element Android använder nu Rust-krypto-SDK:t +Full ändringslogg: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/sv-SE/changelogs/40106010.txt b/fastlane/metadata/android/sv-SE/changelogs/40106010.txt new file mode 100644 index 0000000000..215691cf4b --- /dev/null +++ b/fastlane/metadata/android/sv-SE/changelogs/40106010.txt @@ -0,0 +1,2 @@ +Huvudsakliga ändringar i den här versionen: Element Android använder nu Rust-krypto-SDK:t +Full ändringslogg: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/sv-SE/changelogs/40106020.txt b/fastlane/metadata/android/sv-SE/changelogs/40106020.txt new file mode 100644 index 0000000000..215691cf4b --- /dev/null +++ b/fastlane/metadata/android/sv-SE/changelogs/40106020.txt @@ -0,0 +1,2 @@ +Huvudsakliga ändringar i den här versionen: Element Android använder nu Rust-krypto-SDK:t +Full ändringslogg: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/uk/changelogs/40106000.txt b/fastlane/metadata/android/uk/changelogs/40106000.txt new file mode 100644 index 0000000000..0066e0c597 --- /dev/null +++ b/fastlane/metadata/android/uk/changelogs/40106000.txt @@ -0,0 +1,2 @@ +Основні зміни в цій версії: Element Android тепер використовує Crypto Rust SDK. +Перелік усіх змін: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/uk/changelogs/40106010.txt b/fastlane/metadata/android/uk/changelogs/40106010.txt new file mode 100644 index 0000000000..0066e0c597 --- /dev/null +++ b/fastlane/metadata/android/uk/changelogs/40106010.txt @@ -0,0 +1,2 @@ +Основні зміни в цій версії: Element Android тепер використовує Crypto Rust SDK. +Перелік усіх змін: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/uk/changelogs/40106020.txt b/fastlane/metadata/android/uk/changelogs/40106020.txt new file mode 100644 index 0000000000..0066e0c597 --- /dev/null +++ b/fastlane/metadata/android/uk/changelogs/40106020.txt @@ -0,0 +1,2 @@ +Основні зміни в цій версії: Element Android тепер використовує Crypto Rust SDK. +Перелік усіх змін: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/vi/changelogs/40103020.txt b/fastlane/metadata/android/vi/changelogs/40103020.txt index 33a81f4a5d..d2eafcb2c6 100644 --- a/fastlane/metadata/android/vi/changelogs/40103020.txt +++ b/fastlane/metadata/android/vi/changelogs/40103020.txt @@ -1,2 +1,2 @@ -Những thay đổi chính trong phiên bản này: Thêm hỗ trợ Android Auto. Sửa rất nhiều lỗi! -Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.3.2 +Thay đổi chính trong phiên bản này: Hỗ trợ Android Auto. Sửa rất nhiều lỗi! +Toàn bộ nhật ký sửa đổi: https://github.com/vector-im/element-android/releases/tag/v1.3.2 diff --git a/fastlane/metadata/android/vi/changelogs/40103030.txt b/fastlane/metadata/android/vi/changelogs/40103030.txt index a36a3bb46d..91bab8d655 100644 --- a/fastlane/metadata/android/vi/changelogs/40103030.txt +++ b/fastlane/metadata/android/vi/changelogs/40103030.txt @@ -1,2 +1,2 @@ -Những thay đổi chính trong phiên bản này: Hiển thị (các) chính sách máy chủ xác thực trong phần cài đặt. Tạm thời bỏ hỗ trợ Android Auto. -Log thay đổi đầy đủ: https://github.com/vector-im/element-android/releases/tag/v1.3.3 +Thay đổi chính trong phiên bản này: Hiển thị (các) chính sách máy chủ định danh trong phần cài đặt. Tạm thời bỏ hỗ trợ Android Auto. +Toàn bộ nhật ký sửa đổi: https://github.com/vector-im/element-android/releases/tag/v1.3.3 diff --git a/fastlane/metadata/android/vi/changelogs/40103040.txt b/fastlane/metadata/android/vi/changelogs/40103040.txt index a1f6a8b22e..f6217c143b 100644 --- a/fastlane/metadata/android/vi/changelogs/40103040.txt +++ b/fastlane/metadata/android/vi/changelogs/40103040.txt @@ -1,2 +1,2 @@ -Những thay đổi chính trong phiên bản này: Thêm hỗ trợ hiển thị, cho phòng Tin nhắn Trực tiếp (lưu ý: hiển thị bị vô hiệu hóa trên matrix.org. Hỗ trợ Android Auto trở lại. -Nhật ký thay đổi: https://github.com/vector-im/element-android/releases/tag/v1.3.4 +Thay đổi chính trong phiên bản này: Hỗ trợ trạng thái, cho các phòng nhắn tin trực tiếp (ghi chú: trạng thái bị vô hiệu trên matrix.org). Hỗ trợ Android Auto trở lại. +Toàn bộ nhật ký sửa đổi: https://github.com/vector-im/element-android/releases/tag/v1.3.4 diff --git a/fastlane/metadata/android/vi/changelogs/40103050.txt b/fastlane/metadata/android/vi/changelogs/40103050.txt new file mode 100644 index 0000000000..64f0b89929 --- /dev/null +++ b/fastlane/metadata/android/vi/changelogs/40103050.txt @@ -0,0 +1,2 @@ +Thay đổi chính trong phiên bản này: Hỗ trợ trạng thái, cho các phòng nhắn tin trực tiếp (ghi chú: trạng thái bị vô hiệu trên matrix.org). Hỗ trợ Android Auto trở lại. +Toàn bộ nhật ký sửa đổi: https://github.com/vector-im/element-android/releases/tag/v1.3.5 diff --git a/fastlane/metadata/android/vi/changelogs/40103060.txt b/fastlane/metadata/android/vi/changelogs/40103060.txt new file mode 100644 index 0000000000..7ee925059e --- /dev/null +++ b/fastlane/metadata/android/vi/changelogs/40103060.txt @@ -0,0 +1,2 @@ +Thay đổi chính trong phiên bản này: Hỗ trợ trạng thái, cho các phòng nhắn tin trực tiếp (ghi chú: trạng thái bị vô hiệu trên matrix.org). Hỗ trợ Android Auto trở lại. +Toàn bộ nhật ký sửa đổi: https://github.com/vector-im/element-android/releases/tag/v1.3.6 diff --git a/fastlane/metadata/android/vi/changelogs/40105080.txt b/fastlane/metadata/android/vi/changelogs/40105080.txt new file mode 100644 index 0000000000..b2f91aeb98 --- /dev/null +++ b/fastlane/metadata/android/vi/changelogs/40105080.txt @@ -0,0 +1,2 @@ +Thay đổi chính trong phiên bản này: Sửa lỗi và cải thiện. +Toàn bộ nhật ký sửa đổi: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/vi/changelogs/40105100.txt b/fastlane/metadata/android/vi/changelogs/40105100.txt new file mode 100644 index 0000000000..caba6b7927 --- /dev/null +++ b/fastlane/metadata/android/vi/changelogs/40105100.txt @@ -0,0 +1,2 @@ +Thay đổi chính trong phiên bản này: Triển khai chế độ toàn màn hình mới cho trình soạn thảo văn bản phong phú và sửa lỗi. +Toàn bộ nhật ký sửa đổi: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/vi/changelogs/40105110.txt b/fastlane/metadata/android/vi/changelogs/40105110.txt new file mode 100644 index 0000000000..caba6b7927 --- /dev/null +++ b/fastlane/metadata/android/vi/changelogs/40105110.txt @@ -0,0 +1,2 @@ +Thay đổi chính trong phiên bản này: Triển khai chế độ toàn màn hình mới cho trình soạn thảo văn bản phong phú và sửa lỗi. +Toàn bộ nhật ký sửa đổi: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/vi/changelogs/40105120.txt b/fastlane/metadata/android/vi/changelogs/40105120.txt index 803f1d99bd..ef2d600e1e 100644 --- a/fastlane/metadata/android/vi/changelogs/40105120.txt +++ b/fastlane/metadata/android/vi/changelogs/40105120.txt @@ -1,2 +1,2 @@ Thay đổi chính trong phiên bản này: Chức năng chủ đề được bật theo mặc định. -Toàn bộ nhật ký thay đổi: https://github.com/vector-im/element-android/releases +Toàn bộ nhật ký sửa đổi: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/vi/changelogs/40105130.txt b/fastlane/metadata/android/vi/changelogs/40105130.txt index 803f1d99bd..ef2d600e1e 100644 --- a/fastlane/metadata/android/vi/changelogs/40105130.txt +++ b/fastlane/metadata/android/vi/changelogs/40105130.txt @@ -1,2 +1,2 @@ Thay đổi chính trong phiên bản này: Chức năng chủ đề được bật theo mặc định. -Toàn bộ nhật ký thay đổi: https://github.com/vector-im/element-android/releases +Toàn bộ nhật ký sửa đổi: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/vi/changelogs/40105140.txt b/fastlane/metadata/android/vi/changelogs/40105140.txt index 803f1d99bd..ef2d600e1e 100644 --- a/fastlane/metadata/android/vi/changelogs/40105140.txt +++ b/fastlane/metadata/android/vi/changelogs/40105140.txt @@ -1,2 +1,2 @@ Thay đổi chính trong phiên bản này: Chức năng chủ đề được bật theo mặc định. -Toàn bộ nhật ký thay đổi: https://github.com/vector-im/element-android/releases +Toàn bộ nhật ký sửa đổi: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/vi/changelogs/40105160.txt b/fastlane/metadata/android/vi/changelogs/40105160.txt index 803f1d99bd..ef2d600e1e 100644 --- a/fastlane/metadata/android/vi/changelogs/40105160.txt +++ b/fastlane/metadata/android/vi/changelogs/40105160.txt @@ -1,2 +1,2 @@ Thay đổi chính trong phiên bản này: Chức năng chủ đề được bật theo mặc định. -Toàn bộ nhật ký thay đổi: https://github.com/vector-im/element-android/releases +Toàn bộ nhật ký sửa đổi: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/vi/changelogs/40105180.txt b/fastlane/metadata/android/vi/changelogs/40105180.txt index 803f1d99bd..ef2d600e1e 100644 --- a/fastlane/metadata/android/vi/changelogs/40105180.txt +++ b/fastlane/metadata/android/vi/changelogs/40105180.txt @@ -1,2 +1,2 @@ Thay đổi chính trong phiên bản này: Chức năng chủ đề được bật theo mặc định. -Toàn bộ nhật ký thay đổi: https://github.com/vector-im/element-android/releases +Toàn bộ nhật ký sửa đổi: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/vi/changelogs/40105200.txt b/fastlane/metadata/android/vi/changelogs/40105200.txt index 4ec1289898..eda4b66d50 100644 --- a/fastlane/metadata/android/vi/changelogs/40105200.txt +++ b/fastlane/metadata/android/vi/changelogs/40105200.txt @@ -1,2 +1,2 @@ Thay đổi chính trong phiên bản này: Hầu hết là sửa lỗi. -Toàn bộ nhật ký thay đổi: https://github.com/vector-im/element-android/releases +Toàn bộ nhật ký sửa đổi: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/vi/changelogs/40105220.txt b/fastlane/metadata/android/vi/changelogs/40105220.txt index ab503fd458..881cf0601f 100644 --- a/fastlane/metadata/android/vi/changelogs/40105220.txt +++ b/fastlane/metadata/android/vi/changelogs/40105220.txt @@ -1,2 +1,2 @@ Thay đổi chính trong phiên bản này: Hầu hết là cải thiện chức năng phát thanh. -Toàn bộ nhật ký thay đổi: https://github.com/vector-im/element-android/releases +Toàn bộ nhật ký sửa đổi: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/vi/changelogs/40105240.txt b/fastlane/metadata/android/vi/changelogs/40105240.txt index 8ea7cb0c54..302e0ed184 100644 --- a/fastlane/metadata/android/vi/changelogs/40105240.txt +++ b/fastlane/metadata/android/vi/changelogs/40105240.txt @@ -1,2 +1,2 @@ Thay đổi chính trong phiên bản này: Hầu hết là sửa lỗi, cụ thể là sửa lỗi khiến cho tin nhắn không xuất hiện trên dòng thời gian. -Toàn bộ nhật ký thay đổi: https://github.com/vector-im/element-android/releases +Toàn bộ nhật ký sửa đổi: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/vi/changelogs/40105250.txt b/fastlane/metadata/android/vi/changelogs/40105250.txt index 8ea7cb0c54..302e0ed184 100644 --- a/fastlane/metadata/android/vi/changelogs/40105250.txt +++ b/fastlane/metadata/android/vi/changelogs/40105250.txt @@ -1,2 +1,2 @@ Thay đổi chính trong phiên bản này: Hầu hết là sửa lỗi, cụ thể là sửa lỗi khiến cho tin nhắn không xuất hiện trên dòng thời gian. -Toàn bộ nhật ký thay đổi: https://github.com/vector-im/element-android/releases +Toàn bộ nhật ký sửa đổi: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/vi/changelogs/40105260.txt b/fastlane/metadata/android/vi/changelogs/40105260.txt index e9ca191393..124a0f504c 100644 --- a/fastlane/metadata/android/vi/changelogs/40105260.txt +++ b/fastlane/metadata/android/vi/changelogs/40105260.txt @@ -1,2 +1,2 @@ Thay đổi chính trong phiên bản này: Chủ yếu là sửa lỗi. -Toàn bộ nhật ký thay đổi: https://github.com/vector-im/element-android/releases +Toàn bộ nhật ký sửa đổi: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/vi/changelogs/40105280.txt b/fastlane/metadata/android/vi/changelogs/40105280.txt index e9ca191393..124a0f504c 100644 --- a/fastlane/metadata/android/vi/changelogs/40105280.txt +++ b/fastlane/metadata/android/vi/changelogs/40105280.txt @@ -1,2 +1,2 @@ Thay đổi chính trong phiên bản này: Chủ yếu là sửa lỗi. -Toàn bộ nhật ký thay đổi: https://github.com/vector-im/element-android/releases +Toàn bộ nhật ký sửa đổi: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/vi/changelogs/40105300.txt b/fastlane/metadata/android/vi/changelogs/40105300.txt index 374a609262..617b41c00b 100644 --- a/fastlane/metadata/android/vi/changelogs/40105300.txt +++ b/fastlane/metadata/android/vi/changelogs/40105300.txt @@ -1,2 +1,2 @@ Thay đổi chính trong phiên bản này: Liên kết cố định tới các phòng, spaces, người dùng và tin nhắn giờ được hiển thị hình viên thuốc. Chúng tôi cũng đã sửa một số vấn đề với những nhãn dãn (sticker) tùy chỉnh và thanh đánh dấu đã đọc bị kẹt ở quá khứ. -Toàn bộ nhật ký thay đổi: https://github.com/vector-im/element-android/releases +Toàn bộ nhật ký sửa đổi: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/vi/changelogs/40105320.txt b/fastlane/metadata/android/vi/changelogs/40105320.txt index 57963d522b..d66fe4802d 100644 --- a/fastlane/metadata/android/vi/changelogs/40105320.txt +++ b/fastlane/metadata/android/vi/changelogs/40105320.txt @@ -1,2 +1,2 @@ Thay đổi chính trong phiên bản này: Chủ yếu là sửa lỗi -Toàn bộ nhật ký thay đổi: https://github.com/vector-im/element-android/releases +Toàn bộ nhật ký sửa đổi: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/vi/changelogs/40106000.txt b/fastlane/metadata/android/vi/changelogs/40106000.txt new file mode 100644 index 0000000000..08b7503d74 --- /dev/null +++ b/fastlane/metadata/android/vi/changelogs/40106000.txt @@ -0,0 +1,2 @@ +Thay đổi chính trong phiên bản này: Element Android giờ dùng công cụ phát triển phần mềm Rust cho mã hóa +Toàn bộ nhật ký sửa đổi: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/vi/changelogs/40106010.txt b/fastlane/metadata/android/vi/changelogs/40106010.txt new file mode 100644 index 0000000000..08b7503d74 --- /dev/null +++ b/fastlane/metadata/android/vi/changelogs/40106010.txt @@ -0,0 +1,2 @@ +Thay đổi chính trong phiên bản này: Element Android giờ dùng công cụ phát triển phần mềm Rust cho mã hóa +Toàn bộ nhật ký sửa đổi: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/vi/changelogs/40106020.txt b/fastlane/metadata/android/vi/changelogs/40106020.txt new file mode 100644 index 0000000000..08b7503d74 --- /dev/null +++ b/fastlane/metadata/android/vi/changelogs/40106020.txt @@ -0,0 +1,2 @@ +Thay đổi chính trong phiên bản này: Element Android giờ dùng công cụ phát triển phần mềm Rust cho mã hóa +Toàn bộ nhật ký sửa đổi: https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/vi/full_description.txt b/fastlane/metadata/android/vi/full_description.txt index 282914188b..b54e04e1c8 100644 --- a/fastlane/metadata/android/vi/full_description.txt +++ b/fastlane/metadata/android/vi/full_description.txt @@ -1,42 +1,42 @@ Element vừa là một ứng dụng nhắn tin bảo mật vừa là một ứng dụng cộng tác nhóm năng suất, lý tưởng cho các cuộc trò chuyện nhóm khi làm việc từ xa. Ứng dụng trò chuyện này sử dụng mã hóa đầu cuối để cung cấp tính năng hội thảo truyền hình, chia sẻ tệp và cuộc gọi thoại mạnh mẽ. - Các tính năng của Element bao gồm: -- Các công cụ giao tiếp trực tuyến tiên tiến +Các tính năng của Element bao gồm: +- Công cụ giao tiếp trực tuyến nâng cao - Các tin nhắn được mã hóa hoàn toàn để cho phép liên lạc doanh nghiệp an toàn hơn, ngay cả đối với những người làm việc từ xa - Trò chuyện phi tập trung dựa trên khung mã nguồn mở Matrix -- Chia sẻ tệp một cách an toàn với dữ liệu được mã hóa trong khi quản lý dự án -- Trò chuyện video với gọi thoại qua giao thức Internet (IP - VoIP) và chia sẻ màn hình +- Chia sẻ tệp bảo mật với dữ liệu được mã hóa trong khi quản lý dự án +- Trò chuyện video với gọi thoại qua giao thức Internet (VoIP) và chia sẻ màn hình - Tích hợp dễ dàng với các công cụ cộng tác trực tuyến yêu thích của bạn, công cụ quản lý dự án, dịch vụ VoIP và các ứng dụng nhắn tin nhóm khác -Element hoàn toàn khác với các ứng dụng nhắn tin và cộng tác khác. Hoạt động trên Matrix, một mạng mở để nhắn tin bảo mật và giao tiếp phi tập trung. Đồng thời, cho phép tự lưu trữ để cung cấp cho người dùng quyền sở hữu và kiểm soát tối đa dữ liệu và tin nhắn của họ. +Element hoàn toàn khác với các ứng dụng nhắn tin và cộng tác khác. Hoạt động trên Matrix, một mạng mở để nhắn tin bảo mật và giao tiếp phi tập trung. Đồng thời, cho phép tự vận hành để cung cấp cho người dùng quyền sở hữu và kiểm soát tối đa dữ liệu và tin nhắn của họ. - Nhắn tin mã hóa và riêng tư -Element bảo vệ bạn khỏi các quảng cáo không mong muốn, khai thác dữ liệu và kiểm soát khu vực. Element cũng bảo mật tất cả dữ liệu của bạn, video 1-1 và giao tiếp thoại thông qua mã hóa đầu cuối và xác minh thiết bị có chữ ký chéo. +Nhắn tin mã hóa và riêng tư +Element bảo vệ bạn khỏi các quảng cáo không mong muốn, khai thác dữ liệu và kiểm soát khu vực. Element cũng bảo mật tất cả dữ liệu của bạn, truyền hình 1-1 và giao tiếp thoại thông qua mã hóa đầu cuối và xác thực chéo thiết bị. -Element cung cấp cho bạn quyền kiểm soát quyền riêng tư của mình đồng thời cho phép bạn giao tiếp an toàn với bất kỳ ai trên mạng Matrix hoặc các công cụ cộng tác kinh doanh khác bằng cách tích hợp với các ứng dụng như Slack. +Element cung cấp cho bạn quyền kiểm soát quyền riêng tư của mình đồng thời cho phép bạn giao tiếp bảo mật với bất kỳ ai trên mạng Matrix hoặc các công cụ cộng tác kinh doanh khác bằng cách tích hợp với các ứng dụng như Slack. - Element có thể được tự lưu trữ -Để cho phép kiểm soát nhiều hơn dữ liệu nhạy cảm và các cuộc trò chuyện của bạn, Element có thể được tự lưu trữ hoặc bạn có thể chọn bất kỳ máy chủ Matrix nào - tiêu chuẩn cho giao tiếp phi tập trung, mã nguồn mở. Element cung cấp cho bạn quyền riêng tư, tuân thủ bảo mật và tính linh hoạt trong tích hợp. +Element có thể được tự vận hành +Để cho phép kiểm soát nhiều hơn dữ liệu nhạy cảm và các cuộc trò chuyện của bạn, Element có thể được tự vận hành hoặc bạn có thể chọn bất kỳ máy chủ Matrix nào - tiêu chuẩn cho giao tiếp phi tập trung, mã nguồn mở. Element cung cấp cho bạn quyền riêng tư, tuân thủ bảo mật và tính linh hoạt trong tích hợp. - Sở hữu dữ liệu của bạn -Bạn quyết định nơi lưu giữ dữ liệu và tin nhắn của mình. Không có rủi ro khai thác dữ liệu hoặc truy cập từ bên thứ ba. +Sở hữu dữ liệu của bạn +Bạn quyết định nơi lưu trữ dữ liệu và tin nhắn của mình. Không có rủi ro khai thác dữ liệu hoặc truy cập từ bên thứ ba. Element giúp bạn kiểm soát theo những cách khác nhau: -1. Tạo một tài khoản miễn phí trên máy chủ công cộng matrix.org do các nhà phát triển Matrix vận hành hoặc chọn từ hàng nghìn máy chủ công cộng do các tình nguyện viên lưu trữ +1. Tạo một tài khoản miễn phí trên máy chủ công cộng matrix.org do các nhà phát triển Matrix vận hành hoặc chọn từ hàng nghìn máy chủ công cộng do các tình nguyện viên vận hành 2. Tự lưu trữ tài khoản của bạn bằng cách chạy một máy chủ trên cơ sở hạ tầng CNTT của riêng bạn 3. Đăng ký tài khoản trên máy chủ tùy chỉnh bằng cách chỉ cần đăng ký nền tảng Element Matrix Services hosting - Nhắn tin và cộng tác mở +Nhắn tin và cộng tác mở Bạn có thể trò chuyện với bất kỳ ai trên mạng Matrix, cho dù họ đang sử dụng Element, một ứng dụng Matrix khác hay ngay cả khi họ đang sử dụng một ứng dụng nhắn tin khác. - Siêu bảo mật -Mã hóa đầu-cuối thực (chỉ những người trong cuộc trò chuyện mới có thể giải mã tin nhắn) và xác minh thiết bị xác thực chéo. +Siêu bảo mật +Mã hóa đầu-cuối có thực (chỉ những người trong cuộc trò chuyện mới có thể giải mã tin nhắn) và xác thực chéo thiết bị. - Giao tiếp và tích hợp hoàn chỉnh -Nhắn tin, cuộc gọi thoại và video, chia sẻ tệp, chia sẻ màn hình và một loạt các tích hợp, bot và widget. Xây dựng phòng, cộng đồng, giữ liên lạc và hoàn thành công việc. +Giao tiếp và tích hợp hoàn chỉnh +Nhắn tin, gọi thoại và truyền hình, chia sẻ tệp, chia sẻ màn hình và một loạt các tích hợp, bot và widget. Tạo phòng, cộng đồng, giữ liên lạc và hoàn thành công việc. - Tiếp tục nơi bạn đã dừng lại +Tiếp tục nơi bạn đã dừng lạ Giữ liên lạc mọi lúc mọi nơi với lịch sử tin nhắn được đồng bộ hóa hoàn toàn trên tất cả các thiết bị của bạn và trên web tại https://app.element.io - Mã nguồn mở -Element Android là một dự án mã nguồn mở, được lưu trữ trên GitHub. Vui lòng báo cáo lỗi và / hoặc đóng góp phát triển tại https://github.com/vector-im/element-android +Mã nguồn mở +Element Android là một dự án mã nguồn mở, được lưu trữ trên GitHub. Vui lòng báo cáo lỗi và / hoặc đóng góp, phát triển tại https://github.com/vector-im/element-android diff --git a/fastlane/metadata/android/zh-TW/changelogs/40106000.txt b/fastlane/metadata/android/zh-TW/changelogs/40106000.txt new file mode 100644 index 0000000000..0ee6434a8d --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/40106000.txt @@ -0,0 +1,2 @@ +此版本的主要變更:現在起,Element Android 使用 Crypto Rust SDK。 +完整異動:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/zh-TW/changelogs/40106010.txt b/fastlane/metadata/android/zh-TW/changelogs/40106010.txt new file mode 100644 index 0000000000..0ee6434a8d --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/40106010.txt @@ -0,0 +1,2 @@ +此版本的主要變更:現在起,Element Android 使用 Crypto Rust SDK。 +完整異動:https://github.com/vector-im/element-android/releases diff --git a/fastlane/metadata/android/zh-TW/changelogs/40106020.txt b/fastlane/metadata/android/zh-TW/changelogs/40106020.txt new file mode 100644 index 0000000000..0ee6434a8d --- /dev/null +++ b/fastlane/metadata/android/zh-TW/changelogs/40106020.txt @@ -0,0 +1,2 @@ +此版本的主要變更:現在起,Element Android 使用 Crypto Rust SDK。 +完整異動:https://github.com/vector-im/element-android/releases diff --git a/library/external/autocomplete/build.gradle b/library/external/autocomplete/build.gradle new file mode 100644 index 0000000000..39d4d4b19e --- /dev/null +++ b/library/external/autocomplete/build.gradle @@ -0,0 +1,32 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + +android { + namespace "com.otaliastudios.autocomplete" + + compileSdk versions.compileSdk + + defaultConfig { + minSdk versions.minSdk + targetSdk versions.targetSdk + } + + compileOptions { + sourceCompatibility versions.sourceCompat + targetCompatibility versions.targetCompat + } + + kotlinOptions { + jvmTarget = "11" + } +} + +dependencies { + implementation libs.androidx.recyclerview +} + +afterEvaluate { + tasks.findAll { it.name.startsWith("lint") }.each { + it.enabled = false + } +} diff --git a/library/external/autocomplete/src/main/java/com/otaliastudios/autocomplete/Autocomplete.java b/library/external/autocomplete/src/main/java/com/otaliastudios/autocomplete/Autocomplete.java new file mode 100644 index 0000000000..cf58146f14 --- /dev/null +++ b/library/external/autocomplete/src/main/java/com/otaliastudios/autocomplete/Autocomplete.java @@ -0,0 +1,434 @@ +package com.otaliastudios.autocomplete; + +import android.database.DataSetObserver; +import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.os.Looper; +import android.text.Editable; +import android.text.Selection; +import android.text.SpanWatcher; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.TextWatcher; +import android.util.Log; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.Window; +import android.view.WindowManager; +import android.widget.EditText; +import android.widget.PopupWindow; + +import androidx.annotation.NonNull; + + +/** + * Entry point for adding Autocomplete behavior to a {@link EditText}. + * + * You can construct a {@code Autocomplete} using the builder provided by {@link Autocomplete#on(EditText)}. + * Building is enough, but you can hold a reference to this class to call its public methods. + * + * Requires: + * - {@link EditText}: this is both the anchor for the popup, and the source of text events that we listen to + * - {@link AutocompletePresenter}: this presents items in the popup window. See class for more info. + * - {@link AutocompleteCallback}: if specified, this listens to click events and visibility changes + * - {@link AutocompletePolicy}: if specified, this controls how and when to show the popup based on text events + * If not, this defaults to {@link SimplePolicy}: shows the popup when text.length() bigger than 0. + */ +public final class Autocomplete implements TextWatcher, SpanWatcher { + + private final static String TAG = Autocomplete.class.getSimpleName(); + private final static boolean DEBUG = false; + + private static void log(String log) { + if (DEBUG) Log.e(TAG, log); + } + + /** + * Builder for building {@link Autocomplete}. + * The only mandatory item is a presenter, {@link #with(AutocompletePresenter)}. + * + * @param the data model + */ + public final static class Builder { + private EditText source; + private AutocompletePresenter presenter; + private AutocompletePolicy policy; + private AutocompleteCallback callback; + private Drawable backgroundDrawable; + private float elevationDp = 6; + + private Builder(EditText source) { + this.source = source; + } + + /** + * Registers the {@link AutocompletePresenter} to be used, responsible for showing + * items. See the class for info. + * + * @param presenter desired presenter + * @return this for chaining + */ + public Builder with(AutocompletePresenter presenter) { + this.presenter = presenter; + return this; + } + + /** + * Registers the {@link AutocompleteCallback} to be used, responsible for listening to + * clicks provided by the presenter, and visibility changes. + * + * @param callback desired callback + * @return this for chaining + */ + public Builder with(AutocompleteCallback callback) { + this.callback = callback; + return this; + } + + /** + * Registers the {@link AutocompletePolicy} to be used, responsible for showing / dismissing + * the popup when certain events happen (e.g. certain characters are typed). + * + * @param policy desired policy + * @return this for chaining + */ + public Builder with(AutocompletePolicy policy) { + this.policy = policy; + return this; + } + + /** + * Sets a background drawable for the popup. + * + * @param backgroundDrawable drawable + * @return this for chaining + */ + public Builder with(Drawable backgroundDrawable) { + this.backgroundDrawable = backgroundDrawable; + return this; + } + + /** + * Sets elevation for the popup. Defaults to 6 dp. + * + * @param elevationDp popup elevation, in DP + * @return this for chaning. + */ + public Builder with(float elevationDp) { + this.elevationDp = elevationDp; + return this; + } + + /** + * Builds an Autocomplete instance. This is enough for autocomplete to be set up, + * but you can hold a reference to the object and call its public methods. + * + * @return an Autocomplete instance, if you need it + * + * @throws RuntimeException if either EditText or the presenter are null + */ + public Autocomplete build() { + if (source == null) throw new RuntimeException("Autocomplete needs a source!"); + if (presenter == null) throw new RuntimeException("Autocomplete needs a presenter!"); + if (policy == null) policy = new SimplePolicy(); + return new Autocomplete(this); + } + + private void clear() { + source = null; + presenter = null; + callback = null; + policy = null; + backgroundDrawable = null; + elevationDp = 6; + } + } + + /** + * Entry point for building autocomplete on a certain {@link EditText}. + * @param anchor the anchor for the popup, and the source of text events + * @param your data model + * @return a Builder for set up + */ + public static Builder on(EditText anchor) { + return new Builder(anchor); + } + + private AutocompletePolicy policy; + private AutocompletePopup popup; + private AutocompletePresenter presenter; + private AutocompleteCallback callback; + private EditText source; + + private boolean block; + private boolean disabled; + private boolean openBefore; + private String lastQuery = "null"; + + private Autocomplete(Builder builder) { + policy = builder.policy; + presenter = builder.presenter; + callback = builder.callback; + source = builder.source; + + // Set up popup + popup = new AutocompletePopup(source.getContext()); + popup.setAnchorView(source); + popup.setGravity(Gravity.START); + popup.setModal(false); + popup.setBackgroundDrawable(builder.backgroundDrawable); + popup.setElevation(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, builder.elevationDp, + source.getContext().getResources().getDisplayMetrics())); + + // popup dimensions + AutocompletePresenter.PopupDimensions dim = this.presenter.getPopupDimensions(); + popup.setWidth(dim.width); + popup.setHeight(dim.height); + popup.setMaxWidth(dim.maxWidth); + popup.setMaxHeight(dim.maxHeight); + + // Fire visibility events + popup.setOnDismissListener(new PopupWindow.OnDismissListener() { + @Override + public void onDismiss() { + lastQuery = "null"; + if (callback != null) callback.onPopupVisibilityChanged(false); + boolean saved = block; + block = true; + policy.onDismiss(source.getText()); + block = saved; + presenter.hideView(); + } + }); + + // Set up source + source.getText().setSpan(this, 0, source.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); + source.addTextChangedListener(this); + + // Set up presenter + presenter.registerClickProvider(new AutocompletePresenter.ClickProvider() { + @Override + public void click(@NonNull T item) { + AutocompleteCallback callback = Autocomplete.this.callback; + EditText edit = Autocomplete.this.source; + if (callback == null) return; + boolean saved = block; + block = true; + boolean dismiss = callback.onPopupItemClicked(edit.getText(), item); + if (dismiss) dismissPopup(); + block = saved; + } + }); + + builder.clear(); + } + + /** + * Controls how the popup operates with an input method. + * + * If the popup is showing, calling this method will take effect only + * the next time the popup is shown. + * + * @param mode a {@link PopupWindow} input method mode + */ + public void setInputMethodMode(int mode) { + popup.setInputMethodMode(mode); + } + + /** + * Sets the operating mode for the soft input area. + * + * @param mode The desired mode, see {@link WindowManager.LayoutParams#softInputMode} + */ + public void setSoftInputMode(int mode) { + popup.setSoftInputMode(mode); + } + + /** + * Shows the popup with the given query. + * There is rarely need to call this externally: it is already triggered by events on the anchor. + * To control when this is called, provide a good implementation of {@link AutocompletePolicy}. + * + * @param query query text. + */ + public void showPopup(@NonNull CharSequence query) { + if (isPopupShowing() && lastQuery.equals(query.toString())) return; + lastQuery = query.toString(); + + log("showPopup: called with filter "+query); + if (!isPopupShowing()) { + log("showPopup: showing"); + presenter.registerDataSetObserver(new Observer()); // Calling new to avoid leaking... maybe... + popup.setView(presenter.getView()); + presenter.showView(); + popup.show(); + if (callback != null) callback.onPopupVisibilityChanged(true); + } + log("showPopup: popup should be showing... "+isPopupShowing()); + presenter.onQuery(query); + } + + /** + * Dismisses the popup, if showing. + * There is rarely need to call this externally: it is already triggered by events on the anchor. + * To control when this is called, provide a good implementation of {@link AutocompletePolicy}. + */ + public void dismissPopup() { + if (isPopupShowing()) { + popup.dismiss(); + } + } + + /** + * Returns true if the popup is showing. + * @return whether the popup is currently showing + */ + public boolean isPopupShowing() { + return this.popup.isShowing(); + } + + /** + * Switch to control the autocomplete behavior. When disabled, no popup is shown. + * This is useful if you want to do runtime edits to the anchor text, without triggering + * the popup. + * + * @param enabled whether to enable autocompletion + */ + public void setEnabled(boolean enabled) { + disabled = !enabled; + } + + /** + * Sets the gravity for the popup. Basically only {@link Gravity#START} and {@link Gravity#END} + * do work. + * + * @param gravity gravity for the popup + */ + public void setGravity(int gravity) { + popup.setGravity(gravity); + } + + /** + * Controls the vertical offset of the popup from the EditText anchor. + * + * @param offset offset in pixels. + */ + public void setOffsetFromAnchor(int offset) { popup.setVerticalOffset(offset); } + + /** + * Controls whether the popup should listen to clicks outside its boundaries. + * + * @param outsideTouchable true to listen to outside clicks + */ + public void setOutsideTouchable(boolean outsideTouchable) { popup.setOutsideTouchable(outsideTouchable); } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + if (block || disabled) return; + openBefore = isPopupShowing(); + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + if (block || disabled) return; + if (openBefore && !isPopupShowing()) { + return; // Copied from somewhere. + } + if (!(s instanceof Spannable)) { + source.setText(new SpannableString(s)); + return; + } + Spannable sp = (Spannable) s; + + int cursor = source.getSelectionEnd(); + log("onTextChanged: cursor end position is "+cursor); + if (cursor == -1) { // No cursor present. + dismissPopup(); return; + } + if (cursor != source.getSelectionStart()) { + // Not sure about this. We should have no problems dealing with multi selections, + // we just take the end... + // dismissPopup(); return; + } + + boolean b = block; + block = true; // policy might add spans or other stuff. + if (isPopupShowing() && policy.shouldDismissPopup(sp, cursor)) { + log("onTextChanged: dismissing"); + dismissPopup(); + } else if (isPopupShowing() || policy.shouldShowPopup(sp, cursor)) { + // LOG.now("onTextChanged: updating with filter "+policy.getQuery(sp)); + showPopup(policy.getQuery(sp)); + } + block = b; + } + + @Override + public void afterTextChanged(Editable s) {} + + @Override + public void onSpanAdded(Spannable text, Object what, int start, int end) {} + + @Override + public void onSpanRemoved(Spannable text, Object what, int start, int end) {} + + @Override + public void onSpanChanged(Spannable text, Object what, int ostart, int oend, int nstart, int nend) { + if (disabled || block) return; + if (what == Selection.SELECTION_END) { + // Selection end changed from ostart to nstart. Trigger a check. + log("onSpanChanged: selection end moved from "+ostart+" to "+nstart); + log("onSpanChanged: block is "+block); + boolean b = block; + block = true; + if (!isPopupShowing() && policy.shouldShowPopup(text, nstart)) { + showPopup(policy.getQuery(text)); + } + block = b; + } + } + + private class Observer extends DataSetObserver implements Runnable { + private Handler ui = new Handler(Looper.getMainLooper()); + + @Override + public void onChanged() { + // ??? Not sure this is needed... + ui.post(this); + } + + @Override + public void run() { + if (isPopupShowing()) { + // Call show again to revisit width and height. + popup.show(); + } + } + } + + /** + * A very simple {@link AutocompletePolicy} implementation. + * Popup is shown when text length is bigger than 0, and hidden when text is empty. + * The query string is the whole text. + */ + public static class SimplePolicy implements AutocompletePolicy { + @Override + public boolean shouldShowPopup(@NonNull Spannable text, int cursorPos) { + return text.length() > 0; + } + + @Override + public boolean shouldDismissPopup(@NonNull Spannable text, int cursorPos) { + return text.length() == 0; + } + + @NonNull + @Override + public CharSequence getQuery(@NonNull Spannable text) { + return text; + } + + @Override + public void onDismiss(@NonNull Spannable text) {} + } +} diff --git a/library/external/autocomplete/src/main/java/com/otaliastudios/autocomplete/AutocompleteCallback.java b/library/external/autocomplete/src/main/java/com/otaliastudios/autocomplete/AutocompleteCallback.java new file mode 100644 index 0000000000..56870db610 --- /dev/null +++ b/library/external/autocomplete/src/main/java/com/otaliastudios/autocomplete/AutocompleteCallback.java @@ -0,0 +1,29 @@ +package com.otaliastudios.autocomplete; + +import android.text.Editable; + +import androidx.annotation.NonNull; + +/** + * Optional callback to be passed to {@link Autocomplete.Builder}. + */ +public interface AutocompleteCallback { + + /** + * Called when an item inside your list is clicked. + * This works if your presenter has dispatched a click event. + * At this point you can edit the text, e.g. {@code editable.append(item.toString())}. + * + * @param editable editable text that you can work on + * @param item item that was clicked + * @return true if the action is valid and the popup can be dismissed + */ + boolean onPopupItemClicked(@NonNull Editable editable, @NonNull T item); + + /** + * Called when popup visibility state changes. + * + * @param shown true if the popup was just shown, false if it was just hidden + */ + void onPopupVisibilityChanged(boolean shown); +} diff --git a/library/external/autocomplete/src/main/java/com/otaliastudios/autocomplete/AutocompletePolicy.java b/library/external/autocomplete/src/main/java/com/otaliastudios/autocomplete/AutocompletePolicy.java new file mode 100644 index 0000000000..05dfaa9f0a --- /dev/null +++ b/library/external/autocomplete/src/main/java/com/otaliastudios/autocomplete/AutocompletePolicy.java @@ -0,0 +1,64 @@ +package com.otaliastudios.autocomplete; + +import android.text.Spannable; + +import androidx.annotation.NonNull; + +/** + * This interface controls when to show or hide the popup window, and, in the first case, + * what text should be passed to the popup {@link AutocompletePresenter}. + * + * @see Autocomplete.SimplePolicy for the simplest possible implementation + */ +public interface AutocompletePolicy { + + /** + * Called to understand whether the popup should be shown. Some naive examples: + * - Show when there's text: {@code return text.length() > 0} + * - Show when last char is @: {@code return text.getCharAt(text.length()-1) == '@'} + * + * @param text current text, along with its Spans + * @param cursorPos the position of the cursor + * @return true if popup should be shown + */ + boolean shouldShowPopup(@NonNull Spannable text, int cursorPos); + + /** + * Called to understand whether a currently shown popup should be closed, maybe + * because text is invalid. A reasonable implementation is + * {@code return !shouldShowPopup(text, cursorPos)}. + * + * However this is defined so you can add or clear spans. + * + * @param text current text, along with its Spans + * @param cursorPos the position of the cursor + * @return true if popup should be hidden + */ + boolean shouldDismissPopup(@NonNull Spannable text, int cursorPos); + + /** + * Called to understand which query should be passed to {@link AutocompletePresenter} + * for a showing popup. If this is called, {@link #shouldShowPopup(Spannable, int)} just returned + * true, or {@link #shouldDismissPopup(Spannable, int)} just returned false. + * + * This is useful to understand which part of the text should be passed to presenters. + * For example, user might have typed '@john' to select a username, but you just want to + * search for 'john'. + * + * For more complex cases, you can add inclusive Spans in {@link #shouldShowPopup(Spannable, int)}, + * and get the span position here. + * + * @param text current text, along with its Spans + * @return the query for presenter + */ + @NonNull + CharSequence getQuery(@NonNull Spannable text); + + /** + * Called when popup is dismissed. This can be used, for instance, to clear custom Spans + * from the text. + * + * @param text text at the moment of dismissing + */ + void onDismiss(@NonNull Spannable text); +} diff --git a/library/external/autocomplete/src/main/java/com/otaliastudios/autocomplete/AutocompletePopup.java b/library/external/autocomplete/src/main/java/com/otaliastudios/autocomplete/AutocompletePopup.java new file mode 100644 index 0000000000..6467085068 --- /dev/null +++ b/library/external/autocomplete/src/main/java/com/otaliastudios/autocomplete/AutocompletePopup.java @@ -0,0 +1,521 @@ +package com.otaliastudios.autocomplete; + +import android.content.Context; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.PopupWindow; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StyleRes; +import androidx.core.view.ViewCompat; +import androidx.core.widget.PopupWindowCompat; + +/** + * A simplified version of andriod.widget.ListPopupWindow, which is the class used by + * AutocompleteTextView. + * + * Other than being simplified, this deals with Views rather than ListViews, so the content + * can be whatever. Lots of logic (clicks, selections etc.) has been removed because we manage that + * in {@link AutocompletePresenter}. + * + */ +class AutocompletePopup { + private Context mContext; + private ViewGroup mView; + private int mHeight = ViewGroup.LayoutParams.WRAP_CONTENT; + private int mWidth = ViewGroup.LayoutParams.WRAP_CONTENT; + private int mMaxHeight = Integer.MAX_VALUE; + private int mMaxWidth = Integer.MAX_VALUE; + private int mUserMaxHeight = Integer.MAX_VALUE; + private int mUserMaxWidth = Integer.MAX_VALUE; + private int mHorizontalOffset = 0; + private int mVerticalOffset = 0; + private boolean mVerticalOffsetSet; + private int mGravity = Gravity.NO_GRAVITY; + private boolean mAlwaysVisible = false; + private boolean mOutsideTouchable = true; + private View mAnchorView; + private final Rect mTempRect = new Rect(); + private boolean mModal; + private PopupWindow mPopup; + + + /** + * Create a new, empty popup window capable of displaying items from a ListAdapter. + * Backgrounds should be set using {@link #setBackgroundDrawable(Drawable)}. + * + * @param context Context used for contained views. + */ + AutocompletePopup(@NonNull Context context) { + super(); + mContext = context; + mPopup = new PopupWindow(context); + mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED); + } + + + /** + * Set whether this window should be modal when shown. + * + *

If a popup window is modal, it will receive all touch and key input. + * If the user touches outside the popup window's content area the popup window + * will be dismissed. + * @param modal {@code true} if the popup window should be modal, {@code false} otherwise. + */ + @SuppressWarnings("SameParameterValue") + void setModal(boolean modal) { + mModal = modal; + mPopup.setFocusable(modal); + } + + /** + * Returns whether the popup window will be modal when shown. + * @return {@code true} if the popup window will be modal, {@code false} otherwise. + */ + @SuppressWarnings("unused") + boolean isModal() { + return mModal; + } + + void setElevation(float elevationPx) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) mPopup.setElevation(elevationPx); + } + + /** + * Sets whether the drop-down should remain visible under certain conditions. + * + * The drop-down will occupy the entire screen below {@link #getAnchorView} regardless + * of the size or content of the list. {@link #getBackground()} will fill any space + * that is not used by the list. + * @param dropDownAlwaysVisible Whether to keep the drop-down visible. + * + */ + @SuppressWarnings("unused") + void setDropDownAlwaysVisible(boolean dropDownAlwaysVisible) { + mAlwaysVisible = dropDownAlwaysVisible; + } + + /** + * @return Whether the drop-down is visible under special conditions. + */ + @SuppressWarnings("unused") + boolean isDropDownAlwaysVisible() { + return mAlwaysVisible; + } + + void setOutsideTouchable(boolean outsideTouchable) { + mOutsideTouchable = outsideTouchable; + } + + @SuppressWarnings("WeakerAccess") + boolean isOutsideTouchable() { + return mOutsideTouchable && !mAlwaysVisible; + } + + /** + * Sets the operating mode for the soft input area. + * @param mode The desired mode, see + * {@link android.view.WindowManager.LayoutParams#softInputMode} + * for the full list + * @see android.view.WindowManager.LayoutParams#softInputMode + * @see #getSoftInputMode() + */ + void setSoftInputMode(int mode) { + mPopup.setSoftInputMode(mode); + } + + /** + * Returns the current value in {@link #setSoftInputMode(int)}. + * @see #setSoftInputMode(int) + * @see android.view.WindowManager.LayoutParams#softInputMode + */ + @SuppressWarnings({"WeakerAccess", "unused"}) + int getSoftInputMode() { + return mPopup.getSoftInputMode(); + } + + /** + * @return The background drawable for the popup window. + */ + @SuppressWarnings({"WeakerAccess", "unused"}) + @Nullable + Drawable getBackground() { + return mPopup.getBackground(); + } + + /** + * Sets a drawable to be the background for the popup window. + * @param d A drawable to set as the background. + */ + void setBackgroundDrawable(@Nullable Drawable d) { + mPopup.setBackgroundDrawable(d); + } + + /** + * Set an animation style to use when the popup window is shown or dismissed. + * @param animationStyle Animation style to use. + */ + @SuppressWarnings("unused") + void setAnimationStyle(@StyleRes int animationStyle) { + mPopup.setAnimationStyle(animationStyle); + } + + /** + * Returns the animation style that will be used when the popup window is + * shown or dismissed. + * @return Animation style that will be used. + */ + @SuppressWarnings("unused") + @StyleRes + int getAnimationStyle() { + return mPopup.getAnimationStyle(); + } + + /** + * Returns the view that will be used to anchor this popup. + * @return The popup's anchor view + */ + @SuppressWarnings("WeakerAccess") + View getAnchorView() { + return mAnchorView; + } + + /** + * Sets the popup's anchor view. This popup will always be positioned relative to + * the anchor view when shown. + * @param anchor The view to use as an anchor. + */ + void setAnchorView(@NonNull View anchor) { + mAnchorView = anchor; + } + + /** + * Set the horizontal offset of this popup from its anchor view in pixels. + * @param offset The horizontal offset of the popup from its anchor. + */ + @SuppressWarnings("unused") + void setHorizontalOffset(int offset) { + mHorizontalOffset = offset; + } + + /** + * Set the vertical offset of this popup from its anchor view in pixels. + * @param offset The vertical offset of the popup from its anchor. + */ + void setVerticalOffset(int offset) { + mVerticalOffset = offset; + mVerticalOffsetSet = true; + } + + /** + * Set the gravity of the dropdown list. This is commonly used to + * set gravity to START or END for alignment with the anchor. + * @param gravity Gravity value to use + */ + void setGravity(int gravity) { + mGravity = gravity; + } + + /** + * @return The width of the popup window in pixels. + */ + @SuppressWarnings("unused") + int getWidth() { + return mWidth; + } + + /** + * Sets the width of the popup window in pixels. Can also be MATCH_PARENT + * or WRAP_CONTENT. + * @param width Width of the popup window. + */ + void setWidth(int width) { + mWidth = width; + } + + /** + * Sets the width of the popup window by the size of its content. The final width may be + * larger to accommodate styled window dressing. + * @param width Desired width of content in pixels. + */ + @SuppressWarnings("unused") + void setContentWidth(int width) { + Drawable popupBackground = mPopup.getBackground(); + if (popupBackground != null) { + popupBackground.getPadding(mTempRect); + width += mTempRect.left + mTempRect.right; + } + setWidth(width); + } + + void setMaxWidth(int width) { + if (width > 0) { + mUserMaxWidth = width; + } + } + + /** + * @return The height of the popup window in pixels. + */ + @SuppressWarnings("unused") + int getHeight() { + return mHeight; + } + + /** + * Sets the height of the popup window in pixels. Can also be MATCH_PARENT. + * @param height Height of the popup window. + */ + void setHeight(int height) { + mHeight = height; + } + + /** + * Sets the height of the popup window by the size of its content. The final height may be + * larger to accommodate styled window dressing. + * @param height Desired height of content in pixels. + */ + @SuppressWarnings("unused") + void setContentHeight(int height) { + Drawable popupBackground = mPopup.getBackground(); + if (popupBackground != null) { + popupBackground.getPadding(mTempRect); + height += mTempRect.top + mTempRect.bottom; + } + setHeight(height); + } + + void setMaxHeight(int height) { + if (height > 0) { + mUserMaxHeight = height; + } + } + + void setOnDismissListener(PopupWindow.OnDismissListener listener) { + mPopup.setOnDismissListener(listener); + } + + /** + * Show the popup list. If the list is already showing, this method + * will recalculate the popup's size and position. + */ + void show() { + if (!ViewCompat.isAttachedToWindow(getAnchorView())) return; + + int height = buildDropDown(); + final boolean noInputMethod = isInputMethodNotNeeded(); + int mDropDownWindowLayoutType = WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL; + PopupWindowCompat.setWindowLayoutType(mPopup, mDropDownWindowLayoutType); + + if (mPopup.isShowing()) { + // First pass for this special case, don't know why. + if (mHeight == ViewGroup.LayoutParams.MATCH_PARENT) { + int tempWidth = mWidth == ViewGroup.LayoutParams.MATCH_PARENT ? ViewGroup.LayoutParams.MATCH_PARENT : 0; + if (noInputMethod) { + mPopup.setWidth(tempWidth); + mPopup.setHeight(0); + } else { + mPopup.setWidth(tempWidth); + mPopup.setHeight(ViewGroup.LayoutParams.MATCH_PARENT); + } + } + + // The call to PopupWindow's update method below can accept -1 + // for any value you do not want to update. + + // Width. + int widthSpec; + if (mWidth == ViewGroup.LayoutParams.MATCH_PARENT) { + widthSpec = -1; + } else if (mWidth == ViewGroup.LayoutParams.WRAP_CONTENT) { + widthSpec = getAnchorView().getWidth(); + } else { + widthSpec = mWidth; + } + widthSpec = Math.min(widthSpec, mMaxWidth); + widthSpec = (widthSpec < 0) ? - 1 : widthSpec; + + // Height. + int heightSpec; + if (mHeight == ViewGroup.LayoutParams.MATCH_PARENT) { + heightSpec = noInputMethod ? height : ViewGroup.LayoutParams.MATCH_PARENT; + } else if (mHeight == ViewGroup.LayoutParams.WRAP_CONTENT) { + heightSpec = height; + } else { + heightSpec = mHeight; + } + heightSpec = Math.min(heightSpec, mMaxHeight); + heightSpec = (heightSpec < 0) ? - 1 : heightSpec; + + // Update. + mPopup.setOutsideTouchable(isOutsideTouchable()); + if (heightSpec == 0) { + dismiss(); + } else { + mPopup.update(getAnchorView(), mHorizontalOffset, mVerticalOffset, widthSpec, heightSpec); + } + + } else { + int widthSpec; + if (mWidth == ViewGroup.LayoutParams.MATCH_PARENT) { + widthSpec = ViewGroup.LayoutParams.MATCH_PARENT; + } else if (mWidth == ViewGroup.LayoutParams.WRAP_CONTENT) { + widthSpec = getAnchorView().getWidth(); + } else { + widthSpec = mWidth; + } + widthSpec = Math.min(widthSpec, mMaxWidth); + + int heightSpec; + if (mHeight == ViewGroup.LayoutParams.MATCH_PARENT) { + heightSpec = ViewGroup.LayoutParams.MATCH_PARENT; + } else if (mHeight == ViewGroup.LayoutParams.WRAP_CONTENT) { + heightSpec = height; + } else { + heightSpec = mHeight; + } + heightSpec = Math.min(heightSpec, mMaxHeight); + + // Set width and height. + mPopup.setWidth(widthSpec); + mPopup.setHeight(heightSpec); + mPopup.setClippingEnabled(true); + + // use outside touchable to dismiss drop down when touching outside of it, so + // only set this if the dropdown is not always visible + mPopup.setOutsideTouchable(isOutsideTouchable()); + PopupWindowCompat.showAsDropDown(mPopup, getAnchorView(), mHorizontalOffset, mVerticalOffset, mGravity); + } + } + + /** + * Dismiss the popup window. + */ + void dismiss() { + mPopup.dismiss(); + mPopup.setContentView(null); + mView = null; + } + + /** + * Control how the popup operates with an input method: one of + * INPUT_METHOD_FROM_FOCUSABLE, INPUT_METHOD_NEEDED, + * or INPUT_METHOD_NOT_NEEDED. + * + *

If the popup is showing, calling this method will take effect only + * the next time the popup is shown or through a manual call to the {@link #show()} + * method.

+ * + * @see #show() + */ + void setInputMethodMode(int mode) { + mPopup.setInputMethodMode(mode); + } + + + /** + * @return {@code true} if the popup is currently showing, {@code false} otherwise. + */ + boolean isShowing() { + return mPopup.isShowing(); + } + + /** + * @return {@code true} if this popup is configured to assume the user does not need + * to interact with the IME while it is showing, {@code false} otherwise. + */ + @SuppressWarnings("WeakerAccess") + boolean isInputMethodNotNeeded() { + return mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED; + } + + + void setView(ViewGroup view) { + mView = view; + mView.setFocusable(true); + mView.setFocusableInTouchMode(true); + ViewGroup dropDownView = mView; + mPopup.setContentView(dropDownView); + ViewGroup.LayoutParams params = mView.getLayoutParams(); + if (params != null) { + if (params.height > 0) setHeight(params.height); + if (params.width > 0) setWidth(params.width); + } + } + + /** + *

Builds the popup window's content and returns the height the popup + * should have. Returns -1 when the content already exists.

+ * + * @return the content's wrap content height or -1 if content already exists + */ + private int buildDropDown() { + int otherHeights = 0; + + // getMaxAvailableHeight() subtracts the padding, so we put it back + // to get the available height for the whole window. + final int paddingVert; + final int paddingHoriz; + final Drawable background = mPopup.getBackground(); + if (background != null) { + background.getPadding(mTempRect); + paddingVert = mTempRect.top + mTempRect.bottom; + paddingHoriz = mTempRect.left + mTempRect.right; + + // If we don't have an explicit vertical offset, determine one from + // the window background so that content will line up. + if (!mVerticalOffsetSet) { + mVerticalOffset = -mTempRect.top; + } + } else { + mTempRect.setEmpty(); + paddingVert = 0; + paddingHoriz = 0; + } + + // Redefine dimensions taking into account maxWidth and maxHeight. + final boolean ignoreBottomDecorations = mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED; + final int maxContentHeight = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ? + mPopup.getMaxAvailableHeight(getAnchorView(), mVerticalOffset, ignoreBottomDecorations) : + mPopup.getMaxAvailableHeight(getAnchorView(), mVerticalOffset); + final int maxContentWidth = mContext.getResources().getDisplayMetrics().widthPixels - paddingHoriz; + + mMaxHeight = Math.min(maxContentHeight + paddingVert, mUserMaxHeight); + mMaxWidth = Math.min(maxContentWidth + paddingHoriz, mUserMaxWidth); + // if (mHeight > 0) mHeight = Math.min(mHeight, maxContentHeight); + // if (mWidth > 0) mWidth = Math.min(mWidth, maxContentWidth); + + if (mAlwaysVisible || mHeight == ViewGroup.LayoutParams.MATCH_PARENT) { + return mMaxHeight; + } + + final int childWidthSpec; + switch (mWidth) { + case ViewGroup.LayoutParams.WRAP_CONTENT: + childWidthSpec = View.MeasureSpec.makeMeasureSpec(maxContentWidth, View.MeasureSpec.AT_MOST); break; + case ViewGroup.LayoutParams.MATCH_PARENT: + childWidthSpec = View.MeasureSpec.makeMeasureSpec(maxContentWidth, View.MeasureSpec.EXACTLY); break; + default: + //noinspection Range + childWidthSpec = View.MeasureSpec.makeMeasureSpec(mWidth, View.MeasureSpec.EXACTLY); break; + } + + // Add padding only if the list has items in it, that way we don't show + // the popup if it is not needed. For this reason, we measure as wrap_content. + mView.measure(childWidthSpec, View.MeasureSpec.makeMeasureSpec(maxContentHeight, View.MeasureSpec.AT_MOST)); + final int viewHeight = mView.getMeasuredHeight(); + if (viewHeight > 0) { + otherHeights += paddingVert + mView.getPaddingTop() + mView.getPaddingBottom(); + } + + return Math.min(viewHeight + otherHeights, mMaxHeight); + } + + +} \ No newline at end of file diff --git a/library/external/autocomplete/src/main/java/com/otaliastudios/autocomplete/AutocompletePresenter.java b/library/external/autocomplete/src/main/java/com/otaliastudios/autocomplete/AutocompletePresenter.java new file mode 100644 index 0000000000..d49e8c8f30 --- /dev/null +++ b/library/external/autocomplete/src/main/java/com/otaliastudios/autocomplete/AutocompletePresenter.java @@ -0,0 +1,129 @@ +package com.otaliastudios.autocomplete; + +import android.content.Context; +import android.database.DataSetObserver; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +/** + * Base class for presenting items inside a popup. This is abstract and must be implemented. + * + * Most important methods are {@link #getView()} and {@link #onQuery(CharSequence)}. + */ +public abstract class AutocompletePresenter { + + private Context context; + private boolean isShowing; + + @SuppressWarnings("WeakerAccess") + public AutocompletePresenter(@NonNull Context context) { + this.context = context; + } + + /** + * At this point the presenter is passed the {@link ClickProvider}. + * The contract is that {@link ClickProvider#click(Object)} must be called when a list item + * is clicked. This ensure that the autocomplete callback will receive the event. + * + * @param provider a click provider for this presenter. + */ + protected void registerClickProvider(ClickProvider provider) { + + } + + /** + * Useful if you wish to change width/height based on content height. + * The contract is to call {@link DataSetObserver#onChanged()} when your view has + * changes. + * + * This is called after {@link #getView()}. + * + * @param observer the observer. + */ + protected void registerDataSetObserver(@NonNull DataSetObserver observer) {} + + /** + * Called each time the popup is shown. You are meant to inflate the view here. + * You can get a LayoutInflater using {@link #getContext()}. + * + * @return a ViewGroup for the popup + */ + @NonNull + protected abstract ViewGroup getView(); + + /** + * Provide the {@link PopupDimensions} for this popup. Called just once. + * You can use fixed dimensions or {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} and + * {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT}. + * + * @return a PopupDimensions object + */ + // Called at first to understand which dimensions to use for the popup. + @NonNull + protected PopupDimensions getPopupDimensions() { + return new PopupDimensions(); + } + + /** + * Perform firther initialization here. Called after {@link #getView()}, + * each time the popup is shown. + */ + protected abstract void onViewShown(); + + /** + * Called to update the view to filter results with the query. + * It is called any time the popup is shown, and any time the text changes and query is updated. + * + * @param query query from the edit text, to filter our results + */ + protected abstract void onQuery(@Nullable CharSequence query); + + /** + * Called when the popup is hidden, to release resources. + */ + protected abstract void onViewHidden(); + + /** + * @return this presenter context + */ + @NonNull + protected final Context getContext() { + return context; + } + + /** + * @return whether we are showing currently + */ + @SuppressWarnings("unused") + protected final boolean isShowing() { + return isShowing; + } + + final void showView() { + isShowing = true; + onViewShown(); + } + + final void hideView() { + isShowing = false; + onViewHidden(); + } + + public interface ClickProvider { + void click(@NonNull T item); + } + + /** + * Provides width, height, maxWidth and maxHeight for the popup. + * @see #getPopupDimensions() + */ + @SuppressWarnings("WeakerAccess") + public static class PopupDimensions { + public int width = ViewGroup.LayoutParams.WRAP_CONTENT; + public int height = ViewGroup.LayoutParams.WRAP_CONTENT; + public int maxWidth = Integer.MAX_VALUE; + public int maxHeight = Integer.MAX_VALUE; + } +} diff --git a/library/external/autocomplete/src/main/java/com/otaliastudios/autocomplete/CharPolicy.java b/library/external/autocomplete/src/main/java/com/otaliastudios/autocomplete/CharPolicy.java new file mode 100644 index 0000000000..9c94983317 --- /dev/null +++ b/library/external/autocomplete/src/main/java/com/otaliastudios/autocomplete/CharPolicy.java @@ -0,0 +1,184 @@ +package com.otaliastudios.autocomplete; + +import android.text.Spannable; +import android.text.Spanned; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + + +/** + * A special {@link AutocompletePolicy} for cases when you want to trigger the popup when a + * certain character is shown. + * + * For instance, this might be the case for hashtags ('#') or usernames ('@') or whatever you wish. + * Passing this to {@link Autocomplete.Builder} ensures the following behavior (assuming '@'): + * - text "@john" : presenter will be passed the query "john" + * - text "You should see this @j" : presenter will be passed the query "j" + * - text "You should see this @john @m" : presenter will be passed the query "m" + */ +public class CharPolicy implements AutocompletePolicy { + + private final static String TAG = CharPolicy.class.getSimpleName(); + private final static boolean DEBUG = false; + + private static void log(@NonNull String log) { + if (DEBUG) Log.e(TAG, log); + } + + private final char CH; + private final int[] INT = new int[2]; + private boolean needSpaceBefore = true; + + /** + * Constructs a char policy for the given character. + * + * @param trigger the triggering character. + */ + public CharPolicy(char trigger) { + CH = trigger; + } + + /** + * Constructs a char policy for the given character. + * You can choose whether a whitespace is needed before 'trigger'. + * + * @param trigger the triggering character. + * @param needSpaceBefore whether we need a space before trigger + */ + @SuppressWarnings("unused") + public CharPolicy(char trigger, boolean needSpaceBefore) { + CH = trigger; + this.needSpaceBefore = needSpaceBefore; + } + + /** + * Can be overriden to understand which characters are valid. The default implementation + * returns true for any character except whitespaces. + * + * @param ch the character + * @return whether it's valid part of a query + */ + @SuppressWarnings("WeakerAccess") + protected boolean isValidChar(char ch) { + return !Character.isWhitespace(ch); + } + + @Nullable + private int[] checkText(@NonNull Spannable text, int cursorPos) { + final int spanEnd = cursorPos; + char last = 'x'; + cursorPos -= 1; // If the cursor is at the end, we will have cursorPos = length. Go back by 1. + while (cursorPos >= 0 && last != CH) { + char ch = text.charAt(cursorPos); + log("checkText: char is "+ch); + if (isValidChar(ch)) { + // We are going back + log("checkText: char is valid"); + cursorPos -= 1; + last = ch; + } else { + // We got a whitespace before getting a CH. This is invalid. + log("checkText: char is not valid, returning NULL"); + return null; + } + } + cursorPos += 1; // + 1 because we end BEHIND the valid selection + + // Start checking. + if (cursorPos == 0 && last != CH) { + // We got to the start of the string, and no CH was encountered. Nothing to do. + log("checkText: got to start but no CH, returning NULL"); + return null; + } + + // Additional checks for cursorPos - 1 + if (cursorPos > 0 && needSpaceBefore) { + char ch = text.charAt(cursorPos-1); + if (!Character.isWhitespace(ch)) { + log("checkText: char before is not whitespace, returning NULL"); + return null; + } + } + + // All seems OK. + final int spanStart = cursorPos + 1; // + 1 because we want to exclude CH from the query + INT[0] = spanStart; + INT[1] = spanEnd; + log("checkText: found! cursorPos="+cursorPos); + log("checkText: found! spanStart="+spanStart); + log("checkText: found! spanEnd="+spanEnd); + return INT; + } + + @Override + public boolean shouldShowPopup(@NonNull Spannable text, int cursorPos) { + // Returning true if, right before cursorPos, we have a word starting with @. + log("shouldShowPopup: text is "+text); + log("shouldShowPopup: cursorPos is "+cursorPos); + int[] show = checkText(text, cursorPos); + if (show != null) { + text.setSpan(new QuerySpan(), show[0], show[1], Spanned.SPAN_INCLUSIVE_INCLUSIVE); + return true; + } + log("shouldShowPopup: returning false"); + return false; + } + + @Override + public boolean shouldDismissPopup(@NonNull Spannable text, int cursorPos) { + log("shouldDismissPopup: text is "+text); + log("shouldDismissPopup: cursorPos is "+cursorPos); + boolean dismiss = checkText(text, cursorPos) == null; + log("shouldDismissPopup: returning "+dismiss); + return dismiss; + } + + @NonNull + @Override + public CharSequence getQuery(@NonNull Spannable text) { + QuerySpan[] span = text.getSpans(0, text.length(), QuerySpan.class); + if (span == null || span.length == 0) { + // Should never happen. + log("getQuery: there's no span!"); + return ""; + } + log("getQuery: found spans: "+span.length); + QuerySpan sp = span[0]; + log("getQuery: span start is "+text.getSpanStart(sp)); + log("getQuery: span end is "+text.getSpanEnd(sp)); + CharSequence seq = text.subSequence(text.getSpanStart(sp), text.getSpanEnd(sp)); + log("getQuery: returning "+seq); + return seq; + } + + + @Override + public void onDismiss(@NonNull Spannable text) { + // Remove any span added by shouldShow. Should be useless, but anyway. + QuerySpan[] span = text.getSpans(0, text.length(), QuerySpan.class); + for (QuerySpan s : span) { + text.removeSpan(s); + } + } + + private static class QuerySpan {} + + /** + * Returns the current query out of the given Spannable. + * @param text the anchor text + * @return an int[] with query start and query end positions + */ + @Nullable + public static int[] getQueryRange(@NonNull Spannable text) { + QuerySpan[] span = text.getSpans(0, text.length(), QuerySpan.class); + if (span == null || span.length == 0) return null; + if (span.length > 1) { + // Won't happen + log("getQueryRange: ERR: MORE THAN ONE QuerySpan."); + } + QuerySpan sp = span[0]; + return new int[]{text.getSpanStart(sp), text.getSpanEnd(sp)}; + } +} diff --git a/library/external/autocomplete/src/main/java/com/otaliastudios/autocomplete/RecyclerViewPresenter.java b/library/external/autocomplete/src/main/java/com/otaliastudios/autocomplete/RecyclerViewPresenter.java new file mode 100644 index 0000000000..1338ec7cac --- /dev/null +++ b/library/external/autocomplete/src/main/java/com/otaliastudios/autocomplete/RecyclerViewPresenter.java @@ -0,0 +1,152 @@ +package com.otaliastudios.autocomplete; + +import android.content.Context; +import android.database.DataSetObserver; +import android.view.ViewGroup; + +import androidx.annotation.CallSuper; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +/** + * Simple {@link AutocompletePresenter} implementation that hosts a {@link RecyclerView}. + * Supports {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} natively. + * The only contract is to + * + * - provide a {@link RecyclerView.Adapter} in {@link #instantiateAdapter()} + * - call {@link #dispatchClick(Object)} when an object is clicked + * - update your data during {@link #onQuery(CharSequence)} + * + * @param your model object (the object displayed by the list) + */ +public abstract class RecyclerViewPresenter extends AutocompletePresenter { + + private RecyclerView recycler; + private ClickProvider clicks; + private Observer observer; + + public RecyclerViewPresenter(@NonNull Context context) { + super(context); + } + + @Override + protected final void registerClickProvider(@NonNull ClickProvider provider) { + this.clicks = provider; + } + + @Override + protected final void registerDataSetObserver(@NonNull DataSetObserver observer) { + this.observer = new Observer(observer); + } + + @NonNull + @Override + protected ViewGroup getView() { + recycler = new RecyclerView(getContext()); + RecyclerView.Adapter adapter = instantiateAdapter(); + recycler.setAdapter(adapter); + recycler.setLayoutManager(instantiateLayoutManager()); + if (observer != null) { + adapter.registerAdapterDataObserver(observer); + observer = null; + } + return recycler; + } + + @Override + protected void onViewShown() {} + + @CallSuper + @Override + protected void onViewHidden() { + recycler = null; + observer = null; + } + + @SuppressWarnings("unused") + @Nullable + protected final RecyclerView getRecyclerView() { + return recycler; + } + + /** + * Dispatch click event to {@link AutocompleteCallback}. + * Should be called when items are clicked. + * + * @param item the clicked item. + */ + protected final void dispatchClick(@NonNull T item) { + if (clicks != null) clicks.click(item); + } + + /** + * Request that the popup should recompute its dimensions based on a recent change in + * the view being displayed. + * + * This is already managed internally for {@link RecyclerView} events. + * Only use it for changes in other views that you have added to the popup, + * and only if one of the dimensions for the popup is WRAP_CONTENT . + */ + @SuppressWarnings("unused") + protected final void dispatchLayoutChange() { + if (observer != null) observer.onChanged(); + } + + /** + * Provide an adapter for the recycler. + * This should be a fresh instance every time this is called. + * + * @return a new adapter. + */ + @NonNull + protected abstract RecyclerView.Adapter instantiateAdapter(); + + /** + * Provides a layout manager for the recycler. + * This should be a fresh instance every time this is called. + * Defaults to a vertical LinearLayoutManager, which is guaranteed to work well. + * + * @return a new layout manager. + */ + @SuppressWarnings("WeakerAccess") + @NonNull + protected RecyclerView.LayoutManager instantiateLayoutManager() { + return new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false); + } + + private final static class Observer extends RecyclerView.AdapterDataObserver { + + private DataSetObserver root; + + Observer(@NonNull DataSetObserver root) { + this.root = root; + } + + @Override + public void onChanged() { + root.onChanged(); + } + + @Override + public void onItemRangeChanged(int positionStart, int itemCount) { + root.onChanged(); + } + + @Override + public void onItemRangeChanged(int positionStart, int itemCount, Object payload) { + root.onChanged(); + } + + @Override + public void onItemRangeInserted(int positionStart, int itemCount) { + root.onChanged(); + } + + @Override + public void onItemRangeRemoved(int positionStart, int itemCount) { + root.onChanged(); + } + } +} diff --git a/library/external/barcodescanner/core/build.gradle b/library/external/barcodescanner/core/build.gradle new file mode 100644 index 0000000000..583b435dd7 --- /dev/null +++ b/library/external/barcodescanner/core/build.gradle @@ -0,0 +1,26 @@ +apply plugin: 'com.android.library' + +android { + namespace "me.dm7.barcodescanner.core" + compileSdk versions.compileSdk + + defaultConfig { + minSdk versions.minSdk + targetSdk versions.targetSdk + } + + compileOptions { + sourceCompatibility versions.sourceCompat + targetCompatibility versions.targetCompat + } +} + +dependencies { + implementation 'androidx.annotation:annotation-jvm:1.6.0' +} + +afterEvaluate { + tasks.findAll { it.name.startsWith("lint") }.each { + it.enabled = false + } +} diff --git a/library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/BarcodeScannerView.java b/library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/BarcodeScannerView.java new file mode 100644 index 0000000000..ecfba76d89 --- /dev/null +++ b/library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/BarcodeScannerView.java @@ -0,0 +1,339 @@ +package me.dm7.barcodescanner.core; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.graphics.Rect; +import android.hardware.Camera; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.RelativeLayout; + +import androidx.annotation.ColorInt; + +public abstract class BarcodeScannerView extends FrameLayout implements Camera.PreviewCallback { + + private CameraWrapper mCameraWrapper; + private CameraPreview mPreview; + private IViewFinder mViewFinderView; + private Rect mFramingRectInPreview; + private CameraHandlerThread mCameraHandlerThread; + private Boolean mFlashState; + private boolean mAutofocusState = true; + private boolean mShouldScaleToFill = true; + + private boolean mIsLaserEnabled = true; + @ColorInt private int mLaserColor = getResources().getColor(R.color.viewfinder_laser); + @ColorInt private int mBorderColor = getResources().getColor(R.color.viewfinder_border); + private int mMaskColor = getResources().getColor(R.color.viewfinder_mask); + private int mBorderWidth = getResources().getInteger(R.integer.viewfinder_border_width); + private int mBorderLength = getResources().getInteger(R.integer.viewfinder_border_length); + private boolean mRoundedCorner = false; + private int mCornerRadius = 0; + private boolean mSquaredFinder = false; + private float mBorderAlpha = 1.0f; + private int mViewFinderOffset = 0; + private float mAspectTolerance = 0.1f; + + public BarcodeScannerView(Context context) { + super(context); + init(); + } + + public BarcodeScannerView(Context context, AttributeSet attributeSet) { + super(context, attributeSet); + + TypedArray a = context.getTheme().obtainStyledAttributes( + attributeSet, + R.styleable.BarcodeScannerView, + 0, 0); + + try { + setShouldScaleToFill(a.getBoolean(R.styleable.BarcodeScannerView_shouldScaleToFill, true)); + mIsLaserEnabled = a.getBoolean(R.styleable.BarcodeScannerView_laserEnabled, mIsLaserEnabled); + mLaserColor = a.getColor(R.styleable.BarcodeScannerView_laserColor, mLaserColor); + mBorderColor = a.getColor(R.styleable.BarcodeScannerView_borderColor, mBorderColor); + mMaskColor = a.getColor(R.styleable.BarcodeScannerView_maskColor, mMaskColor); + mBorderWidth = a.getDimensionPixelSize(R.styleable.BarcodeScannerView_borderWidth, mBorderWidth); + mBorderLength = a.getDimensionPixelSize(R.styleable.BarcodeScannerView_borderLength, mBorderLength); + + mRoundedCorner = a.getBoolean(R.styleable.BarcodeScannerView_roundedCorner, mRoundedCorner); + mCornerRadius = a.getDimensionPixelSize(R.styleable.BarcodeScannerView_cornerRadius, mCornerRadius); + mSquaredFinder = a.getBoolean(R.styleable.BarcodeScannerView_squaredFinder, mSquaredFinder); + mBorderAlpha = a.getFloat(R.styleable.BarcodeScannerView_borderAlpha, mBorderAlpha); + mViewFinderOffset = a.getDimensionPixelSize(R.styleable.BarcodeScannerView_finderOffset, mViewFinderOffset); + } finally { + a.recycle(); + } + + init(); + } + + private void init() { + mViewFinderView = createViewFinderView(getContext()); + } + + public final void setupLayout(CameraWrapper cameraWrapper) { + removeAllViews(); + + mPreview = new CameraPreview(getContext(), cameraWrapper, this); + mPreview.setAspectTolerance(mAspectTolerance); + mPreview.setShouldScaleToFill(mShouldScaleToFill); + if (!mShouldScaleToFill) { + RelativeLayout relativeLayout = new RelativeLayout(getContext()); + relativeLayout.setGravity(Gravity.CENTER); + relativeLayout.setBackgroundColor(Color.BLACK); + relativeLayout.addView(mPreview); + addView(relativeLayout); + } else { + addView(mPreview); + } + + if (mViewFinderView instanceof View) { + addView((View) mViewFinderView); + } else { + throw new IllegalArgumentException("IViewFinder object returned by " + + "'createViewFinderView()' should be instance of android.view.View"); + } + } + + /** + *

Method that creates view that represents visual appearance of a barcode scanner

+ *

Override it to provide your own view for visual appearance of a barcode scanner

+ * + * @param context {@link Context} + * @return {@link android.view.View} that implements {@link ViewFinderView} + */ + protected IViewFinder createViewFinderView(Context context) { + ViewFinderView viewFinderView = new ViewFinderView(context); + viewFinderView.setBorderColor(mBorderColor); + viewFinderView.setLaserColor(mLaserColor); + viewFinderView.setLaserEnabled(mIsLaserEnabled); + viewFinderView.setBorderStrokeWidth(mBorderWidth); + viewFinderView.setBorderLineLength(mBorderLength); + viewFinderView.setMaskColor(mMaskColor); + + viewFinderView.setBorderCornerRounded(mRoundedCorner); + viewFinderView.setBorderCornerRadius(mCornerRadius); + viewFinderView.setSquareViewFinder(mSquaredFinder); + viewFinderView.setViewFinderOffset(mViewFinderOffset); + return viewFinderView; + } + + public void setLaserColor(int laserColor) { + mLaserColor = laserColor; + mViewFinderView.setLaserColor(mLaserColor); + mViewFinderView.setupViewFinder(); + } + public void setMaskColor(int maskColor) { + mMaskColor = maskColor; + mViewFinderView.setMaskColor(mMaskColor); + mViewFinderView.setupViewFinder(); + } + public void setBorderColor(int borderColor) { + mBorderColor = borderColor; + mViewFinderView.setBorderColor(mBorderColor); + mViewFinderView.setupViewFinder(); + } + public void setBorderStrokeWidth(int borderStrokeWidth) { + mBorderWidth = borderStrokeWidth; + mViewFinderView.setBorderStrokeWidth(mBorderWidth); + mViewFinderView.setupViewFinder(); + } + public void setBorderLineLength(int borderLineLength) { + mBorderLength = borderLineLength; + mViewFinderView.setBorderLineLength(mBorderLength); + mViewFinderView.setupViewFinder(); + } + public void setLaserEnabled(boolean isLaserEnabled) { + mIsLaserEnabled = isLaserEnabled; + mViewFinderView.setLaserEnabled(mIsLaserEnabled); + mViewFinderView.setupViewFinder(); + } + public void setIsBorderCornerRounded(boolean isBorderCornerRounded) { + mRoundedCorner = isBorderCornerRounded; + mViewFinderView.setBorderCornerRounded(mRoundedCorner); + mViewFinderView.setupViewFinder(); + } + public void setBorderCornerRadius(int borderCornerRadius) { + mCornerRadius = borderCornerRadius; + mViewFinderView.setBorderCornerRadius(mCornerRadius); + mViewFinderView.setupViewFinder(); + } + public void setSquareViewFinder(boolean isSquareViewFinder) { + mSquaredFinder = isSquareViewFinder; + mViewFinderView.setSquareViewFinder(mSquaredFinder); + mViewFinderView.setupViewFinder(); + } + public void setBorderAlpha(float borderAlpha) { + mBorderAlpha = borderAlpha; + mViewFinderView.setBorderAlpha(mBorderAlpha); + mViewFinderView.setupViewFinder(); + } + + public void startCamera(int cameraId) { + if(mCameraHandlerThread == null) { + mCameraHandlerThread = new CameraHandlerThread(this); + } + mCameraHandlerThread.startCamera(cameraId); + } + + public void setupCameraPreview(CameraWrapper cameraWrapper) { + mCameraWrapper = cameraWrapper; + if(mCameraWrapper != null) { + setupLayout(mCameraWrapper); + mViewFinderView.setupViewFinder(); + if(mFlashState != null) { + setFlash(mFlashState); + } + setAutoFocus(mAutofocusState); + } + } + + public void startCamera() { + startCamera(CameraUtils.getDefaultCameraId()); + } + + public void stopCamera() { + if(mCameraWrapper != null) { + mPreview.stopCameraPreview(); + mPreview.setCamera(null, null); + mCameraWrapper.mCamera.release(); + mCameraWrapper = null; + } + if(mCameraHandlerThread != null) { + mCameraHandlerThread.quit(); + mCameraHandlerThread = null; + } + } + + public void stopCameraPreview() { + if(mPreview != null) { + mPreview.stopCameraPreview(); + } + } + + protected void resumeCameraPreview() { + if(mPreview != null) { + mPreview.showCameraPreview(); + } + } + + public synchronized Rect getFramingRectInPreview(int previewWidth, int previewHeight) { + if (mFramingRectInPreview == null) { + Rect framingRect = mViewFinderView.getFramingRect(); + int viewFinderViewWidth = mViewFinderView.getWidth(); + int viewFinderViewHeight = mViewFinderView.getHeight(); + if (framingRect == null || viewFinderViewWidth == 0 || viewFinderViewHeight == 0) { + return null; + } + + Rect rect = new Rect(framingRect); + + if(previewWidth < viewFinderViewWidth) { + rect.left = rect.left * previewWidth / viewFinderViewWidth; + rect.right = rect.right * previewWidth / viewFinderViewWidth; + } + + if(previewHeight < viewFinderViewHeight) { + rect.top = rect.top * previewHeight / viewFinderViewHeight; + rect.bottom = rect.bottom * previewHeight / viewFinderViewHeight; + } + + mFramingRectInPreview = rect; + } + return mFramingRectInPreview; + } + + public void setFlash(boolean flag) { + mFlashState = flag; + if(mCameraWrapper != null && CameraUtils.isFlashSupported(mCameraWrapper.mCamera)) { + + Camera.Parameters parameters = mCameraWrapper.mCamera.getParameters(); + if(flag) { + if(parameters.getFlashMode().equals(Camera.Parameters.FLASH_MODE_TORCH)) { + return; + } + parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); + } else { + if(parameters.getFlashMode().equals(Camera.Parameters.FLASH_MODE_OFF)) { + return; + } + parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); + } + mCameraWrapper.mCamera.setParameters(parameters); + } + } + + public boolean getFlash() { + if(mCameraWrapper != null && CameraUtils.isFlashSupported(mCameraWrapper.mCamera)) { + Camera.Parameters parameters = mCameraWrapper.mCamera.getParameters(); + if(parameters.getFlashMode().equals(Camera.Parameters.FLASH_MODE_TORCH)) { + return true; + } else { + return false; + } + } + return false; + } + + public void toggleFlash() { + if(mCameraWrapper != null && CameraUtils.isFlashSupported(mCameraWrapper.mCamera)) { + Camera.Parameters parameters = mCameraWrapper.mCamera.getParameters(); + if(parameters.getFlashMode().equals(Camera.Parameters.FLASH_MODE_TORCH)) { + parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); + } else { + parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); + } + mCameraWrapper.mCamera.setParameters(parameters); + } + } + + public void setAutoFocus(boolean state) { + mAutofocusState = state; + if(mPreview != null) { + mPreview.setAutoFocus(state); + } + } + + public void setShouldScaleToFill(boolean shouldScaleToFill) { + mShouldScaleToFill = shouldScaleToFill; + } + + public void setAspectTolerance(float aspectTolerance) { + mAspectTolerance = aspectTolerance; + } + + public byte[] getRotatedData(byte[] data, Camera camera) { + Camera.Parameters parameters = camera.getParameters(); + Camera.Size size = parameters.getPreviewSize(); + int width = size.width; + int height = size.height; + + int rotationCount = getRotationCount(); + + if(rotationCount == 1 || rotationCount == 3) { + for (int i = 0; i < rotationCount; i++) { + byte[] rotatedData = new byte[data.length]; + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) + rotatedData[x * height + height - y - 1] = data[x + y * width]; + } + data = rotatedData; + int tmp = width; + width = height; + height = tmp; + } + } + + return data; + } + + public int getRotationCount() { + int displayOrientation = mPreview.getDisplayOrientation(); + return displayOrientation / 90; + } +} + diff --git a/library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/CameraHandlerThread.java b/library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/CameraHandlerThread.java new file mode 100644 index 0000000000..2d4bcee7bf --- /dev/null +++ b/library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/CameraHandlerThread.java @@ -0,0 +1,37 @@ +package me.dm7.barcodescanner.core; + + +import android.hardware.Camera; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; + +// This code is mostly based on the top answer here: http://stackoverflow.com/questions/18149964/best-use-of-handlerthread-over-other-similar-classes +public class CameraHandlerThread extends HandlerThread { + private static final String LOG_TAG = "CameraHandlerThread"; + + private BarcodeScannerView mScannerView; + + public CameraHandlerThread(BarcodeScannerView scannerView) { + super("CameraHandlerThread"); + mScannerView = scannerView; + start(); + } + + public void startCamera(final int cameraId) { + Handler localHandler = new Handler(getLooper()); + localHandler.post(new Runnable() { + @Override + public void run() { + final Camera camera = CameraUtils.getCameraInstance(cameraId); + Handler mainHandler = new Handler(Looper.getMainLooper()); + mainHandler.post(new Runnable() { + @Override + public void run() { + mScannerView.setupCameraPreview(CameraWrapper.getWrapper(camera, cameraId)); + } + }); + } + }); + } +} diff --git a/library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/CameraPreview.java b/library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/CameraPreview.java new file mode 100644 index 0000000000..b066e25b2c --- /dev/null +++ b/library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/CameraPreview.java @@ -0,0 +1,312 @@ +package me.dm7.barcodescanner.core; + +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.Point; +import android.hardware.Camera; +import android.os.Handler; +import android.util.AttributeSet; +import android.util.Log; +import android.view.Display; +import android.view.Surface; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; + +import java.util.List; + +public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { + private static final String TAG = "CameraPreview"; + + private CameraWrapper mCameraWrapper; + private Handler mAutoFocusHandler; + private boolean mPreviewing = true; + private boolean mAutoFocus = true; + private boolean mSurfaceCreated = false; + private boolean mShouldScaleToFill = true; + private Camera.PreviewCallback mPreviewCallback; + private float mAspectTolerance = 0.1f; + + public CameraPreview(Context context, CameraWrapper cameraWrapper, Camera.PreviewCallback previewCallback) { + super(context); + init(cameraWrapper, previewCallback); + } + + public CameraPreview(Context context, AttributeSet attrs, CameraWrapper cameraWrapper, Camera.PreviewCallback previewCallback) { + super(context, attrs); + init(cameraWrapper, previewCallback); + } + + public void init(CameraWrapper cameraWrapper, Camera.PreviewCallback previewCallback) { + setCamera(cameraWrapper, previewCallback); + mAutoFocusHandler = new Handler(); + getHolder().addCallback(this); + getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); + } + + public void setCamera(CameraWrapper cameraWrapper, Camera.PreviewCallback previewCallback) { + mCameraWrapper = cameraWrapper; + mPreviewCallback = previewCallback; + } + + public void setShouldScaleToFill(boolean scaleToFill) { + mShouldScaleToFill = scaleToFill; + } + + public void setAspectTolerance(float aspectTolerance) { + mAspectTolerance = aspectTolerance; + } + + @Override + public void surfaceCreated(SurfaceHolder surfaceHolder) { + mSurfaceCreated = true; + } + + @Override + public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) { + if(surfaceHolder.getSurface() == null) { + return; + } + stopCameraPreview(); + showCameraPreview(); + } + + @Override + public void surfaceDestroyed(SurfaceHolder surfaceHolder) { + mSurfaceCreated = false; + stopCameraPreview(); + } + + public void showCameraPreview() { + if(mCameraWrapper != null) { + try { + getHolder().addCallback(this); + mPreviewing = true; + setupCameraParameters(); + mCameraWrapper.mCamera.setPreviewDisplay(getHolder()); + mCameraWrapper.mCamera.setDisplayOrientation(getDisplayOrientation()); + mCameraWrapper.mCamera.setOneShotPreviewCallback(mPreviewCallback); + mCameraWrapper.mCamera.startPreview(); + if(mAutoFocus) { + if (mSurfaceCreated) { // check if surface created before using autofocus + safeAutoFocus(); + } else { + scheduleAutoFocus(); // wait 1 sec and then do check again + } + } + } catch (Exception e) { + Log.e(TAG, e.toString(), e); + } + } + } + + public void safeAutoFocus() { + try { + mCameraWrapper.mCamera.autoFocus(autoFocusCB); + } catch (RuntimeException re) { + // Horrible hack to deal with autofocus errors on Sony devices + // See https://github.com/dm77/barcodescanner/issues/7 for example + scheduleAutoFocus(); // wait 1 sec and then do check again + } + } + + public void stopCameraPreview() { + if(mCameraWrapper != null) { + try { + mPreviewing = false; + getHolder().removeCallback(this); + mCameraWrapper.mCamera.cancelAutoFocus(); + mCameraWrapper.mCamera.setOneShotPreviewCallback(null); + mCameraWrapper.mCamera.stopPreview(); + } catch(Exception e) { + Log.e(TAG, e.toString(), e); + } + } + } + + public void setupCameraParameters() { + Camera.Size optimalSize = getOptimalPreviewSize(); + Camera.Parameters parameters = mCameraWrapper.mCamera.getParameters(); + parameters.setPreviewSize(optimalSize.width, optimalSize.height); + mCameraWrapper.mCamera.setParameters(parameters); + adjustViewSize(optimalSize); + } + + private void adjustViewSize(Camera.Size cameraSize) { + Point previewSize = convertSizeToLandscapeOrientation(new Point(getWidth(), getHeight())); + float cameraRatio = ((float) cameraSize.width) / cameraSize.height; + float screenRatio = ((float) previewSize.x) / previewSize.y; + + if (screenRatio > cameraRatio) { + setViewSize((int) (previewSize.y * cameraRatio), previewSize.y); + } else { + setViewSize(previewSize.x, (int) (previewSize.x / cameraRatio)); + } + } + + @SuppressWarnings("SuspiciousNameCombination") + private Point convertSizeToLandscapeOrientation(Point size) { + if (getDisplayOrientation() % 180 == 0) { + return size; + } else { + return new Point(size.y, size.x); + } + } + + @SuppressWarnings("SuspiciousNameCombination") + private void setViewSize(int width, int height) { + ViewGroup.LayoutParams layoutParams = getLayoutParams(); + int tmpWidth; + int tmpHeight; + if (getDisplayOrientation() % 180 == 0) { + tmpWidth = width; + tmpHeight = height; + } else { + tmpWidth = height; + tmpHeight = width; + } + + if (mShouldScaleToFill) { + int parentWidth = ((View) getParent()).getWidth(); + int parentHeight = ((View) getParent()).getHeight(); + float ratioWidth = (float) parentWidth / (float) tmpWidth; + float ratioHeight = (float) parentHeight / (float) tmpHeight; + + float compensation; + + if (ratioWidth > ratioHeight) { + compensation = ratioWidth; + } else { + compensation = ratioHeight; + } + + tmpWidth = Math.round(tmpWidth * compensation); + tmpHeight = Math.round(tmpHeight * compensation); + } + + layoutParams.width = tmpWidth; + layoutParams.height = tmpHeight; + setLayoutParams(layoutParams); + } + + public int getDisplayOrientation() { + if (mCameraWrapper == null) { + //If we don't have a camera set there is no orientation so return dummy value + return 0; + } + + Camera.CameraInfo info = new Camera.CameraInfo(); + if(mCameraWrapper.mCameraId == -1) { + Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, info); + } else { + Camera.getCameraInfo(mCameraWrapper.mCameraId, info); + } + + WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); + Display display = wm.getDefaultDisplay(); + + int rotation = display.getRotation(); + int degrees = 0; + switch (rotation) { + case Surface.ROTATION_0: degrees = 0; break; + case Surface.ROTATION_90: degrees = 90; break; + case Surface.ROTATION_180: degrees = 180; break; + case Surface.ROTATION_270: degrees = 270; break; + } + + int result; + if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { + result = (info.orientation + degrees) % 360; + result = (360 - result) % 360; // compensate the mirror + } else { // back-facing + result = (info.orientation - degrees + 360) % 360; + } + return result; + } + + private Camera.Size getOptimalPreviewSize() { + if(mCameraWrapper == null) { + return null; + } + + List sizes = mCameraWrapper.mCamera.getParameters().getSupportedPreviewSizes(); + int w = getWidth(); + int h = getHeight(); + if (DisplayUtils.getScreenOrientation(getContext()) == Configuration.ORIENTATION_PORTRAIT) { + int portraitWidth = h; + h = w; + w = portraitWidth; + } + + double targetRatio = (double) w / h; + if (sizes == null) return null; + + Camera.Size optimalSize = null; + double minDiff = Double.MAX_VALUE; + + int targetHeight = h; + + // Try to find an size match aspect ratio and size + for (Camera.Size size : sizes) { + double ratio = (double) size.width / size.height; + if (Math.abs(ratio - targetRatio) > mAspectTolerance) continue; + if (Math.abs(size.height - targetHeight) < minDiff) { + optimalSize = size; + minDiff = Math.abs(size.height - targetHeight); + } + } + + // Cannot find the one match the aspect ratio, ignore the requirement + if (optimalSize == null) { + minDiff = Double.MAX_VALUE; + for (Camera.Size size : sizes) { + if (Math.abs(size.height - targetHeight) < minDiff) { + optimalSize = size; + minDiff = Math.abs(size.height - targetHeight); + } + } + } + return optimalSize; + } + + public void setAutoFocus(boolean state) { + if(mCameraWrapper != null && mPreviewing) { + if(state == mAutoFocus) { + return; + } + mAutoFocus = state; + if(mAutoFocus) { + if (mSurfaceCreated) { // check if surface created before using autofocus + Log.v(TAG, "Starting autofocus"); + safeAutoFocus(); + } else { + scheduleAutoFocus(); // wait 1 sec and then do check again + } + } else { + Log.v(TAG, "Cancelling autofocus"); + mCameraWrapper.mCamera.cancelAutoFocus(); + } + } + } + + private Runnable doAutoFocus = new Runnable() { + public void run() { + if(mCameraWrapper != null && mPreviewing && mAutoFocus && mSurfaceCreated) { + safeAutoFocus(); + } + } + }; + + // Mimic continuous auto-focusing + Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback() { + public void onAutoFocus(boolean success, Camera camera) { + scheduleAutoFocus(); + } + }; + + private void scheduleAutoFocus() { + mAutoFocusHandler.postDelayed(doAutoFocus, 1000); + } +} diff --git a/library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/CameraUtils.java b/library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/CameraUtils.java new file mode 100644 index 0000000000..599bd5fa48 --- /dev/null +++ b/library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/CameraUtils.java @@ -0,0 +1,63 @@ +package me.dm7.barcodescanner.core; + +import android.hardware.Camera; + +import java.util.List; + +public class CameraUtils { + /** A safe way to get an instance of the Camera object. */ + public static Camera getCameraInstance() { + return getCameraInstance(getDefaultCameraId()); + } + + /** Favor back-facing camera by default. If none exists, fallback to whatever camera is available **/ + public static int getDefaultCameraId() { + int numberOfCameras = Camera.getNumberOfCameras(); + Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); + int defaultCameraId = -1; + for (int i = 0; i < numberOfCameras; i++) { + defaultCameraId = i; + Camera.getCameraInfo(i, cameraInfo); + if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { + return i; + } + } + return defaultCameraId; + } + + /** A safe way to get an instance of the Camera object. */ + public static Camera getCameraInstance(int cameraId) { + Camera c = null; + try { + if(cameraId == -1) { + c = Camera.open(); // attempt to get a Camera instance + } else { + c = Camera.open(cameraId); // attempt to get a Camera instance + } + } + catch (Exception e) { + // Camera is not available (in use or does not exist) + } + return c; // returns null if camera is unavailable + } + + public static boolean isFlashSupported(Camera camera) { + /* Credits: Top answer at http://stackoverflow.com/a/19599365/868173 */ + if (camera != null) { + Camera.Parameters parameters = camera.getParameters(); + + if (parameters.getFlashMode() == null) { + return false; + } + + List supportedFlashModes = parameters.getSupportedFlashModes(); + if (supportedFlashModes == null || supportedFlashModes.isEmpty() || supportedFlashModes.size() == 1 && supportedFlashModes.get(0).equals(Camera.Parameters.FLASH_MODE_OFF)) { + return false; + } + } else { + return false; + } + + return true; + } +} \ No newline at end of file diff --git a/library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/CameraWrapper.java b/library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/CameraWrapper.java new file mode 100644 index 0000000000..49759ae0f9 --- /dev/null +++ b/library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/CameraWrapper.java @@ -0,0 +1,23 @@ +package me.dm7.barcodescanner.core; + +import android.hardware.Camera; + +import androidx.annotation.NonNull; + +public class CameraWrapper { + public final Camera mCamera; + public final int mCameraId; + + private CameraWrapper(@NonNull Camera camera, int cameraId) { + this.mCamera = camera; + this.mCameraId = cameraId; + } + + public static CameraWrapper getWrapper(Camera camera, int cameraId) { + if (camera == null) { + return null; + } else { + return new CameraWrapper(camera, cameraId); + } + } +} diff --git a/library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/DisplayUtils.java b/library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/DisplayUtils.java new file mode 100644 index 0000000000..6c47312221 --- /dev/null +++ b/library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/DisplayUtils.java @@ -0,0 +1,41 @@ +package me.dm7.barcodescanner.core; + +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.Point; +import android.view.Display; +import android.view.WindowManager; + +public class DisplayUtils { + public static Point getScreenResolution(Context context) { + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + Display display = wm.getDefaultDisplay(); + Point screenResolution = new Point(); + if (android.os.Build.VERSION.SDK_INT >= 13) { + display.getSize(screenResolution); + } else { + screenResolution.set(display.getWidth(), display.getHeight()); + } + + return screenResolution; + } + + public static int getScreenOrientation(Context context) + { + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + Display display = wm.getDefaultDisplay(); + + int orientation = Configuration.ORIENTATION_UNDEFINED; + if(display.getWidth()==display.getHeight()){ + orientation = Configuration.ORIENTATION_SQUARE; + } else{ + if(display.getWidth() < display.getHeight()){ + orientation = Configuration.ORIENTATION_PORTRAIT; + }else { + orientation = Configuration.ORIENTATION_LANDSCAPE; + } + } + return orientation; + } + +} diff --git a/library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/IViewFinder.java b/library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/IViewFinder.java new file mode 100644 index 0000000000..a6caaa4cb6 --- /dev/null +++ b/library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/IViewFinder.java @@ -0,0 +1,53 @@ +package me.dm7.barcodescanner.core; + +import android.graphics.Rect; + +public interface IViewFinder { + + void setLaserColor(int laserColor); + void setMaskColor(int maskColor); + void setBorderColor(int borderColor); + void setBorderStrokeWidth(int borderStrokeWidth); + void setBorderLineLength(int borderLineLength); + void setLaserEnabled(boolean isLaserEnabled); + + void setBorderCornerRounded(boolean isBorderCornersRounded); + void setBorderAlpha(float alpha); + void setBorderCornerRadius(int borderCornersRadius); + void setViewFinderOffset(int offset); + void setSquareViewFinder(boolean isSquareViewFinder); + /** + * Method that executes when Camera preview is starting. + * It is recommended to update framing rect here and invalidate view after that.
+ * For example see: {@link ViewFinderView#setupViewFinder()} + */ + void setupViewFinder(); + + /** + * Provides {@link Rect} that identifies area where barcode scanner can detect visual codes + *

Note: This rect is a area representation in absolute pixel values.
+ * For example:
+ * If View's size is 1024x800 so framing rect might be 500x400

+ * + * @return {@link Rect} that identifies barcode scanner area + */ + Rect getFramingRect(); + + /** + * Width of a {@link android.view.View} that implements this interface + *

Note: this is already implemented in {@link android.view.View}, + * so you don't need to override method and provide your implementation

+ * + * @return width of a view + */ + int getWidth(); + + /** + * Height of a {@link android.view.View} that implements this interface + *

Note: this is already implemented in {@link android.view.View}, + * so you don't need to override method and provide your implementation

+ * + * @return height of a view + */ + int getHeight(); +} diff --git a/library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/ViewFinderView.java b/library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/ViewFinderView.java new file mode 100644 index 0000000000..307a8a42b4 --- /dev/null +++ b/library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/ViewFinderView.java @@ -0,0 +1,259 @@ +package me.dm7.barcodescanner.core; + +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.Canvas; +import android.graphics.CornerPathEffect; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Point; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.view.View; + +public class ViewFinderView extends View implements IViewFinder { + private static final String TAG = "ViewFinderView"; + + private Rect mFramingRect; + + private static final float PORTRAIT_WIDTH_RATIO = 6f/8; + private static final float PORTRAIT_WIDTH_HEIGHT_RATIO = 0.75f; + + private static final float LANDSCAPE_HEIGHT_RATIO = 5f/8; + private static final float LANDSCAPE_WIDTH_HEIGHT_RATIO = 1.4f; + private static final int MIN_DIMENSION_DIFF = 50; + + private static final float DEFAULT_SQUARE_DIMENSION_RATIO = 5f / 8; + + private static final int[] SCANNER_ALPHA = {0, 64, 128, 192, 255, 192, 128, 64}; + private int scannerAlpha; + private static final int POINT_SIZE = 10; + private static final long ANIMATION_DELAY = 80l; + + private final int mDefaultLaserColor = getResources().getColor(R.color.viewfinder_laser); + private final int mDefaultMaskColor = getResources().getColor(R.color.viewfinder_mask); + private final int mDefaultBorderColor = getResources().getColor(R.color.viewfinder_border); + private final int mDefaultBorderStrokeWidth = getResources().getInteger(R.integer.viewfinder_border_width); + private final int mDefaultBorderLineLength = getResources().getInteger(R.integer.viewfinder_border_length); + + protected Paint mLaserPaint; + protected Paint mFinderMaskPaint; + protected Paint mBorderPaint; + protected int mBorderLineLength; + protected boolean mSquareViewFinder; + private boolean mIsLaserEnabled; + private float mBordersAlpha; + private int mViewFinderOffset = 0; + + public ViewFinderView(Context context) { + super(context); + init(); + } + + public ViewFinderView(Context context, AttributeSet attributeSet) { + super(context, attributeSet); + init(); + } + + private void init() { + //set up laser paint + mLaserPaint = new Paint(); + mLaserPaint.setColor(mDefaultLaserColor); + mLaserPaint.setStyle(Paint.Style.FILL); + + //finder mask paint + mFinderMaskPaint = new Paint(); + mFinderMaskPaint.setColor(mDefaultMaskColor); + + //border paint + mBorderPaint = new Paint(); + mBorderPaint.setColor(mDefaultBorderColor); + mBorderPaint.setStyle(Paint.Style.STROKE); + mBorderPaint.setStrokeWidth(mDefaultBorderStrokeWidth); + mBorderPaint.setAntiAlias(true); + + mBorderLineLength = mDefaultBorderLineLength; + } + + @Override + public void setLaserColor(int laserColor) { + mLaserPaint.setColor(laserColor); + } + + @Override + public void setMaskColor(int maskColor) { + mFinderMaskPaint.setColor(maskColor); + } + + @Override + public void setBorderColor(int borderColor) { + mBorderPaint.setColor(borderColor); + } + + @Override + public void setBorderStrokeWidth(int borderStrokeWidth) { + mBorderPaint.setStrokeWidth(borderStrokeWidth); + } + + @Override + public void setBorderLineLength(int borderLineLength) { + mBorderLineLength = borderLineLength; + } + + @Override + public void setLaserEnabled(boolean isLaserEnabled) { mIsLaserEnabled = isLaserEnabled; } + + @Override + public void setBorderCornerRounded(boolean isBorderCornersRounded) { + if (isBorderCornersRounded) { + mBorderPaint.setStrokeJoin(Paint.Join.ROUND); + } else { + mBorderPaint.setStrokeJoin(Paint.Join.BEVEL); + } + } + + @Override + public void setBorderAlpha(float alpha) { + int colorAlpha = (int) (255 * alpha); + mBordersAlpha = alpha; + mBorderPaint.setAlpha(colorAlpha); + } + + @Override + public void setBorderCornerRadius(int borderCornersRadius) { + mBorderPaint.setPathEffect(new CornerPathEffect(borderCornersRadius)); + } + + @Override + public void setViewFinderOffset(int offset) { + mViewFinderOffset = offset; + } + + // TODO: Need a better way to configure this. Revisit when working on 2.0 + @Override + public void setSquareViewFinder(boolean set) { + mSquareViewFinder = set; + } + + public void setupViewFinder() { + updateFramingRect(); + invalidate(); + } + + public Rect getFramingRect() { + return mFramingRect; + } + + @Override + public void onDraw(Canvas canvas) { + if(getFramingRect() == null) { + return; + } + + drawViewFinderMask(canvas); + drawViewFinderBorder(canvas); + + if (mIsLaserEnabled) { + drawLaser(canvas); + } + } + + public void drawViewFinderMask(Canvas canvas) { + int width = canvas.getWidth(); + int height = canvas.getHeight(); + Rect framingRect = getFramingRect(); + + canvas.drawRect(0, 0, width, framingRect.top, mFinderMaskPaint); + canvas.drawRect(0, framingRect.top, framingRect.left, framingRect.bottom + 1, mFinderMaskPaint); + canvas.drawRect(framingRect.right + 1, framingRect.top, width, framingRect.bottom + 1, mFinderMaskPaint); + canvas.drawRect(0, framingRect.bottom + 1, width, height, mFinderMaskPaint); + } + + public void drawViewFinderBorder(Canvas canvas) { + Rect framingRect = getFramingRect(); + + // Top-left corner + Path path = new Path(); + path.moveTo(framingRect.left, framingRect.top + mBorderLineLength); + path.lineTo(framingRect.left, framingRect.top); + path.lineTo(framingRect.left + mBorderLineLength, framingRect.top); + canvas.drawPath(path, mBorderPaint); + + // Top-right corner + path.moveTo(framingRect.right, framingRect.top + mBorderLineLength); + path.lineTo(framingRect.right, framingRect.top); + path.lineTo(framingRect.right - mBorderLineLength, framingRect.top); + canvas.drawPath(path, mBorderPaint); + + // Bottom-right corner + path.moveTo(framingRect.right, framingRect.bottom - mBorderLineLength); + path.lineTo(framingRect.right, framingRect.bottom); + path.lineTo(framingRect.right - mBorderLineLength, framingRect.bottom); + canvas.drawPath(path, mBorderPaint); + + // Bottom-left corner + path.moveTo(framingRect.left, framingRect.bottom - mBorderLineLength); + path.lineTo(framingRect.left, framingRect.bottom); + path.lineTo(framingRect.left + mBorderLineLength, framingRect.bottom); + canvas.drawPath(path, mBorderPaint); + } + + public void drawLaser(Canvas canvas) { + Rect framingRect = getFramingRect(); + + // Draw a red "laser scanner" line through the middle to show decoding is active + mLaserPaint.setAlpha(SCANNER_ALPHA[scannerAlpha]); + scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length; + int middle = framingRect.height() / 2 + framingRect.top; + canvas.drawRect(framingRect.left + 2, middle - 1, framingRect.right - 1, middle + 2, mLaserPaint); + + postInvalidateDelayed(ANIMATION_DELAY, + framingRect.left - POINT_SIZE, + framingRect.top - POINT_SIZE, + framingRect.right + POINT_SIZE, + framingRect.bottom + POINT_SIZE); + } + + @Override + protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld) { + updateFramingRect(); + } + + public synchronized void updateFramingRect() { + Point viewResolution = new Point(getWidth(), getHeight()); + int width; + int height; + int orientation = DisplayUtils.getScreenOrientation(getContext()); + + if(mSquareViewFinder) { + if(orientation != Configuration.ORIENTATION_PORTRAIT) { + height = (int) (getHeight() * DEFAULT_SQUARE_DIMENSION_RATIO); + width = height; + } else { + width = (int) (getWidth() * DEFAULT_SQUARE_DIMENSION_RATIO); + height = width; + } + } else { + if(orientation != Configuration.ORIENTATION_PORTRAIT) { + height = (int) (getHeight() * LANDSCAPE_HEIGHT_RATIO); + width = (int) (LANDSCAPE_WIDTH_HEIGHT_RATIO * height); + } else { + width = (int) (getWidth() * PORTRAIT_WIDTH_RATIO); + height = (int) (PORTRAIT_WIDTH_HEIGHT_RATIO * width); + } + } + + if(width > getWidth()) { + width = getWidth() - MIN_DIMENSION_DIFF; + } + + if(height > getHeight()) { + height = getHeight() - MIN_DIMENSION_DIFF; + } + + int leftOffset = (viewResolution.x - width) / 2; + int topOffset = (viewResolution.y - height) / 2; + mFramingRect = new Rect(leftOffset + mViewFinderOffset, topOffset + mViewFinderOffset, leftOffset + width - mViewFinderOffset, topOffset + height - mViewFinderOffset); + } +} + diff --git a/library/external/barcodescanner/core/src/main/res/values-hdpi/integers.xml b/library/external/barcodescanner/core/src/main/res/values-hdpi/integers.xml new file mode 100644 index 0000000000..d5979caaf8 --- /dev/null +++ b/library/external/barcodescanner/core/src/main/res/values-hdpi/integers.xml @@ -0,0 +1,5 @@ + + + 4 + 60 + \ No newline at end of file diff --git a/library/external/barcodescanner/core/src/main/res/values-xhdpi/integers.xml b/library/external/barcodescanner/core/src/main/res/values-xhdpi/integers.xml new file mode 100644 index 0000000000..7f57b00a3a --- /dev/null +++ b/library/external/barcodescanner/core/src/main/res/values-xhdpi/integers.xml @@ -0,0 +1,5 @@ + + + 5 + 80 + \ No newline at end of file diff --git a/library/external/barcodescanner/core/src/main/res/values-xxhdpi/integers.xml b/library/external/barcodescanner/core/src/main/res/values-xxhdpi/integers.xml new file mode 100644 index 0000000000..d69e2a8b0f --- /dev/null +++ b/library/external/barcodescanner/core/src/main/res/values-xxhdpi/integers.xml @@ -0,0 +1,5 @@ + + + 6 + 100 + \ No newline at end of file diff --git a/library/external/barcodescanner/core/src/main/res/values/attrs.xml b/library/external/barcodescanner/core/src/main/res/values/attrs.xml new file mode 100644 index 0000000000..8e7485ebb3 --- /dev/null +++ b/library/external/barcodescanner/core/src/main/res/values/attrs.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/library/external/barcodescanner/core/src/main/res/values/colors.xml b/library/external/barcodescanner/core/src/main/res/values/colors.xml new file mode 100644 index 0000000000..58c019a6a9 --- /dev/null +++ b/library/external/barcodescanner/core/src/main/res/values/colors.xml @@ -0,0 +1,6 @@ + + + #60000000 + #ffcc0000 + #ffafed44 + \ No newline at end of file diff --git a/library/external/barcodescanner/core/src/main/res/values/integers.xml b/library/external/barcodescanner/core/src/main/res/values/integers.xml new file mode 100644 index 0000000000..690b6cd3c9 --- /dev/null +++ b/library/external/barcodescanner/core/src/main/res/values/integers.xml @@ -0,0 +1,5 @@ + + + 4 + 60 + diff --git a/library/external/barcodescanner/zxing/build.gradle b/library/external/barcodescanner/zxing/build.gradle new file mode 100644 index 0000000000..e84d0f5bb9 --- /dev/null +++ b/library/external/barcodescanner/zxing/build.gradle @@ -0,0 +1,29 @@ +apply plugin: 'com.android.library' + +android { + namespace "me.dm7.barcodescanner.zxing" + + compileSdk versions.compileSdk + + defaultConfig { + minSdk versions.minSdk + targetSdk versions.targetSdk + } + + compileOptions { + sourceCompatibility versions.sourceCompat + targetCompatibility versions.targetCompat + } +} + +dependencies { + api project(":library:external:barcodescanner:core") + // Stick to 3.3.3 because of https://github.com/zxing/zxing/issues/1170 + api 'com.google.zxing:core:3.3.3' +} + +afterEvaluate { + tasks.findAll { it.name.startsWith("lint") }.each { + it.enabled = false + } +} diff --git a/library/external/barcodescanner/zxing/src/main/java/me/dm7/barcodescanner/zxing/ZXingScannerView.java b/library/external/barcodescanner/zxing/src/main/java/me/dm7/barcodescanner/zxing/ZXingScannerView.java new file mode 100644 index 0000000000..d1717ba5be --- /dev/null +++ b/library/external/barcodescanner/zxing/src/main/java/me/dm7/barcodescanner/zxing/ZXingScannerView.java @@ -0,0 +1,198 @@ +package me.dm7.barcodescanner.zxing; + +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.Rect; +import android.hardware.Camera; +import android.os.Handler; +import android.os.Looper; +import android.util.AttributeSet; +import android.util.Log; + +import com.google.zxing.BarcodeFormat; +import com.google.zxing.BinaryBitmap; +import com.google.zxing.DecodeHintType; +import com.google.zxing.LuminanceSource; +import com.google.zxing.MultiFormatReader; +import com.google.zxing.NotFoundException; +import com.google.zxing.PlanarYUVLuminanceSource; +import com.google.zxing.ReaderException; +import com.google.zxing.Result; +import com.google.zxing.common.HybridBinarizer; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; + +import me.dm7.barcodescanner.core.BarcodeScannerView; +import me.dm7.barcodescanner.core.DisplayUtils; + +public class ZXingScannerView extends BarcodeScannerView { + private static final String TAG = "ZXingScannerView"; + + public interface ResultHandler { + void handleResult(Result rawResult); + } + + private MultiFormatReader mMultiFormatReader; + public static final List ALL_FORMATS = new ArrayList<>(); + private List mFormats; + private ResultHandler mResultHandler; + + static { + ALL_FORMATS.add(BarcodeFormat.AZTEC); + ALL_FORMATS.add(BarcodeFormat.CODABAR); + ALL_FORMATS.add(BarcodeFormat.CODE_39); + ALL_FORMATS.add(BarcodeFormat.CODE_93); + ALL_FORMATS.add(BarcodeFormat.CODE_128); + ALL_FORMATS.add(BarcodeFormat.DATA_MATRIX); + ALL_FORMATS.add(BarcodeFormat.EAN_8); + ALL_FORMATS.add(BarcodeFormat.EAN_13); + ALL_FORMATS.add(BarcodeFormat.ITF); + ALL_FORMATS.add(BarcodeFormat.MAXICODE); + ALL_FORMATS.add(BarcodeFormat.PDF_417); + ALL_FORMATS.add(BarcodeFormat.QR_CODE); + ALL_FORMATS.add(BarcodeFormat.RSS_14); + ALL_FORMATS.add(BarcodeFormat.RSS_EXPANDED); + ALL_FORMATS.add(BarcodeFormat.UPC_A); + ALL_FORMATS.add(BarcodeFormat.UPC_E); + ALL_FORMATS.add(BarcodeFormat.UPC_EAN_EXTENSION); + } + + public ZXingScannerView(Context context) { + super(context); + initMultiFormatReader(); + } + + public ZXingScannerView(Context context, AttributeSet attributeSet) { + super(context, attributeSet); + initMultiFormatReader(); + } + + public void setFormats(List formats) { + mFormats = formats; + initMultiFormatReader(); + } + + public void setResultHandler(ResultHandler resultHandler) { + mResultHandler = resultHandler; + } + + public Collection getFormats() { + if(mFormats == null) { + return ALL_FORMATS; + } + return mFormats; + } + + private void initMultiFormatReader() { + Map hints = new EnumMap<>(DecodeHintType.class); + hints.put(DecodeHintType.POSSIBLE_FORMATS, getFormats()); + mMultiFormatReader = new MultiFormatReader(); + mMultiFormatReader.setHints(hints); + } + + @Override + public void onPreviewFrame(byte[] data, Camera camera) { + if(mResultHandler == null) { + return; + } + + try { + Camera.Parameters parameters = camera.getParameters(); + Camera.Size size = parameters.getPreviewSize(); + int width = size.width; + int height = size.height; + + if (DisplayUtils.getScreenOrientation(getContext()) == Configuration.ORIENTATION_PORTRAIT) { + int rotationCount = getRotationCount(); + if (rotationCount == 1 || rotationCount == 3) { + int tmp = width; + width = height; + height = tmp; + } + data = getRotatedData(data, camera); + } + + Result rawResult = null; + PlanarYUVLuminanceSource source = buildLuminanceSource(data, width, height); + + if (source != null) { + BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); + try { + rawResult = mMultiFormatReader.decodeWithState(bitmap); + } catch (ReaderException re) { + // continue + } catch (NullPointerException npe) { + // This is terrible + } catch (ArrayIndexOutOfBoundsException aoe) { + + } finally { + mMultiFormatReader.reset(); + } + + if (rawResult == null) { + LuminanceSource invertedSource = source.invert(); + bitmap = new BinaryBitmap(new HybridBinarizer(invertedSource)); + try { + rawResult = mMultiFormatReader.decodeWithState(bitmap); + } catch (NotFoundException e) { + // continue + } finally { + mMultiFormatReader.reset(); + } + } + } + + final Result finalRawResult = rawResult; + + if (finalRawResult != null) { + Handler handler = new Handler(Looper.getMainLooper()); + handler.post(new Runnable() { + @Override + public void run() { + // Stopping the preview can take a little long. + // So we want to set result handler to null to discard subsequent calls to + // onPreviewFrame. + ResultHandler tmpResultHandler = mResultHandler; + mResultHandler = null; + + stopCameraPreview(); + if (tmpResultHandler != null) { + tmpResultHandler.handleResult(finalRawResult); + } + } + }); + } else { + camera.setOneShotPreviewCallback(this); + } + } catch(RuntimeException e) { + // TODO: Terrible hack. It is possible that this method is invoked after camera is released. + Log.e(TAG, e.toString(), e); + } + } + + public void resumeCameraPreview(ResultHandler resultHandler) { + mResultHandler = resultHandler; + super.resumeCameraPreview(); + } + + public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) { + Rect rect = getFramingRectInPreview(width, height); + if (rect == null) { + return null; + } + // Go ahead and assume it's YUV rather than die. + PlanarYUVLuminanceSource source = null; + + try { + source = new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top, + rect.width(), rect.height(), false); + } catch(Exception e) { + } + + return source; + } +} diff --git a/library/external/jsonviewer/build.gradle b/library/external/jsonviewer/build.gradle index 7b3b62c082..c501f583d0 100644 --- a/library/external/jsonviewer/build.gradle +++ b/library/external/jsonviewer/build.gradle @@ -58,9 +58,7 @@ dependencies { implementation libs.airbnb.mavericks // Span utils - implementation('me.gujun.android:span:1.7') { - exclude group: 'com.android.support', module: 'support-annotations' - } + implementation project(":library:external:span") implementation libs.jetbrains.coroutinesCore implementation libs.jetbrains.coroutinesAndroid diff --git a/library/external/realmfieldnameshelper/build.gradle b/library/external/realmfieldnameshelper/build.gradle new file mode 100644 index 0000000000..e051550210 --- /dev/null +++ b/library/external/realmfieldnameshelper/build.gradle @@ -0,0 +1,23 @@ +apply plugin: 'kotlin' +apply plugin: 'java' + +sourceCompatibility = versions.sourceCompat +targetCompatibility = versions.sourceCompat + +dependencies { + implementation 'com.squareup:javapoet:1.13.0' +} + +task javadocJar(type: Jar, dependsOn: 'javadoc') { + from javadoc.destinationDir + classifier = 'javadoc' +} +task sourcesJar(type: Jar, dependsOn: 'classes') { + from sourceSets.main.allSource + classifier = 'sources' +} + +sourceSets { + main.java.srcDirs += 'src/main/kotlin' +} + diff --git a/library/external/realmfieldnameshelper/src/main/kotlin/dk/ilios/realmfieldnames/ClassData.kt b/library/external/realmfieldnameshelper/src/main/kotlin/dk/ilios/realmfieldnames/ClassData.kt new file mode 100644 index 0000000000..d683a2adef --- /dev/null +++ b/library/external/realmfieldnameshelper/src/main/kotlin/dk/ilios/realmfieldnames/ClassData.kt @@ -0,0 +1,24 @@ +package dk.ilios.realmfieldnames + +import java.util.TreeMap + +/** + * Class responsible for keeping track of the metadata for each Realm model class. + */ +class ClassData(val packageName: String?, val simpleClassName: String, val libraryClass: Boolean = false) { + + val fields = TreeMap() // + + fun addField(field: String, linkedType: String?) { + fields.put(field, linkedType) + } + + val qualifiedClassName: String + get() { + if (packageName != null && !packageName.isEmpty()) { + return packageName + "." + simpleClassName + } else { + return simpleClassName + } + } +} diff --git a/library/external/realmfieldnameshelper/src/main/kotlin/dk/ilios/realmfieldnames/FieldNameFormatter.kt b/library/external/realmfieldnameshelper/src/main/kotlin/dk/ilios/realmfieldnames/FieldNameFormatter.kt new file mode 100644 index 0000000000..95f0024721 --- /dev/null +++ b/library/external/realmfieldnameshelper/src/main/kotlin/dk/ilios/realmfieldnames/FieldNameFormatter.kt @@ -0,0 +1,79 @@ +package dk.ilios.realmfieldnames + +import java.util.Locale + +/** + * Class for encapsulating the rules for converting between the field name in the Realm model class + * and the matching name in the "<class>Fields" class. + */ +class FieldNameFormatter { + + @JvmOverloads + fun format(fieldName: String?, locale: Locale = Locale.US): String { + if (fieldName == null || fieldName == "") { + return "" + } + + // Normalize word separator chars + val normalizedFieldName: String = fieldName.replace('-', '_') + + // Iterate field name using the following rules + // lowerCase m followed by upperCase anything is considered hungarian notation + // lowercase char followed by uppercase char is considered camel case + // Two uppercase chars following each other is considered non-standard camelcase + // _ and - are treated as word separators + val result = StringBuilder(normalizedFieldName.length) + + if (normalizedFieldName.codePointCount(0, normalizedFieldName.length) == 1) { + result.append(normalizedFieldName) + } else { + var previousCodepoint: Int? + var currentCodepoint: Int? = null + val length = normalizedFieldName.length + var offset = 0 + while (offset < length) { + previousCodepoint = currentCodepoint + currentCodepoint = normalizedFieldName.codePointAt(offset) + + if (previousCodepoint != null) { + if (Character.isUpperCase(currentCodepoint) && + !Character.isUpperCase(previousCodepoint) && + previousCodepoint === 'm'.code as Int? && + result.length == 1 + ) { + // Hungarian notation starting with: mX + result.delete(0, 1) + result.appendCodePoint(currentCodepoint) + } else if (Character.isUpperCase(currentCodepoint) && Character.isUpperCase(previousCodepoint)) { + // InvalidCamelCase: XXYx (should have been xxYx) + if (offset + Character.charCount(currentCodepoint) < normalizedFieldName.length) { + val nextCodePoint = normalizedFieldName.codePointAt(offset + Character.charCount(currentCodepoint)) + if (Character.isLowerCase(nextCodePoint)) { + result.append("_") + } + } + result.appendCodePoint(currentCodepoint) + } else if (currentCodepoint === '-'.code as Int? || currentCodepoint === '_'.code as Int?) { + // Word-separator: x-x or x_x + result.append("_") + } else if (Character.isUpperCase(currentCodepoint) && !Character.isUpperCase(previousCodepoint) && Character.isLetterOrDigit( + previousCodepoint + )) { + // camelCase: xX + result.append("_") + result.appendCodePoint(currentCodepoint) + } else { + // Unknown type + result.appendCodePoint(currentCodepoint) + } + } else { + // Only triggered for first code point + result.appendCodePoint(currentCodepoint) + } + offset += Character.charCount(currentCodepoint) + } + } + + return result.toString().uppercase(locale) + } +} diff --git a/library/external/realmfieldnameshelper/src/main/kotlin/dk/ilios/realmfieldnames/FileGenerator.kt b/library/external/realmfieldnameshelper/src/main/kotlin/dk/ilios/realmfieldnames/FileGenerator.kt new file mode 100644 index 0000000000..2ddba1ccbd --- /dev/null +++ b/library/external/realmfieldnameshelper/src/main/kotlin/dk/ilios/realmfieldnames/FileGenerator.kt @@ -0,0 +1,77 @@ +package dk.ilios.realmfieldnames + +import com.squareup.javapoet.FieldSpec +import com.squareup.javapoet.JavaFile +import com.squareup.javapoet.TypeSpec +import java.io.IOException +import javax.annotation.processing.Filer +import javax.lang.model.element.Modifier + +/** + * Class responsible for creating the final output files. + */ +class FileGenerator(private val filer: Filer) { + private val formatter: FieldNameFormatter + + init { + this.formatter = FieldNameFormatter() + } + + /** + * Generates all the "<class>Fields" fields with field name references. + * @param fileData Files to create. + * * + * @return `true` if the files where generated, `false` if not. + */ + fun generate(fileData: Set): Boolean { + return fileData + .filter { !it.libraryClass } + .all { generateFile(it, fileData) } + } + + private fun generateFile(classData: ClassData, classPool: Set): Boolean { + val fileBuilder = TypeSpec.classBuilder(classData.simpleClassName + "Fields") + .addModifiers(Modifier.PUBLIC, Modifier.FINAL) + .addJavadoc("This class enumerate all queryable fields in {@link \$L.\$L}\n", + classData.packageName, classData.simpleClassName) + + // Add a static field reference to each queryable field in the Realm model class + classData.fields.forEach { fieldName, value -> + if (value != null) { + // Add linked field names (only up to depth 1) + for (data in classPool) { + if (data.qualifiedClassName == value) { + val linkedTypeSpec = TypeSpec.classBuilder(formatter.format(fieldName)) + .addModifiers(Modifier.PUBLIC, Modifier.FINAL, Modifier.STATIC) + val linkedClassFields = data.fields + addField(linkedTypeSpec, "$", fieldName) + for (linkedFieldName in linkedClassFields.keys) { + addField(linkedTypeSpec, linkedFieldName, fieldName + "." + linkedFieldName) + } + fileBuilder.addType(linkedTypeSpec.build()) + } + } + } else { + // Add normal field name + addField(fileBuilder, fieldName, fieldName) + } + } + + val javaFile = JavaFile.builder(classData.packageName, fileBuilder.build()).build() + try { + javaFile.writeTo(filer) + return true + } catch (e: IOException) { + // e.printStackTrace() + return false + } + } + + private fun addField(fileBuilder: TypeSpec.Builder, fieldName: String, fieldNameValue: String) { + val field = FieldSpec.builder(String::class.java, formatter.format(fieldName)) + .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL) + .initializer("\$S", fieldNameValue) + .build() + fileBuilder.addField(field) + } +} diff --git a/library/external/realmfieldnameshelper/src/main/kotlin/dk/ilios/realmfieldnames/RealmFieldNamesProcessor.kt b/library/external/realmfieldnameshelper/src/main/kotlin/dk/ilios/realmfieldnames/RealmFieldNamesProcessor.kt new file mode 100644 index 0000000000..29d044c46c --- /dev/null +++ b/library/external/realmfieldnameshelper/src/main/kotlin/dk/ilios/realmfieldnames/RealmFieldNamesProcessor.kt @@ -0,0 +1,197 @@ +package dk.ilios.realmfieldnames + +import javax.annotation.processing.AbstractProcessor +import javax.annotation.processing.Messager +import javax.annotation.processing.ProcessingEnvironment +import javax.annotation.processing.RoundEnvironment +import javax.annotation.processing.SupportedAnnotationTypes +import javax.lang.model.SourceVersion +import javax.lang.model.element.Element +import javax.lang.model.element.ElementKind +import javax.lang.model.element.Modifier +import javax.lang.model.element.PackageElement +import javax.lang.model.element.TypeElement +import javax.lang.model.element.VariableElement +import javax.lang.model.type.DeclaredType +import javax.lang.model.type.TypeMirror +import javax.lang.model.util.Elements +import javax.lang.model.util.Types +import javax.tools.Diagnostic + +/** + * The Realm Field Names Generator is a processor that looks at all available Realm model classes + * and create an companion class with easy, type-safe access to all field names. + */ + +@SupportedAnnotationTypes("io.realm.annotations.RealmClass") +class RealmFieldNamesProcessor : AbstractProcessor() { + + private val classes = HashSet() + private lateinit var typeUtils: Types + private lateinit var messager: Messager + private lateinit var elementUtils: Elements + private var ignoreAnnotation: TypeMirror? = null + private var realmClassAnnotation: TypeElement? = null + private var realmModelInterface: TypeMirror? = null + private var realmListClass: DeclaredType? = null + private var realmResultsClass: DeclaredType? = null + private var fileGenerator: FileGenerator? = null + private var done = false + + @Synchronized + override fun init(processingEnv: ProcessingEnvironment) { + super.init(processingEnv) + typeUtils = processingEnv.typeUtils!! + messager = processingEnv.messager!! + elementUtils = processingEnv.elementUtils!! + + // If the Realm class isn't found something is wrong the project setup. + // Most likely Realm isn't on the class path, so just disable the + // annotation processor + val isRealmAvailable = elementUtils.getTypeElement("io.realm.Realm") != null + if (!isRealmAvailable) { + done = true + } else { + ignoreAnnotation = elementUtils.getTypeElement("io.realm.annotations.Ignore")?.asType() + realmClassAnnotation = elementUtils.getTypeElement("io.realm.annotations.RealmClass") + realmModelInterface = elementUtils.getTypeElement("io.realm.RealmModel")?.asType() + realmListClass = typeUtils.getDeclaredType( + elementUtils.getTypeElement("io.realm.RealmList"), + typeUtils.getWildcardType(null, null) + ) + realmResultsClass = typeUtils.getDeclaredType( + elementUtils.getTypeElement("io.realm.RealmResults"), + typeUtils.getWildcardType(null, null) + ) + fileGenerator = FileGenerator(processingEnv.filer) + } + } + + override fun getSupportedSourceVersion(): SourceVersion { + return SourceVersion.latestSupported() + } + + override fun process(annotations: Set, roundEnv: RoundEnvironment): Boolean { + if (done) { + return CONSUME_ANNOTATIONS + } + + // Create all proxy classes + roundEnv.getElementsAnnotatedWith(realmClassAnnotation).forEach { classElement -> + if (typeUtils.isAssignable(classElement.asType(), realmModelInterface)) { + val classData = processClass(classElement as TypeElement) + classes.add(classData) + } + } + + // If a model class references a library class, the library class will not be part of this + // annotation processor round. For all those references we need to pull field information + // from the classpath instead. + val libraryClasses = HashMap() + classes.forEach { + it.fields.forEach { _, value -> + // Analyze the library class file the first time it is encountered. + if (value != null) { + if (classes.all { it.qualifiedClassName != value } && !libraryClasses.containsKey(value)) { + libraryClasses.put(value, processLibraryClass(value)) + } + } + } + } + classes.addAll(libraryClasses.values) + + done = fileGenerator!!.generate(classes) + return CONSUME_ANNOTATIONS + } + + private fun processClass(classElement: TypeElement): ClassData { + val packageName = getPackageName(classElement) + val className = classElement.simpleName.toString() + val data = ClassData(packageName, className) + + // Find all appropriate fields + classElement.enclosedElements.forEach { + val elementKind = it.kind + if (elementKind == ElementKind.FIELD) { + val variableElement = it as VariableElement + + val modifiers = variableElement.modifiers + if (modifiers.contains(Modifier.STATIC)) { + return@forEach // completely ignore any static fields + } + + // Don't add any fields marked with @Ignore + val ignoreField = variableElement.annotationMirrors + .map { it.annotationType.toString() } + .contains("io.realm.annotations.Ignore") + + if (!ignoreField) { + data.addField(it.getSimpleName().toString(), getLinkedFieldType(it)) + } + } + } + + return data + } + + private fun processLibraryClass(qualifiedClassName: String): ClassData { + val libraryClass = Class.forName(qualifiedClassName) // Library classes should be on the classpath + val packageName = libraryClass.`package`.name + val className = libraryClass.simpleName + val data = ClassData(packageName, className, libraryClass = true) + + libraryClass.declaredFields.forEach { field -> + if (java.lang.reflect.Modifier.isStatic(field.modifiers)) { + return@forEach // completely ignore any static fields + } + + // Add field if it is not being ignored. + if (field.annotations.all { it.toString() != "io.realm.annotations.Ignore" }) { + data.addField(field.name, field.type.name) + } + } + + return data + } + + /** + * Returns the qualified name of the linked Realm class field or `null` if it is not a linked + * class. + */ + private fun getLinkedFieldType(field: Element): String? { + if (typeUtils.isAssignable(field.asType(), realmModelInterface)) { + // Object link + val typeElement = elementUtils.getTypeElement(field.asType().toString()) + return typeElement.qualifiedName.toString() + } else if (typeUtils.isAssignable(field.asType(), realmListClass) || typeUtils.isAssignable(field.asType(), realmResultsClass)) { + // List link or LinkingObjects + val fieldType = field.asType() + val typeArguments = (fieldType as DeclaredType).typeArguments + if (typeArguments.size == 0) { + return null + } + return typeArguments[0].toString() + } else { + return null + } + } + + private fun getPackageName(classElement: TypeElement): String? { + val enclosingElement = classElement.enclosingElement + + if (enclosingElement.kind != ElementKind.PACKAGE) { + messager.printMessage( + Diagnostic.Kind.ERROR, + "Could not determine the package name. Enclosing element was: " + enclosingElement.kind + ) + return null + } + + val packageElement = enclosingElement as PackageElement + return packageElement.qualifiedName.toString() + } + + companion object { + private const val CONSUME_ANNOTATIONS = false + } +} diff --git a/library/external/realmfieldnameshelper/src/main/resources/META-INF/gradle/incremental.annotation.processors b/library/external/realmfieldnameshelper/src/main/resources/META-INF/gradle/incremental.annotation.processors new file mode 100644 index 0000000000..57897c8297 --- /dev/null +++ b/library/external/realmfieldnameshelper/src/main/resources/META-INF/gradle/incremental.annotation.processors @@ -0,0 +1 @@ +dk.ilios.realmfieldnames.RealmFieldNamesProcessor,aggregating \ No newline at end of file diff --git a/library/external/realmfieldnameshelper/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/library/external/realmfieldnameshelper/src/main/resources/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 0000000000..58fadd699c --- /dev/null +++ b/library/external/realmfieldnameshelper/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1 @@ +dk.ilios.realmfieldnames.RealmFieldNamesProcessor \ No newline at end of file diff --git a/library/external/span/build.gradle b/library/external/span/build.gradle new file mode 100644 index 0000000000..05adbacb4d --- /dev/null +++ b/library/external/span/build.gradle @@ -0,0 +1,20 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + +android { + namespace "me.gujun.android.span" + compileSdk versions.compileSdk + + defaultConfig { + minSdk versions.minSdk + targetSdk versions.targetSdk + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } +} + +dependencies { + implementation 'com.android.support:support-annotations:28.0.0' +} diff --git a/library/external/span/src/main/kotlin/me/gujun/android/span/Span.kt b/library/external/span/src/main/kotlin/me/gujun/android/span/Span.kt new file mode 100644 index 0000000000..5ca63b7e01 --- /dev/null +++ b/library/external/span/src/main/kotlin/me/gujun/android/span/Span.kt @@ -0,0 +1,316 @@ +package me.gujun.android.span + +import android.graphics.Typeface +import android.graphics.drawable.Drawable +import android.text.Layout +import android.text.Spannable +import android.text.SpannableStringBuilder +import android.text.TextUtils +import android.text.style.AbsoluteSizeSpan +import android.text.style.AlignmentSpan +import android.text.style.BackgroundColorSpan +import android.text.style.ForegroundColorSpan +import android.text.style.ImageSpan +import android.text.style.QuoteSpan +import android.text.style.StyleSpan +import android.text.style.SubscriptSpan +import android.text.style.SuperscriptSpan +import android.text.style.TypefaceSpan +import android.text.style.URLSpan +import android.view.View +import androidx.annotation.ColorInt +import androidx.annotation.Dimension +import me.gujun.android.span.style.CustomTypefaceSpan +import me.gujun.android.span.style.LineSpacingSpan +import me.gujun.android.span.style.SimpleClickableSpan +import me.gujun.android.span.style.TextDecorationLineSpan +import me.gujun.android.span.style.VerticalPaddingSpan + +class Span(val parent: Span? = null) : SpannableStringBuilder() { + + companion object { + val EMPTY_STYLE = Span() + + var globalStyle: Span = EMPTY_STYLE + } + + var text: CharSequence = "" + + @ColorInt var textColor: Int? = parent?.textColor + + @ColorInt var backgroundColor: Int? = parent?.backgroundColor + + @Dimension(unit = Dimension.PX) var textSize: Int? = parent?.textSize + + var fontFamily: String? = parent?.fontFamily + + var typeface: Typeface? = parent?.typeface + + var textStyle: String? = parent?.textStyle + + var alignment: String? = parent?.alignment + + var textDecorationLine: String? = parent?.textDecorationLine + + @Dimension(unit = Dimension.PX) var lineSpacing: Int? = null + + @Dimension(unit = Dimension.PX) var paddingTop: Int? = null + + @Dimension(unit = Dimension.PX) var paddingBottom: Int? = null + + @Dimension(unit = Dimension.PX) var verticalPadding: Int? = null + + var onClick: (() -> Unit)? = null + + var spans: ArrayList = ArrayList() + + var style: Span = EMPTY_STYLE + + private fun buildCharacterStyle(builder: ArrayList) { + if (textColor != null) { + builder.add(ForegroundColorSpan(textColor!!)) + } + + if (backgroundColor != null) { + builder.add(BackgroundColorSpan(backgroundColor!!)) + } + + if (textSize != null) { + builder.add(AbsoluteSizeSpan(textSize!!)) + } + + if (!TextUtils.isEmpty(fontFamily)) { + builder.add(TypefaceSpan(fontFamily)) + } + + if (typeface != null) { + builder.add(CustomTypefaceSpan(typeface!!)) + } + + if (!TextUtils.isEmpty(textStyle)) { + builder.add(StyleSpan(when (textStyle) { + "normal" -> Typeface.NORMAL + "bold" -> Typeface.BOLD + "italic" -> Typeface.ITALIC + "bold_italic" -> Typeface.BOLD_ITALIC + else -> throw RuntimeException("Unknown text style") + })) + } + + if (!TextUtils.isEmpty(textDecorationLine)) { + builder.add(TextDecorationLineSpan(textDecorationLine!!)) + } + + if (onClick != null) { + builder.add(object : SimpleClickableSpan() { + override fun onClick(widget: View) { + onClick?.invoke() + } + }) + } + } + + private fun buildParagraphStyle(builder: ArrayList) { + if (!TextUtils.isEmpty(alignment)) { + builder.add(AlignmentSpan.Standard(when (alignment) { + "normal" -> Layout.Alignment.ALIGN_NORMAL + "opposite" -> Layout.Alignment.ALIGN_OPPOSITE + "center" -> Layout.Alignment.ALIGN_CENTER + else -> throw RuntimeException("Unknown text alignment") + })) + } + + if (lineSpacing != null) { + builder.add(LineSpacingSpan(lineSpacing!!)) + } + + paddingTop = when { + paddingTop != null -> paddingTop + verticalPadding != null -> verticalPadding + else -> 0 + } + paddingBottom = when { + paddingBottom != null -> paddingBottom + verticalPadding != null -> verticalPadding + else -> 0 + } + if (paddingTop != 0 || paddingBottom != 0) { + builder.add(VerticalPaddingSpan(paddingTop!!, paddingBottom!!)) + } + } + + private fun prebuild() { + override(style) + } + + fun build(): Span { + prebuild() + val builder = ArrayList() + if (!TextUtils.isEmpty(text)) { + var p = this.parent + while (p != null) { + if (!TextUtils.isEmpty(p.text)) { + throw RuntimeException("Can't nest \"$text\" in spans") + } + p = p.parent + } + append(text) + buildCharacterStyle(builder) + buildParagraphStyle(builder) + } else { + buildParagraphStyle(builder) + } + + builder.addAll(spans) + builder.forEach { + setSpan(it, 0, length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) + } + return this + } + + fun override(style: Span) { + if (textColor == null) { + textColor = style.textColor + } + if (backgroundColor == null) { + backgroundColor = style.backgroundColor + } + if (textSize == null) { + textSize = style.textSize + } + if (fontFamily == null) { + fontFamily = style.fontFamily + } + if (typeface == null) { + typeface = style.typeface + } + if (textStyle == null) { + textStyle = style.textStyle + } + if (alignment == null) { + alignment = style.alignment + } + if (textDecorationLine == null) { + textDecorationLine = style.textDecorationLine + } + if (lineSpacing == null) { + lineSpacing = style.lineSpacing + } + if (paddingTop == null) { + paddingTop = style.paddingTop + } + if (paddingBottom == null) { + paddingBottom = style.paddingBottom + } + if (verticalPadding == null) { + verticalPadding = style.verticalPadding + } + if (onClick == null) { + onClick = style.onClick + } + spans.addAll(style.spans) + } + + operator fun CharSequence.unaryPlus(): CharSequence { + return append(Span(parent = this@Span).apply { + text = this@unaryPlus + build() + }) + } + + operator fun Span.plus(other: CharSequence): CharSequence { + return append(Span(parent = this).apply { + text = other + build() + }) + } +} + +fun span(init: Span.() -> Unit): Span = Span().apply { + override(Span.globalStyle) + init() + build() +} + +fun span(text: CharSequence, init: Span.() -> Unit): Span = Span().apply { + override(Span.globalStyle) + this.text = text + init() + build() +} + +fun style(init: Span.() -> Unit): Span = Span().apply { + init() +} + +fun Span.span(init: Span.() -> Unit = {}): Span = apply { + append(Span(parent = this).apply { + init() + build() + }) +} + +fun Span.span(text: CharSequence, init: Span.() -> Unit = {}): Span = apply { + append(Span(parent = this).apply { + this.text = text + init() + build() + }) +} + +fun Span.link(url: String, text: CharSequence = "", + init: Span.() -> Unit = {}): Span = apply { + append(Span(parent = this).apply { + this.text = text + this.spans.add(URLSpan(url)) + init() + build() + }) +} + +fun Span.quote(@ColorInt color: Int, text: CharSequence = "", + init: Span.() -> Unit = {}): Span = apply { + append(Span(parent = this).apply { + this.text = text + this.spans.add(QuoteSpan(color)) + init() + build() + }) +} + +fun Span.superscript(text: CharSequence = "", init: Span.() -> Unit = {}): Span = apply { + append(Span(parent = this).apply { + this.text = text + this.spans.add(SuperscriptSpan()) + init() + build() + }) +} + +fun Span.subscript(text: CharSequence = "", init: Span.() -> Unit = {}): Span = apply { + append(Span(parent = this).apply { + this.text = text + this.spans.add(SubscriptSpan()) + init() + build() + }) +} + +fun Span.image(drawable: Drawable, alignment: String = "bottom", + init: Span.() -> Unit = {}): Span = apply { + drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight) + append(Span(parent = this).apply { + this.text = " " + this.spans.add(ImageSpan(drawable, when (alignment) { + "bottom" -> ImageSpan.ALIGN_BOTTOM + "baseline" -> ImageSpan.ALIGN_BASELINE + else -> throw RuntimeException("Unknown image alignment") + })) + init() + build() + }) +} + +fun Span.addSpan(what: Any) = apply { + this.spans.add(what) +} diff --git a/library/external/span/src/main/kotlin/me/gujun/android/span/style/CustomTypefaceSpan.kt b/library/external/span/src/main/kotlin/me/gujun/android/span/style/CustomTypefaceSpan.kt new file mode 100644 index 0000000000..c737c5bf11 --- /dev/null +++ b/library/external/span/src/main/kotlin/me/gujun/android/span/style/CustomTypefaceSpan.kt @@ -0,0 +1,36 @@ +package me.gujun.android.span.style + +import android.graphics.Paint +import android.graphics.Typeface +import android.text.TextPaint +import android.text.style.MetricAffectingSpan + +class CustomTypefaceSpan(private val tf: Typeface) : MetricAffectingSpan() { + + override fun updateMeasureState(paint: TextPaint) { + apply(paint, tf) + } + + override fun updateDrawState(ds: TextPaint) { + apply(ds, tf) + } + + private fun apply(paint: Paint, tf: Typeface) { + val oldStyle: Int + + val old = paint.typeface + oldStyle = old?.style ?: 0 + + val fake = oldStyle and tf.style.inv() + + if (fake and Typeface.BOLD != 0) { + paint.isFakeBoldText = true + } + + if (fake and Typeface.ITALIC != 0) { + paint.textSkewX = -0.25f + } + + paint.typeface = tf + } +} diff --git a/library/external/span/src/main/kotlin/me/gujun/android/span/style/LineSpacingSpan.kt b/library/external/span/src/main/kotlin/me/gujun/android/span/style/LineSpacingSpan.kt new file mode 100644 index 0000000000..53aa42aa83 --- /dev/null +++ b/library/external/span/src/main/kotlin/me/gujun/android/span/style/LineSpacingSpan.kt @@ -0,0 +1,31 @@ +package me.gujun.android.span.style + +import android.graphics.Paint.FontMetricsInt +import android.text.Spanned +import android.text.style.LineHeightSpan + +class LineSpacingSpan(private val add: Int) : LineHeightSpan { + + override fun chooseHeight(text: CharSequence, start: Int, end: Int, spanstartv: Int, v: Int, + fm: FontMetricsInt) { + text as Spanned + /*val spanStart =*/ text.getSpanStart(this) + val spanEnd = text.getSpanEnd(this) + +// Log.d("DEBUG", "Text: start=$start end=$end v=$v") // end may include the \n character +// Log.d("DEBUG", "${text.slice(start until end)}".replace("\n", "#")) +// Log.d("DEBUG", "LineSpacingSpan: spanStart=$spanStart spanEnd=$spanEnd spanstartv=$spanstartv") +// Log.d("DEBUG", "$fm") +// Log.d("DEBUG", "-----------------------") + + if (spanstartv == v) { + fm.descent += add + } else if (text[start - 1] == '\n') { + fm.descent += add + } + + if (end == spanEnd || end - 1 == spanEnd) { + fm.descent -= add + } + } +} diff --git a/library/external/span/src/main/kotlin/me/gujun/android/span/style/SimpleClickableSpan.kt b/library/external/span/src/main/kotlin/me/gujun/android/span/style/SimpleClickableSpan.kt new file mode 100644 index 0000000000..2ae524bca9 --- /dev/null +++ b/library/external/span/src/main/kotlin/me/gujun/android/span/style/SimpleClickableSpan.kt @@ -0,0 +1,10 @@ +package me.gujun.android.span.style + +import android.text.TextPaint +import android.text.style.ClickableSpan + +abstract class SimpleClickableSpan : ClickableSpan() { + override fun updateDrawState(ds: TextPaint) { + // no-op + } +} diff --git a/library/external/span/src/main/kotlin/me/gujun/android/span/style/TextDecorationLineSpan.kt b/library/external/span/src/main/kotlin/me/gujun/android/span/style/TextDecorationLineSpan.kt new file mode 100644 index 0000000000..ce37c138f7 --- /dev/null +++ b/library/external/span/src/main/kotlin/me/gujun/android/span/style/TextDecorationLineSpan.kt @@ -0,0 +1,29 @@ +package me.gujun.android.span.style + +import android.text.TextPaint +import android.text.style.CharacterStyle + +class TextDecorationLineSpan(private val textDecorationLine: String) : CharacterStyle() { + + override fun updateDrawState(tp: TextPaint) { + when (textDecorationLine) { + "none" -> { + tp.isUnderlineText = false + tp.isStrikeThruText = false + } + "underline" -> { + tp.isUnderlineText = true + tp.isStrikeThruText = false + } + "line-through" -> { + tp.isUnderlineText = false + tp.isStrikeThruText = true + } + "underline line-through" -> { + tp.isUnderlineText = true + tp.isStrikeThruText = true + } + else -> throw RuntimeException("Unknown text decoration line") + } + } +} diff --git a/library/external/span/src/main/kotlin/me/gujun/android/span/style/VerticalPaddingSpan.kt b/library/external/span/src/main/kotlin/me/gujun/android/span/style/VerticalPaddingSpan.kt new file mode 100644 index 0000000000..600ea72e57 --- /dev/null +++ b/library/external/span/src/main/kotlin/me/gujun/android/span/style/VerticalPaddingSpan.kt @@ -0,0 +1,41 @@ +package me.gujun.android.span.style + +import android.graphics.Paint.FontMetricsInt +import android.text.Spanned +import android.text.style.LineHeightSpan + +class VerticalPaddingSpan(private val paddingTop: Int, + private val paddingBottom: Int) : LineHeightSpan { + + private var flag: Boolean = true + + override fun chooseHeight(text: CharSequence, start: Int, end: Int, spanstartv: Int, v: Int, + fm: FontMetricsInt) { + text as Spanned + /*val spanStart =*/ text.getSpanStart(this) + val spanEnd = text.getSpanEnd(this) + +// Log.d("DEBUG", "Text: start=$start end=$end v=$v") // end may include the \n character +// Log.d("DEBUG", "${text.slice(start until end)}".replace("\n", "#")) +// Log.d("DEBUG", "VerticalPadding: spanStart=$spanStart spanEnd=$spanEnd spanstartv=$spanstartv") +// Log.d("DEBUG", "$fm") +// Log.d("DEBUG", "-----------------------") + + if (spanstartv == v) { + fm.top -= paddingTop + fm.ascent -= paddingTop + flag = true + } else if (flag && text[start - 1] != '\n') { + fm.top += paddingTop + fm.ascent += paddingTop + flag = false + } else { + flag = false + } + + if (end == spanEnd || end - 1 == spanEnd) { + fm.descent += paddingBottom + fm.bottom += paddingBottom + } + } +} diff --git a/library/external/textdrawable/build.gradle b/library/external/textdrawable/build.gradle new file mode 100644 index 0000000000..5eb27bf6aa --- /dev/null +++ b/library/external/textdrawable/build.gradle @@ -0,0 +1,25 @@ +apply plugin: 'com.android.library' + +apply plugin: 'com.android.library' + +android { + namespace "com.amulyakhare.textdrawable" + + compileSdk versions.compileSdk + + defaultConfig { + minSdk versions.minSdk + targetSdk versions.targetSdk + } + + compileOptions { + sourceCompatibility versions.sourceCompat + targetCompatibility versions.targetCompat + } +} + +afterEvaluate { + tasks.findAll { it.name.startsWith("lint") }.each { + it.enabled = false + } +} diff --git a/library/external/textdrawable/src/main/java/com/amulyakhare/textdrawable/TextDrawable.java b/library/external/textdrawable/src/main/java/com/amulyakhare/textdrawable/TextDrawable.java new file mode 100644 index 0000000000..db42f8b764 --- /dev/null +++ b/library/external/textdrawable/src/main/java/com/amulyakhare/textdrawable/TextDrawable.java @@ -0,0 +1,316 @@ +package com.amulyakhare.textdrawable; + +import android.graphics.*; +import android.graphics.drawable.ShapeDrawable; +import android.graphics.drawable.shapes.OvalShape; +import android.graphics.drawable.shapes.RectShape; +import android.graphics.drawable.shapes.RoundRectShape; + +/** + * @author amulya + * @datetime 14 Oct 2014, 3:53 PM + */ +public class TextDrawable extends ShapeDrawable { + + private final Paint textPaint; + private final Paint borderPaint; + private static final float SHADE_FACTOR = 0.9f; + private final String text; + private final int color; + private final RectShape shape; + private final int height; + private final int width; + private final int fontSize; + private final float radius; + private final int borderThickness; + + private TextDrawable(Builder builder) { + super(builder.shape); + + // shape properties + shape = builder.shape; + height = builder.height; + width = builder.width; + radius = builder.radius; + + // text and color + text = builder.toUpperCase ? builder.text.toUpperCase() : builder.text; + color = builder.color; + + // text paint settings + fontSize = builder.fontSize; + textPaint = new Paint(); + textPaint.setColor(builder.textColor); + textPaint.setAntiAlias(true); + textPaint.setFakeBoldText(builder.isBold); + textPaint.setStyle(Paint.Style.FILL); + textPaint.setTypeface(builder.font); + textPaint.setTextAlign(Paint.Align.CENTER); + textPaint.setStrokeWidth(builder.borderThickness); + + // border paint settings + borderThickness = builder.borderThickness; + borderPaint = new Paint(); + borderPaint.setColor(getDarkerShade(color)); + borderPaint.setStyle(Paint.Style.STROKE); + borderPaint.setStrokeWidth(borderThickness); + + // drawable paint color + Paint paint = getPaint(); + paint.setColor(color); + + } + + private int getDarkerShade(int color) { + return Color.rgb((int)(SHADE_FACTOR * Color.red(color)), + (int)(SHADE_FACTOR * Color.green(color)), + (int)(SHADE_FACTOR * Color.blue(color))); + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + Rect r = getBounds(); + + + // draw border + if (borderThickness > 0) { + drawBorder(canvas); + } + + int count = canvas.save(); + canvas.translate(r.left, r.top); + + // draw text + int width = this.width < 0 ? r.width() : this.width; + int height = this.height < 0 ? r.height() : this.height; + int fontSize = this.fontSize < 0 ? (Math.min(width, height) / 2) : this.fontSize; + textPaint.setTextSize(fontSize); + canvas.drawText(text, width / 2, height / 2 - ((textPaint.descent() + textPaint.ascent()) / 2), textPaint); + + canvas.restoreToCount(count); + + } + + private void drawBorder(Canvas canvas) { + RectF rect = new RectF(getBounds()); + rect.inset(borderThickness/2, borderThickness/2); + + if (shape instanceof OvalShape) { + canvas.drawOval(rect, borderPaint); + } + else if (shape instanceof RoundRectShape) { + canvas.drawRoundRect(rect, radius, radius, borderPaint); + } + else { + canvas.drawRect(rect, borderPaint); + } + } + + @Override + public void setAlpha(int alpha) { + textPaint.setAlpha(alpha); + } + + @Override + public void setColorFilter(ColorFilter cf) { + textPaint.setColorFilter(cf); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + + @Override + public int getIntrinsicWidth() { + return width; + } + + @Override + public int getIntrinsicHeight() { + return height; + } + + public static IShapeBuilder builder() { + return new Builder(); + } + + public static class Builder implements IConfigBuilder, IShapeBuilder, IBuilder { + + private String text; + + private int color; + + private int borderThickness; + + private int width; + + private int height; + + private Typeface font; + + private RectShape shape; + + public int textColor; + + private int fontSize; + + private boolean isBold; + + private boolean toUpperCase; + + public float radius; + + private Builder() { + text = ""; + color = Color.GRAY; + textColor = Color.WHITE; + borderThickness = 0; + width = -1; + height = -1; + shape = new RectShape(); + font = Typeface.create("sans-serif-light", Typeface.NORMAL); + fontSize = -1; + isBold = false; + toUpperCase = false; + } + + public IConfigBuilder width(int width) { + this.width = width; + return this; + } + + public IConfigBuilder height(int height) { + this.height = height; + return this; + } + + public IConfigBuilder textColor(int color) { + this.textColor = color; + return this; + } + + public IConfigBuilder withBorder(int thickness) { + this.borderThickness = thickness; + return this; + } + + public IConfigBuilder useFont(Typeface font) { + this.font = font; + return this; + } + + public IConfigBuilder fontSize(int size) { + this.fontSize = size; + return this; + } + + public IConfigBuilder bold() { + this.isBold = true; + return this; + } + + public IConfigBuilder toUpperCase() { + this.toUpperCase = true; + return this; + } + + @Override + public IConfigBuilder beginConfig() { + return this; + } + + @Override + public IShapeBuilder endConfig() { + return this; + } + + @Override + public IBuilder rect() { + this.shape = new RectShape(); + return this; + } + + @Override + public IBuilder round() { + this.shape = new OvalShape(); + return this; + } + + @Override + public IBuilder roundRect(int radius) { + this.radius = radius; + float[] radii = {radius, radius, radius, radius, radius, radius, radius, radius}; + this.shape = new RoundRectShape(radii, null, null); + return this; + } + + @Override + public TextDrawable buildRect(String text, int color) { + rect(); + return build(text, color); + } + + @Override + public TextDrawable buildRoundRect(String text, int color, int radius) { + roundRect(radius); + return build(text, color); + } + + @Override + public TextDrawable buildRound(String text, int color) { + round(); + return build(text, color); + } + + @Override + public TextDrawable build(String text, int color) { + this.color = color; + this.text = text; + return new TextDrawable(this); + } + } + + public interface IConfigBuilder { + public IConfigBuilder width(int width); + + public IConfigBuilder height(int height); + + public IConfigBuilder textColor(int color); + + public IConfigBuilder withBorder(int thickness); + + public IConfigBuilder useFont(Typeface font); + + public IConfigBuilder fontSize(int size); + + public IConfigBuilder bold(); + + public IConfigBuilder toUpperCase(); + + public IShapeBuilder endConfig(); + } + + public static interface IBuilder { + + public TextDrawable build(String text, int color); + } + + public static interface IShapeBuilder { + + public IConfigBuilder beginConfig(); + + public IBuilder rect(); + + public IBuilder round(); + + public IBuilder roundRect(int radius); + + public TextDrawable buildRect(String text, int color); + + public TextDrawable buildRoundRect(String text, int color, int radius); + + public TextDrawable buildRound(String text, int color); + } +} \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-ar/strings.xml b/library/ui-strings/src/main/res/values-ar/strings.xml index 1df5a29451..14c322330d 100644 --- a/library/ui-strings/src/main/res/values-ar/strings.xml +++ b/library/ui-strings/src/main/res/values-ar/strings.xml @@ -1162,12 +1162,12 @@ كلمة السر الجديدة التالي - صفر - واحد - اثنان - قليلة - كثيرة - اخرى + لم تحدد + واحد محدد + اثنان محددان + %1$d محددة + %1$d محددة + %1$d محددة صفر @@ -1210,4 +1210,14 @@ د سا أنهى %1$s البث الصوتي. + أظهر كل الغرف في دليل الغرف. حتى الغرف ذات المحتوى الحساس. + هنا ستجد الطلبات والدعوات. + لا جديد. + الدعوات + الفضاءات هي طريقة جديدة لتنظيم الغرف والأفراد.أنشئ فضاءً للبدأ. + بدون فضاءات. + تفضيلات التخطيط + غير %1$s اسمه العلني إلى %2$s + إغلاق %s العناصر الفرعية + توسيع %s العناصر الفرعية \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-cs/strings.xml b/library/ui-strings/src/main/res/values-cs/strings.xml index 25b877648a..b74d4825e0 100644 --- a/library/ui-strings/src/main/res/values-cs/strings.xml +++ b/library/ui-strings/src/main/res/values-cs/strings.xml @@ -4,7 +4,7 @@ %1$s pozval(a) %2$s %1$s vás pozval(a) %1$s vstoupil(a) do místnosti - Uživatel %1$s opustil místnost + %1$s opustil(a) místnost %1$s odmítl(a) pozvání %1$s odebral(a) %2$s %1$s zrušil(a) vykázání %2$s @@ -28,7 +28,7 @@ (profilový obrázek byl také změněn) %1$s odstranili název místnosti %1$s odstranili téma místnosti - %1$s do této místnosti pozvali %2$s + %1$s do této místnosti pozval(a) %2$s %1$s přijali pozvání pro %2$s ** Nelze dešifrovat: %s ** Odesílatelovo zařízení nám neposlalo klíče pro tuto zprávu. @@ -40,7 +40,7 @@ %1$s a %2$s Prázdná místnost %s aktualizoval(a) tuto místnost. - %1$s zrušili pozvánku do místnosti pro %2$s + %1$s zrušil(a) pozvánku do místnosti pro %2$s Úvodní synchronizace: \nImportuji účet… Úvodní synchronizace: @@ -91,8 +91,8 @@ Odstranili jste téma místnosti %1$s odstranili obrázek místnosti Odstranili jste obrázek místnosti - Poslali jste %1$s pozvání ke vstupu do místnosti - Zrušili jste pozvánku ke vstupu do místnosti pro %1$s + Poslali jste %1$s pozvání do místnosti + Zrušili jste pozvánku do místnosti pro %1$s Přijali jste pozvání pro %1$s %1$s přidali widget %2$s Přidali jste widget %1$s @@ -177,7 +177,7 @@ Zpřístupnili jste budoucí zprávy pro %1$s %1$s zpřístupnil(a) budoucí zprávy pro %2$s Odešli jste z místnosti - Uživatel %1$s odešel z místnosti + %1$s opustil(a) místnost Vstoupili jste %1$s vstoupil(a) Založili jste diskusi @@ -278,8 +278,8 @@ Žádné výsledky Místnosti Odeslat záznamy - Odeslat záznamy zřícení - Odeslat screenshot + Odeslat záznamy o selhání + Odeslat snímek obrazovky Ohlásit chybu Zde popište svůj problém Za účelem diagnostiky problémů budou logy tohoto klienta odeslány s touto zprávou o chybě. Tato zpráva o chybě včetně logů a snímku obrazovky nebude veřejně viditelná. Pokud byste raději poslali pouze text výše, prosím odznačte: @@ -306,7 +306,7 @@ Nesprávné uživatelské jméno nebo heslo Zdá se, že toto není platná e-mailová adresa Tato e-mailová adresa je již zadána. - Zapomenuté heslo? + Zapomněli jste heslo\? Tento domovský server by se rád přesvědčil, že nejste robot E-mailovou adresu se nepodařilo ověřit. Přesvědčte se, že jste klepli na zaslaný odkaz Prosím, zadejte platné URL @@ -317,7 +317,7 @@ Přijmout Chyba Systémová upozornění - Prosím, popište chybu. Co jste provedli\? Jaké bylo očekávané chování\? Co se ve skutečnosti stalo\? + Popište prosím chybu. Co jste udělali\? Co jste očekávali, že se stane\? Co se ve skutečnosti stalo\? Pokud je to možné, prosím, napište popis anglicky. Třesením oznámit chybu Odeslat hlasovou zprávu @@ -380,7 +380,7 @@ %s píše… %1$s a %2$s píší… %1$s a %2$s a další píší… - Nemáte právo odesílat v této místnosti. + Nemáte oprávnění zveřejňovat příspěvky v této místnosti. %d nová zpráva %d nové zprávy @@ -798,7 +798,7 @@ Tiché Hlučné Vytvořit - Úvod + Domov Místnosti Pozvaní %2$s Vás vykopnul z %1$s @@ -1512,7 +1512,7 @@ Odeslat Přehrát Odmítnout - Nemáte povolení zahájit konferenční hovor v této místnosti + Nemáte oprávnění zahájit konferenční hovor v této místnosti Zahájit video schůzku Zahájit hlasovou schůzku Schůzky používají pravidla zabezpečení a přístupu Jitsi. Všichni lidé nyní v místnosti uvidí pozvánku k připojení, zatímco vaše schůzka probíhá. @@ -1635,7 +1635,7 @@ Role Otevřít chat Umlčet mikrofon - Zrušit umlčení mikrofonu + Zrušit ztlumení mikrofonu Zastavit fotoaparát Spustit fotoaparát Bezpečná záloha @@ -1795,7 +1795,7 @@ Toto je počátek této konverzace. Toto je počátek %s. Exportovat audit - K zapnutí šifrování v této místnosti nemáte oprávnění. + Nemáte oprávnění povolit šifrování v této místnosti. Přímá zpráva Zakládám místnost… Některé znaky nejsou dovoleny @@ -2182,8 +2182,8 @@ Propojte tento e-mail se svým účtem Pozvánka do této místnosti byla odeslána na adresu %s, která není spojena s vaším účtem Pozvánka do tohoto prostoru byla odeslána na adresu %s, která není spojena s vaším účtem - Všechny místnosti, ve kterých se nacházíte, se zobrazí v Úvodu. - Zobrazit všechny místnosti v Úvodu + Všechny místnosti, ve kterých se nacházíte, se zobrazí v Domovu. + Zobrazit všechny místnosti v Domovu Posunutím ukončíte hovor %1$s Klepněte pro návrat Probíhající hovor (%1$s) · @@ -2942,8 +2942,8 @@ Nastavit odkaz Přístupový token umožňuje plný přístup k účtu. Nikomu ho nesdělujte. Přístupový token - Přepnout na odrážky - Přepnout na číslovaný seznam + Přepnout seznam s odrážkami + Přepnout číslovaný seznam V této místnosti nejsou žádné předchozí hlasování Předchozí hlasování V této místnosti nejsou žádné aktivní hlasování @@ -3009,4 +3009,21 @@ Zásady přijatelného používání Přejít k obnovení Verze šifrování + %1$s změnil(a) své zobrazované jméno na %2$s + Profilový obrázek uživatele %1$s + Avatar místnosti %1$s + Avatar prostoru %1$s + Nejnovější aktualizace vylepšila zabezpečené zasílání zpráv. Znovu ověřte své zařízení. + Dokud tento uživatel této relaci nedůvěřuje, jsou zprávy odesílané do ní a z ní označeny varováním. + Aplikace aktualizována + Přesto se odhlásit + Nelze se spojit s domovským serverem. Pokud se přesto odhlásíte, nebude toto zařízení vymazáno ze seznamu zařízení, můžete jej odstranit pomocí jiného klienta. + Přesto zahájit chat + Přesto pozvat + Nelze najít profily pro níže uvedené Matrix identifikátory. Chcete přesto zahájit chat\? +\n +\n%s + Nelze najít profily pro níže uvedené Matrix identifikátory. Chcete je přesto pozvat\? +\n +\n%s \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-de/strings.xml b/library/ui-strings/src/main/res/values-de/strings.xml index 65dd4157ea..0871842a4d 100644 --- a/library/ui-strings/src/main/res/values-de/strings.xml +++ b/library/ui-strings/src/main/res/values-de/strings.xml @@ -11,7 +11,7 @@ %1$s hat %2$s gebannt %1$s hat die Einladung für %2$s zurückgezogen %1$s hat das Profilbild geändert - %1$s hat den Anzeigenamen geändert in %2$s + %1$s hat den Anzeigenamen zu %2$s geändert %1$s hat den Anzeigenamen von %2$s auf %3$s geändert %1$s hat den Anzeigenamen gelöscht (war %2$s) %1$s hat das Raumthema geändert auf: %2$s @@ -2948,4 +2948,21 @@ Mit Sicherheitsschlüssel oder -phrase verifizieren … Nutzungsbedingungen Verschlüsselungsversion + %1$s hat den Anzeigenamen zu %2$s geändert + Benutzer-Profilbild von %1$s + Raum-Avatar von %1$s + Space-Avatar von %1$s + Verschlüsselte Kommunikation wurde mit der neuesten Aktualisierung verbessert. Bitte verifiziere deine Geräte erneut. + Solange der Benutzer dieser Sitzung nicht vertraut, werden Nachrichten mit Warnungen versehen. + App aktualisiert + Dein Heim-Server ist nicht erreichbar. Falls du dich dennoch abmeldest, wird dieses Gerät nicht von deiner Geräteliste entfernt, also müsstest du dies mit einer anderen Sitzung selbst machen. + Dennoch abmelden + Dennoch Unterhaltung beginnen + Konnte keine Profile für die folgenden Matrix-IDs finden. Möchtest du dennoch eine Unterhaltung beginnen\? +\n +\n%s + Konnte keine Profile für die folgenden Matrix-IDs finden. Möchtest du sie dennoch einladen\? +\n +\n%s + Dennoch einladen \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-el/strings.xml b/library/ui-strings/src/main/res/values-el/strings.xml new file mode 100644 index 0000000000..3c8ec19a78 --- /dev/null +++ b/library/ui-strings/src/main/res/values-el/strings.xml @@ -0,0 +1,514 @@ + + + Ηλεκτρονική διεύθυνση + Ο/Η %1$s σας προσκάλεσε + Ο/Η %1$s αποχώρησε + Ο/Η %1$s απέρριψε την πρόσκληση + Ο/Η %1$s έδιωξε τον/την %2$s + Ο/Η %1$s προσκάλεσε τον/την %2$s + Η πρόσκληση του/της %s + Αριθμός τηλεφώνου + Ο/Η %1$s απέκλεισε τον/την %2$s + Ο/Η %1$s απέσυρε την πρόσκληση του/της %2$s + Ο/Η %1$s άλλαξε εικονίδιο χρήστη + Ο/Η %1$s άλλαξε το εμφανιζόμενό του/της όνομα σε %2$s + Ο/Η %1$s άλλαξε το εμφανιζόμενό του/της όνομα από %2$s σε %3$s + Ο/Η %1$s αφαίρεσε το εμφανιζόμενό του/της όνομα (%2$s) + Ο/Η %1$s άλλαξε το θέμα σε: %2$s + Ο/Η %1$s άλλαξε το όνομα του δωματίου σε: %2$s + Ο/Η %s απάντησε στην κλήση. + Ο/Η %s τερμάτισε την κλήση. + Ο/Η %s πραγματοποίησε μια κλήση βίντεο. + Ο/Η %s πραγματοποίησε μια κλήση ήχου. + Ο/Η %1$s κατέστησε το μελλοντικό ιστορικό του δωματίου ορατό στον/στην %2$s + όλα τα μέλη του δωματίου, από την στιγμή που προσκλήθηκαν. + όλα τα μέλη του δωματίου. + οποιοσδήποτε. + (έγινε αλλαγή και του εικονιδίου χρήστη) + Ο/Η %1$s αφαίρεσε το όνομα του δωματίου + Ο/Η %1$s αφαίρεσε το θέμα του δωματίου + Ο/Η %1$s δέχτηκε την πρόσκληση για το %2$s + ** Αδυναμία αποκρυπτογράφησης: %s ** + Η συσκευή του/της αποστολέα δεν μας έχει στείλει τα κλειδιά για αυτό το μήνυμα. + Αποτυχία αποστολής μηνύματος + Σφάλμα του Matrix + Ο/Η %1$s εισήλθε στο δωμάτιο + Πρόσκληση στο δωμάτιο + %1$s και %2$s + Άδειο δωμάτιο + όλα τα μέλη του δωματίου από την στιγμή που εισήλθαν. + Ο/Η %1$s έστειλε μία πρόσκληση στον/στην %2$s για να εισέλθει στο δωμάτιο + Ακύρωση + Κλείσιμο + Ενεργοποίηση ειδοποιήσεων για τον λογαριασμό + Προκειμένου να διαγνωστούν προβλήματα, τα αρχεία καταγραφής από αυτόν τον πελάτη θα σταλούν με αυτήν την αναφορά σφάλματος. Αν προτιμάτε να στείλετε μόνο το παραπάνω κείμενο, απενεργοποιήστε: + Αποχώρηση + Μηνύματα από bots + Μόνιμος σύνδεσμος + Παρακαλούμε περιγράψτε το σφάλμα. Τι κάνατε; Τι περιμένατε να συμβεί; Τι έγινε τελικά; + Παράθεση + Απόρριψη + Αφαίρεση + Αποστολή + Αποστολή πληροφοριών + Προβολή αποκρυπτογραφημένου κώδικα + Προβολή κώδικα + Εντάξει + Προειδοποίηση + Συνέχεια + Ηχητικές ειδοποιήσεις + Αθόρυβες ειδοποιήσεις + Ρυθμίσεις + Αναφορά σφάλματος + Φόρτωση… + Αποθήκευση + Κρυπτογραφημένο μήνυμα + Ανοιχτόχρωμο θέμα + Σκουρόχρωμο θέμα + Μαύρο θέμα + Αποστολή αυτοκόλλητου + Αργότερα + Διαγραφή + Μετονομασία + Αναφορά περιεχομένου + ή + Πρόσκληση + Αποδοχή + Αποσύνδεση + Κλήση ήχου + Κλήση βίντεο + Σημείωση όλων ως αναγνωσμένων + Γρήγορη απάντηση + Άνοιγμα + Επιβεβαίωση + Σφάλμα + Αγαπημένα + Δωμάτια + Αναζήτηση στα δωμάτια + Προσκλήσεις + Χαμηλής προτεραιότητας + Ειδοποιήσεις συστήματος + Συζητήσεις + Μόνο οι επαφές Matrix + Δεν βρέθηκαν αποτελέσματα + Δωμάτια + Αποστολή καταγραφών σφαλμάτων + Αναφορά σφάλματος + Εφόσον είναι δυνατό, παρακαλώ γράψτε την περιγραφή στα αγγλικά. + Περιγράψτε το πρόβλημά σας εδώ + Φαίνεται να κουνάτε το τηλέφωνο από εκνευρισμό. Θέλετε να ανοίξετε την οθόνη αναφοράς σφάλματος; + Κουνήστε το τηλέφωνο για αναφορά σφάλματος + Η αναφορά σφάλματος εστάλη επιτυχώς + Η αποστολή της αναφοράς σφάλματος απέτυχε (%s) + Πρόοδος (%s%%) + Όνομα χρήστη + Αποσύνδεση + Αναζήτηση + Αποστολή αρχείων + %d+ + %1$s: %2$s + Πατήστε εδώ για να δείτε παλαιότερα μηνύματα + Η συζήτηση συνεχίζεται εδώ + Αυτό το δωμάτιο είναι συνέχεια μιας άλλης συζήτησης + Πρωτότυπο + Μεγάλο + Μεσαίο + Μικρό + Κλήσεις + Χρήση του προεπιλεγμένου ήχου κλήσης του ${app_name} για τις εισερχόμενες κλήσεις + Ήχος εισερχομένων κλήσεων + Επιλέξτε ήχο κλήσης: + Κλήση + Εισερχόμενη κλήση βίντεο + Εισερχόμενη κλήση ήχου + Κλήση σε εξέλιξη… + Κλήση βίντεο σε εξέλιξη… + ΝΑΙ + ΟΧΙ + Προσθήκη διεύθυνσης ηλεκτρονικού ταχυδρομείου + Προσθήκη αριθμού τηλεφώνου + Πληροφορίες εφαρμογής + Εκτελείται… (%1$d από %2$d) + Ρυθμίσεις συστήματος. + Άνοιγμα ρυθμίσεων + Ρυθμίσεις λογαριασμού. + Οι ειδοποιήσεις είναι ενεργοποιημένες για τον λογαριασμό σας. + Οι ειδοποιήσεις είναι απενεργοποιημένες για τον λογαριασμό σας. +\nΠαρακαλώ ελέγξτε τις ρυθμίσεις λογαριασμού. + Ενεργοποίηση + Ρυθμίσεις συσκευής. + Οι ειδοποιήσεις είναι ενεργοποιημένες για αυτή την συσκευή. + Οι ειδοποιήσεις δεν επιτρέπονται για αυτή την συσκευή. +\nΠαρακαλώ ελέγξτε τις ρυθμίσεις του ${app_name}. + Ενεργοποίηση + Προεπισκόπιση συνδέσμων + Μορφοποίηση Markdown + Απενεργοποίηση λογαριασμού + Απενεργοποίηση του λογαριασμού μου + Στατιστικά χρήσης + Αποστολή στατιστικών χρήσης + Αναγνωριστικό + Όνομα + Όνομα συσκευής + %1$s @ %2$s + Συνδεδεμένος/η ως + Γλώσσα + Επιλέξτε γλώσσα + Αυτός ο αριθμός τηλεφώνου χρησιμοποιείται ήδη. + Κωδικός + Αλλαγή κωδικού + Προηγούμενος κωδικός + Νέος κωδικός + Η ανανέωση κωδικού απέτυχε + Ο κωδικός σας ανανεώθηκε + Επιλέξτε μία χώρα + 3 μέρες + 1 βδομάδα + 1 μήνας + Για πάντα + Θέμα + Οποιοσδήποτε + Προχωρημένες + Θέμα + Σφάλμα αποκρυπτογράφησης + Όνομα συσκευής + Αναγνωριστικό συσκευής + Εξαγωγή + Εισαγωγή + Επιλέξτε ένα ευρετήριο δωματίων + Όλα τα δωμάτια στον διακομιστή %s + + 1 δωμάτιο + %d δωμάτια + + %1$s στο %2$s + Μέγεθος γραμματοσειράς + Πολύ μικρό + Μικρό + Κανονικό + Μεγάλο + Τεράστιο + + 1 ενεργό widget + %d ενεργά widget + + Το δωμάτιο %s δεν είναι ορατό. + Σφάλμα εντολής + Δημιουργία + Δωμάτια + Λόγος: %1$s + Απενεργοποίηση λογαριασμού + Απενεργοποίηση λογαριασμού + Παρακαλώ εισάγετε τον κωδικό σας. + Αρχική σελίδα + Αρχική + Άτομα + Αναμονή για συμβάντα + Δημιουργία αντιγράφων ασφαλείας κλειδιών + Χρησιμοποιήστε το αντίγραφο ασφαλείας κλειδιών + Θα χάσετε τα κρυπτογραφημένα μηνύματά σας εάν αποσυνδεθείτε τώρα + Δημιουργία αντίγραφου κλειδιού ασφαλείας σε εξέλιξη. Εάν αποσυνδεθείτε τώρα, θα χάσετε την πρόσβαση στα κρυπτογραφημένα μηνύματά σας. + Δεν θέλω τα κρυπτογραφημένα μηνύματά μου + Δημιουργία αντιγράφων ασφαλείας κλειδιών… + Είστε σίγουρος; + Δημιουργία αντίγραφου ασφαλείας + Θα χάσετε την πρόσβαση στα κρυπτογραφημένα μηνύματά σας, εκτός εάν δημιουργήσετε αντίγραφα ασφαλείας των κλειδιών σας πριν αποσυνδεθείτε. + Κατεβάστε + Διαμοιρασμός + Ανάκληση + Αποσύνδεση + Прямі повідомлення + Απόρριψη + Απόρριψη + Αποδοχή + Αγνοείστε + Ολοκληρώθηκε + Παραλείψτε + Αποτυχία αφαίρεσης widget + Αποτυχία προσθήκης widget + Δεν μπορείτε να πραγματοποιήσετε μια κλήση με τον εαυτό σας, περιμένετε τους συμμετέχοντες να αποδεχθούν πρόσκληση + Δεν μπορείτε να πραγματοποιήσετε μια κλήση με τον εαυτό σας + Οι συσκέψεις χρησιμοποιούν πολιτικές ασφάλειας και αδειών του Jitsi. Όλα τα άτομα που βρίσκονται στην αίθουσα θα δουν μια πρόσκληση για συμμετοχή ενώ πραγματοποιείται η συνάντησή σας. + Ξεκινήστε τη συνάντηση με βίντεο + Ξεκινήστε τη συνάντηση με ήχο + Δεν έχετε άδεια να ξεκινήσετε μια κλήση + Δεν έχετε άδεια να ξεκινήσετε μια κλήση σε αυτό το δωμάτιο + Δεν έχετε άδεια να ξεκινήσετε μια κλήση συνδιάσκεψης + Δεν έχετε άδεια να ξεκινήσετε μια κλήση συνδιάσκεψης σε αυτήν την αίθουσα + Επαναφορά + Απόρριψη + Παίξε + Κανένα + H δημιουργία αντιγράφων κλειδιού ασφαλείας θα πρέπει να είναι ενεργή σε όλες τις συνεδρίες σας για να αποφύγετε την απώλεια πρόσβασης στα κρυπτογραφημένα μηνύματά σας. + Επαναφόρτωση γραφικού στοιχείου + Αποτυχία φόρτωσης γραφικού στοιχείου +\n%s + Η χρήση του ενδέχεται να δημιουγίσει cookies και να κοινοποιήσει δεδομένα με %s: + Η χρήση του ενδέχεται να κοινοποιεί δεδομένα με %s: + Αυτο το γραφικό στοιχείο προστέθηκε από: + Φόρτωση Γραφικού στοιχείου + Γραφικό στοιχείο + Ενεργά γραφικά στοιχεία + Προβολή + Είστε βέβαιοι ότι θέλετε να διαγράψετε το γραφικό στοιχείο από αυτό το δωμάτιο; + Εξαιρετικά Μεγάλο + Μεγαλύτερο + %1$s: %2$s %3$s + %1$s: %2$s + ** Αποτυχία αποστολής - Παρακαλώ ανοίξτε το δωμάτιο + Εγώ + Καυνούργια Πρόσκληση + Καινούργια Μηνύματα + Δωμάτιο + Καινούργιο Συμβάν + %1$s και %2$s + %1$s στο %2$s και %3$s + + %d ειδοποιήση + %d ειδοποιήσεις + + + %1$s: %2$d μήνυμα + %1$s: %2$d μηνύματα + + + %d πρόσκληση + %d προσκλήσεις + + Σύνδεση + Λόγος οριστικής αποβολής + Αποκλεισμός χρήστη + Αποβάλλοντας αυτό το χρήση θα τους αφαιρέσαι από το δωμάτιο. +\n +\nΕάν θέλετε να τους αποτρέψετε να συμμετάσχουν ξανά, θα πρέπει να τους αποβάλλετε οριστικά. + Λόγος αποβολής + Αποβολή χρήστη + Είστε σίγουροι πως θέλετε να καταργήσετε την πρόσκληση προς αυτό τον χρήστη; + Ακύρωση πρόσκλησης + Κατάργηση παράβλεψης + Καταργώντας την παράβλεψη αυτού του χρήστη θα επανφανίσει όλα τα μηνύματα από αυτούς. + Παράβλεψη χρήστη + Παραβλέποντας αυτό το χρήση θα αφαιρέσει τα μηνύματα τους από δωμάτια που μοιράζεστε. +\n +\nΜπορείτε να αντιστρέψετε αυτή την ενέργεια οποτεδήποτε στις γενικές ρυθμίσεις. + Παράβλεψη + Κατάργηση παράβλεψης χρήστη + Υποβίβαση + Αυτή δεν είναι έγκυρη διεύθυνση διακομιστή Matrix + Παρακαλω εισάξετε έγκυρη διεύθυνση + Υποβολή + Αυτά είναι πειραματικά χαρακτηριστικά τα οποία μπορούν να παρουσιάσουν μη αναμενόμενα σφάλματα. Χρησιμοποιήστε με προσοχή. + Εργαστήρια + Εσωτερικός κωδικός δωματίου + + %d απαγορευμένος χρήστης + %d απαγορευμένοι χρήστες + + Απαγορευμένοι χρήστες + Μέλη μόνο (από τη στιγμή που μπήκαν) + Μέλη μόνο (από τη στιγμή που καλέστηκαν) + Μέλη μόνο (από τη στιγμή επιλογής αυτής της ρύθμισης) + Δημοσίευση αυτού του δωματίου στο κοινό κατάλογο δωματίων του %1$s; + Δεν είναι δυνατή η ανάκτηση της τρέχουσας ορατότητας καταλόγου δωματίων (%1$s). + Κατάργηση δημοσίευσης αυτής της διεύθυνσης + Δεν βρέθηκαν εξωτερικές εφαρμογές για αυτή την πράξη. + Δεν έχετε ενεργοποιημένα πακέτα αυτοκόλλητων. +\n +\nΘέλετε να προσθέσετε μερικά τώρα; + Φωτογραφία ή βίντεο + Βίντεο + Φωτογραφία + Αποστολή αυτοκόλλητου + Ενεργοποίηση Υψηλής Ανάλυσης + Απενεργοποίηση Υψηλής Ανάλυσης + Πίσω + Μπροστινή + Αλλαγή Κάμερας + Ασύρματο Ακουστικό + Ακουστικό + Ομιλητής + Τηλέφωνο + Αλλαγή Συσκευής Ήχου + Αποτυχία σύνδεσης σε πραγματικό χρόνο. +\nΖητήστε από τον διαχειριστή του οικιακού σας διακομιστή να διαμορφώσει έναν διακομιστή TURN ώστε οι κλήσεις να λειτουργούν αξιόπιστα. + Η Κλήση ${app_name} Aπέτυχε + Είσαστε σίγουροι ότι θέλετε να κάνετε κλήση βίντεο; + Είσαστε σίγουροι ότι θέλετε να κάνετε κλήση ήχου; + Αποστολή φωνής + Κλήση βίντεο + Κλήση ήχου + Διέυθυνση URL Ιδιαίτερου Διακομιστή + Είσοδος στο δωμάτιο + Η εφαργμογή διακόπηκε απότομα προηγουμένως. Θα θέλατε να ανοίξετε την οθόνη αναφοράς σφάλματος; + Αποστολή στιγμιότυπου οθόνης + Αποστολή ιστορικού αιτήσεων αποστολής κλειδιού + Δεν υπάρχουν άλλα αποτελέσματα + Επιτυχία + Κατάργηση δημοσίευσης + Αντιγραφή + Τέλος κλήσης + Ειδοποιήσεις + Αντιγράφηκε στο πρόχειρο + Πρόσθεση + Σημείωσε ως διαβασμένο + Είσαστε σίγουροι ότι θέλετε να αποσυνδεθείτε; + Ξεκινήστε συζήτηση + Παρακαλώ εισάγετε όνομα χρήστη. + Παρακαλώ ξεχάστε όλα τα μηνύματα τα οποία έχω στείλει μόλις απενεργοποιηθεί ο λογαριασμός μου (Προειδοποίηση: αυτό σημαίνει οτι μελλοντικοί χρήστες θα έχουν μία ατελή εικόνα των συζητήσεων) + Αυτό θα κάνει το λογαριασμό σας μόνιμα άχρηστο. Δε θα μπορέσετε να συνδεθείτε ξανα, και κανείς δεν θα μπορεί να εγγραφεί με το ίδιο όνομα χρήστη. Ο λογαριασμός σας θα αναχωρήσει από όλα τα δωμάτια στα οποία συμμετέχει, και οι πληροφορίες λογαριασμού θα αφαιρεθούν από το διακομιστή ταυτότητας. Αυτή η πράξη είναι μη αναστρέψιμη. +\n +\nΜε την απενεργοποίηση του λογαρισμού σας δεν θα ξεχαστούν τα μηνύματά που έχετε στείλει. Εάν θα θέλατε να ξεχαστούν, τότε δηλώστε το στο κουτί πιο κάτω. +\n +\nΗ ορατότητα μηνυμάτων δουλεύει σαν το ηλεκτρονικό ταχυδρομείο. Το να ξεχαστούν τα μηνύματα σημαίνει οτι μηνύματα τα οποία έχετε στείλει δεν θα σταλούν σε νέους ή μη-εγγεγραμμένους χρήστες, αλλα εγγεγραμμένοι χρήστες οι οποίοι έχουν ήδη πρόσβαση σε αυτά τα μηνύματα θα μπορούν ακόμα να τα δούν. + Αυτό το δωμάτιο έχει αντικατασταθεί και δεν είναι πια ενεργό. + Παράβλεψη + Αποσύνδεση + Δεν εμπιστεύομαι + Δεν έχετε εξουσιοδότηση να δημοσιεύσετε σε αυτό το δωμάτιο. + %1$s & %2$s & άλλοι γράφουν… + %s γράφει… + %1$s & %2$s γράφουν… + Δεν εξακριβώθηκε η ταυτότητα του εξωτερικού διακομιστή. + Κανένα αποτέλεσμα + Φιλτράρισμα αποβεβλημένων χρηστών + Φιλτράρισμα μελών δωματίου + Εύρεση + Αποδεκτείτε το πιστοποιητικό εαν ο διαχειριστής του διακομιστή έχει εκδόσει ένα αποτύπωμα που ταιριάζει με το παρά πάνω. + Το πιστοποιτικό έχει αλλάξει από ένα προηγούμενο αξιόπιστο, σε ένα αναξιόπιστο. Ο διακομιστής ενδέχεται να έχει αλλάξει το πιστοποιητικό του. Επικοινωνείστε με το διαχειριστή του διακομιστή για το αναμενόμενο αποτύπωμα. + Το πιστοποιητικό έχει αλλάξει από αυτό που εμπιστεύθηκε προηγουμένως η συσκευή σας. Αυτό είναι ΑΚΡΩΣ ΑΣΥΝΗΘΙΣΤΟ. Προτείνεται να ΜΗΝ ΑΠΟΔΕΚΤΕΙΤΕ το νεο πιστοποιητικό. + Προεπιλογή Συστήματος + Λανθασμένο όνομα χρήστη και/ή κωδικού + Τερματισμός δημοσκόπησης + Επεξεργασία δημοσκόπησης + Άνοιγμα με + Αποστολή αυτοκόλλητου + %1$s δημιούργησε το δωμάτιο + Εισήλθες + Αποχώρησες από το δωμάτιο + %1$s αποχώρισε από το δωμάτιο + Έχετε απορρίψει την πρόσκληση + Ορίσατε το όνομά σας ω; %1$s + Η πρόσκλησή σου + Δημιούργησες αυτό το δωμάτιο + %1$s δημιούργησε την συζήτηση + "Προσκάλεσες τον χρήστη %1$s" + Έχετε αποκλείσει τον χρήστη %1$s + Αλλάξατε το άβατάρ σας + Άλλαξες το θέμα σε: %1$s + Δωμάτιο/Χώρος + Σύνδεση + + %1$d επιλέχθηκε + %1$d επιλέχθηκαν + + + %d ACLs του server άλλαξε + %d ACLs του server άλλαξαν + + Πραγματοποιείται σύνδεση στην συσκευή + Δεν ταιριάζει; + Προσπάθησε ξανά + "Οι servers που περιλαμβάνουν %s επιτρέπονται." + Δημιούργησες αυτή την συζήτηση + Αποχώρισες από το δωμάτιο + Ο χρήστης %1$s αφαίρεσε τον αποκλείσμο του χρήστη %2$s + Άλλαξες το όνομα του δωματίου σε: %1$s + Έχετε ξεκινήσει μία βιντεοκλήση. + Το μελλοντικό ιστορικό του δωματίου θα είναι εμφανή στο χρήστη %1$s + Έχετε ξεκινησει μία κλήση. + Ο χρήστης %s αναβάθμισε αυτό το δωμάτιο. + Η εύρεση server που περιλαμβάνει %s είναι απεκλεισμένη. + "• Οι servers οπού περιλαμβάνουν %s είναι τώρα απεκλεισμένοι." + Επιβεβαίωση + Παρακαλώ επιβεβαιώστε ότι γνωρίζετε την προέλευση του κώδικα αυτού. Όταν συνδέετε νέες συσκευές, ενδεχομένως να δίνετε σε κάποιον άλλο πλήρης πρόσβαση στον λογαριασμό σας. + Εκαθάρριση προσωπικών δεδομένων + Αφαιρέσατε τον χρήστη %1$s + Ο χρήστης %1$s άλλαξε το όνομά του σε %2$s + %1$s άλλαξε το άβαταρ του δωματίου + Άλλαξες το άβαταρ του δωματίου + "%s απέστειλε δεδομένα ώστε να πραγματοποιηθεί η κλήση." + Απέστειλες δεδομένα ώστε να ξεκινήσει η κλήση. + Απάντησες στην κλήση. + Ο χρήστης %1$s έκανε τα μελλοντικά μηνύματα διαθέσιμα στον χρήστη %2$s + Έχετε αναβαθμίσει αυτό το δωμάτιο. + %s αναβαθμίστηκε εδώ. + Αναβαθμίστηκες εδώ. + %s όρισε τα ACLs αυτού του server σε αυτό το δωμάτιο. + Έχεις ορίσει το ACL του server για αυτό το δωμάτιο. + "• Οι servers που περιλαμβάνονται αυτή την IP είναι απεκλεισμένοι." + %s άλλαξε τα ACLs του server γι αυτό το δωμάτιο. + Άλλαξες τα ACLs του server γι αυτό το δωμάτιο. + Κωδικός Πρόσβασης + Οι διαχειριστές του server σας (%1$s), σας έχουν αποσυνδέσει από τον λογαριασμό σας %2$s (%3$s). + Η πειργραφή είναι πολύ σύντομη + Έχετε αποσυνδεθεί + Επιπρόσθετες ρυθμίσεις + Λειτουργίες Προγραμματιστή + Τρέχουσα συνεδρία + Διαγραφή δεδομένων + Άλλες συνεδρίες + Πραγματοποιείται η σύνδεση + Συμμετέχεις σε αυτό το δωμάτιο + %1$s εισήλθε + Έχετε αφαιρέσει τον αποκλεισμό από τον χρήστη %1$s + Αφαιρέσατε την πρόσκληση του χρήστη %1$s + Άλλαξες το όνομά σου από %1$s σε %2$s + Αφαίρεσες το όνομά όπου εμφανιζόταν ο λογαριασμός σου ( προηγουμένως ήταν %1$s) + .Τερμάτισες την κλήση. + Έκανες τα μελλοντικά μηνύματα διαθέσιμα στον χρήστη %1$s + Ορισμός συνδέσμου + Συνδεθείτε ξανά + Σύνδεση + Διαγρφή όλων των δεδομένων + Ρυθμίσεις + Γενικά + Γενικά + %1$s Έχει αφαιρεθεί το avatar του δωματίου + Έχεις αφαιρέσει το avatar του δωματίου + Καμία αλλαγή. + Έχεις αφαίρεσει το όνομα του δωματίου + Ο χρήστης %1$s προσκάλεσε τον χρήστη %2$s + Προσκάλεσες τον χρήστη %1$s + Διαχειριστής + Moderator + Άλλαξες το power του level %1$s. + Οι Servers που ταιριάζουν με %s έχουν αφαιρεθεί από την επιτρεπόμενη λίστα. + Οι Servers που ταιριάζουν με το IP έχουν αποκλειστικοί. + Έχεις αφαιρέσει το θέμα του δωματίου + Αποδέχτηκες την πρόσκληση για το %1$s + Προεπιλογή + Custom (%1$d) + Προσαρμοσμένο + 🎉Όλοι οι Servers έχουν αποκλειστεί από συμμετέχοντες!Το δωμάτιο αυτό δεν μπορεί πια να χρησιμοποιηθεί. + Έστειλες μια πρόσκληση στο %1$s για να συνδεθείς στο δωμάτιο + Το μήνυμα στάλθηκε + Δημιουργώ ένα δωμάτιο + Δεν επιτρέπεται να συνδεθείς σε αυτό το δωμάτιο + %1$s,%2$s και %3$s + Αλλάζω το Space + %1$s, %2$s, %3$s και %4$s + Ερευνάω τα δωμάτια + -Κάποιοι χρήστες έχουν αγνοηθεί + + %1$s, %2$s, %3$s και %4$d άλλος χρήστης + %1$s, %2$s, %3$s και %4$d άλλοι χρήστες + + Το μήνυμα στέλνεται… + Μύνημα + Δημιουργώ έναν σύνδεσμο + Σύνδεσμος + Στέλνω ένα αρχείο. + Μύνημα από τον χρήστη %s + Στέλνω ένα ηχητικό μύνημα. + Στέλνω μια εικόνα. + + Πρόσθεσες εναλλακτική διεύθυνση %1$ για αυτό το δωμάτιο. + Πρόσθεσες εναλλακτικές διευθύνσεις %1$ για αυτό το δωμάτιο. + + Στέλνω ένα βίντεο. + Στέλνω ένα αρχείο ήχου. + Επεξεργάζομαι ένα σύνδεσμο + Κείμενο + Στέλνω ένα αυτοκόλλητο. + Σκανάρω ένα QR code + \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-et/strings.xml b/library/ui-strings/src/main/res/values-et/strings.xml index ff6fe32a25..cf70cbf5d8 100644 --- a/library/ui-strings/src/main/res/values-et/strings.xml +++ b/library/ui-strings/src/main/res/values-et/strings.xml @@ -2949,4 +2949,21 @@ Sõnum Sõnum kasutajalt %s Krüptoteekide versioon + %1$s muutis oma uueks kuvatavaks nimeks %2$s + Kasutaja %1$s tunnuspilt + %1$s jututoa tunnuspilt + %1$s kogukonna tunnuspilt + Turvalisele sõnumivahetusele on lisandunud palju täiendusi. Palun verifitseeri oma seade uuesti. + Seni kuni nimetatud kasutaja usaldab seda sessiooni, kõik siit ja siia saadetud sõnumid on märgistatud hoiatusega. + Rakendus on uuendatud + Jah, ikkagi logi välja + Ühendus koduserveriga puudub. Kui sa jätkad ja logid võrgust välja, siis seda seadet ei kustutata sinu seadmete loendist ning saad seda hiljem mõnest muust Matrixi kliendist teha. + Ikkagi alusta vestlust + Kutsu siiski + Allpool loetletud Matrix\'i kasutajatunnustele ei leidunud profiile. Kas sa ikkagi tahaksid nendega vestlust alustada\? +\n +\n%s + Allpool loetletud Matrix\'i kasutajatunnustele ei leidunud profiile. Kas sa ikkagi tahaksid neile kutse saata\? +\n +\n%s \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-fa/strings.xml b/library/ui-strings/src/main/res/values-fa/strings.xml index 9e971ce69b..fb5fd92f6b 100644 --- a/library/ui-strings/src/main/res/values-fa/strings.xml +++ b/library/ui-strings/src/main/res/values-fa/strings.xml @@ -10,7 +10,7 @@ %1$s، انسداد %2$s را رفع کرد %1$s، %2$s را مسدود کرد %1$s دعوت %2$s را نپذیرفت - %1$s تصویرش را عوض کرد + %1$s چهرکش را عوض کرد %1$s نام نمایشی خود را به %2$s تنظیم کرد %1$s نام نمایشیش را از %2$s به %3$s تغییر داد %1$s نام نمایشیش (%2$s) را پاک کرد @@ -26,7 +26,7 @@ همهٔ اعضای اتاق. هرکسی. %s این اتاق را ارتقا داد. - (تصویر هم عوض شد) + (چهرک نیز تغییر کرد) %1$s نام اتاق را پاک کرد %1$s موضوع اتاق را پاک کرد %1$s دعوتی برای پیوستن %2$s به اتاق فرستاد @@ -94,13 +94,13 @@ تحریم %1$s را برداشتید %1$s را تحریم کردید دعوت %1$s را پس‌گرفتید - آواتارتان را عوض کردید + چهرکتان را عوض کردید نام نمایشیتان را به %1$s تغییر دادید نام نمایشیتان را از %1$s به %2$s تغییر دادید نام نمایشیتان را برداشتید (%1$s بود) موضوع را به %1$s تغییر دادید - %1$s آواتار اتاق را تغییر داد - آواتار اتاق را تغییر دادید + %1$s چهرک اتاق را تغییر داد + چهرک اتاق را تغییر دادید نام اتاق را به %1$s تغییر دادید تماس تصویری گرفتید. تماس صوتی گرفتید. @@ -112,8 +112,8 @@ این اتاق را ارتقا دادید. نام اتاق را برداشتید موضوع اتاق را برداشتید - %1$s آواتار اتاق را برداشت - آواتار اتاق را برداشتید + %1$s چهرک اتاق را برداشت + چهرک اتاق را برداشتید برای %1$s دعوت پیوستن به اتاق فرستادید دعوت پیوستن %1$s به اتاق را پس گرفتید دعوت برای %1$s را پذیرفتید @@ -1065,7 +1065,7 @@ بازنشاندن از نشانی اصلی ارتباط با مدیر خدمتتان اکنون بازبینی شود - آواتار + چهرک دلیل: %1$s به دست %2$s از %1$s تحریم شدید به دست %2$s از %1$s اخراج شدید @@ -1185,7 +1185,7 @@ پیش‌نمایش محتوای چندرسانه‌ای قبل از ارسال لرزیدن گوشی در هنگام ذکر یک کاربر شامل تغییرات نام نمایشی و چهرک. - نمایش پیام‌های مربوط به حساب کاربری + نمایش رویدادهای حساب دعوت‌ها، برداشتن‌ها و انسدادها تأثیر نمی‌پذیرند. نمایش پیام‌های پیوستن و ترک اتاق پیش‌نمایشی از آدرس‌های URL در پیام‌ها نمایش داده شود. @@ -1691,7 +1691,7 @@ نمی‌توانید به خودتان پیام دهید! هم‌رسانی با متن جست‌وجوی آشنایان روی ماتریکس - تنظیم آواتار + تنظیم چهرک برای تأیید عبارت امنیتیتان، دوباره واردش کنید. عبارت امنیتی تنظیم یک عبارت امنیتی @@ -1794,7 +1794,7 @@ برداشتن پیام‌های دیگران آگاه کردن همه دستکاری ابزارک‌ها - تغییر آواتار اتاق + تغییر چهرک اتاق تغییر نشانی اصلی اتاق به کار انداختن رمزنگاری اتاق تغییر نمایانی تاریخچه @@ -2949,4 +2949,13 @@ سیاست استفادهٔ پذیرفتنی ادامه برای بازنشانی نگارش Crypto + %1$s نام نمایشیش را به %2$s تغییر داد + نگارهٔ نمایهٔ کاربر %1$s + چهرک اتاق %1$s + چهرک فضای %1$s + پیام‌رسانی امن با جدیدترین به‌روز رسانی بهبود یافته است. لطفاً افزاره‌تان را دوباره تأیید کنید. + تا کاربر این نشست را تأیید کند، پیام‌های فرستاده و گرفته‌اش با هشدار برچسب می‌خورند. + کاره به‌روز شد + خروج به هر صورت + نمی‌توان به کارساز خانگی رسید. اگر همچنان خارج شوید این افزاره از سیاههٔ افزاره‌هایتان پاک نخواهد شد و باید از کارخواهس دیگر برش دارید. \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-fi/strings.xml b/library/ui-strings/src/main/res/values-fi/strings.xml new file mode 100644 index 0000000000..74018e87d1 --- /dev/null +++ b/library/ui-strings/src/main/res/values-fi/strings.xml @@ -0,0 +1,2509 @@ + + + Käyttäjän %s kutsu + %1$s kutsui käyttäjän %2$s + %1$s kutsui sinut + %1$s liittyi huoneeseen + %1$s poistui huoneesta + %1$s hylkäsi kutsun + %1$s poisti käyttäjän %2$s + %1$s poisti porttikiellon käyttäjältä %2$s + %1$s antoi porttikiellon käyttäjälle %2$s + %1$s veti takaisin kutsun käyttäjälle %2$s + %1$s vaihtoi profiilikuvaansa + %1$s asetti näyttönimekseen %2$s + %1$s vaihtoi näyttönimensä nimestä %2$s nimeen %3$s + %1$s poisti näyttönimensä (%2$s) + %1$s vaihtoi aiheeksi: %2$s + %1$s vaihtoi huoneen nimeksi %2$s + %s soitti videopuhelun. + %s soitti äänipuhelun. + %s vastasi puheluun. + %s lopetti puhelun. + %1$s muutti tulevan huonehistorian näkyväksi seuraaville: %2$s + kaikki huoneen jäsenet, kutsumisestaan asti. + kaikki huoneen jäsenet, liittymisestään asti. + kaikki huoneen jäsenet. + kaikki. + (myös kuva vaihdettiin) + %1$s poisti huoneen nimen + %1$s poisti huoneen aiheen + %1$s lähetti liittymiskutsun huoneeseen käyttäjälle %2$s + %1$s hyväksyi kutsun käyttäjän %2$s puolesta + ** Salauksen purku epäonnistui: %s ** + Lähettäjän laite ei ole lähettänyt avaimia tähän viestiin. + Viestin lähetys epäonnistui + Matrix-virhe + Sähköpostiosoite + Puhelinnumero + Huonekutsu + %1$s ja %2$s + Tyhjä huone + Alkusynkronointi: +\nTuodaan tiliä… + Alkusynkronointi: +\nTuodaan krypto + Alkusynkronointi: +\nTuodaan huoneita + Alkusynkronointi: +\nLadataan keskustelujasi +\nMikäli olet liittynyt moniin huoneisiin, tässä voi mennä tovi + Alkusynkronointi: +\nTuodaan kutsuttuja huoneita + Alkusynkronointi: +\nTuodaan poistuttuja huoneita + Alkusynkronointi: +\nTuodaan tilin tietoja + %s päivitti tämän huoneen. + Lähetetään viestiä… + %1$s veti takaisin käyttäjän %2$s liittymiskutsun huoneeseen + Henkilön %1$s kutsu. Syy: %2$s + %1$s kutsui henkilön %2$s. Syy: %3$s + %1$s kutsui sinut. Syy: %2$s + %1$s liittyi huoneeseen. Syy: %2$s + %1$s poistui huoneesta. Syy: %2$s + %1$s hylkäsi kutsun. Syy: %2$s + %1$s poisti käyttäjän %2$s huoneesta. Syy: %3$s + %1$s poisti porttikiellon käyttäjältä %2$s. Syy: %3$s + %1$s antoi porttikiellon käyttäjälle %2$s. Syy: %3$s + %1$s hyväksyi kutsun liityäkseen huoneeseen %2$s. Syy: %3$s + %1$s veti takaisin käyttäjän %2$s kutsun. Syy: %3$s + + %1$s lisäsi tälle huoneelle osoitteen %2$s. + %1$s lisäsi tälle huoneelle osoitteet %2$s. + + + %1$s poisti tältä huoneelta osoitteen %2$s. + %1$s poisti tältä huoneelta osoitteet %2$s. + + %1$s lisäsi tälle huoneelle osoitteen %2$s ja poisti osoitteen %3$s. + %1$s asetti tämän huoneen pääosoitteeksi %2$s. + %1$s poisti tämän huoneen pääosoitteen. + %1$s salli vieraiden liittyä huoneeseen. + %1$s esti vieraita liittymästä huoneeseen. + %1$s laittoi päälle osapuolten välisen salauksen. + %1$s laittoi päälle osapuolisten välisen salauksen (tuntematon algoritmi %2$s). + Hyväksyit käyttäjän %1$s kutsun. Syy: %2$s + Estit käyttäjän %1$s. Syy: %2$s + Peruutit eston %1$s. Syy: %2$s + Poistit käyttäjän %1$s. Syy: %2$s + Hylkäsit kutsun. Syy: %1$s + Poistuit. Syy: %1$s + %1$s poistui. Syy: %2$s + Poistuit huoneesta. Syy: %1$s + Liityit. Syy: %1$s + %1$s liittyi. Syy: %2$s + Liityit ryhmään. Syy: %1$s + Kutsuit %1$s. Syy: %2$s + Kutsusi. Syy: %1$s + Tyhjä huone (oli %s) + %1$s, %2$s, %3$s ja %4$s + %1$s, %2$s ja %3$s + Mukautettu + Mukautettu (%1$d) + Oletus + Valvoja + Ylläpitäjä + %1$s muutti %2$s sovelmaa + Poistit %1$s sovelman + %1$s poisti %2$s sovelman + Lisäsit %1$s sovelman + %1$s lisäsi %2$s sovelman + Muutit %1$s sovelmaa + Hyväksyit kutsun henkilölle %1$s + Peruutit kutsun henkilöltä %1$s + %1$s peruutti kutsun henkilöltä %2$s + Peruutit henkilön %1$s kutsun liittyä ryhmään + Kutsuit %1$s + %1$s kutsui %2$s + Lähetit henkilölle %1$s kutsun liittyä huoneeseen + Poistit huoneen profiilikuvan + %1$s poisti huoneen profiilikuvan + Poistit huoneen aiheen + Poistit huoneen nimen + 🎉 Kaikki palvelimet on estetty osallistumasta! Tätä huonetta ei voi enää käyttää. + Ei muutosta. + • Palvelimet jotka %s poistettiin estolistalta. + • Palvelimen haku %s on nyt kielletty. + • Palvelimen haku %s on sallittu. + • Palvelimen haku %s on kielletty. + %1$s on estänyt vieraita liittymästä huoneeseen. + Estit vieraita liittymästä huoneeseen. + Annoit vieraille luvan liittyä huoneeseen. + Annoit vieraille luvan liittyä tänne. + %1$s on antanut vieraille luvan liittyä tänne. + Poistit tämän huoneen pääosoitteen. + Otit käyttöön päästä päähän -salauksen. + Olet estänyt vieraiden liittymisen huoneeseen. + Otit päästä päähän -salauksen käyttöön (tuntematon algoritmi %1$s). + Päivitit tässä. + %s päivitti täällä. + Päivitit tämän huoneen. + Teit tulevista viesteistä näkyviä seuraaville: %1$s + %1$s teki tulevista viesteistä näkyviä seuraaville: %2$s + Teit tulevan huonehistorian näkyväksi seuraaville: %1$s + Lopetit puhelun. + Vastasit puheluun. + Lähetit tietoja puhelun valmistelemiseksi. + %s lähetti tietoja puhelun valmistelemiseksi. + Aloitit äänipuhelun. + Aloitit videopuhelun. + Vaihdoit huoneen nimeksi: %1$s + Vaihdoit huoneen profiilikuvaa + %1$s vaihtoi huoneen profiilikuvaa + Vaihdoit aiheen: %1$s + Poistit nimimerkkisi (se oli %1$s) + Vaihdoit nimimerkkisi %1$s nimeen %2$s + Asetit nimimerkiksesi %1$s + Kutsusi + Vaihdoit profiilikuvaasi + Peruutit %1$sn kutsun + Estit %1$s + Poistit eston %1$s + Poistit %1$s + Hylkäsit kutsun + Poistuit huoneesta + %1$s poistui huoneesta + Poistuit huoneesta + Liityit + %1$s liittyi + Liityit huoneeseen + Kutsuit käyttäjän %1$s + Loit keskustelun + %1$s loi keskustelun + Loit huoneen + %1$s loi huoneen + Asetukset + OK + Peruuta + Tallenna + Poistu + Lähetä + Lainaa + Jaa + Myöhemmin + Pysyvä linkki + Lähdekoodi + Näytä salaamaton lähde + Poista + Nimeä uudelleen + Ilmoita epäilyttävästä sisällöstä + tai + Kutsu + Kirjaudu ulos + Äänipuhelu + Videopuhelu + Merkitse kaikki luetuiksi + Pikavastaus + Avaa + Sulje + Kopioitu leikepöydälle + Vahvistus + Varoitus + Suosikit + Ihmiset + Huoneet + Suodata huoneista + Kutsut + Matala prioriteetti + Keskustelut + Ainoastaan Matrix-yhteyshenkilöt + Ei tuloksia + Huoneet + Lähetä lokit + Lähetä kaatumislokit + Lähetä näytönkaappauskuva + Ilmoita virheestä + Kuvaile virhettä. Mitä teit? Mitä odotit tapahtuvan? Mitä tapahtui? + Kuvaile ongelmaa + Ongelman diagnosointia varten sovelluksen lokit lähetetään virheilmoituksen mukana. Tämä virheilmoitus, sisältäen lähetetyt lokit ja kuvankaappauksen, eivät ole julkisesti nähtävissä. Jos haluat lähettää vain ylläolevan tekstin, poista valinta: + Huomaan, että ravistelet puhelintasi tuskissasi. Haluaisitko lähettää virheilmoituksen\? + Virheraportti lähetettiin + Virheraporttia ei voitu lähettää (%s) + Lähetetään (%s%%) + Sovellus kaatui viime kerralla. Haluatko tehdä kaatumisesta virheilmoituksen\? + Liity huoneeseen + Käyttäjätunnus + Kirjaudu ulos + Kotipalvelimen URL-osoite + Etsi + Aloita puhelu + Aloita videopuhelu + Lähetä tiedostoja + Ota kuva tai video + Kirjaudu sisään + Lähetä + Väärä käyttäjätunnus ja/tai salasana + Tämä ei näytä oikealta sähköpostiosoitteelta + Tämä sähköpostiosoite on jo käytössä. + Unohditko salasanasi? + Tämä kotipalvelin haluaa varmistaa, ettet ole robotti + Sähköpostiosoitteesi vahvistaminen epäonnistui. Varmista, että klikkasit sähköpostissa olevaa linkkiä + Syötäthän toimivan osoitteen + Epämuotoinen JSON + Ei sisällä kelvollista JSON:ia + Liian monta pyyntöä + Alkuperäinen + Iso + Keskikokoinen + Pieni + Yhdistetään… + Puhelu loppui + Saapuva videopuhelu + Saapuva puhelu + Puhelu käynnissä… + Toinen osapuoli ei vastannut. + Huomio + ${app_name} tarvitsee käyttöluvan mikrofoniin suorittakseen puheluita. + ${app_name} tarvitsee käyttöluvan kameraan ja mikrofoniin suorittakseen videopuheluita. +\n +\nSalli mikrofonin ja kameran käyttö seuraavilla näytöillä aloittaaksesi tämän puhelun. + KYLLÄ + EI + Jatka + Poista + Liity + Hylkää + Siirry lukemattomaan + Poistu huoneesta + Haluatko varmasti poistua huoneesta? + YKSITYISKESKUSTELUT + Kutsu + Anna porttikielto + Poista porttikielto + Piilota kaikki tämän käyttäjän viestit + Näytä kaikki tämän käyttäjän viestit + Mainitse + Olet ylentämässä käyttäjää samalle tasolle kuin oma käyttäjätasosi. Et voi perua tätä toimintoa.\nOletko varma? + %s kirjoittaa… + %1$s ja %2$s kirjoittavat… + %1$s, %2$s ja muita kirjoittaa… + Sinulla ei ole oikeutta lähettää viestejä tähän huoneeseen. + Luota + Älä luota + Kirjaudu ulos + Jätä huomiotta + Sormenjälki (%s): + Palvelimen identiteettiä ei voitu vahvistaa. + Tämä voi tarkoittaa että joku yrittää kaapata sinun viestintääsi tai että laitteesi ei luota palvelimen varmenteeseen. + Jos palvelimen ylläpitäjä on ilmoittanut, että tämä on odotettua, varmista että alla oleva sormenjälki on sama kuin hänen antamansa. + Sertifikaatti johon laitteesi luotti aikaisemmin on vaihtunut. Tämä on HYVIN EPÄTAVALLISTA. On suositeltavaa, että ET hyväksy tätä uutta sertifikaattia. + Sertifikaatti on vaihtunut ennestään luotetusta ei-luotettuun. Palvelin on voinut uusia sertifikaattinsa. Kysy palvelimen ylläpitäjältä, mikä sormenjäljen pitäisi olla. + Hyväksy sertifikaatti vain, jos palvelimen ylläpitäjä on julkaissut sormenjäljen, joka täsmää yllä olevan kanssa. + Etsi + Etsi huoneen jäsenistä + Ei tuloksia + Profiilikuva + Nimi + Lisää sähköpostiosoite + Lisää puhelinnumero + Näytä sovelluksen tiedot järjestelmän asetuksissa. + Sovelluksen tiedot + Ota ilmoitukset käyttöön tällä tilillä + Ota ilmoitukset käyttöön tässä istunnossa + Yksityisviestit + Viestit ryhmistä + Kun minut kutsutaan huoneeseen + Saapuvat puhelut + Bottien lähettämät viestit + Taustasynkronointi + Synkronointipyynnön aikakatkaisu + Viive synkronointien välillä + Versio + olm-versio + Käyttöehdot + Kolmannen osapuolen tiedot + Tekijänoikeus + Tietosuojakäytäntö + Tyhjennä välimuisti + Käyttäjäasetukset + Ilmoitukset + Piilotetut henkilöt + Muut + Lisäasetukset + Kryptografia + Ilmoituskohteet + Paikalliset yhteystiedot + Oikeus yhteystietoihin + Yhteystiedot (maa) + Koti + Kiinnitä huoneet, joissa on huomaamatta jääneitä ilmoituksia + Kiinnitä huoneet, joissa on lukemattomia viestejä + ID + Julkinen nimi + Päivitä julkinen nimi + Viimeksi käytetty + %1$s @ %2$s + Tunnistautuminen + Kirjautuneena nimellä + Kotipalvelin + Identiteettipalvelin + Tarkista sähköpostisi ja klikkaa sinne saamaasi linkkiä. Kun olet tehnyt tämän, paina jatka. + Tämä sähköpostiosoite on jo käytössä. + Tämä puhelinnumero on jo käytössä. + Vaihda salasana + Nykyinen salasana + Uusi salasana + Salasanan päivittäminen epäonnistui + Salasanasi on vaihdettu + Näytä kaikki viestit käyttäjältä %s\? +\n +\nHuomaa, että tämä toiminto käynnistää sovelluksen uudelleen ja siinä saattaa kestää jonkin aikaa. + Valitse maa + Aihe + Huoneen historian näkyvyys + Ketkä saavat nähdä huoneen historian\? + Kuka tahansa + Vain jäsenet (tämän asetuksen valitsemisesta alkaen) + Vain jäsenet (kutsumisestaan alkaen) + Vain jäsenet (liittymisestään alkaen) + Porttikiellon saaneet käyttäjät + Lisäasetukset + Tämän huoneen sisäinen ID + Kokeelliset + Nämä ovat kokeellisia ominaisuuksia, jotka voivat mennä rikki. Käytä varoen. + Aseta pääosoitteeksi + Kumoa pääosoitteeksi asettaminen + Salauksenpurkuvirhe + Julkinen nimi + Istunnon tunnus + Istunnon avain + Vie salatun huoneen avaimet + Vie huoneen avaimet + Vie avaimet paikalliseen tiedostoon + Vie + Anna salasana + Vahvista salasana + Tuo salatun huoneen avaimet + Tuo huoneen avaimet + Tuo avaimet paikallisesta tiedostosta + Tuo + Lähetä salatut viestit vain vahvistetuille laitteille + Älä lähetä salattuja viestejä vahvistamattomille laitteille tästä laitteesta. + Vahvistamaton + Vahvistettu + Vahvista + Vahvistaaksesi, että tähän laitteeseen voi luottaa, ota yhteyttä sen omistajaan jollain muulla tavalla (esimerkiksi soittamalla tai tapaamalla) ja varmista että hänen laitteensa avain on sama kuin alla oleva: + Jos avaimet eivät täsmää, keskustelusi eivät luultavasti ole turvassa. + Valitse huoneluettelo + Palvelimen nimi + Kaikki huoneet palvelimella %s + Kaikki alkuperäiset %s huoneet + Käynnistä automaattisesti + Tyhjennä mediavälimuisti + Säilytä media + Näytä aikaleimat kaikille viesteille + Käyttöliittymä + Kieli + Valitse kieli + 3 päivää + 1 viikko + 1 kuukausi + Ikuisesti + Teema + Fontin koko + Pienin + Pieni + Normaali + Iso + Isompi + Isoin + Valtava + Vaalea teema + Tumma teema + Musta teema + Kuunnellaan tapahtumia + Äänekkäät ilmoitukset + Hiljaiset ilmoitukset + Virheraportti + Ota kuva + Kaappaa video + Puhelu + Ilmoitusääni + Viesti sisältää nimeni + Viesti sisältää käyttäjänimeni + Näytä aikaleimat 12 tunnin muodossa + Analytiikka + Haluatko varmasti poistaa sovelman tästä huoneesta\? + Sovelmaa ei voitu luoda. + Pyynnön lähetys epäonnistui. + Oikeustason täytyy olla positiivinen kokonaisluku. + Et ole tässä huoneessa. + Sinulla ei ole oikeutta suorittaa toimintoa tässä huoneessa. + room_id puuttuu pyynnöstä. + user_id puuttuu pyynnöstä. + Huone %s ei ole näkyvillä. + Lisää integraatioita + Käytä järjestelmän kamerasovellusta + Lisäsit uuden istunnon \'%s\', joka pyytää salausavaimia. + Vahvistamaton laitteesi \'%s\' pyytää salausavaimia. + Aloita varmennus + Komentovirhe + Tuntematon komento: %s + Pois + Äänekäs + Salattu viesti + Ladataan… + Haluatko varmasti aloittaa äänipuhelun\? + Haluatko varmasti aloittaa videopuhelun\? + Käyttäjän estäminen poistaa hänet tästä huoneesta ja estää häntä liittymästä huoneeseen uudelleen. + Kaikki viestit + Lisää aloitusruudulle + Linkkien esikatselu + Värise, kun käyttäjä mainitaan + Luo + Koti + Huoneet + Kutsuttu + Sinut poistettiin %1$s käyttäjän %2$s toimesta + Sinut estettiin %1$s käyttäjän %2$s toimesta + Syy: %1$s + Markdown-muotoilu + Markdown on käytössä. + Markdown on pois käytöstä. + Puhelut + Valitse soittoääni puheluille: + Salasana + Kirjoita salasanasi. + Lähetä kirjoitusilmoitukset + Näytä lukukuittaukset + Näytä liittymiset ja poistumiset + Näytä tilin tapahtumat + Esikatsele media ennen lähettämistä + Lähetä analytiikkatietoja + Ravista ilmoittaaksesi virheestä + Poista tili pysyvästi + Poista tili pysyvästi + Poista tili pysyvästi + Poista tili pysyvästi + Lähetä tarra + Oletko varma? + Lataa + Hyväksy + Ohita + Oletko varma, että haluat kirjautua ulos? + Virhe + Jos mahdollista, kirjoita kuvaus englanniksi. + Lähetä tarra + Sinulla ei ole yhtään tarrapakettia käytössä. +\n +\nHaluatko lisätä paketteja\? + Lue ja hyväksy tämän kotipalvelimen käytännöt: + Avainten varmuuskopiointi + Käytä avainten varmuuskopiointia + Menetät salatut viestisi, jos kirjaudut ulos nyt + Avainten varmuuskopio on meneillään. Jos kirjaudut ulos, menetät pääsyn salattuihin viesteihisi. + Turvallinen avainten varmuuskopio pitäisi olla käytössä kaikissa istunnoissasi, jotta et menettäisi pääsyä salattuihin viesteihisi. + En halua salattuja viestejäni + Varmuuskopioidaan avaimia… + Varmuuskopioi + Menetät pääsyn salattuihin viesteihisi, ellet varmuuskopioi avaimiasi ennen uloskirjautumista. + Valmis + Järjestelmähälytykset + Lähetä ääntä + Yhtään ulkopuolista sovellusta tämän toiminnon suorittamiseksi ei löytynyt. + Pyydä salausavaimia uudelleen muista istunnoistasi. + Käynnistä ${app_name} toisella laitteella, joka voi purkaa viestin, jotta se voi lähettää avaimet tähän istuntoon. + + yksi jäsenyysmuutos + %d jäsenyysmuutosta + + Käytä ${app_name}in oletussoittoääntä saapuville puheluille + Saapuvien puheluiden soittoääni + Videopuhelu menossa… + Jäsenet + + yksi jäsen + %d jäsentä + + Poista keskustelusta + + yksi uusi viesti + %d uutta viestiä + + + yksi valittu + %d valittu + + Edistyneet ilmoitusasetukset + Ilmoituksen tärkeys tapahtumakohtaisesti + Ratkaise ilmoituksien ongelmia + Vianmääritys + Suorita testit uudelleen + Suoritetaan… (%1$d / %2$d) + Vianmäärityksessä ei löytynyt ongelmia. Jos et edelleenkään saa ilmoituksia, lähetä virheraportti, jotta meidän on helpompi tutkia ongelmaa. + Yksi tai useampi testi epäonnistui, kokeile ehdotettuja korjauksia. + Yksi tai useampi testi epäonnistui. Lähetäthän virheraportin, jotta meidän on helpompi tutkia ongelmaa. + Järjestelmäasetukset. + Ilmoitukset ovat käytössä järjestelmäasetuksissa. + Ilmoitukset ovat pois käytöstä järjestelmäasetuksissa. +\nTarkistathan järjestelmäasetukset. + Avaa asetukset + Tilin asetukset. + Ilmoitukset ovat käytössä tililläsi. + Ilmoitukset eivät ole käytössä tililläsi. +\nTarkista tilisi asetukset. + Ota käyttöön + Istunnon asetukset. + Ilmoitukset ovat käytössä tässä istunnossa. + Ilmoitukset eivät ole käytössä tässä istunnossa. +\nTarkista ${app_name}in asetukset. + Ota käyttöön + Mukautetut asetukset. + Huomaathan, että osa viestityypeistä on asetettu olemaan hiljaisia (tuottavat ilmoituksen ilman ääntä). + Osa ilmoituksista on otettu pois käytöstä mukautetuissa asetuksissasi. + Play Services -palvelun tarkistus + Google Play Services APK on saatavilla ja ajan tasalla. + ${app_name} käyttää Google Play Services -palvelua ilmoitusten välittämiseen, mutta se ei näytä olevan määritetty oikein: +\n%1$s + Korjaa Play Services -palvelu + Firebase-tunniste + FCM-tunniste haettu onnistuneesti: +\n%1$s + FCM-tunnisteen haku epäonnistui: +\n%1$s + [%1$s] +\n${app_name} ei voi vaikuttaa tähän virheeseen, ja Googlen mukaan tämä virhe tarkoittaa, että tällä laitteella on liikaa FCM:ään rekisteröityjä sovelluksia. Tämä virhe ilmenee vain tapauksissa, joissa on erittäin paljon FCM:ään rekisteröityjä sovelluksia asennettuna, joten tätä ei pitäisi tapahtua normaalisti. + [%1$s] +\nTämä virhe ei ole ${app_name}in ratkaistavissa. Se voi johtua useasta eri syystä. Ehkä tämä toimii, jos yrität myöhemmin. Voit myös tarkistaa, että Google Play Services -palvelu ei ole rajoitettuna järjestelmäasetuksissa, ja että laitteesi kello on oikein. Tämä voi tapahtua myös mukautetun käyttöjärjestelmän kanssa. + [%1$s] +\nTämä virhe ei ole ${app_name}in ratkaistavissa. Tässä puhelimessa ei ole Google-tiliä. Lisää laitteeseesi Google-tili tätä toimintoa varten. + Lisää tili + Tunnisteen rekisteröinti + FCM-tunniste rekisteröity onnistuneesti kotipalvelimelle. + FCM-tunnisteen rekisteröinti kotipalvelimelle epäonnistui: +\n%1$s + Käynnistä laitteen käynnistyessä + Palvelu käynnistetään, kun laite käynnistetään uudelleen. + Palvelua ei käynnistetä laitteen uudelleenkäynnistyksen yhteydessä. Et tule saamaan ilmoituksia ennen kuin ${app_name} on käynnistetty uudelleen. + Ota käyttöön automaattinen käynnistys + Tarkista taustapalveluiden rajoitukset + Taustapalveluiden rajoitukset ovat pois käytöstä. Tämä testi tulee ajaa mobiilidatayhteydellä (ilman wlania). +\n%1$s + Taustapalveluiden rajoitukset ovat käytössä. +\nTyötä, jota ${app_name} yrittää tehdä, rajoitetaan aggressiivisesti, kun se on taustalla, mikä saattaa vaikuttaa ilmoituksiin. +\n%1$s + Poista rajoitukset + Akunkäytön optimointi + Akunkäytön optimointi ei vaikuta ${app_name}in toimintaan. + Jos käyttäjä jättää laitteen paikalleen ilman latausjohtoa niin, että näyttö on pois päältä, laite siirtyy torkkutilaan. Tämä estää sovelluksia käyttämästä verkkoyhteyksiä ja lykkää niiden töitä, synkronointeja ja perushälytyksiä. + Jätä optimointi huomiotta + Mukauta äänekkäitä ilmoituksia + Mukauta soittoilmoituksia + Mukauta hiljaisia ilmoituksia + Valitse Ledin väri, värinä ja ääni… + Salausavainten hallinta + Esikatsele linkit, kun kotipalvelin tukee sitä. + Ilmoita muille, että olet kirjoittamassa viestiä. + Muotoile viestit Markdownilla ennen niiden lähettämistä. Tämä sallii edistyneen muotoilun, kuten asteriskien käytön kursivoidun tekstin aikaansaamiseksi. + Paina lukukuittauksesta nähdäksesi tarkemman listan. + Ei vaikuta kutsuihin, poistamisiin ja porttikieltoihin. + Sisältää hahmokuvat ja näyttönimien vaihdot. + ${app_name} kerää anonyymiä analytiikkaa sovelluksen parantamiseksi. + Luo salalause salataksesi viedyt avaimet. Tarvitset saman salalauseen avainten tuomiseen. + Salattujen viestien palautus + Hallitse avainten varmuuskopiointia + + yksi lukematon ilmoitettu viesti + %d lukematonta ilmoitettua viestiä + + + yksi huone + %d huonetta + + + yksi aktiivinen sovelma + %d aktiivista sovelmaa + + Vaadittu parametri puuttuu. + Käynnistä järjestelmän kamera Elementin kameraruudun sijaan. + Komento ”%s” vaatii enemmän parametreja, tai jotkin parametrit ovat virheellisiä. + Näyttää toiminnon + Estää käyttäjän annetulla id:llä + Sallii käyttäjän annetulla id:llä + Määritä käyttäjän oikeuksien taso + Poistaa käyttäjän operaattorioikeudet + Kutsuu käyttäjän nykyiseen huoneeseen + Liittyy osoitteen mukaiseen huoneeseen + Poistu huoneesta + Aseta huoneen aihe + Potkaisee käyttäjän pois + Vaihtaa näytettävän nimimerkkisi + Markdown päällä/pois + Matrix-sovellusten hallinnan korjaamiseen + Hiljainen + Hahmokuva + Jatkaaksesi kotipalvelimen %1$s käyttöä, sinun täytyy hyväksyä palvelun käyttöehdot. + Näytä ehdot + Tämä tekee tilistäsi lopullisesti käyttökelvottoman. Et voi kirjautua sisään eikä kukaan pysty rekisteröitymään samalla käyttäjätunnuksella. Tämä saa tilisi poistumaan kaikista huoneista, joissa se on osallisena, ja poistaa tilin tiedot identiteettipalvelimelta. Tämä toiminto on peruuttamaton. +\n +\nTilin poistaminen ei oletuksena saa meitä unohtamaan lähettämiäsi viestejä. Jos haluat meidän unohtavan viestisi, merkitse alapuolella oleva valintaruutu. +\n +\nViestien näkyvyys Matrixissa on samantapainen kuin sähköpostissa. Viestiesi unohtaminen tarkoittaa, että lähettämiäsi viestejä ei näytetä uusille tai rekisteröitymättömille käyttäjille. Ne rekisteröityneet käyttäjät, joilla viestisi jo on, pääsevät kuitenkin näkemään oman kopionsa niistä jatkossakin. + Unohda kaikki viestit, jotka olen lähettänyt, kun tilini on poistettu (Varoitus: tästä seuraa, että tulevat käyttäjät näkevät vanhat keskustelut epätäydellisinä) + Syötä käyttäjätunnus. + Tämä huone on korvattu toisella eikä ole enää aktiivinen. + Keskustelu jatkuu täällä + Tämä huone on jatkoa toiselle keskustelulle + Paina tästä nähdäksesi vanhemmat viestit + ota yhteys palvelun ylläpitäjään + Tämä kotipalvelin on ylittänyt yhden resurssirajoistaan, joten osa käyttäjistä ei pysty kirjautumaan sisään. + Tämä kotipalvelin on ylittänyt yhden resurssirajoistaan. + Tämä kotipalvelin on saavuttanut kuukausittaisten aktiivisten käyttäjien rajansa, joten osa käyttäjistä ei pysty kirjautumaan sisään. + Tämä kotipalvelin on saavuttanut kuukausittaisten aktiivisten käyttäjien rajansa. + Tee %s saadaksesi tätä rajaa korotettua. + Tee %s jatkaaksesi palvelun käyttöä. + Törmäsimme virheeseen + laajenna + supista + %1$s: %2$s + %d+ + Kelvollista Google Play Services APK:ta ei löytynyt. Ilmoitukset eivät ehkä toimi oikein. + Luo salalause + Salalause ei täsmää + Syötä salalause + Salalause on liian heikko + Poista salalause, jos haluat ${app_name} generoivan palautusavaimen. + Älä koskaan menetä salattuja viestejä + Salatuissa huoneissa viestit ovat suojattuna osapuolten välisellä salauksella. Vain sinä ja vastaanottaja(t) omistavat avaimet näiden viestien lukemiseen. +\n +\nVarmuuskopioi avaimesi, jotta et menetä niitä. + Aloita avainten varmuuskopioinnin käyttö + (Edistynyt) + Tallenna avaimet käsin + Turvaa varmuuskopiosi salalauseella. + Tallennamme salatun kopion avaimistasi kotipalvelimellesi. Suojaa varmuuskopiosi salalauseella pitääksesi sen turvattuna. +\n +\nParhaan turvallisuuden takaamiseksi salalauseen tulisi olla eri kuin tilisi salasana. + Aseta salalause + Luodaan varmuuskopiota + Tai, turvaa varmuuskopio palautusavaimella, tallentamalla palautusavain johonkin turvalliseen paikkaan. + (Edistynyt) Aseta palautusavaimella + Onnistui ! + Avaimiasi varmuuskopioidaan. + Palautusavaimesi on turvaverkko: voit käyttää sitä palauttaaksesi pääsyn salattuihin viesteihisi, mikäli unohdat salalauseesi. +\nPidä palautusavaimesi jossain erittäin turvallisessa paikassa, kuten salasanojen hallintasovelluksessa (tai kassakaapissa) + Pidä palautusavaimesi jossain erittäin turvallisessa paikassa, kuten salasanojen hallintasovelluksessa (tai kassakaapissa) + Valmis + Olen tehnyt kopion + Tallenna palautusavain + Jaa + Tallenna tiedostona + Teethän kopion + Jaa palautusavain kohteelle… + Luodaan palautusavainta käyttäen salalausetta. Tässä saattaa kestää useampi sekunti. + Palautusavain + Odottamaton virhe + Oletko varma\? + Saatat menettää pääsyn viesteihisi jos kirjaudut ulos tai menetät tämän laitteen. + Haetaan varmuuskopion versiota… + Käytä palautuksen salalausetta ottaaksesi käyttöön salatun viestihistoriasi + käyttää palautusavaintasi + Jos et tiedä palautuksen salalausettasi, voit %s. + Käytä palautusavainta ottaaksesi salatun viestihistoriasi käyttöön + Syötä palautusavain + Menetitkö palautusavaimesi\? Voit asettaa uuden asetuksissa. + Varmuuskopiota ei pystytty purkamaan tällä salalauseella. Tarkista, että syötit oikean palautuksen salalauseen. + Palautetaan varmuuskopiota: + Lasketaan palautusavainta… + Ladataan avaimia… + Tuodaan avaimia… + Otetaan historia käyttöön + Syötä palautusavain + Varmuuskopiota ei pystytty purkamaan tällä palautusavaimella. Tarkista, että olet syöttänyt oikean palautusavaimen. + Varmuuskopio palautettu %s ! + + Varmuuskopio palautettiin yhdellä avaimella. + Varmuuskopio palautettiin %d avaimella. + + + Yksi uusi avain lisätty tähän istuntoon. + %d uutta avainta lisätty tähän listuntoon. + + Uusimman palautusavaimen version hakeminen epäonnistui (%s). + Palauta varmuuskopiosta + Poista varmuuskopio + Avaimien varmuuskopiointi on käytössä tällä laitteella. + Avaimien varmuuskopiointi ei ole käytössä tässä istunnossa. + Avaimiasi ei varmuuskopioida tästä istunnosta. + Varmuuskopiossa on allekirjoitus tuntemattomasta laitteesta ID:llä %s. + Varmuuskopiossa on pätevä allekirjoitus tästä istunnosta. + Varmuuskopiossa on pätevä allekirjoitus varmennetulta laitteelta %s. + Varmuuskopiossa on pätevä allekirjoitus varmentamattomalta laitteelta %s + Varmuuskopiossa on epäkelpo allekirjoitus varmennetulta laitteelta %s + Varmuuskopiossa on epäkelpo allekirjoitus tuntemattomalta laitteelta %s + Käyttääksesi avainten varmuuskopiointia tällä laitteella, palauta salalauseellasi tai palautusavaimella nyt. + Poistetaan varmuuskopiota… + Poista varmuuskopio + Poista varmuuskopioidut salausavaimesi palvelimelta\? Et voi sen jälkeen käyttää palautusavaintasi lukeaksesi salattuja viestejäsi. + Älä koskaan menetä salattuja viestejäsi + Käytä avainten varmuuskopiointia + Uudet salattujen viestien avaimet + Hallinnoi avainten varmuuskopioinnissa + Varmuuskopioidaan avaimia… + Kaikki avaimet varmuuskopioitu + + Varmuuskopioidaan yhtä avainta… + Varmuuskopioidaan %d avainta… + + Versio + Algoritmi + Allekirjoitus + Jätä huomiotta + Kirjaudu sisään kertakirjautumisella + Lähetä viesti enter-näppäimellä + Näppäimistön enter-näppäin lähettää viestin sen sijaan, että se lisäisi rivinvaihdon + Salasana ei ole kelvollinen + %1$s -> %2$s + Media + Oletuksena oleva pakkauksen määrä + Valitse + Oletuksena oleva medialähde + Valitse + Toista sulkimen ääni + Merkitse luetuksi + + %1$s: yksi viesti + %1$s: %2$d viestiä + + + yksi ilmoitus + %d ilmoitusta + + Uusi tapahtuma + Huone + Uusia viestejä + Uusi kutsu + Minä + ** Lähetys epäonnistui — avaathan huoneen + Valitettavasti ryhmäpuhelut Jitsillä eivät toimi vanhoissa laitteissa (laitteet, joissa on Android 6.0 tai vanhempi) + tuntematon IP-osoite + Uusi istunto pyytää salausavaimia. +\nIstunnon nimi: %1$s +\nNähty viimeksi: %2$s +\nJos et kirjautunut toisessa paikkaa, jätä tämä pyyntö huomiotta. + Jaa + Selvä + Tuntematon virhe + Kotipalvelimellasi on jo varmuuskopio + Näyttää, että olet jo asettanut avainten varmuuskopioinnin toisesta istunnosta. Halutatko korvata sen tällä\? + Korvaa + Seis + Tarkistetaan varmuuskopion tilaa + Muokkaa + Vastaa + Yritä uudelleen + Lähetti sinulle kutsun + %s kutsui + Sinulla ei ole enempää lukemattomia viestejä + Keskustelut + Yksityisviestisi näytetään tässä. Napauta + oikeasta alakulmasta aloittaaksesi keskustelun. + Huoneet + Huoneesi näytetään tässä. Napauta + oikeasta alakulmasta löytääksesi olemassa olevia tai perustaaksesi omiasi. + Reaktiot + Samaa mieltä + Lisää reaktio + Näytä reaktiot + Reaktiot + Käyttäjä poisti tapahtuman + Huoneen ylläpitäjä moderoi tapahtuman + Epämuotoinen tapahtuma, ei voida näyttää + Luo uusi huone + Ei verkkoa. Tarkista internet-yhteytesi. + Odota… + Tätä huonetta ei voi esikatsella + Huoneet + Yksityisviestit + LUO + Nimi + Julkinen + Kuka tahansa voi liittyä tähän huoneeseen + Luottamustietoa haettaessa tapahtui virhe + Avainten varmuuskopioinnin tietoja haettaessa tapahtui virhe + Tuntematon laite pyytää salausavaimia +\nLaitteen nimi: %1$s +\nViimeksi nähty: %2$s +\nJos et kirjautunut toisella laitteella, voit jättää tämän pyynnön huomiotta. + Matrix SDK:n versio + Muut kolmansien osapuolten huomautukset + Asetukset + Tietoturva ja yksityisyys + Olet ajan tasalla! + Vaihda verkkoa + Katselet jo tätä huonetta! + Yleiset + Ääni ja video + Tietoa sovelluksesta + Tee ehdotus + Kirjoita ehdotuksesi alle. + Kuvaile ehdotuksesi tässä + Kiitos, ehdotus on lähetetty + Ehdotuksen lähettäminen epäonnistui (%s) + Näytä piilotetut tapahtumat aikajanalla + Yksityisviestit + Odotetaan… + Salataan tiedostoa… + Lähetetään tiedostoa (%1$s / %2$s) + Tiedosto %1$s ladattu! + (muokattu) + Muokkauksia ei löytynyt + Suodata keskusteluja… + Etkö löydä, mitä etsit\? + Luo uusi huone + Lähetä uusi yksityisviesti + Näytä huoneluettelo + Linkki kopioitu leikepöydälle + Luodaan huonetta… + Näytä muokkaushistoria + Avaimen jakopyyntö + Vahvistettu! + Vahvistuspyyntö + %s haluaa vahvistaa laitteesi + Viesti-ilmoitusten säännöt + Katkaise yhteys + Kieltäydy + Kotipalvelinta ei voi tavoittaa tästä URL-osoitteesta, tarkista osoite + Taustasynkronointitila + Ei taustasynkronointia + Et saa ilmoituksia saapuvista viesteistä, kun sovellus on taustalla. + Jatkaaksesi sinun täytyy hyväksyä palvelun käyttöehdot. + Et käytä mitään identiteettipalvelinta + Näyttää, että yrität yhdistää toiseen kotipalvelimeen. Haluatko kirjautua ulos\? + URL-osoite: + Ota käyttöön pyyhkäisemällä vastaaminen aikajanalla + Käyttöehdot + Käytä botteja, siltoja, sovelmia ja tarrapaketteja + Identiteettipalvelin + Katkaise yhteys identiteettipalvelimeen + Määritä identiteettipalvelin + Vaihda identiteettipalvelinta + Käytät palvelinta %1$s löytääksesi tuntemiasi ihmisiä ja ollaksesi heidän löydettävissään. + Et käytä tällä hetkellä identiteettipalvelinta. Jotta voit löytää tuntemiasi ihmisiä ja jotta he löytävät sinut, määritä identiteettipalvelin alla. + Syötä uusi identiteettipalvelin + Identiteettipalvelimeen ei saatu yhteyttä + Syötä identiteettipalvelimen URL-osoite + Identiteettipalvelimella ei ole käyttöehtoja + Valitsemallasi identiteettipalvelimella ei ole käyttöehtoja. Jatka vain, jos luotat palvelun omistajaan + Jaat sähköpostiosoitteita tai puhelinnumeroita identiteettipalvelimella %1$s. Sinun täytyy yhdistää uudelleen palvelimeen %2$s, jotta voit lopettaa niiden jakamisen. + Hyväksy identiteettipalvelimen (%s) käyttöehdot salliaksesi, että sinut voi löytää sähköpostiosoitteen tai puhelinnumeron perusteella. + Yhteyden katkaiseminen identiteettipalvelimeesi tarkoittaa, että muut käyttäjät eivät voi etsiä sinua etkä voi kutsua muita sähköpostin tai puhelinnumeron perusteella. + Lähetimme sinulle sähköpostia osoitteeseen %s. Tarkista sähköpostisi ja klikkaa vahvistuslinkkiä. + Ota yksityiskohtaiset lokit käyttöön. + Yritä uudelleen, kun olet hyväksynyt kotipalvelimesi käyttöehdot. + Palvelimen vastaus näyttäisi olevan liian hidas. Tämä voi johtua kehnosta yhteydestä tai palvelimella olevasta ongelmasta. Yritä hetken kuluttua uudelleen. + Lähetä liite + Luo uusi huone + Siirry loppuun + %1$s, %2$s ja %3$s lukivat + %1$s ja %2$s lukivat + %s luki + + 1 käyttäjä on lukenut + %d käyttäjää on lukenut + + Tiedosto + Kamera + Galleria + Tarra + Se on roskapostia + Se on sopimaton + Ei mitään + Optimoitu akunkestoa varten + ${app_name} synkronoi taustalla laitteen rajallisia resursseja (akkua) säästäen. +\nLaitteesi resurssien tilasta riippuen käyttöjärjestelmä saattaa lykätä synkronointia. + Optimoitu reaaliaikaa varten + ${app_name} synkronoi taustalla täsmällisin aikavälein (säädettävä). +\nTämä vaikuttaa radion ja akun käyttöön. Näet pysyvän ilmoituksen, joka kertoo, että ${app_name} kuuntelee tapahtumia. + Viestimuokkaukset + Ole löydettävissä + Tekstiviesti on lähetetty numeroon %s. Syötä sen sisältämä varmistuskoodi. + Viesti-ilmoitusten sääntöjä ei ole määritetty + Luo uusi yksityiskeskustelu + Kumoa + Integraatiot + Käytä Integraatioiden hallintaa botteihin, siltoihin, sovelmiin ja tarroihin. +\nIntegraatioiden hallinnat vastaanottavat määritystietoja ja voivat muokata sovelmia, lähettää huonekutsuja ja asettaa oikeustasoja puolestasi. + Käyttäjien etsintä + Muokkaa etsinnän asetuksia. + Salli integraatiot + Sovelman lähde + Sovelma + Lataa sovelma + Sovelman lisäsi: + Sovelman käyttö saattaa asettaa evästeitä ja jakaa tietoa kohteen %s kanssa: + Sovelman käyttö saattaa jakaa tietoa kohteen %s kanssa: + Sovelman lataus epäonnistui. +\n%s + Lataa sovelma uudelleen + Avaa selaimessa + Kumoa minun pääsyni + Näyttönimesi + Profiilikuvasi osoite + Käyttäjätunnisteesi + Teemasi + Sovelman tunniste + Huoneen tunniste + Tämä sovelma haluaa käyttää seuraavia resursseja: + Salli + Estä kaikki + Käyttää kameraa + Käyttää mikrofonia + Lukea DRM-suojattua mediaa + Huomiotta + Muuta + Tuo osapuolten välisen salauksen avaimet tiedostosta ”%1$s”. + Ei rekisteröityjä viesti-ilmoitusten yhdyskäytäviä + app_id: + push_key: + Sovelluksen näyttönimi: + Istunnon näyttönimi: + Formaatti: + Rekisteröi tunniste + Salataan pikkukuvaa… + Lähetetään pikkukuvaa (%1$s / %2$s) + Nimi tai tunniste (#example:matrix.org) + Etsittävät sähköpostiosoitteet + Vaihtoehdot ilmestyvät, kunhan olet lisännyt sähköpostiosoitteen. + Vaihtoehdot ilmestyvät, kunhan olet lisännyt puhelinnumeron. + Etsittävät puhelinnumerot + Yksityiskohtaiset lokit auttavat antamalla enemmän tietoa kehittäjille, kun lähetät virheilmoituksen. Vaikka yksityiskohtaiset lokit ovat käytössä, sovellus ei lähetä viestien sisältöjä tai mitään muuta yksityistä tietoa. + Avaa navigaatiovalikko + Avaa huoneen luontivalikko + Sulje huoneen luontivalikko… + Sulje avainten varmuuskopion mainos + Yhteystieto + Jakotiedon käsittely epäonnistui + Muokattu ilmianto… + Ilmianna tämä sisältö + Sisällön ilmiannon syy + ILMIANNA + JÄTÄ KÄYTTÄJÄ HUOMIOTTA + Sisältö ilmiannettu + Tämä sisältö on ilmiannettu. +\n +\nJos et halua nähdä enempää sisältöä tältä käyttäjältä, voit estää hänet piilottaaksesi hänen viestit. + Ilmiannettu roskapostina + Tämä sisältö on ilmiannettu roskapostina. +\n +\nJos et halua nähdä enempää sisältöä tältä käyttäjältä, voit estää hänet piilottaaksesi hänen viestit. + Ilmiannettu epäsopivana + Tämä sisältö on ilmiannettu epäsopivana. +\n +\nJos et halua nähdä enempää sisältöä tältä käyttäjältä, voit estää hänet piilottaaksesi hänen viestit. + Tämä ei ole kelvollinen Matrix-palvelimen osoite + Jätä käyttäjä huomiotta + Kaikki viestit (äänekäs) + Kaikki viestit + Vain maininnat + Vaimenna + Asetukset + Poistu huoneesta + %1$s ei tehnyt muutoksia + Lähettää annetun viestin ilonpilaajana + Ilonpilaaja + Syötä avainsanat löytääksesi reaktion. + Et jätä yhtään käyttäjää huomiotta + Tee pitkä klikkaus huoneelle nähdäksesi lisää asetuksia + %1$s asetti huoneen julkiseksi kelle tahansa, joka tietää huoneen osoitteen. + %1$s muutti huoneeseen liittymisen vaatimaan kutsua. + Lukemattomia viestejä + Sinun keskustelusi. Pidä ne hallussasi. + Keskustele kaksistaan tai ryhmissä + Pidä keskustelut yksityisinä ja salattuina + Laajenna ja muokkaa kokemustasi + Aloita + Valitse palvelin + Kuten sähköpostissa, tunnuksilla on yksi koti, mutta voit keskustella koko maailman kanssa + Liity veloituksetta miljoonien joukkoon suurimmalla julkisella palvelimella + Korkealuokkaista isännöintiä organisaatioille + Lue lisää + Muut + Mukautetut ja monimutkaiset asetukset + Jatka + Yhdistä palvelimeen %1$s + Yhdistä Element Matrix Services + Yhdistä itse määritettyyn palvelimeen + Kirjaudu sisään palvelimeen %1$s + Rekisteröidy + Kirjaudu sisään + Jatka kertakirjautumisella + Element Matrix Services in osoite + Osoite + Korkealuokkaista isännöintiä organisaatioille + Syötä Modular Elementin tai haluamasi palvelimen osoite + Sivun lataamisessa tapahtui virhe: %1$s (%2$d) + Sovellus ei pysty kirjautumaan sisään tälle kotipalvelimelle. Tämä kotipalvelin tukee seuraavia kirjautumistyyppejä: %1$s. +\n +\nHaluatko kirjautua sisään web-klientillä\? + Valitettavasti tämä palvelin ei hyväksy uusia tunnuksia. + Sovellus ei pysty luomaan uusia tunnuksia tälle kotipalvelimelle. +\n +\nHaluatko rekisteröityä web-klientillä\? + Tämä sähköpostiosoite ei ole liitettynä mihinkään tiliin. + Palauta salasana palvelimella %1$s + Sähköpostiisi lähetetään viesti uuden salananan asettamiseksi. + Seuraava + Sähköposti + Uusi salasana + Varoitus! + Salasanan vaihtaminen nollaa kaikki osapuolten välisen salauksen avaimet kaikilla laitteillasi, joka estää sinua lukemasta vanhoja viestejä. Ota käyttöön avainten varmuuskopiointi tai vie huoneen avaimet toiselta laitteelta ennen kuin vaihdat salasanasi. + Jatka + Tämä sähköposti ei ole liitettynä mihinkään tiliin + Tarkista sähköpostisi + Vahvistusviesti lähetettiin osoitteeseen %1$s. + Näpäytä linkkiä vahvistaaksesi uuden salasanasi. Seurattuasi siinä olevaa linkkiä, klikkaa alapuolelta. + Olen vahvistanut sähköpostiosoitteeni + Valmis! + Salasanasi on vaihdettu. + Olet kirjautunut ulos kaikilta laitteilta, etkä saa enää viesti-ilmoituksia. Ottaaksesi viesti-ilmoitukset uudelleen käyttöön, kirjaudu sisään jokaisella laitteellasi. + Takaisin sisäänkirjautumiseen + Varoitus + Salasanaasi ei ole vielä vaihdettu. +\n +\nPeru salasananvaihtoprosessi\? + Aseta sähköpostiosoite + Aseta sähköpostiosoite palauttaaksesi tilisi. Myöhemmin voit antaa muiden löytää sinut sähköpostiosoitettasi etsimällä. + Sähköposti + Sähköposti (vapaaehtoinen) + Seuraava + Aseta puhelinnumero + Aseta puhelinnumero antaaksesi muiden löytää sinut puhellinumerosi perusteella. + Käytä kansainvälistä puhelinnumeron muotoa. + Puhelinnumero + Puhelinnumero (vapaaehtoinen) + Seuraava + Vahvista puhelinnumero + Lähetimme sinulle koodin numeroon %1$s. Syötä se alapuolelle vahvistaaksesi numeron. + Syötä koodi + Lähetä uudelleen + Seuraava + Kansainvälisten puhelinnumeroiden pitää alkaa merkillä \'+\' + Puhelinnumero vaikuttaa epäkelvolta. Tarkista numero + Rekisteröidy palvelimelle %1$s + Käyttäjätunnus tai sähköpostiosoite + Salasana + Seuraava + Käyttäjätunnus on varattu + Varoitus + Tunnustasi ei ole vielä luotu. Peru rekisteröintiprosessi\? + Valitse matrix.org + Valitse Element Matrix Services + Valitse muu kotipalvelin + Ratkaise seuraava kuvavarmennushaaste + Hyväksy ehdot jatkaaksesi + Tarkista sähköpostisi + Lähetimme sähköpostin osoitteeseen %1$s. +\nKlikkaa siinä olevaa linkkiä jatkaaksesi tunnuksen luontia. + Syöttämäsi koodi ei ole kelvollinen. Tarkista se. + Vanhentunut kotipalvelin + + Liian monta pyyntöä lähetettiin. Voit yrittää uudelleen sekunnin kuluttua… + Liian monta pyyntöä lähetettiin. Voit yrittää uudelleen %1$d sekunnin kuluttua… + + Nähneet + Olet kirjautunut ulos + Kirjaudu sisään uudelleen + Olet kirjautunut ulos + Kirjaudu sisään + Kotipalvelimen (%1$s) ylläpitäjä on kirjannut sinut ulos tunnukseltasi %2$s (%3$s). + Kirjaudu sisään + Salasana + Poista henkilökohtaiset tiedot + Varoitus: henkilökohtaiset tietosi (sisältää salausavaimesi) ovat vielä tallennettuna tälle laitteelle. +\n +\nPoista ne jos olet lopettanut tämän laitteen käytön, tai haluat kirjautua sisään toiselle tunnukselle. + Poista kaikki tiedot + Poista tiedot + Poista kaikki tälle laitteelle tallennetut tiedot\? +\nKirjaudu sisään päästäksesi käsiksi tunnuksesi tietoihin ja viesteihin. + Menetät pääsyn salattuihin viesteihisi ellet kirjaudu sisään palauttaaksesi salausavaimesi. + Nykyinen istunto on käyttäjälle %1$s, ja yritit kirjautuas isään käyttäjälle %2$s. ${app_name} ei tue tätä. +\nPoista ensin tietosi ja kirjaudu sen jälkeen toisella tunnuksella. Voit vaihtoehtoisesti käyttää ${app_name}in selainversiota. + matrix.to-linkkisi oli epämuodostunut + Kuvaus on liian lyhyt + Se voi johtua monesta eri syystä: +\n +\n• olet vaihtanut salasanasi toisella laitteella +\n +\n• olet poistanut tämän laitteen toisella laitteella +\n +\n• palvelimen ylläpitäjä on estänyt pääsysi turvallisuussyistä. + Kirjaudu sisään palauttaaksesi salausavaimesi, jotka ovat tallessa vain tällä laitteella. Tarvitset niitä lukeaksi kaikki salatut viestisi millä tahansa laitteella. + Lisäasetukset + Asetukset + Nykyinen istunto + Muut istunnot + Ota salaus käyttöön + Salausta ei voi poistaa käytöstä, kun se on kerran otettu käyttöön. + Odotetaan… + %s peruutti + Sinä peruutit + %s hyväksyi + Sinä hyväksyit + Lue lisää + Ilmoitukset + + Yksi henkilö + %1$d ihmistä + + Poistu huoneesta + Poistutaan huoneesta… + Käyttäjätunnus + Synkronoidaan tietoja ensimmäistä kertaa… + Kehittäjäasetukset + Kehittäjäasetuksissa on piilotettuja ominaisuuksia, jotka voivat myös tehdä sovelluksesta epävakaan. Vain kehittäjille! + Ravistus + Tunnistusraja + Ravista puhelintasi testataksesi tunnistusrajan + Ravistus tunnistettu! + Näytetään vain ensimmäiset tulokset, kirjoita lisää kirjaimia… + ${app_name} voi kaatuilla tavallista useammin odottamattomien virheiden vuoksi + Lisää ¯\\_(ツ)_/¯ tavallisen viestin alkuun + Käyttämäsi sähköpostipalvelun ei ole sallittu rekisteröityä tälle palvelimelle + Täsmäävät + Eivät täsmää + Ei turvallinen + Video. + Kuva. + Johonkin näistä on mahdollisesti murtauduttu: +\n +\n - Kotipalvelimesi +\n - Varmentamasi toisen käyttäjän kotipalvelin +\n - Sinun tai toisen käyttäjän Internet-yhteys +\n - Sinun tai toisen käyttäjän käyttämä laite + Äänitiedosto + Tiedosto + Varmennus lähetetty + Varmennuspyyntö + Varmenna istunto + Lue koodi toisen käyttäjän laitteesta varmentaaksenne toisenne tietoturvallisesti + Lue toisen käyttäjän koodi + Lukeminen ei onnistu + Vertailkaa emojeilla jos et ole toisen käyttäjän luona + Varmenna vertaamalla emojeja + Varmenna %s + Varmennettu %s + Odotetaan käyttäjää %s… + Huoneessa olevat viesti eivät ole salattu osapuolten välisellä salauksella. + Huoneen viestit ovat salattu osapuolten välisellä salauksella. +\n +\nViestisi salataan niin, että vain sinä ja vastaanottaja pystytte avaamaan ne henkilökohtaisilla salausavaimillanne. + Tietoturva + Lisää + Huoneen asetukset + Tiedostojen lähetys + Ylläpitäjät + Valvojat + Käyttäjät + Ylläpitäjä %1$s:ssä + Valvoja %1$s:ssä + Siirry lukukuittaukseen + ${app_name} ei osaa käsitellä tapahtumia joiden tyyppi on \'%1$s\' + ${app_name} ei osannut piirtää tapahtuman jonka tunniste on \'%1$s\' sisältöä + Lähettää annetun viestin väritettynä sateenkaaren väreillä + Ota käyttöön osapuolten välinen salaus… + Otetaanko salaus käyttöön\? + Salausta ei voi ottaa pois käytöstä sen jälkeen kun se on otettu käyttöön. Salattuja viestejä ei pysty lukemaan edes palvelin, vain ainoastaan huoneessa olijat. Salauksen käyttöönotto voi estää bottien ja siltojen toiminnan huoneessa. + Ota salaus käyttöön + Salauksen mahdollistamiseksi varmenna %s tarkastamalla kertakäyttöinen koodi. + Tee tämä toisen käyttäjän ollessa läsnä tai käyttäkää toista viestintävälinettä tietoturvan varmistamiseksi. + Verratkaa emojeja ja varmistakaa että ne ovat samassa järjestyksessä kummallakin. + Vertaa koodia joka näkyy toisen käyttäjän ruudulla. + Tämän käyttäjän kanssa käyty viestintä on nyt päästä päähän salattu ja sitä ei pysty kukaan ulkopuolinen vakoilemaan. + Istuntosi on nyt vahvistettu. Sillä on pääsy salattuihin viesteihisi ja muut käyttäjät näkevät sen luotettuna. + Aktiiviset istunnot + Näytä kaikki istunnot + Istuntojen hallinta + Kirjaudu ulos tästä istunnosta + Ei salaukseen liittyvää tietoa + Istunto on luotettu, koska olet vahvistanut sen: + Vahvista tämä istunto jotta se merkitään luotetuksi ja se saa pääsyn salattuihin viesteihin. Jos et ole kirjautunut tähän istuntoon, tunnuksesi on saattanut vuotaa hyökkääjälle: + + %d käynnissä oleva istunto + %d käynnissä olevaa istuntoa + + Varmenna tämä kirjautuminen + Käytä olemassaolevaa istuntoa tämän istunnon varmentamiseksi jotta se saa oikeudet salattuihin viesteihin. + Varmenna + Varmennettu + Varoitus + Ei saatu istuntoja + Istunnot + Luotettu + Ei luotettu + Tähän istuntoon luotetetaan salatussa viestinnässä, koska %1$s (%2$s) varmensi sen: + %1$s (%2$s) kirjautui sisään uuteen istuntoon: + Tämän käyttäjän kanssa käyty viestintä merkitään virheiksi kunnes käyttäjä luottaa tähän istuntoon. Voit vaihtoehtoisesti käsin varmentaa sen. + Nollaa avaimet + QR-koodi + Melkein valmista! Näkyykö %s:lla sama kilpi\? + Kyllä + Ei + Yhteys kotipalvelimeen on poikki + Kehittäjätyökalut + Jos et pääse käsiksi olemassaolevaan istuntoon + Poista… + Haluatko lähettää tämän liitteen %1$s\?:lle\? + + Lähetä kuva alkuperäisessä koossa + Lähetä kuvat alkuperäisessä koossa + + Vahvista poisto + Haluatko varmasti poistaa tämän tapahtuman\? Huomaa, että jos poistat huoneen nimen tai aiheen muutostapahtuman, se voi perua muutoksen. + Anna syy + Käyttäjä poistanut tapahtuman, syynä: %1$s + Huoneen ylläpitäjä moderoi tapahtuman, syy: %1$s + Avaimet ovat jo ajan tasalla! + ${app_name} Android + Avainpyynnöt + Päivitä + Uusi kirjautuminen. Olitko se sinä\? + En ollut + Tilillesi saatetaan olla murtauduttu + Jos perut, et voi lukea salattuja viestejäsi tällä laitteella eivätkä muut käyttäjät luota siihen + Jos perut, et voi lukea salattuja viestejäsi uudella laitteellasi eivätkä muut käyttäjät luota siihen + Varmenna laitteesi ohjelman asetuksista. + Vahvistus peruttu + Palautussalasana + Anna %s jatkaaksesi. + Älä käytä tilisi salasanaa muualla. + Odota hetki, kiitos. + Alustetaan palautusta. + Valmista! + Pidä se turvassa + Lopeta + Julkaistaan luodut identiteettiavaimet + Luodaan salausavain salasanasta + Määritetään SSSS-oletusavain + Synkronoidaan pääavain + Synkronoidaan käyttäjän avain + Synkronoidaan allekirjoitusavain + Alustetaan avainten varmuuskopiointi + %2$s ja %1$s asetettu. +\n +\nPidä ne tallessa. Tarvitset ne salattujen viestiesi ja tietojesi avaamiseen, jos suljet kaikki istuntosi. + Tulosta se jos mahdollista ja säilytä tuloste turvallisessa paikassa + Tallenna se muistitikulle tai varmuuskopiolevylle talteen + Kopioi se henkilökohtaiseen pilvitallennustilaasi + Mukautettu + Mukautettu (%1$d) %2$s:ssä + Syy poistoon + Viestin avain + Tapaamiset käyttävät Jitsin turvallisuus- ja käyttöoikeuskäytäntöjä. Kaikki huoneessa olevat henkilöt näkevät kutsun tapaamiseen liittymiseksi niin kauan kuin tapaaminen on käynnissä. + Aloita äänitapaaminen + Aloita videotapaaminen + Sinulla ei ole oikeuksia puhelun aloittamiseen + Sinulla ei ole oikeuksia puhelun aloittamiseen tässä huoneessa + Sinulla ei ole oikeuksia ryhmäpuhelun aloittamiseen + Sinulla ei ole oikeuksia ryhmäpuhelun aloittamiseen tässä huoneessa + Nollaa + Jätä huomiotta + Toista + Käyttäjän huomiotta jättäminen piilottaa kyseisen käyttäjän viestit sinulta. +\n +\nVoit perua tämän milloin tahansa yleisissä asetuksissa. + Jätä käyttäjä huomiotta + Alenna + Et voi perua tätä muutosta, koska olet alentamassa itseäsi. Jos olet viimeinen oikeutettu henkilö tässä huoneessa, oikeuksia ei voi enää saada takaisin. + Alenna itsesi\? + Peruuta kutsu + Anna lupa hakea yhteystiedot. + QR-koodin skannaaminen vaatii luvan kameran käyttöön. + Kysy varmistusta ennen puhelun aloittamista + Estä vahinkopuhelut + SSL-virhe. + Takakamera + Etukamera + Vaihda kameraa + Langattomat kuulokkeet + Kuulokkeet + Kaiutin + Puhelin + Valitse äänilaite + ${app_name}-puhelu epäonnistui + Lähetä avaimen jakopyyntöjen historia + Ei enempää tuloksia + Ilmoitukset + Onnistui + Kopioi + Lopeta puhelu + Hylkää + Sovelman poistaminen epäonnistui + Sovelman lisääminen epäonnistui + Et voi aloittaa puhelua itsesi kanssa. Odota, että muut osallistujat hyväksyvät kutsun + Et voi aloittaa puhelua itsesi kanssa + Peruuta kutsu + Korkea laatu päälle + Korkea laatu pois + Reaaliaikaisen yhteyden muodostus epäonnistui. +\nPyydäthän kotipalvelimesi ylläpitäjää asentamaan TURN-palvelimen varmistaaksesi puhelujen luotettavan toiminnan. + Vastaa + Aloita keskustelu + Poista suosikeista + Lisää suosikiksi + Ei aktiivisia sovelmia + %1$s: %2$s %3$s + %1$s: %2$s + %1$s ja %2$s + %1$s %2$s ja %3$s + + %d kutsu + %d kutsua + + + %d estetty käyttäjä + %d estettyä käyttäjää + + Tämä on pääosoite + Näytä emoji-näppäimistö + Tiliisi ei ole lisätty sähköpostiosoitetta + Tiliisi ei ole lisätty puhelinnumeroa + Ilmoita kaikille + Haluatko peruuttaa tämän käyttäjän kutsun\? + Tämä huone ei ole julkinen. Jos poistut, et voi liittyä takaisin ilman kutsua. + Tämän asetuksen käyttöön ottaminen lisää FLAG_SECURE kaikkiin toimintoihin. Käynnistä sovellus uudestaan, jotta muutos tulee voimaan. + Estä kuvakaappausten ottaminen sovelluksesta + Et voi lähettää yksityisviestiä itsellesi! + Hylkää muutokset + Virheellinen QR-koodi (virheellinen URI)! + Tämä ei ole kelvollinen Matrix QR-koodi + Melkein valmista! Näkyykö toisella laitteella sama kilpi\? + Melkein valmista! Odottaa vahvistusta… + Odotetaan %s… + QR-koodia ei skannattu! + Skannaa QR-koodi + Jaa koodini + Jaa tämä koodi ihmisten kanssa, jotta he voivat skannata sen lisätäksesi sinut ja aloittaa keskustelu. + Lisää QR-koodilla + Ota integraatiot asetuksista käyttöön tekeäksesi tämän. + Integraatiot ovat poissa käytöstä + Integraatioiden hallinta + Käytä kansainvälistä muotoa (puhelinnumeron on alettava merkillä \'+\') + Sähköpostiosoitteet ja puhelinnumerot + Hallitse Matrix-tiliisi linkitettyjä sähköpostiosoitteita ja puhelinnumeroita + Aseta tilille uusi salasana… + Katselet ilmoitusta! Napsauta minua! + Napsauta ilmoitusta. Jos ilmoitusta ei näy, tarkasta järjestelmäasetukset. + Ilmoitusnäyttö + Vianmääritys + Ilmoitustapa + Salatut yksityisviestit + Salatut viestit ryhmistä + Kun huoneita on päivitetty + Viesti sisältää @room + Aikajana + Lisää lukemattomille ilmoituksille oma välilehti päänäyttöön. + Näytä koko historia salatuissa huoneissa + Viestieditori + Muut kielet + Näytä merkki poistettujen viestien paikalla + Käytä /confetti-komentoa tai lähetä viesti jossa on ❄️ tai 🎉 + Näytä keskustelujen tehosteet + Näytä poistetut viestit + Jos poistat käyttäjän porttikiellon, hän voi liittyä huoneeseen uudelleen. + Tämä poistaa käyttäjän huoneesta, mutta hän voi liittyä uudelleen. +\n +\nJos haluat estää häntä liittymästä uudelleen, anna hänelle porttikielto. + Syy porttikielolle + Syy poistolle + Poista käyttäjä + Valitse ketkä näkevät huoneen historian. Tähänastinen historian näkyvyys ei muutu. + Muuttaa huoneen profiilikuvaa + Muuttaa ryhmän nimeä + Muuttaa historian näkyvyyttä + Ottaa huoneen salauksen käyttöön + Muuttaa huoneen pääosoitettta + Poistaa muiden viestejä + Muuttaa aihetta + Muuttaa oikeuksia + Hallita sovelmia + Estää käyttäjiä + Poistaa käyttäjiä + Muuttaa asetuksia + Kutsua käyttäjiä + Oikeudet + Lähettää viestejä + Oletusrooli + Paikalliset osoitteet + Julkaistut osoitteet + Aseta profiilikuva + Kutsu kavereita + Lisää jäseniä + Luodaan huonetta… + Piilota lisäasetukset + Näytä lisäasetukset + Tutut käyttäjät + QR-koodi + Yksityisviesti + Lisää kuva + Voit ottaa tämän käyttöön, jos haluat rajoittaa huoneen käytön ainoastaan käyttämäsi palvelimen käyttäjiin. Tätä ei voi perua. + Rajoita huoneeseen liittyminen %s -käyttäjiin + Huoneen aihe + Huoneen asetukset + Huoneen nimi + Liityit. + %s liittyi. + + %d sekunti + %d sekuntia + + Puhelinnumerot + Sähköpostit + Yhteystiedot + Huoneen nimi + Avaa keskustelu + Aseta rooli + Nykyinen kieli + Kutsu huoneeseen + Kutsutaan jäseniä huoneeseen… + Lisää jäseniä + Tilitiedot + Järjestelmän oletus + Matrix ID + Poistettu viesti + Aktiiviset sovelmat + Poista esto + Estä käyttäjä + Tai + Oikeudet + Lisää + "Aihe: " + Ehdotukset + Aihe + Poistu + Asetukset + Äänestys + Koodi + Aihe + Rooli + KUTSU + Viesti + Kutsut + Tarra + TIEDOSTOT + MEDIA + Asetit palvelimen käyttäjäoikeuslistan tähän huoneeseen. + %s asetti palvelimen käyttäjäoikeuslistan tähän huoneeseen. + Asetit huoneen pääosoitteeksi %1$s. + Lisäsit %1$s ja poistit %2$s huoneen osoitteista. + + Poistit %1$s huoneen osoitteista. + Poistitt %1$s huoneen osoitteista. + + + Lisäsit %1$s osoitteeksi tähän huoneeseen. + Lisäsit %1$s osoitteiksi tähän huoneeseen. + + Peruit %1$s:n kutsun. Syynä: %2$s + Viesti lähetetty + Ensimmäinen synkronointi: +\nLadataan tietoja… + Ensimmäinen synkronointi: +\nOdotetaan palvelimen vastausta… + + %1$s, %2$s, %3$s ja %4$d muu + %1$s, %2$s, %3$s ja %4$d muuta + + %1$s %2$s:sta %3$s:n + %1$s muutti käyttäjän %2$s oikeustasoa. + Muutit käyttäjän %1$s oikeustasoa. + Muutit huoneen palvelimien käyttäjäoikeuslistaa. + %s muutti huoneen palvelimien käyttäjäoikeuslistaa. + Linkitä tämä sähköpostiosoite tiliisi + Ääniviesti (%1$s) + Vastaaminen tai muokkaaminen ei ole mahdollista, kun ääniviesti on aktiivinen + Ääniviestiä ei voi äänittää + Tätä ääniviestiä ei voi toistaa + Napauta äänitystä pysäyttääksesi tai kuunnellaksesi + %1$d s jäljellä + Poista äänitys + Äänitetään ääniviestiä + Pysäytä äänitys + Keskeytä ääniviesti + Toista ääniviesti + Liu\'uta peruaksesi + Äänitä ääniviesti + Liittymisen yhteydessä tapahtui virhe: %s + Päivitä suositeltuun huoneversioon + Tarvitset oikeuden huoneen päivittämiseen + Kutsu käyttäjiä automaattisesti + Päivitä yksityinen huone + Päivitä julkinen huone + Päivitys vaaditaan + Päivitä + Odota hetki, tämä saattaa kestää jonkin aikaa. + Nimetön huone + Jotkin huoneet saattavat olla piilotettuja, koska ne ovat yksityisiä. Liittyäksesi tarvitset kutsun. + Jotkin huoneet saattavat olla piilotettuja, koska ne ovat yksityisiä. Liittyäksesi tarvitset kutsun. +\nSinulla ei ole oikeutta lisätä huoneita. + Tässä avaruudessa ei ole huoneita + Ole yhteydessä kotipalvelimesi ylläpitäjään saadaksesi lisätietoja + Vaikuttaa siltä, ettei kotipalvelimesi tue vielä avaruuksia + Onko olosi kokeellinen\? +\nVoit lisätä olemassa olevia avaruuksia avaruuteen. + Hallitse huoneita ja avaruuksia + Ehdotettu + Hallitse huoneita + %s kutsuu sinut + Sinut on kutsuttu + Avaruudet ovat uusi tapa ryhmitellä huoneita ja ihmisiä. + Lisää avaruus mihin tahansa hallitsemaasi avaruuteen. + Lisää olemassa olevia avaruuksia + Lisää olemassa olevia huoneita + Et voi liittyä uudelleen, ellei sinua kutsuta uudelleen. + Olet ainoa henkilö täällä. Jos poistut, kukaan ei voi liittyä tänne tulevaisuudessa, et edes sinä. + Haluatko varmasti poistua avaruudesta %s\? + Poistu + Lisää huoneita + Selaa huoneita + + %d tuntemasi henkilö on jo liittynyt + %d tuntemaasi henkilöä on jo liittynyt + + Liity silti + Liity avaruuteen + Luo avaruus + Ohita toistaiseksi + Liity avaruuteeni %1$s %2$s + He voivat selata avaruutta %s + Kutsu avaruuteen %s + Jaa linkki + Kutsu käyttäjänimellä tai sähköpostilla + Kutsu sähköpostitse + Kutsu avaruuteen %s + Kutsu ihmisiä + Kutsu ihmisiä avaruuteesi + Kuvaus + Luodaan avaruutta… + Satunnainen + Yleinen + Minkä asioiden parissa työskentelette\? + Anna sille nimi jatkaaksesi. + Lisää hieman tietoja, jotta ihmiset tunnistavat sen. Voit muuttaa näitä tietoja milloin tahansa. + Lisää hieman tietoja, jotta se erottuu muista. Voit muuttaa näitä tietoja milloin tahansa. + Luo avaruus + Yksityinen + Avoin kaikille, paras vaihtoehto yhteisöille + Julkinen + Yksityinen avaruus huoneiden järjestämiseen + Vain minä + Kenen kanssa työskentelet\? + Tarvitset kutsun liittyäksesi olemassa olevaan avaruuteen. + Voit muuttaa tämän myöhemmin + Minkä tyyppisen avaruuden haluat luoda\? + Yksityinen avaruutesi + Julkinen avaruutesi + Lisää avaruus + Yksityinen avaruus + Julkinen avaruus + Haluatko poistaa kaikki lähettämättömät viestit tästä huoneesta\? + Poista lähettämättömät viestit + Haluatko perua viestin lähettämisen\? + Poista kaikki epäonnistuneet viestit + Epäonnistui + Lähetetty + Lähetetään + Päivittää huoneen uuteen versioon + Luo avaruus + Viestin tyyppi puuttuu + Ei sisältöä + Muokkaa sisältöä + Kehittäjätyökalut + Julkinen huone + Näytä lukukuittaukset + Älä ilmoita + Ilmoita ilman ääntä + Ilmoita äänen kera + Viestiä ei lähetetty virheen vuoksi + Sulje emojivalitsin + Avaa emojivalitsin + Valittu + Video + Joitain viestejä ei ole lähetetty + Kuva + Tuo avain tiedostosta + Kuvakaappaus + Tunnistautuminen epäonnistui + ${app_name} vaatii tämän toimenpiteen suorittamiseksi, että annat kirjautumistietosi. + Tunnistautuminen uudelleen vaaditaan + Liu\'uta lopettaaksesi puhelun + Tuntematon henkilö + Käyttäjät + %1$s Napauta palataksesi + Aktiivinen puhelu (%1$s) · + + Aktiivinen puhelu · + %1$d aktiivista puhelua · + + Aktiivinen puhelu (%1$s) + Numeronäppäimistö + Ei vastausta + Vastaamaton videopuhelu + Vastaamaton äänipuhelu + Kieltäydytty videopuhelusta + Kieltäydytty äänipuhelusta + Videopuhelu päättyi • %1$s + Äänipuhelu päättyi • %1$s + Aktiivinen videopuhelu + Aktiivinen äänipuhelu + Saapuva videopuhelu + Saapuva äänipuhelu + Soita takaisin + Puhelu on päättynyt + %1$s kieltäytyi tästä puhelusta + Kieltäydyit tästä puhelusta + Tallentamattomia muutoksia. Hylätäänkö muutokset\? + Huonetta ei ole vielä luotu. Perutaanko huoneen luominen\? + Linkki oli muodostettu väärin + Tätä huonetta ei löydy. Varmista että se on olemassa. + Vaihda nykyinen PIN-koodisi + Vaihda PIN-koodi + PIN-koodi vaaditaan joka kerta, kun avaat sovelluksen ${app_name}. + PIN-koodi vaaditaan, kun sovellusta ${app_name} ei ole käytetty 2 minuuttiin. + Vaadi PIN-koodi 2 minuutin jälkeen + Näytä vain lukemattomien viestien määrä yksinkertaisessa ilmoituksessa. + Näytä tiedot kuten huoneiden nimet ja viestien sisältö. + Näytä sisältö ilmoituksissa + PIN-koodi on ainoa tapa avata sovelluksen ${app_name} lukitus. + Ota biometriikka käyttöön + Ota PIN-koodi käyttöön + Suojaa pääsy käyttäen PIN-koodia ja biometriikkaa. + Suojaa pääsy + Määritä suojaus + Uusi PIN-koodi + Nollaa PIN-koodi + Unohditko PIN-koodisi\? + Anna PIN-koodi + Vahvista PIN-koodi + Valitse PIN-koodi turvallisuuden parantamiseksi + Liian monta virhettä, sinut on kirjattu ulos + Varoitus! Viimeinen yrityskerta ennen uloskirjaamista! + + %d tietue + %d tietuetta + + + Väärä koodi, %d yritys jäljellä + Väärä koodi, %d yritystä jäljellä + + Katselmoi asetukset ottaaksesi push-ilmoitukset käyttöön + Push-ilmoitukset ovat pois käytöstä + Etsi yhteystietojasi Matrixista + LUE LISÄÄ + SELVÄ + Olemme iloisia uuden nimen lanseerauksesta! Sovelluksesi on ajan tasalla ja olet kirjautunut tilillesi. + Riot on nyt Element! + Muutit huoneen asetuksia onnistuneesti + Käynnistä kamera + Pysäytä kamera + Poista mikrofonin mykistys + Mykistä mikrofoni + Lähetä + Anna identiteettipalvelimen URL-osoite + Vaihtoehtoisesti voit kirjoittaa minkä tahansa muun identiteettipalvelimen URL-osoitteen + Käytä %1$s + Hyväksy ensin identiteettipalvelimen ehdot asetusten kautta. + Määritä ensin identiteettipalvelin. + Tämä toiminto ei ole mahdollinen. Kotipalvelin on vanhentunut. + Tämä identiteettipalvelin on vanhentunut. ${app_name} tukee vain API V2:ta. + Katkaistaanko yhteys identiteettipalvelimeen %s\? + Ladataan käytettävissä olevia kieliä… + Oma koodi + Käyttäjiä ei voitu kutsua. Tarkista käyttäjät, jotka haluat kutsua, ja yritä uudelleen. + Linkki %1$s vie sinut toiselle sivustolle: %2$s. +\n +\nHaluatko varmasti jatkaa\? + Valitse salasana. + Valitse käyttäjänimi. + Vahvista vuorovaikutteisesti emojilla + Vahvista kirjautuminen + Salattu vahvistamattomalla laitteella + Salaamaton + Käytä palautusavainta + Tuettu vain salatuissa huoneissa + Mediatiedostoa ei voitu tallentaa + Anna palautusavain + Ei kelvollinen palautusavain + Käytä tiedostoa + Salauksen päivitys saatavilla + Tämä tili on deaktivoitu. + Virheellinen käyttäjänimi ja/tai salasana. Annettu salasana alkaa tai päättyy välilyönnillä, tarkista salasana. + Avainten tuonti epäonnistui + Lisää aihe + Tämä on keskustelun alku. + Loit ja määritit huoneen. + %s loi ja määritti huoneen. + Tämän huoneen käyttämä salaus ei ole tuettu + Salaus ei käytössä + Viestit tässä huoneessa ovat päästä päähän -salattuja. + Viestit tässä huoneessa ovat päästä päähän -salattuja. Lue lisää ja vahvista käyttäjät heidän profiilissaan. + Salaus käytössä + Lähetä media alkuperäisessä koossa + + Lähetä video alkuperäisessä koossa + Lähetä videot alkuperäisessä koossa + + Lentokonetila on päällä + epävakaa + vakaa + Oletusversio + Huoneversiot 👓 + Raja ei ole tiedossa. + Kotipalvelimesi hyväksyy liitteitä (tiedostoja, mediaa jne.) joiden koko on enintään %s. + Palvelimen asettama tiedoston lähetysraja + Palvelimen versio + Palvelimen nimi + Sinulla ei ole oikeutta ottaa salausta käyttöön tässä huoneessa. + Viestit täällä ovat päästä päähän -salattuja. +\n +\nViestisi turvataan lukolla ja vain sinä sekä vastaanottaja omaatte avaimet, joilla salauksen voi purkaa. + Viestit täällä eivät ole päästä päähän -salattuja. + Skannaa tällä laitteella + Ääni + Luodaan avaruutta… + Jotkin merkit eivät ole sallittuja + Anna huoneen osoite + Tämä osoite on jo käytössä + Avaruuden osoite + Lisää ( ͡° ͜ʖ ͡°) tavalliseen viestiin + Jos et muista salasanaasi, palaa nollaamaan se. + Ei vaikuta kelvolliselta sähköpostiosoitteelta + Anna sen palvelimen osoite, jota haluat käyttää + Tyhjennä historia + %1$s asetti huoneen pääsyvaatimukseksi kutsun. + Asetit huoneen pääsyvaatimukseksi kutsun. + Teit huoneen julkiseksi kaikille, jotka tuntevat linkin. + Et tehnyt muutoksia + Huoneen asetukset + Tässä huoneessa ei ole tiedostoja + Tässä huoneessa ei ole mediaa + %1$d/%2$d + Kierrä ja rajaa + Tiedosto on liian suuri lähetettäväksi. + Vahvistuskoodi ei ole oikein. + Anna hyväksyntä + Kumoa antamani hyväksyntä + Pakataan videota %d%% + Pakataan kuvaa… + Anna palautetta + Palautteen lähetys epäonnistui (%s) + Kiitos, palautteesi on lähetetty onnistuneesti + Voitte olla yhteydessä minuun, jos teillä on lisäkysymyksiä + Palaute + Palaute avaruuksista + Tätä huonetta ei voi esikatsella. Haluatko liittyä siihen\? + Luo uusi avaruus + Palautusavain on tallennettu. + Näyttää tietoja käyttäjästä + Vaihtaa näyttönimesi vain nykyisessä huoneessa + Asettaa huoneen nimen + Lisää uusi palvelin + + %1$d/%2$d avain tuotu onnistuneesti. + %1$d/%2$d avainta tuotu onnistuneesti. + + Avaimet viety onnistuneesti + Huoneen versio + Päätä kuka voi löytää huoneen ja liittyä siihen. + Napauta muokataksesi avaruuksia + Valitse avaruudet + Avaruuden %s jäsenet voivat löytää, esikatsella ja liittyä. + Vain avaruuden jäsenet + Kuka tahansa voi löytää ja liittyä avaruuteen + Kuka tahansa voi löytää ja liittyä huoneeseen + Julkinen + Vain kutsutut henkilöt voivat löytää ja liittyä + Yksityinen (vain kutsulla) + Yksityinen + Julkaise tämä osoite + Lisää paikallinen osoite + Poistetaanko osoite \"%1$s\"\? + Julkaise + Muut julkaistut osoitteet: + Salli vieraiden liittyä + Avaruuden pääsy + Huoneen pääsy + Kenellä on pääsy\? + Tilin asetukset + Lisää painike viestin lähetysikkunaan emoji-näppäimistön avaamiseksi + Huonekutsut + Avainsanat + Salatut ryhmäviestit + Ryhmäviestit + Salatut suoraviestit + Suoraviestit + Käyttäjänimeni + Näyttönimeni + Ilmoitusta on napsautettu! + Avainsanat eivät voi sisältää \'%s\' + Avainsanat eivät voi alkaa merkillä \'.\' + Lisää uusi avainsana + Avainsanoistani + Ilmoita minulle + Muu + Maininnat ja avainsanat + Oletusilmoitukset + Lähetä sähköposti-ilmoituksia osoitteeseen %s + Jotta voit vastaanottaa sähköposti-ilmoituksia, sido sähköpostiosoite Matrix-tiliisi + Sähköposti-ilmoitus + Poistetaanko %s\? + Ei mitään + Vain maininnat ja avainsanat + Vaihda avaruuden nimeä + Ota avaruuden salaus käyttöön + Avaruuden käyttöoikeudet + Lopetetaan puhelu… + Ei vastausta + Käyttäjä, jolle soitit, on varattu. + Käyttäjä on varattu + Laitoit puhelun pitoon + %s laittoi puhelun pitoon + Pitoon + Palaa + Äänipuhelu henkilön %s kanssa + Videopuhelu henkilön %s kanssa + + Vastaamatta jäänyt videopuhelu + %d vastaamatta jäänyttä videopuhelua + + + Vastaamatta jäänyt puhelu + %d vastaamatta jäänyttä puhelua + + Puhelu soi… + SSL-virhe: vertaisen identiteettiä ei ole vahvistettu. + Tämä puhelinnumero on jo käytössä. + Käytä oletuksena, älä kysy uudelleen + Kysy aina + Kotipalvelimen rajapinnan URL-osoite + Avaruudet + Huonehakemisto + Ehdotetut huoneet + Uusi arvo + Puuttuvat oikeudet + Avaruudet + + Vähintään yksi vaihtoehto vaaditaan + Vähintään %1$s vaihtoehtoa vaaditaan + + Kysymys ei voi olla tyhjä + LUO KYSELY + LISÄÄ VAIHTOEHTO + Vaihtoehto %1$d + Luo vaihtoehdot + Kysymys tai aihe + Kyselyn kysymys tai aihe + Luo kysely + Määritä + Turvallinen varmuuskopio + Määritä turvallinen varmuuskopio + Turvallinen varmuuskopio + Palvelimesi + Tällä huoneella ei ole paikallisia osoitteita + Julkaise uusi osoite manuaalisesti + Avaruuden osoitteet + Huoneen osoitteet + Määritä tälle laitteelle + Nollaa turvallinen varmuuskopio + Määritä turvallinen varmuuskopio + Turvallinen varmuuskopio + Istunto on kirjattu ulos! + Lähetä m.room.server_acl-tapahtumia + Valitse kotipalvelin + Ei nyt + Palauta salaus + lähettää lumisadetta ❄️ + lähettää konfettia 🎉 + 🔐️ Liity seuraani ${app_name}-sovelluksessa + Hei, juttele minulle ${app_name}-sovelluksessa: %s + Kotipalvelimesi (%1$s) ehdottaa, että käytät palvelinta %2$s identiteettipalvelimenasi + Odotetaan salaushistoriaa + Sinulla ei ole pääsyä tähän viestiin, koska lähettäjä jätti avaimet tarkoituksella lähettämättä + Sinulla ei ole pääsyä tähän viestiin, koska lähettäjä ei luota istuntoosi + Sinulla ei ole pääsyä tähän viestiin, koska lähettäjä esti sinut + Ei saatavilla + Tapahtuma lähetetty! + Odotetaan tätä viestiä, tässä voi kestää jonkin aikaa + Sinulla ei ole pääsyä tähän viestiin + %1$s antoi porttikiellon + Äänestäjät näkevät tulokset heti äänestettyään + + Lopullinen tulos yhden äänen perusteella + Lopullinen tulos %1$d äänen perusteella + + + Yksi ääni annettu. Äänestä nähdäksesi tulokset + %1$d ääntä annettu. Äänestä nähdäksesi tulokset + + Ääniä ei annettu + + Perustuen yhteen ääneen + Perustuen %1$d ääneen + + + yksi ääni + %1$d ääntä + + Ääni annettu + Kartta + Sijainti + Jaa sijainti + Suljettu kysely + Avoin kysely + Kyselyn tyyppi + Muokkaa kyselyä + Poista kysely + Lähetä tarra + Lähetä kuvia ja videoita + Avaa kamera + Näytä viestikuplat + Kartan lataaminen epäonnistui + Luo kysely + Jaa sijainti + Näytä vähemmän + Läpisalattu, puhelinnumeroa ei vaadita. Ei mainoksia tai tiedonlouhintaa. + Valitse missä keskustelujasi säilytetään – sinä päätät ja olet riippumaton. Yhdistäjänä Matrix. + Sinä päätät. + Turvallista ja riippumatonta viestintää, joka on yhtä yksityistä kuin keskustelisit kasvokkain kotonasi. + Viestintää tiimillesi. + Turvallista viestintää. + Pidä keskustelusi hallussasi. + Yhdistä palvelimeen + Minulla on jo tili + Luo tili + ${app_name} ei voinut käyttää sijaintiasi. Yritä myöhemmin uudelleen. + ${app_name} ei voinut käyttää sijaintiasi + Haluatko varmasti poistaa tämän kyselyn\? Et voi palauttaa sitä poistamisen jälkeen. + Huomaa: sovellus käynnistetään uudelleen + Tapahtuman sisältö + Tapahtuman sisältö + Lähetä mukautettu tapahtuma + Oletusluottamustaso + Huonetta, johon olet saanut porttikiellon ei voi avata. + Noudetaan yhteystietojasi… + Lähettää viestin lumisateen kera + Lähettää viestin konfetin kera + ${app_name} iOS +\n${app_name} Android + Lähettää viestin pelkkänä tekstinä, tulkitsematta sitä markdowniksi + Ota yhteyttä ylläpitäjään salauksen palauttamiseksi kelvolliseen tilaan. + Lue koodi toisella laitteellasi tai vaihda ja lue tällä laitteella + Ei-luotettu kirjautuminen + Teit tästä kutsua edellyttävän. + Sijainti + Kysely + + %1$s, %2$s ja yksi muu lukivat + %1$s, %2$s ja %3$d muuta lukivat + + Hyväksytkö näiden tietojen lähettämisen\? + Versiot + Ohje ja tuki + Ohje + Huone on luotu, mutta joitakin kutsuja ei ole lähetetty seuraavasta syystä: +\n +\n%s + Tähän huoneeseen ei pääse tällä hetkellä. +\nYritä myöhemmin uudelleen tai kysy huoneen ylläpitäjältä onko sinulla pääsyä. + Näytä huoneessa + Tuntematon pääsyasetus (%s) + Aseta osoitteita tälle huoneelle, jotta käyttäjät voivat löytää tämän huoneen kotipalvelimesi (%1$s) kautta + Uusi julkaistu osoite (esim. #alias:palvelin) + Kuka hyvänsä millä hyvänsä palvelimella voi käyttää julkaistua osoitetta huoneeseesi liittymiseen. Osoitteen julkaisemiseksi se täytyy ensin asettaa paikalliseksi osoitteeksi. + Kolmansien osapuolten kirjastot + Voit poistaa tämän käytöstä koska tahansa asetuksista + Emme jaa tietoa kolmansien tahojen kanssa + Emme tallenna tai profiloi mitään tilin tietoja + Huoneesta on poistuttu! + Sinulla ei ole lupaa päivittää rooleja, jotka vaaditaan huoneen eri osien muuttamiseen + Valitse roolit, jotka vaaditaan huoneen eri osien muuttamiseen + Tarkastele ja päivitä rooleja, jotka vaaditaan huoneen eri osien muuttamiseen. + %1$s, %2$s ja muita + %1$s ja %2$s + Kotipalvelinta URL-osoitteesta %s ei tavoiteta. Tarkista linkki tai valitse kotipalvelin manuaalisesti. + Näytä huoneessa + Ota käyttöön + + Poistit tältä huoneelta vaihtoehtoisen osoitteen %1$s. + Poistit tältä huoneelta vaihtoehtoiset osoitteet %1$s. + + + %1$s poisti tältä huoneelta vaihtoehtoisen osoitteen %2$s. + %1$s poisti tältä huoneelta vaihtoehtoiset osoitteet %2$s. + + + Lisäsit tälle huoneelle vaihtoehtoisen osoitteen %1$s. + Lisäsit tälle huoneelle vaihtoehtoiset osoitteet %1$s. + + + %1$s lisäsi tälle huoneelle vaihtoehtoisen osoitteen %2$s. + %1$s lisäsi tälle huoneelle vaihtoehtoiset osoitteet %2$s. + + Sinulla ei ole lupaa liittyä tähän huoneeseen + Käyttäjät + + %1$d lisää + %1$d lisää + + Lähetä tiedosto + Pysäytä + Jaa tämä sijainti + Jaa tämä sijainti + Jaa nykyinen sijaintini + Jaa nykyinen sijaintini + Käynnistä sovellus uudelleen, jotta muutos tulee voimaan. + Lisää olemassa olevia huoneita ja avaruuksia + Käytä ${app_name}in uusinta versiota muilla laitteillasi: + Ohita tämä vaihe + Tallenna ja jatka + Asetukset on tallennettu. + Kaikki valmista! + Menoksi + Voit vaihtaa tämän milloin tahansa. + Lisää profiilikuva + Voit vaihtaa tämän myöhemmin + Näyttönimi + Valitse näyttönimi + Tilisi %s on luotu. + Onnittelut! + Personoi profiili + ohittaa tämän kysymyksen + Etkö ole vielä varma\? Voit %s + Identiteettipalvelin ei tarjoa käytäntöä + Piilota identiteettipalvelimen käytäntö + Näytä identiteettipalvelimen käytäntö + Valitettavasti ryhmäpuheluun liityttäessä ilmeni virhe + Tämä palvelin ei tarjoa mitään käytäntöä. + Identiteettipalvelimesi käytäntö + Kotipalvelimesi käytäntö + ${app_name}-käytäntö + Kopioi linkki ketjuun + Poista käytöstä + Järjestelmän asetukset + Apua ${app_name}in käyttöön + Lainopilliset asiat + tästä + Auta meitä tunnistamaan mahdollisia ongelmia ja parantamaan ${app_name}iä jakamalla anonyymia käyttödataa. Ymmärtääksemme miten ihmiset käyttävät useita laitteita, luomme satunnaisen tunnisteen, joka jaetaan kaikkien laitteidesi kesken. +\n +\nLue käyttöehdot %s. + Auta parantamaan ${app_name}iä + Jokin seuraavista voi olla vaarantunut: +\n +\n- Salasanasi +\n- Kotipalvelimesi +\n- Tämä laite tai vastapuolen laite +\n- Jomman kumman laitteen käyttämä internet-yhteys +\n +\nSuosittelemme, että vaihdat salasanasi ja palautusavaimesi välittömästi asetuksista. + Ei vielä muita julkaistuja osoitteita. + Yhteydetön tila + Läsnäolo + Varmista, että olet napsauttanut linkkiä saamassasi sähköpostissa. + Lopeta näytön jako + Jaa näyttö + Lue lisää + Kokeile + t + s + min + Muutit tämän huoneen osoitteita. + %1$s muutti tämän huoneen osoitteita. + Muutit tämän huoneen pää- ja vaihtoehtoisia osoitteita. + %1$s muutti tämän huoneen pää- ja vaihtoehtoisia osoitteita. + Muutit tämän huoneen vaihtoehtoisia osoitteita. + %1$s muutti tämän huoneen vaihtoehtoisia osoitteita. + Alkusynkronointipyyntö + Poista tämän osoitteen julkaisu + Vahvistamaton + Parhaan turvallisuuden takaamiseksi kirjaudu ulos istunnoista, joita et tunnista tai et enää käytä. + Vahvistetu + Suodata + + Käyttämättä vuorokauden tai pidempään + Käyttämättä %1$d vuorokautta tai pidempään + + Käyttämätön + Ei valmis turvallista viestintää varten + Vahvistamaton + Valmis turvallista viestintää varten + Vahvistettu + Kaikki istunnot + Suodata + Viimeisin toiminta %1$s + Laite + Istunto + Nykyinen istunto + Käyttämättä olevat istunnot + Vahvista nämä istunnot tai kirjaudu niistä ulos. + Vahvistamattomat istunnot + Paranna tilisi turvallisuutta noudattamalla näitä suosituksia. + Turvallisuussuositukset + + Käyttämättä %1$d+ päivän (%2$s) + Käyttämättä %1$d+ päivää (%2$s) + + Vahvistamaton · Nykyinen istuntosi + Vahvistamaton · Viimeisin toiminta %1$s + Vahvistettu · Viimeisin toiminta %1$s + Näytä kaikki (%1$d) + Näytä tiedot + Vahvista istunto + Tuntematon vahvistuksen tila + Vahvistamaton istunto + Vahvistettu istunto + Tuntematon laitetyyppi + Työpöytä + Mobiili + Turvallisuuden vuoksi vahvista istunnot ja kirjaudu ulos niistä istunnoista, joita et tunnista tai et enää käytä. + Muut istunnot + + %d viesti poistettu + %d viestiä poistettu + + Käytä sijainnin jakamista + Tällä hetkellä käytössä %s. + Menetelmä + + Yksi menetelmä löytyi. + %d menetelmää löytyi. + + Saatavilla olevat menetelmät + Ilmoitusmenetelmä + Taustasynkronointi + Valitse miten ilmoitukset vastaanotetaan + Näytönjako on päällä + ${app_name}-näytönjako + Huoneilmoitus + Ilmoita koko huoneelle + Jaa sijainti + Päivitetty %1$s sitten + %1$s jäljellä + Avaa sovelluksella + 8 tuntia + 1 tunti + 15 minuuttia + Tulokset näytetään vain kun lopetat kyselyn + Kysely lopetettu + Lopeta kysely + Lopetetaanko tämä kysely\? + Tulokset tulevat näkyviin kun kysely lopetetaan + Lopeta kysely + (%1$s) + %1$s (%2$s) + Ei voi toistaa %1$s + Keskeytä %1$s + Toista %1$s + %1$d minuuttia %2$d sekuntia + Tuloksia ei löydy + Avaa asetukset + Incognito-näppäimistö + Istunnot + Tätä linkkiä ei voi avata: yhteisöt on korvattu avaruuksilla + Skannaa QR-koodi + Käyttäjänimi / sähköposti / puhelin + Olethan ihminen\? + Seuraa sähköpostiosoitteeseen %s lähetettyjä ohjeita + Salasanan nollaus + Unohtunut salasana + Lähetä sähköposti uudelleen + Etkö saanut sähköpostia\? + Seuraa sähköpostiosoitteeseen %s lähetettyjä ohjeita + Vahvista sähköpostiosoitteesi + Lähetä koodi uudelleen + Koodi lähetettiin numeroon %s + Vahvista puhelinnumerosi + Kirjaudu ulos kaikilta laitteilta + Nollaa salasana + Vähintään kahdeksan merkkiä. + Valitse uusi salasana + Uusi salasana + Tarkista sähköpostisi. + %s lähettää sinulle vahvistuslinkin + Vahvistuskoodi + Puhelinnumero + %s haluaa vahvistaa tilisi + Anna puhelinnumerosi + Sähköpostiosoite + %s haluaa vahvistaa tilisi + Anna sähköpostiosoitteesi + Lue palvelimen %s käyttöehdot + Palvelimen käytännöt + Haluatko ylläpitää omaa palvelinta\? + Palvelimen verkko-osoite + Mikä on palvelimesi osoite\? + Mikä on palvelimesi osoite\? Se on kuin koti kaikille tiedoillesi + Valitse palvelin + Tervetuloa takaisin! + Muokkaa + Vähintään kahdeksan merkkiä + Luo tili + Vie minut kotiin + Aikeissa liittyä olemassa olevalle palvelimelle\? + Yhteisöt + Tiimit + Kaverit ja perhe + Avaa avaruusluettelo + Luo uusi keskustelu tai huone + Anna palautetta + Käytössä: + Istunnon ID: + Katselet jo tätä ketjua! + Päivitetään tietojasi… + Jokin meni vikaan. Tarkista verkkoyhteys ja yritä uudelleen. + Ihmiset + Suosikit + Lukemattomat + Kaikki + Käytä järjestelmän oletusta + Valitse itse + Aseta automaattisesti + Valitse fontin koko + Myönnä oikeus + + %1$s ja %2$d muu + %1$s ja %2$d muuta + + %1$s ja %2$s + Pidä keskustelut organisoituna ketjujen avulla + Omat ketjut + Kaikki ketjut + Muuta avaruuden pääosoitetta + Täällä näkyvät uudet pyynnöt ja kutsut. + Ei mitään uutta. + Kutsut + Avaruudet ovat uusi tapa ryhmitellä huoneita ja ihmisiä. Luo avaruus aloittaaksesi. + Ei avaruuksia vielä. + Selvä + Seuraava + Näytä ketjut + Käytä avaruuksia (oikealla alhaalla) nopeammin ja helpommin kuin koskaan aiemmin. + Käytä avaruuksia + Selaa huoneita + Vaihda avaruutta + Luo huone + Aloita keskustelu + Kaikki keskustelut + Kokeile + Anna palautetta napauttamalla oikeaa yläkulmaa. + Anna palautetta + ${app_name}in yksinkertaistaminen asetti välilehdet valinnaiseksi. Hallitse välilehtiä oikean yläkulman valikosta. + Tervetuloa uuteen näkymään! + Yksinkertaistettu Element valinnaisilla välilehdillä + Ota uusi asettelu käyttöön + A - Ö + Aktiivisuus + Järjestysperuste + Näytä viimeisimmät + Näytä suodattimet + Asettelun asetukset + %s +\nvaikuttaa hieman tyhjältä. + Ketkä ovat tiimikavereitasi\? + Yksityinen avaruus sinulle ja tiimikavereillesi + Minä ja tiimikaverit + Päivitä avaruus + Vaihda avaruuden kuva + + %1$d valittu + %1$d valittu + + Puskuroidaan… + Ääniviestiä ei voi aloittaa + Tässä huoneessa on käytössä huoneversio %s, jonka tämä kotipalvelin on merkinnyt epävakaaksi. + Älä poistu mistään + Poistu kaikista + Poista profiilikuva + Vaihda profiilikuva + Puhelinnumeron haussa tapahtui virhe + + Kutsut lähetetty käyttäjälle %1$s ja yhdelle muulle + Kutsut lähetetty käyttäjälle %1$s ja %2$d muulle + + Kutsu lähetetty käyttäjille %1$s ja %2$s + Kutsu lähetetty käyttäjälle %1$s + Kutsu %s keskusteluun lähettämällä ensimmäinen viesti + Tästä alkaa yksityisviestihistoriasi sinun ja käyttäjän %s välillä. + %s alkaa tästä. + Salaus on säädetty väärin + Salaus on säädetty väärin. + Tällä kotipalvelimella on vanha versio. Pyydä kotipalvelimesi ylläpitäjää päivittämään se. Voit jatkaa, mutta jotkin ominaisuudet eivät välttämättä toimi oikein. + Ota yhteyttä + Jatka %s-kirjautumisella + tai + Keskustelujesi koti + Keskustelujesi koti + Laitetaan yhteydet kuntoon + Kenen kanssa juttelet eniten\? + ${app_name} toimii mainiosti työpaikallakin. Siihen luottavat maailman turvallisimmat organisaatiot. + Poistutaanko nykyisestä ryhmäpuhelusta ja vaihdetaan toiseen\? + Tämä palvelin on jo luettelossa + Tätä palvelinta tai sen huoneluetteloa ei löydy + Kuka vain voi koputtaa huoneeseen ja jäsenet voivat sen jälkeen hyväksyä tai hylätä + Poista osoitteen \"%1$s\" julkaiseminen\? + Huomaa, että maininnat ja avainsanailmoitukset eivät ole käytössä salausta käyttävissä huoneissa mobiililaitteilla. + Ota suora jako käyttöön + Toista aikajanalla olevat animoidut kuvat heti, kun ne näkyvät + Toista animoidut kuvat automaattisesti + Et saa ilmoituksia maininnoista ja avainsanoista salausta käyttävissä huoneissa mobiililaitteilla. + Huonepäivitykset + Botin lähettämät viestit + ${app_name} tarvitsee luvan ilmoitusten näyttämiseen. +\nAnna lupa. + Päivitä huone + Ota lykätyt yksityisviestit käyttöön + Poista valinta kaikista + Valitse kaikki + Anna mikrofonin käyttöoikeus ääniviestien lähettämiseksi. + Anna kameran käyttöoikeus järjestelmän asetuksista tämän toiminnon suorittamiseksi. + Tämän toiminnon suorittaminen vaatii enemmän oikeuksia. Anna oikeudet järjestelmän asetuksista. + Kuunnellaan ilmoituksia + Lukemattomat viestisi näkyvät tässä sitten kun saat niitä. + Ei ilmoitettavaa. + Kirjaudu QR-koodilla + Huomaa, että istuntojen nimet näkyvät ihmisille, joiden kanssa viestit. + Istunnon nimi + IP-osoite + Käyttöjärjestelmä + Malli + Selain + URL-osoite + Versio + Nimi + Istunnon nimi + Kirjaudu ulos tästä istunnosta + Piilota IP-osoite + Näytä IP-osoite + Kirjaudu ulos kaikista muista istunnoista + + Kirjaudu ulos yhdestä istunnosta + Kirjaudu ulos %1$d istunnosta + + Kirjaudu ulos + + Harkitse vanhoista (yksi vuorokausi tai vanhemmista), käyttämättömistä istunnoista uloskirjautumista. + Harkitse vanhoista (%1$d vuorokautta tai vanhemmista), käyttämättömistä istunnoista uloskirjautumista. + + + Harkitse vanhoista (yksi vuorokausi tai vanhemmista), käyttämättömistä istunnoista uloskirjautumista. + Harkitse vanhoista (%1$d vuorokautta tai vanhemmista), käyttämättömistä istunnoista uloskirjautumista. + + Tämä istunto on valmiina turvalliseen viestintään. + Nykyinen istuntosi on valmina turvalliseen viestintään. + Kamera + Sijainti + Kyselyt + Liitteet + Tarrat + Karttaa ei voida ladata +\nTätä kotipalvelinta ei välttämättä ole säädetty näyttämään karttoja. + Virhe kyselyjä noudettaessa. + Lataa lisää kyselyjä + + Viime vuorokaudelta ei ole menneitä kyselyjä. +\nLataa lisää kyselyjä nähdäksesi aiempien päivien kyselyt. + Viimeisiltä %1$d vuorokaudelta ei ole menneitä kyselyjä. +\nLataa lisää kyselyjä nähdäksesi aiempien päivien kyselyt. + + Tässä huoneessa ei ole menneitä kyselyjä + Menneet kyselyt + + Ei kyselyjä viimeisen vuorokauden ajalta. +\nLataa lisää kyselyjä nähdäksesi aiempien päivien kyselyt. + Ei kyselyjä viimeisen %1$d vuorokauden ajalta. +\nLataa lisää kyselyjä nähdäksesi aiempien päivien kyselyt. + + Tässä huoneessa ei ole aktiivisia kyselyjä + Aktiiviset kyselyt + Salauksen purkamisvirheistä johtuen joitakin ääniä ei ehkä lasketa + Tämä estää ihmisiä äänestämästä ja näyttää kyselyn lopulliset tulokset. + Ota LaTeX-matematiikka käyttöön + %1$s jäljellä + Äänitä pitämällä painettuna, lähetä päästämällä + Huoneen päivittäminen on edistynyt toiminto, jota yleensä suositellaan, kun huone on epävakaa virheistä, puuttuvista ominaisuuksita tai tietoturvahaavoittuvuuksista johtuen. +\nSe vaikuttaa yleensä vain siihen, miten huonetta käsitellään palvelimella. + Merkitse ei-ehdotetuksi + Merkitse ehdotetuksi + Viestien lähettäminen epäonnistui + Varattu + Virhe puhelua siirrettäessä + Yhdistä + Kumoa kutsu + Kotipalvelin ei hyväksy pelkistä numeroista koostuvaa käyttäjänimeä. + Viesti huoneessa + Viesti huoneessa %s + Viesti + Viesti käyttäjältä %s + Kysely + päätti kyselyn. + loi kyselyn. + lähetti tarran. + lähetti videon. + lähetti kuvan. + lähetti ääniviestin. + lähetti äänitiedoston. + lähetti tiedoston. + Muokkaa linkkiä + Luo linkki + Linkki + Teksti + Koko näytön tila päälle/pois + Koodilohko päälle/pois + Lainaus päälle/pois + Aseta linkki + Käytä alleviivaus-muotoilua + Käytä yliviivaus-muotoilua + Käytä kursivointi-muotoilua + Käytä lihavointi-muotoilua + Varmista, että tiedät tämän koodin alkuperän. Laitteet linkittämällä annat täyden pääsyn tiliisi. + Vahvista + Yritä uudelleen + Kirjaudutaan + Yhdistetään laitteeseen + Avaa sovellus toisella laitteellasi + Kotipalvelin ei tue QR-koodilla kirjautumista. + QR-koodi on virheellinen. + Toisen laitteen on oltava kirjattu sisään. + Toinen laite on jo kirjattu sisään. + Pyyntö epäonnistui. + Yhteyden muodostaminen ei onnistunut + Turvallinen yhteys muodostettu + Kirjaudu QR-koodilla + Monikäyttöinen ja turvallinen viestisovellus tiimeille, kavereille ja organisaatioille. Aloita luomalla keskustelu tai liittymällä olemassa olevaan huoneeseen. + ${app_name} toivottaa sinut tervetulleeksi, +\n%s. + Sovellus + Muuta menetelmää kuin taustasynkronointi ei löytynyt. + Tekstin muotoilu + Zoomaa nykyiseen sijaintiin + Näytä kysely aikajanalla + Kelaa 30 sekuntia eteenpäin + Kelaa 30 sekuntia taaksepäin + Osa tuloksista voi olla piilotettu, koska ne ovat yksityisiä ja vaativat kutsun. + Vain kutsulla, paras vaihtoehto itsellesi tai tiimeille + Luotettu-luottamustaso + Varoitus-luottamustaso + Palautusavaimen tallennuspaikka: + %s, jotta ihmiset tietävät, mistä huoneessa on kyse. + Odotetaan käyttäjien liittymistä sovellukseen ${app_name} + Kyselyhistoria + kertakirjautuminen + Kirjaudu käyttäen palvelua %s + Rekisteröidy käyttäen palvelua %s + Olet antanut suostumuksen sähköpostiosoitteiden ja puhelinnumeroiden lähettämiseen identiteettipalvelimelle yhteystiedoissasi olevien käyttäjien löytämiseksi. + Sähköposti lähetettiin osoitteeseen %s, tarkista sähköpostisi ja napsauta vahvistuslinkkiä + Siirry + Suojaudu salattuihin viesteihin ja tietoihin pääsyn menettämiseltä varmuuskopioimalla salausavaimesi palvelimellesi. + Suojaudu salattuihin viesteihin ja tietoihin pääsyn menettämiseltä varmuuskopioimalla salausavaimesi palvelimellesi. + Suojaudu salattuihin viesteihin ja tietoihin pääsyn menettämiseltä + Käyttäjän %1$s profiilikuva + Avaa kehittäjätyökalujen ruutu + Tili + Kryptografian versio + Ilmoitusasetusten päivittämisessä tapahtui virhe. Yritä uudelleen. + Salaus on määritetty virheellisesti, joten et voi lähettää viestejä. Avaa asetukset napsauttamalla. + Salaus on määritetty virheellisesti, joten et voi lähettää viestejä. Ota yhteyttä ylläpitäjään salauksen palauttamiseksi toimintakuntoon. + ${app_name} tarvitsee luvan ilmoitusten näyttämiseen. Ilmoituksia voi saada viesteistä, kutsuista ym. +\n +\nAnna käyttöoikeus seuraavissa ponnahdusikkunoissa, jotta näet ilmoituksia. + %1$s vaihtoi näyttänimekseen %2$s + \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-fr/strings.xml b/library/ui-strings/src/main/res/values-fr/strings.xml index 91efbce467..e5e71dd4a5 100644 --- a/library/ui-strings/src/main/res/values-fr/strings.xml +++ b/library/ui-strings/src/main/res/values-fr/strings.xml @@ -1287,7 +1287,8 @@ On y est presque ! Est-ce que %s affiche une marque cochée \? Oui Non - La connexion avec le serveur a été perdue + La connexion à ${app_name} n’est pas disponible +\npour le moment. Nom d’utilisateur Outils de développement Données du compte @@ -2950,4 +2951,13 @@ Politique d’utilisation acceptable Version de cryptographie Faire la réinitialisation + %1$s a modifié son nom d’affichage en %2$s + Image de profile de l’utilisateur %1$s + Avatar du salon %1$s + Avatar de l’espace %1$s + La messagerie sécurisée a été améliorée avec la dernière mise-à-jour. Veuillez re-vérifier votre appareil. + Jusqu’à ce que cet utilisateur fasse confiance à cette session, les messages sur cette session sont étiquetés avec des avertissements. + Application mise-à-jour + Se déconnecter malgré tout + Impossible de joindre le serveur d’accueil. Si vous vous déconnectez malgré tout, cet appareil ne sera pas effacé de la liste de vos appareils, vous pourrez l’enlever en utilisant un autre client. diff --git a/library/ui-strings/src/main/res/values-fr/strings_tchap.xml b/library/ui-strings/src/main/res/values-fr/strings_tchap.xml index 79b5af159c..90f507a50f 100644 --- a/library/ui-strings/src/main/res/values-fr/strings_tchap.xml +++ b/library/ui-strings/src/main/res/values-fr/strings_tchap.xml @@ -112,4 +112,7 @@ La vérification de votre nouvelle session a échoué. + + + Voir l’état du service diff --git a/library/ui-strings/src/main/res/values-in/strings.xml b/library/ui-strings/src/main/res/values-in/strings.xml index c32cf40e85..c584ca793a 100644 --- a/library/ui-strings/src/main/res/values-in/strings.xml +++ b/library/ui-strings/src/main/res/values-in/strings.xml @@ -2891,4 +2891,13 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan. Kebijakan Penggunaan Wajar Versi kripto Lanjutkan mengatur ulang + %1$s mengubah nama tampilannya ke %2$s + Foto profil pengguna %1$s + Avatar ruangan %1$s + Avatar space %1$s + Perpesanan aman telah ditingkatkan dengan pembaruan terkini. Silakan verifikasi ulang perangkat Anda. + Sampai pengguna ini mempercayai sesi ini, pesan yang dikirim dan diterima akan ditandai dengan peringatan. + Aplikasi diperbarui + Tidak dapat mencapai homeserver. Jika Anda tetap keluar, perangkat ini tidak akan dihapus dari daftar perangkat. Anda dapat menghapusnya menggunakan klien lain. + Tetap keluar \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-it/strings.xml b/library/ui-strings/src/main/res/values-it/strings.xml index 54ad5f5dd9..8a12dc5ca4 100644 --- a/library/ui-strings/src/main/res/values-it/strings.xml +++ b/library/ui-strings/src/main/res/values-it/strings.xml @@ -2,9 +2,9 @@ Invito di %s %1$s ha invitato %2$s - %1$s ti ha invitato - %1$s è entrato nella stanza - %1$s è uscito dalla stanza + %1$s ti ha invitato/a + %1$s è entrato/a nella stanza + %1$s è uscito/a dalla stanza %1$s ha rifiutato l\'invito %1$s ha buttato fuori %2$s %1$s ha rimosso il ban nei confronti di %2$s @@ -60,8 +60,8 @@ Invito di %1$s. Motivo: %2$s %1$s ha invitato %2$s. Motivo: %3$s %1$s ti ha invitato. Motivo: %2$s - %1$s è entrato nella stanza. Motivo: %2$s - %1$s è uscito dalla stanza. Motivo: %2$s + %1$s è entrato/a nella stanza. Motivo: %2$s + %1$s è uscito/a dalla stanza. Motivo: %2$s %1$s ha rifiutato l\'invito. Motivo: %2$s %1$s ha cacciato fuori %2$s. Motivo: %3$s %1$s ha riammesso %2$s. Motivo: %3$s @@ -87,8 +87,8 @@ Il tuo invito Hai creato la stanza Hai invitato %1$s - Sei entrato nella stanza - Sei uscito dalla stanza + Sei entrato/a nella stanza + Sei uscito/a dalla stanza Hai rifiutato l\'invito Hai buttato fuori %1$s Hai rimosso il ban nei confronti di %1$s @@ -133,8 +133,8 @@ %1$s da %2$s a %3$s Il tuo invito. Motivo: %1$s Hai invitato %1$s. Motivo: %2$s - Sei entrato nella stanza. Motivo: %1$s - Sei uscito dalla stanza. Motivo: %1$s + Sei entrato/a nella stanza. Motivo: %1$s + Sei uscito/a dalla stanza. Motivo: %1$s Hai rifiutato l\'invito. Motivo: %1$s Hai cacciato %1$s. Motivo: %2$s Hai riammesso %1$s. Motivo: %2$s @@ -160,10 +160,10 @@ %1$s ha impedito l\'accesso alla stanza agli ospiti. Hai permesso l\'accesso agli ospiti. %1$s ha permesso l\'accesso agli ospiti. - Sei entrato. Motivo: %1$s - Sei uscito. Motivo: %1$s - %1$s è uscito. Motivo: %2$s - %1$s è entrato. Motivo: %2$s + Sei entrato/a. Motivo: %1$s + Sei uscito/a. Motivo: %1$s + %1$s è uscito/a. Motivo: %2$s + %1$s è entrato/a. Motivo: %2$s Hai revocato l\'invito a %1$s %1$s ha revocato l\'invito a %2$s Hai invitato %1$s @@ -172,10 +172,10 @@ %s ha aggiornato la stanza. Hai reso visibili i messaggi futuri a %1$s %1$s ha reso visibili i messaggi futuri a %2$s - Sei uscito dalla stanza - %1$s è uscito dalla stanza - Sei entrato - %1$s è entrato + Sei uscito/a dalla stanza + %1$s è uscito/a dalla stanza + Sei entrato/a + %1$s è entrato/a Hai creato la discussione %1$s ha creato la discussione Stanza vuota (era %s) @@ -528,7 +528,7 @@ Crea Home Stanze - Invitato + Invitato/a %2$s ti ha buttato fuori da %1$s %2$s ti ha bannato da %1$s Motivo: %1$s @@ -677,7 +677,7 @@ ${app_name} non è influenzato dall\'ottimizzazione della batteria. Se si lascia un dispositivo scollegato, fermo e con lo schermo spento, dopo un certo tempo questo entra in modalità Doze. Ciò impedisce alle App di accedere alla rete e ritarda le attività, le sincronizzazioni e la ricezione dei normali allarmi. Ignora l\'ottimizzazione - Nessun APK Google Play Services trovato. Le notifiche non funzioneranno bene. + Google Play Services non trovato. Le notifiche non funzioneranno bene. Chiamata video in corso… Backup delle chiavi Usa il Backup delle chiavi @@ -851,7 +851,7 @@ Rispondi Riprova Ti ha inviato un invito - Invitato da %s + Invitato/a da %s Non hai più messaggi non letti Conversazioni Le tue conversazioni dirette verranno mostrate qui. Tocca il pulsante + in basso a destra per iniziarne qualcuna. @@ -1451,7 +1451,7 @@ MEDIA In questa stanza non ci sono file multimediali FILE - %1$s alle %2$s + %1$s: %2$s In questa stanza non ci sono file Accedi con il tuo ID utente Accedi con il tuo ID utente @@ -1684,7 +1684,7 @@ Fallo solo se non hai altri dispositivi con cui fare la verifica. Reimposta tutto Hai dimenticato o perso tutte le opzioni di ripristino\? Reimposta tutto - Sei entrato. + Sei entrato/a. I messaggi in questa conversazione sono cifrati end-to-end. Esci Impostazioni @@ -1716,7 +1716,7 @@ Il codice PIN è richiesto ogni volta che apri ${app_name}. Il codice PIN è richiesto dopo 2 minuti di inattività su ${app_name}. Richiedi il PIN dopo 2 minuti - %s è entrato. + %s è entrato/a. L\'applicazione è in attesa del PUSH Scarta le modifiche Ci sono modifiche non salvate. Scartare le modifiche\? @@ -1932,7 +1932,7 @@ Sincronizzazione iniziale: \nIn attesa di risposta dal server… Messaggio inviato - Sei stato invitato + Sei stato/a invitato/a Gli Spazi sono un nuovo modo per raggruppare stanze e contatti. Aggiungi stanze e Spazi esistenti Esci @@ -2008,7 +2008,7 @@ Consigliato Gestisci stanze Cerchi qualcuno che non è in %s\? - %s ti ha invitato + %s ti ha invitato/a Stanza pubblica Invia i file multimediali nella dimensione originale @@ -2287,7 +2287,7 @@ Questo server non presenta alcuna informativa. Librerie di terze parti L\'informativa del tuo server d\'identità - L\'informativa del tuo homeserver + Informativa del tuo homeserver Informativa di ${app_name} Puoi disattivarlo in qualsiasi momento nelle impostazioni Non condividiamo informazioni con terze parti @@ -2940,4 +2940,13 @@ Politica di utilizzo accettabile Procedi con la reimpostazione Versione crittografia + %1$s ha cambiato il nome visualizzato in %2$s + La messaggistica sicura è stata migliorata con l\'aggiornamento più recente. Ri-verifica il tuo dispositivo. + Finché l\'utente si fida di questa sessione, i messaggi inviati da e verso essa sono contrassegnati da avvisi. + App aggiornata + Immagine del profilo dell\'utente %1$s + Avatar della stanza %1$s + Avatar dello spazio %1$s + Disconnetti comunque + Impossibile contattare l\'homeserver. Se ti disconnetti comunque, questo dispositivo non verrà cancellato dalla tua lista, meglio se lo rimuovi da un altro client. \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-lv/strings.xml b/library/ui-strings/src/main/res/values-lv/strings.xml new file mode 100644 index 0000000000..4d7cb09b96 --- /dev/null +++ b/library/ui-strings/src/main/res/values-lv/strings.xml @@ -0,0 +1,2506 @@ + + + Uzaicinājums no %s + %1$s uzaicināja %2$s + %1$s uzaicināja Tevi + %1$s pievienojās + %1$s pameta istabu + %1$s noraidīja uzaicinājumu + %1$s padzina %2$s + %1$s atcēla pieejas liegumu %2$s + %1$s liedza pieeju %2$s + %1$s atsauca %2$s uzaicinājumu + %1$s nomainīja avataru + %1$s uzstādīja parādāmo vārdu uz %2$s + %1$s nomainīja parādāmo vārdu no %2$s uz %3$s + %1$s dzēsa savu parādāmo vārdu (iepriekš %2$s) + %1$s nomainīja tematu uz %2$s + %1$s nomainīja istabas nosaukumu uz %2$s + %s veica video zvanu. + %s veica audio zvanu. + %s atbildēja uz zvanu. + %s beidza zvanu. + %1$s padarīja istabas turpmāko ziņu vēsturi redzamu %2$s + visi istabas biedri no brīža, kad tika uzaicināti. + visi istabas biedri no brīža, kad tika pievienojušies. + visi istabas biedri. + ikviens. + (arī avatars tika nomainīts) + %1$s dzēsa istabas nosaukumu + %1$s izdzēsa istabas tematu + %1$s nosūtīja %2$s uzaicinājumu pievienoties istabai + %1$s pieņēma uzaicinājumu %2$s + ** Neizdodas atšifrēt: %s ** + Sūtītāja ierīce mums nav nenosūtījusi atslēgas priekš šīs ziņas. + Neizdodas nosūtīt ziņu + Matrix kļūda + Epasta adrese + Telefona numurs + Uzaicinājums uz istabu + %1$s un %2$s + Tukša istaba + Tu nomainīji savu parādāmo vārdu no %1$s uz %2$s + Tu nomainīji savu parādāmo vārdu uz %1$s + Tu nomainīji savu iemiesojumu + Tu atsauci %1$s uzaicinājumu + Tu liedzi pieeju %1$s + Tu atcēli pieejas liegumu %1$s + Tu noņēmi %1$s + Tu noraidīji uzaicinājumu + Tu pameti istabu + %1$s pameta istabu + Tu pameti istabu + Tu pievienojies + %1$s pievienojās istabai + Tu pievienojies istabai + Tu uzaicināji %1$s + Tu izveidoji apspriedi + %1$s izveidoja diskusiju + Tu izveidoji istabu + %1$s izveidoja istabu + Tavs uzaicinājums + Ir ieslēgta pilnīga šifrēšana (neatpazīts algoritms %1$s). + %1$s ieslēdza pilnīgu šifrēšanu (neatpazīts algoritms %2$s). + Tu ieslēdzi pilnīgu šifrēšanu. + %1$s ieslēdza pilnīgu šifrēšanu. + Tu esi novērsis iespēju viesiem pievienoties istabai. + %1$s ir novērsis iespēju viesiem pievienoties istabai. + Tu esi novērsis iespēju viesiem pievienoties istabai. + %1$s ir novērsis iespēju viesiem pievienoties istabai. + Tu esi atļāvis viesiem pievienoties šeit. + %1$s ir atļāvis viesiem pievienoties istabai. + Tu esi atļāvis viesiem pievienoties istabai. + %1$s ir atļāvis viesiem pievienoties istabai. + Tu nomainīji šīs istabas adreses. + %1$s nomainīja adreses šai istabai. + Tu nomainīji šīs istabas galveno un izvēles adreses. + %1$s nomainīja galveno un alternatīvās adreses šai istabai. + Tu nomainīji šīs istabas izvēles adreses. + %1$s nomainīja alternatīvās adreses šai istabai. + + Tu noņēmi šīs istabas izvēles adresi %1$s. + Tu noņēmi šīs istabas izvēles adresi %1$s. + Tu noņēmi šīs istabas izvēles adreses %1$s. + + + %1$s izdzēsa šīs istabas alternatīvo adresi %2$s. + %1$s izdzēsa šīs istabas alternatīvās adreses %2$s. + %1$s izdzēsa šīs istabas alternatīvās adreses %2$s. + + + Tu pievienoji šīs istabas izvēles adresi %1$s. + Tu pievienoji šīs istabas izvēles adresi %1$s. + Tu pievienoji šīs istabas izvēles adreses %1$s. + + + %1$s pievienoja šīs istabas alternatīvo adresi %2$s. + %1$s pievienoja šīs istabas alternatīvās adreses %2$s. + %1$s pievienoja šīs istabas alternatīvās adreses %2$s. + + Tu noņēmi šīs istabas galveno adresi. + %1$s izdzēsa šis istabas galveno adresi. + Tu iestatīji %1$s kā šis istabas galveno adresi. + %1$s iestatīja %2$s kā šis istabas galveno adresi. + Tu pievienoji %1$s un noņēmi %2$s kā šīs istabas adreses. + %1$s pievienoja %2$s un izdzēsa %3$s kā šīs istabas adreses. + + Tu noņēmi %1$s kā šīs istabas adresi. + Tu noņēmi %1$s kā šīs istabas adresi. + Tu noņēmi %1$s kā šīs istabas adreses. + + + %1$s izdzēsa %2$s kā šīs istabas adresi. + %1$s izdzēsa %2$s kā šīs istabas adreses. + %1$s izdzēsa %2$s kā šīs istabas adreses. + + + Tu pievienoji %1$s kā šīs istabas adresi. + Tu pievienoji %1$s kā šīs istabas adresi. + Tu pievienoji %1$s kā šīs istabas adreses. + + + %1$s pievienoja %2$s kā šīs istabas adresi. + %1$s pievienoja %2$s kā šis istabas adreses. + %1$s pievienoja %2$s kā šīs istabas adreses. + + Tu atsauci %1$s uzaicinājumu. Iemesls: %2$s + %1$s atsauca uzaicinājumu %2$s. Iemesls: %3$s + Tu pieņēmi uzaicinājumu %1$s. Iemesls: %2$s + %1$s pieņēma uzaicinājumu %2$s. Iemesls: %3$s + Tu liedzi pieeju %1$s. Iemesls: %2$s + %1$s liedza pieeju %2$s. Iemesls: %3$s + Tu atcēli pieejas liegumu %1$s. Iemesls: %2$s + %1$s atcēla %2$s pieejas liegumu. Iemesls: %3$s + Tu noņēmi %1$s. Iemesls: %2$s + %1$s padzina %2$s. Iemesls: %3$s + Tu noraidīji uzaicinājumu. Iemesls: %1$s + %1$s noraidīja uzaicinājumu. Iemesls: %2$s + Tu pameti. Iemesls: %1$s + %1$s izgāja. Iemels: %2$s + Tu pameti istabu. Iemesls: %1$s + %1$s pameta istabu. Iemesls: %2$s + Tu pievienojies. Iemesls: %1$s + %1$s pievienojās. Iemesls: %2$s + Tu pievienojies istabai. Iemesls: %1$s + %1$s pievienojās istabai. Iemesls: %2$s + %1$s uzaicināja Tevi. Iemesls: %2$s + Tu uzaicināji %1$s. Iemesls: %2$s + %1$s uzaicināja %2$s. Iemesls: %3$s + Tavs uzaicinājums. Iemesls: %1$s + %1$s uzaicinājums. Iemesls: %2$s + Sūta ziņu… + Sākotnējā sinhronizācija: +\nImportē konta datus + Sākotnējā sinhronizācija: +\nIegūst pamestās istabas + Sākotnējā sinhronizācija: +\nIegūst istabas, uz kurām uzaicināts + Sākotnējā sinhronizācija: +\nIelādē sarunas +\nJa ir dalība daudzās istabās, tas var aizņemt kādu laiku + Sākotnējā sinhronizācija: +\nIegūst istabas + Sākotnējā sinhronizācija: +\nImportē kriptogrāfiju + Sākotnējā sinhronizācija: +\nImportē kontu… + Tukša istaba (bija %s) + + %1$s, %2$s, %3$s un %4$d citi + %1$s, %2$s, %3$s un %4$d cits + %1$s, %2$s, %3$s un %4$d citi + + %1$s, %2$s, %3$s un %4$s + %1$s, %2$s un %3$s + %1$s no %2$s uz %3$s + %1$s nomainīja %2$s pieejas līmeni. + Tu nomainīji %1$s pieejas līmeni. + Pielāgots + Pielāgots (%1$d) + Noklusējuma + Moderators + Administrators + Tu apstiprināji uzaicinājumu %1$s + Tu atsauci uzaicinājumu %1$s + %1$s atsauca uzaicinājumu %2$s + Tu atsauci uzaicinājumu %1$s pievienoties istabai + %1$s atsauca uzaicinājumu %2$s pievienoties istabai + Tu uzaicināji %1$s + %1$s uzaicināja %2$s + Tu nosūtīji %1$s uzaicinājumu pievienoties istabai + Tu izdzēsi istabas iemiesojumu + %1$s izdzēsa istabas avataru + Tu noņēmi istabas tematu + Tu noņēmi istabas nosaukumu + Tu padarīji turpmākās ziņas redzamas %1$s + %1$s padarīja turpmākās ziņas redzamas %2$s + Tu padarīji istabas turpmāko ziņu vēsturi redzamu %1$s + Tu beidzi zvanu. + Tu atbildēji uz zvanu. + Tu nosūtīji datus zvana uzsākšanai. + %s nosūtīja datus zvana uzsākšanai. + Tu veici balss zvanu. + Tu veici video zvanu. + Tu nomainīji istabas nosaukumu uz %1$s + Tu nomainīji istabas iemiesojumu + %1$s nomainīja istabas avataru + Tu nomainīji tematu uz %1$s + Tu noņēmi savu parādāmo vārdu (tas bija %1$s) + Iestatījumi + Labi + Atcelt + Saglabāt + Pamest + Nosūtīt + Citēt + Dalīties + Vēlāk + Iekšējā saite + Skatīt pirmkodu + Skatīt atšifrētu pirmkodu + Izdzēst + Pārdēvēt + Ziņot par saturu + vai + Uzaicināt + Izrakstīties + Balss zvans + Video zvans + Atzīmēt visas ziņas, kā lasītas + Ātrā atbilde + Atvērt + Aizvērt + Nokopēts starpliktuvē + Apstiprinājums + Brīdinājums + Izlase + Cilvēki + Istabas + Filtrēt istabu nosaukumus + Uzaicinājumi + Zema prioritāte + Sarunas + Vienīgi Matrix kontakti + Nav rezultātu + Istabas + Nosūtīt logfailus + Nosūtīt sistēmas avārijas logfailus + Nosūtīt ekrānattēlu + Ziņot par kļūdu + Lūdzu apraksti kļūdu. Kāda darbība tika veikta? Kāds bija gaidāmais rezultāts? Kas tieši notika? + Aprakstiet savu problēmu šeit + Lai diagnosticētu problēmu, logfaili no šīs lietotnes tiks nosūtīti kopā ar šo kļūdas paziņojumu. Ja vēlies nosūtīt vienīgi augstākminēto tekstu, lūdzu noņem: + Šķiet, ka tālrunis tiek kratīts neapmierinātības dēļ. Vai atvērt kļūdu ziņojumu skatu\? + Šī programma iepriekš \"salūza\". Vai vēlies iesniegt paziņojumu par kļūdu? + Paziņojums par kļūdu tika veiksmīgi nosūtīts + Paziņojumu par kļūdu neizdevās nosūtīt (%s) + Progress (%s%%) + Pievienoties istabai + Lietotājvārds + Izrakstīties + Mājasservera URL + Meklēt + Sākt audio zvanu + Sākt video zvanu + Sūtīt failus + Uzņemt foto vai video + Pierakstīties + Iesniegt + Gaiša tēma + Tumša tēma + Melna tēma + Uztver notikumus + Skaņas paziņojumi + Klusi paziņojumi + Kļūdas atskaite + Ielādējas… + Tiešām vēlies uzsākt balss zvanu\? + Tiešām vēlies uzsākt video zvanu\? + Uzņemt foto + Uzņemt video + Nepareizs lietotājvārds un/vai parole + Šķiet ievadīta nederīga epasta adrese + Šī epasta adrese jau tiek izmantota. + Aizmirsāt paroli\? + Mājasserveris vēlas pārliecināties, ka neesi robots + Neizdevās verificēt epasta adresi: pārbaudiet, vai esi noklikšķinājis(usi) uz saiti atsūtītajā epastā + Ievadi korektu URL adresi + Bojāts JSON + Nav derīgs JSON + Nosūtīti par daudz pieprasījumi + Sākotnējais + Lielu + Vidēju + Mazu + Zvans + Tiek veidots savienojums… + Zvans beigts + Ienākošs VIDEO zvans + Ienākošs AUDIO zvans + Notiek zvans… + Adresāts neatbildēja uz zvanu. + Element informācija + ${app_name}-am nepieciešama atļauja piekļūt mikrofonam, lai nodrošinātu audio zvanus. + ${app_name} nepieciešama atļauja piekļūt kamerai un mikrofonam, lai veiktu videozvanus. +\n +\nLūdzu, dodiet piekļuves atļauju nākamajā uznirstošajā logā, lai būtu iespēja veikt zvanus. + + + Turpināt + Dzēst + Pievienoties + Noraidīt + Pāriet uz pirmo neizlasīto ziņu + Pamest istabu + Vai tiešām pamest istabu\? + Tiešās ziņas + Uzaicināt + Nobanot + Atbanot + Ignorēt + Atcelt ignorēšanu + Pieminēt + Tu nevarēsi atdarīt šo izmaiņu, jo Tu paaugstini lietotāju līdz tādam pašam spēka līmenim kā Tev pašam. +\nEsi pārliecināts\? + Liedzot pieeju lietotājam, šī darbība izmetīs viņu no šīs istabas un neļaus pievienoties atkārtoti. + %s raksta… + %1$s & %2$s raksta… + %1$s & %2$s & citi raksta… + Tev nav tiesību rakstīt ziņas šajā istabā. + Uzticēties + Neuzticēties + Izrakstīties + Ignorēt + Nospiedums (%s): + Neizdevās pārbaudīt attālinātā servera identitāti. + Tas var nozīmēt, ka kāds ļaunprātīgi pārtver Tavu trafiku, vai ka Tava ierīce neuzticas sertifikātam, ar kuru apgādāts attālinātais serveris. + Ja servera administrators ir teicis, ka tas ir gaidāms, pārliecinieties, ka zemāk redzamais nospiedums (fingerprint) sakrīt ar nospiedumu, kuru piestādījis administrators. + Servera sertifikāts ir izmanījies un Tava ierīce tam tagad neuzticas. Tas ir ĻOTI NEPARASTI. Iesakām NEUZTICĒTIES šim jaunajam sertifikātam. + Sertifikāts izmainījās no iepriekš uzticama uz neuzticamu. Iespējams, serveris ir aktualizējis savu sertifikātu. Sazinies ar servera administratoru, lai saņemtu sagaidāmo nospiedumu (fingerprint). + Akceptē sertifikātu TIKAI tad, kad servera administrators publicējis sertifikāta nospiedumu, kurš atbilst augstāk redzamajam. + Meklēšana + Istabas dalībnieku filtrs + Rezultātu nav + Visas ziņas + Pievienot sākumekrānam + Profila attēls + Attēlojamais vārds + Pievienot epasta adresi + Pievienot tālruņa numuru + Rādīt lietotnes informāciju sistēmas iestatījumos. + Lietotnes informācija + Paziņojumu skaņa + Iespējot šim kontam paziņojumus + Iespējot šai ierīcei paziņojumus + Ziņas, kuras satur manu rādāmo vārdu + Ziņas, kuras satur manu lietotājvārdu + Ziņas tiešajās tērzēšanās + Ziņas grupu tērzēšanās + Uzaicinājumi uz istabām + Uzaicinājumi ar zvanu + Ziņas no bota + Startēt pie ierīces ielādes + Sinhronizācija + Sinhronizācijas pieprasījuma noildze + Intervāls starp sinhronizācijām + Versija + olm versija + Lietošanas noteikumi + Trešo pušu paziņojumi + Autortiesības + Privātuma politika + Iztīrīt kešatmiņu + Iztīrīt mediju kešatmiņu + Turēt mēdiju (?) + Lietotāja iestatījumi + Paziņojumi + Ignorētie dalībnieki + Citi + Papildu + Kriptogrāfija + Paziņojumus nosūtīt uz + Lokālie kontakti + Piekļuve kontaktiem + Kontaktu valsts + Galvenais ekrāns + Piespraust istabas ar izlaistiem paziņojumiem + Piespraust istabas ar neizlasītām ziņām + Iespējot URL priekšskatu pēc noklusējuma + Vienmēr rādīt ziņu laiku + Rādīt ziņu laiku 12 stundu formātā (piem. 12:12pm) + Vibrācija, kad pieminējums + Analītika + ID + Vārds + Ierīces nosaukums + Pēdējo reizi manīts + %1$s @ %2$s + Autentifikācija + Pierakstījies kā + Mājasserveris + Identitāšu serveris + Lietotāja saskarne + Saskarnes valoda + Izvēlies valodu + Pārbaudi savu epastu un noklikšķini uz epasata sūtījumā esošās tīmekļa saites. Kad tas paveikts, klikšķini uz \"turpināt\". + Šī epasta adrese sistēmā tiek jau lietota. + Šis tālruņa numurs sistēmā tiek jau lietots. + Nomainīt paroli + Pašreizējā parole + Jaunā parole + Paroles nomaiņas kļūda + Parole nomainīta + Rādīt visas ziņas no %s\? + Izvēlies valsti + 3 dienas + 1 nedēļa + 1 mēnesis + Pastāvīgi + Temats + Piekļuve istabas vēsturei + Kas var lasīt vēsturi? + Jebkurš + Tikai dalībnieki (no šīs iespējas izvēlēšanās brīža) + Tikai dalībnieki (kopš tie tika uzaicināti) + Tikai dalībnieki (kopš tie pievienojušies) + Lietotāji, kuriem liegta pieeja + Papildu + Šīs istabas iekšējais ID + Izmēģinājumu lauciņš + Šīs ir eksperimentālas funkcijas, kuras var radīt pārsteidzošus rezultātus! Lietot ar piesardzību. + Ņipri papurināt ierīci, lai paziņotu par kļūdu + + %d biedru izmaiņu + %d biedru izmaiņa + %d biedru izmaiņas + + Biedru katalogs + + %d biedri + %d biedrs + %d biedri + + + %d jaunu ziņu + %d jauna ziņa + %d jaunas ziņas + + Iestatīt kā galveno adresi + Atiestatīt kā galveno adresi + Tēma + Atšifrēšanas kļūda + Ierīces nosaukums + Sesijas ID + Sesijas atslēga + Eksportēt istabas šifrēšanas atslēgas + Eksportēt istabas atslēgas + Eksportēt atslēgas vietējā failā + Eksportēt + Ievadīt paroles vārdkopu + Apstiprināt paroles vārdkopu + Importēt E2E istabas atslēgas + Importēt istabas atslēgas + Importēt atslēgas no vietējā faila + Importēt + Šifrēt vienīgi uz pārbaudītām ierīcēm + Nekad nesūtīt šifrētas ziņas uz nepārbaudītām ierīcēm no šīs ierīces. + Neverificēta + Verificēta + Verificēt + Apstipriniet, salīdzinot sekojošo ar lietotāja iestatījumiem citā savā sesijā: + Ja tā sakrīt, nospied zemāk esošo verifikācijas pogu. Ja tā nesakrīt, tad kāds ir pārtvēris šo ierīci un Tu droši vien vēlies šo ierīci pievienot melnajam sarakstam. +Nākotnē šī pārbaudes procedūra plānota sarežģītāka. + Izvēlies istabu katalogu + Mājasservera nosaukums + Visas servera %s istabas + Visas vietējās %s istabas + + %d paziņojumu par nelasītām ziņām + %d paziņojums par nelasītām ziņām + %d paziņojumi par nelasītām ziņām + + + %d istabu + %d istabas + %d istabu + + %1$s iekš %2$s + Burtu izmērs + Sīks + Mazs + Normāls + Liels + Lielāks + Lielākais + Milzīgs + Vai tiešām izdzēst logrīku šajā istabā\? + + %d aktīvs vidžets + %d aktīvi vidžeti + %d aktīvu vidžetu + + Neizdevās uzstādīt vidžetu. + Neizdevās nosūtīt pieprasījumu. + Pieejas līmenim jābūt lielākam par 0. + Tu neesi šīs istabas iemītnieks (biedrs). + Tev nepietiek tiesību to darīt šajā istabā. + Pieprasījumā iztrūkst room_id. + Pieprasījumā iztrūkst user_id. + Istaba %s ir neredzama. + Pievienot Matrix lietotnes + Lietot iebūvēto kameru + Tu pievienoji jaunu ierīci \'%s\', kura pieprasa šifrēšanas atslēgas. + Tava neverificētā ierīce \'%s\' pieprasa šifrēšanas atslēgas. + Sākt tās verifikāciju + Komandas kļūda + Nepazīstama komanda: %s + Izslēgts + Ar skaņu + Šifrēta ziņa + Izveidot + Sākums + Istabas + Uzaicināts + %2$s noņēma Tevi no %1$s + %2$s liedza jums pieeju %1$s + Iemesls: %1$s + Avatars + Kontaktu grāmata + Temats + Istabas nosaukums + Drošības vārdkopa + Iestatīt drošības vārdkopu + Saglabājiet savu drošības atslēgu + Nodrošinieties pret piekļuves zaudēšanu šifrētām ziņām un datiem, dublējot šifrēšanas atslēgas savā serverī. + Iesniegt + Uzaicināt draugus + Uzaicināt lietotājus + Apstipriniet savu identitāti, verificējot šo pierakstīšanos no kādas citas savas sesijas, tādējādi ļaujot piekļūt šifrētajām ziņām. + Manuāli verificēt ar tekstu + Nešifrēts + vai kādu citu Matrix lietotni ar cross-signing atbalstu + Šis konts ir deaktivizēts. + Šifrētas ziņas grupas tērzēšanās + Šifrētas ziņas tiešajās tērzēšanās + Ziņas, kuras satur @room + Šifrēšana nav iespējota + Ziņas šajā tērzēšanā ir nodrošinātas ar pilnīgu šifrēšanu. + Šifrēšana iespējota + Jauna pieteikšanās. Tas biji Tu\? + Vai tiešām noņemt (izdzēst) šo notikumu\? Jāņem vērā, ka, ja tika izdzēsts istabas nosaukums vai mainīts temats, tas var atdarīt izmaiņas. + Apstipriniet dzēšanu + + + QR kods + Neuzticama + Uzticama + Sesijas + Neizdevās iegūt sesijas + Brīdinājums + Verificēta + Apstiprināt + Verificējiet šo sesiju + Servera pārvaldītājs uzstādījis pilnīgas šifrēšanas atspējošanu privātās istabās un tiešajās ziņās kā noklusējumu. + Jaunā sesija tagad ir apliecināta. Tai ir piekļuve šifrētajām ziņām, un citi lietotāji redzēs to kā uzticamu. + Saziņa ar šo lietotāju ir pilnībā šifrēta un trešās puses to nevar nolasīt. + Iespējot šifrēšanu\? + Iespējot pilnīgu šifrēšanu… + Pārstāt ignorēt + Pāriet uz pēdējo skatīto ziņu + Tiešā ziņa + Lietotāji + Uzaicinājumi + Pamet istabu… + Pamest + Pamest istabu + Augšupielādes + Paziņojumi + Iestatījumi + Istabas iestatījumi + Administratora darības + Vairāk + Uzzināt vairāk + Drošība + Ziņas šeit ir nodrošinātas ar pilnīgu šifrēšanu. +\n +\nZiņas tiek nodrošinātas ar slēdzenēm, un tikai sūtītājam un saņēmējam ir neatkārtojamas atslēgas, lai tās atslēgtu. + Ziņas šeit ir nodrošinātas ar pilnīgu šifrēšanu. +\n +\nZiņas tiek nodrošinātas ar slēdzenēm, un tikai sūtītājam un saņēmējam ir neatkārtojamas atslēgas, lai tās atslēgtu. + Ziņas šeit nav nodrošinātas ar pilnīgu šifrēšanu. + Ziņām šajā istabā netiek piemērota pilnīga šifrēšana. + Tu apstiprināji + Fails + Audio + Attēls. + Video. + Lūdzu, ievadiet istabas adresi + Šī adrese jau tiek izmantota + Šo varētu iespējot, ja istaba tiks izmantota tikai sadarbībai ar mājasservera iekšējām komandām. Vēlāk to nevar mainīt. + Slēpt papildu iestatījumus + Rādīt papildu iestatījumus + Šifrēšana nevar tikt atspējota, ja reiz tikusi iespējota. + Iestatījumi + Dzēst personas datus + Parole + Pierakstīties + Pierakstīties + Matrix ID + Brīdinājums + Šāds lietotājvārds jau ir aizņemts + Tālāk + Parole + Lietotājvārds + Lietotājvārds vai epasts + Reģistrēties uz %1$s + Tālruņa numurs šķietami ir nepareizs. Lūdzu pārbaudiet to + Starptautiskajiem tālruņu numuriem jāsākas ar “+” + Lūdzu, izmantojiet starptautisko formātu (tālruņa numuram jāsākas ar “+”) + Tālāk + Nosūtīt atkārtoti + Ievadīt kodu + Mēs tikko nosūtījām kodu uz %1$s. Tas ir jāievada zemāk, lai apstiprinātu, ka tas esi Tu. + Apstipriniet tālruņa numuru + Tālāk + Tālruņa numurs (izvēles) + Tālruņa numurs + Epasts + Brīdinājums + Atgriezties uz pierakstīšanos + Tu esi izrakstījies no visām sesijām un vairs nesaņemsi pašpiegādes paziņojumus. Lai atkārtoti iespējotu paziņojumus, vēlreiz jāpiesakās katrā ierīcē. + Parole tika atiestatīta. + Esmu verificējis(usi) savu epasta adresi + Turpināt + Paroles mainīšana atiestatīs visas pilnīgas šifrēšanas atslēgas visās sesijās, padarot šifrēto tērzēšanu vēsturi nelasāmu. Pirms paroles atiestatīšanas jāuzstāda atslēgu dublēšana vai jāizgūst istabu atslēgas no citas sesijas. + Uzmanību! + Jauna parole + Epasts + Tālāk + Apliecinājuma e-pasta ziņojums tiks nosūtīts uz Tavu iesūtni, lai apstiprinātu paroles nomaiņu. + Pierakstīties + Reģistrēties + Turpināt + Cits + Iestatījumi + Izslēgt skaņu + Tikai pieminējumi + Visas ziņas + Visas ziņas (ar skaņu) + Iemesls ziņojumam par šo saturu + FAILI + Kamera + Kods + Zināmie lietotāji + Gaida… + Tiešās ziņas + Ieteikumu neizdevās nosūtīt (%s) + Paldies, ieteikums ir veiksmīgi nosūtīts + Aprakstiet savu ieteikumu šeit + Lūdzu, rakstiet savu ieteikumu zemāk. + Ieteikumi + Palīdzība un par lietotni + Drošība un konfidencialitāte + Vispārīgi + Publiska + Istabas iestatījumi + Temats + Istabas temats (izvēles) + Nosaukums + Istabas nosaukums + IZVEIDOT + Tiešās ziņas + Istabas + Šo istabu nevar priekšskatīt + Ziņa ir dzēsta + Reaģēšana + Reaģēšana + Istabas + Sarunas + Atbildēt + Labot + Sapratu + Verificēts! + Algoritms + Versija + Droša rezerves kopija + Vai tiešām to vēlaties\? + Dalīties + Gatavs + sakļaut + izvērst + Deaktivizēt kontu + Deaktivizēt kontu + Nomaina Tavu attēlojamo segvārdu + Padzen lietotāju ar norādīto id + Pamest istabu + Uzaicina lietotāju ar norādīto id uz pašreizējo istabu + Atceļ operatora statusu lietotājam ar norādīto Id + Definē lietotāja statusu + Liedz pieeju lietotājam ar norādīto id + Parāda darbību + Nerādīt nevienu šī dalībnieka ziņu + Dalīties + Tavs attēlojamais vārds + Istaba + Šai istabai nav lokālās adreses + Lokālās adreses + Jauna publiska adrese (piemēram, #alias:server) + Citas publiskotās adreses: + Publiskotas adreses ikviens var izmantot jebkurā serverī, lai pievienotos Tavai istabai. Lai publiskotu adresi, tai vispirms jābūt iestatītai kā vietējai adresei. + Publiskotās adreses + Izmaiņas attiecībā uz to, kas var lasīt vēsturi, attieksies tikai uz nākamajiem ziņojumiem šajā telpā. Esošās vēstures redzamība nemainīsies. + Parole + Integrācijas ir atspējotas + Sūtīt analītikas datus + Deaktivizēt kontu + Nodrošinieties pret piekļuves zaudēšanu šifrētām ziņām un datiem, dublējot šifrēšanas atslēgas savā serverī. + Iestatīt drošu rezerves dublēšanu + Droša rezerves kopija + Sūtīt paziņojumus par rakstīšanu + Startēt pie ierīces ielādes + Iespējot + Iespējot + Dzēst %s\? + Tālruņa numuri + Kontam nav pievienota neviena e-pasta adrese + Epasta adreses + Kontam nav pievienots neviens tālruņa numurs + Mainīt tematu + Mainīt atļaujas + Nomainīt istabas nosaukumu + Mainīt vēstures redzamību + Iespējot istabas šifrēšanu + Mainīt istabas galveno adresi + Mainīt istabas avataru + Apziņot visus + Dzēst citu sūtītas ziņas + Liegt pieeju lietotājiem + Padzīt lietotājus + Mainīt iestatījumus + Uzaicināt lietotājus + Sūtīt ziņas + Noklusējuma loma + Izvēlēties lomas, kuras nepieciešamas, lai mainītu atsevišķas istabas daļas + Atļaujas + Istabas atļaujas + Atcelt uzaicinājumu + Atcelt lietotāja ignorēšanu + Ignorēt lietotāju + Tu nevarēsi atdarīt šo izmaiņu, jo Tu pazemini sevi. Ja esi pēdējais istabas lietotājs ar paaugstinātām tiesībām, būs neiespējami tās atgūt. + Noņemt no tērzēšanas + Atcelt uzaicinājumu + Šī istaba nav publiska. Tai nebūs iespējams atkārtoti pievienoties bez uzaicinājuma. + Atļaujiet piekļuvi savām kontaktpersonām. + Lai skenētu QR kodu, jums jāatļauj piekļuve kamerai. + Notiek video zvans… + Pierakstieties, izmantojot vienoto pierakstīšanos + Atpakaļ + Tālrunis + Sūtīt balsi + Ja iespējams, lūdzu, rakstiet aprakstu angļu valodā. + Vairāk nekādu rezultātu nav + Paziņojumi + Izdevās + Kļūda + Pievienot + Kopēt + Atzīmēt kā izlasītu + Vai tiešām vēlies izrakstīties\? + Noraidīt + Pieņemt + Noraidīt + Nerādīt nevienu šī dalībnieka ziņu + Gatavs + Izlaist + Pieņemt + Jums nav atļaujas sākt konferences zvanu šajā istabā + Atiestatīt + Aizvērt + Atskaņot + Atvienoties + Atsaukt + Nav + Lejupielādēt + Vai tiešām to vēlaties\? + Sistēmas noklusējuma + Pielāgots (%1$d) iekš %2$s + %1$s noklusējums + %1$s moderators + %1$s administrators + Pielāgots + Moderators + Administrators + nepazīstama ip + + %d lietotājs, kuram liegta pieeja + %d lietotāji, kuriem liegta pieeja + %d lietotāji, kuriem liegta pieeja + + + %d sekunde + %d sekundes + %d sekundes + + Šī sesija ir uzticama drošai ziņojumapmaiņai, jo %1$s (%2$s) to verificēja: + Jāapliecina šī sesija, lai atzīmētu to kā uzticamu un piešķirtu piekļuvi šifrētām ziņām. Ja netika veikta pieteikšanās šajā sesijā, konts varētu būt iesaistīts drošības pārkāpumā: + Šī sesija ir uzticama drošai ziņapmaiņai, jo Tu to apliecināji: + Izrakstīties no šīs sesijas + Pārvaldīt sesijas + Parādīt visas sesijas + Aktīvās sesijas + Salīdziniet kodu ar to, kas parādīts otra lietotāja ekrānā. + Salīdziniet unikālās emocijzīmes, pārliecinoties tās ir vienādā secībā. + Lai būtu droši, dariet to klātienē vai izmantojiet citu komunikācijas veidu. + Lai būtu droši, verificējiet %s ar vienreizēja koda palīdzību. + Verifikācijas slēdziens + Aptauja + Uzlīme + Kaut kam no uzskaitītā var būt ietekmēta drošība: +\n +\n - mājasserveris +\n - majassserveris, kuram pieslēdzies apliecināmais lietotājs +\n - Tavs vai otra lietotāja interneta pieslēgums +\n - Tava vai otra lietotāja ierīce + Nav droša + Tie nesakrīt + Tie sakrīt + Neuzticama pieteikšanās + Izveido istabu… + Dažas rakstzīmes nav atļautas + Rāda tikai pirmos rezultātus, ierakstiet vairāk burtus… + Citas sesijas + Pašreizējā sesija + Papildu iestatījumi + matrix.to saite ir nepareizi veidota + Dzēst datus + Dzēst visus datus + Vai + Nelasītas ziņas + Tu padarīji šo pieejamu tikai ar ielūgumiem. + %1$s padarīja šo pieejamu tikai ar ielūgumiem. + Tu padarīji istabu pieejamu tikai ar ielūgumiem. + %1$s padarīja istabu pieejamu tikai ar ielūgumiem. + Tu padarīji istabu publiski pieejamu ikvienam, kas zina saiti. + %1$s padarīja istabu publiski pieejamu visiem, kas zina saiti. + Nav vērā neņemtu lietotāju + Ignorēt lietotāju + ZIŅOT + Ziņot par šo saturu + Pielāgots ziņojums… + Nepiemērots saturs + Tas ir spams + Šajā istabā nav neviena faila + %1$d no %2$d + %s izlasīja + %1$s un %2$s izlasīja + %1$s, %2$s un %3$s izlasīja + Sūtīt pielikumu + Piekrītiet identitāšu servera (%s) pakalpojumu sniegšanas noteikumiem, lai padarītu sevi atrodamu citiem, izmantojot epasta adresi vai tālruņa numuru. + Verifikācijas kods nav pareizs. + Teksta ziņojums ir nosūtīts uz %s. Lūdzu, verifikācijas kodu no ziņojuma. + Neizdevās pieslēgties identitāšu serverim + Konfigurēt identitāšu serveri + Atvienot identitāšu serveri + Identitāšu serveris + Ieteikumi + Izveido istabu… + Pievienot ar QR kodu + Saite nokopēta starpliktuvē + (labots) + Fails %1$s ir lejupielādēts! + Sūta failu (%1$s / %2$s) + Šifrē failu… + Sūta sīktēlu (%1$s / %2$s) + Šifrē sīktēlu… + Balss un video + Preferences + Tu jau apskati šo istabu! + Citi trešo pušu paziņojumi + Matrix SDK versija + Šīs istabas priekšskatījums nav pieejams. Vai vēlaties tai pievienoties\? + Šī istaba šobrīd nav pieejama. +\nMēģiniet vēlreiz vēlāk vai lūdziet istabas administratoru pārbaudīt, vai jums ir piekļuve. + Lūdzu, gaidiet… + Mainīt + Jums vairs nav nelasītu ziņu + Nosūtīja jums uzaicinājumu + %s vēlas apliecināt Tavu sesiju + Verifikācijas pieprasījums + Nodrošinieties pret piekļuves zaudēšanu šifrētām ziņām un datiem + Neparedzēta kļūda + Izveidot paroles vārdkopu + %d+ + %1$s: %2$s + Atvainotie, notikusi kļūda + Nospiediet šeit, lai redzētu vecākas ziņas + Šī istabas ir citas sarakstes turpinājums + Sarakste turpinās šeit + Šī istaba ir aizvietota un vairs nav aktīva. + Pārskatīt tagad + Lai turpinātu izmantot mājasserveri %1$s, ir jāpārskata un jāpiekrīt noteikumiem un nosacījumiem. + Kluss + Neverificēta sesija pieprasa šifrēšanas atslēgas. +\nSesijas nosaukums: %1$s +\nRedzēta pēdējo reizi: %2$s +\nJa neesat pierakstījies citā sesijā, ignorējiet šo pieprasījumu. + Jauna sesija pieprasa šifrēšanas atslēgas. +\nSesijas nosaukums: %1$s +\nRedzēta pēdējo reizi: %2$s +\nJa neesat pierakstījies citā sesijā, ignorējiet šo pieprasījumu. + Lai turpinātu, jums ir jāpieņem šī pakalpojuma noteikumi. + Pārvaldīt integrācijas + Iztrūks obligāts parametrs. + %1$s: %2$s %3$s + %1$s: %2$s + ** Neizdevās nosūtīt - lūgums atvērt istabu + Es + Jauns uzaicinājums + Jaunas ziņas + Jauns notikums + %1$s un %2$s + %1$s iekš %2$s un %3$s + Atslēgas ir veiksmīgi eksportētas + Lūgums izveidot paroles vārdkopu izsgūstamo atslēgu šifrēšanai. Būs jaievada tā pati paroles vārdkopa, lai varētu ievietot atslēgas. + Istabas versija + Pievienot lokālo adresi + Iestati šīs istabas adreses, lai lietotāji var atrast šo istabu caur Tavu mājasserveri (%1$s) + Izdzēst adresi \"%1$s\"\? + Skatiet un pārvaldiet šīs istabas adreses un tās redzamību istabu katalogā. + Istabas adreses + Atskaņot aizvara skaņu + Izvēlēties + Izvēlēties + Noklusējuma kompresija + Lai to izdarītu, iespējojiet ‘Atļaut integrācijas’ iestatījumos. + Priekšskatīt saites tērzēšanā, ja mājasserveris atbalsta šo iespēju. + Integrācijas + Atvērt iestatījumus + Atjaunināt istabu + Sūtīt m.room.server_acl notikumus + Jums nav atļaujas atjaunināt lomas, kas nepieciešamas, lai mainītu dažādas istabas daļas + Skatiet un atjauniniet lomas, kas nepieciešamas, lai mainītu dažādas istabas daļas. + Atceļot pieejas liegumu, lietotājam atkal būs iespēja pievienoties istabai. + Atcelt pieejas liegumu lietotājam + Pieejas lieguma iemesls + Liegt pieeju lietotājam + lietotāja padzīšanas gadījumā tas tiks dzēsts no šis istabas. +\n +\nLai novērstu atkārtotu pievienošanos, tā vietā jums vajadzētu liegt pieeju. + Padzīšanas iemesls + Padzīt lietotāju + Vai tiešām vēlaties atcelt uzaicinājumu šim lietotājam\? + Atceļot ši lietotāja ignorēšanu, visas lietotāja ziņas atkal būs redzamas. + Šī lietotāja neņemšana vērā kopīgajās istabās noņems viņa ziņas. +\n +\nŠo darbību var jebkurā brīdī atcelt vispārīgajos iestatījumos. + Pazemināt + Pazemināt sevi\? + Zvani + Atkārtoti pieprasīt šifrēšanas atslēgas no citām savām sesijām. + Šis tālruņa numurs jau ir definēts. + Sūtīt uzlīmi + Bezvadu austiņas + Austiņas + Skaļrunis + Istabu katalogs + Jaunā vērtība + Pārslēgt + Nevar uzsākt zvanu ar sevi, jāpagaida, līdz dalībnieki apstiprinās uzaicinājumu + Tu nevari uzsākt zvanu ar sevi + Sūtīt uzlīmi + Sakarā ar pilnīgu šifrēšanu, jums var būt nepieciešams sagaidīt ziņu no kāda, jo šifrēšanas atslēgas netika pareizi nosūtītas jums. + Gaida šo ziņu, tas var aizņemt ilgāku laiku + Jums nav piekļuves šai ziņai + + Jāparāda %d ierīces, ar kurām šobrīd var veikt apliecināšanu + Jāparāda %d ierīce, ar kuru šobrīd var veikt apliecināšanu + Jāparāda %d ierīces, ar kurām šobrīd var veikt apliecināšanu + + Jums būs jāatsāk bez vēstures, ziņām, uzticamām ierīcēm un uzticamiem lietotājiem + Ja viss tiek atiestatīts + Veiciet atiestatīšanu tikai tad, ja jums vairs nav nevienas citas ierīces, ar kuru verificēt šo ierīci. + Pilna atiestatīšana + Aizmirstas vai pazaudētas visas atkopšanas iespējas\? Viss jāatiestata + Izmantojiet savu %1$s vai savu %2$s, lai turpinātu. + Izmantojiet jaunāko ${app_name} citās savās ierīcēs: + Izmantojiet jaunāko ${app_name} citās savās ierīcēs, ${app_name} Web, ${app_name} Desktop, ${app_name} iOS, ${app_name} Android, vai kādu citu Matrix lietotni ar cross-signing atbalstu + Iestatiet jaunu konta paroli… + Šis ir sākums tiešo ziņu vēsturei ar %s. + Šis ir šīs sarakstes pats sākums. + Šis ir pats %s sākums. + Tu pievienojies. + %s pievienojās. + Tu izveidoji un uzstādīji istabu. + %s izveidoja un sakonfigurēja istabu. + Šajā istabā izmantotā šifrēšana netiek atbalstīta + Ziņas šajā istabā ir aizsargātas ar pilnīgu šifrēšanu. Uzziniet vairāk un verificējiet lietotājus viņu profilā. + Apliecināšana atcelta + Konts varētu būt iesaistīts drošības pārkāpumā + Tas nebiju es + Izmantojiet šo sesiju jaunās sesijas verifikācijai, tādējādi dodot piekļuvi šifrētām ziņām. + Labošanas iemesls + Iekļaut iemeslu + Dzēst… + Ja nevar piekļūt esošai sesijai + Izmantot atkopšanas paroles vārdkopu vai atslēgu + Izmantojiet citu sesiju šis sesijas verifikācijai, tādējādi dodot piekļuvi šifrētām ziņām. + Iespējot šifrēšanu + Tiklīdz iespējots, istabas šifrēšanu nevar atspējot. Šifrētā istabā sūtītas ziņas nav redzamas serverim, tikai istabas dalībniekiem. Šifrēšanas iespējošana var neļaut pareizi strādāt daudzām robotprogrammatūrām un tiltiem. + Jums nav atļaujas, lai iespējotu šifrēšanu šajā istabā. + + Viena persona + %1$d cilvēki + %1$d cilvēki + + Gaida %s… + Verificēts %s + Verificē %s + Verifikācija, izmantojot emocijzīmju salīdzināšanu + Ja neesi klātienē, jāsalīdzina emocijzīmes + Nevar skenēt + Skenēt viņu kodu + Skenējiet kodu ar otra lietotāja ierīci, lai droši verificētu viens otru + Verificējiet šo sesiju + Verifikācijas pieprasījums + Verifikācija nosūtīta + %s akceptēja + Tu atcēli + %s atcēla + Gaida… + Reaģēja ar %s + Bloķēt pievienošanos šai istabai ikvienam, kas nav daļa no %s + Iespējot šifrēšanu + Sākotnējā sinhronizācija… + Tu esi atteicies + Pierakstīties vēlreiz + Tu esi atteicies + Neizdevās atrast derīgu mājasserveri. Lūgums pārbaudīt savu identifikatoru + Šis nav derīgs identifikators. Sagaidāmais pieraksts: \'@user:homeserver.org\' + Ja sava parole nav zināma, jādodas atpakaļ, lai to atiestatītu. + Ja izveido kontu mājasserverī, zemāk jāizmanto savs Matrix Id (piemēram, @user:domain.com) un parole. + Pierakstīties ar Matrix ID + Pierakstīties ar Matrix ID + Šajā mājasserverī darbojas pārāk vecs laidiens. Jāvaicā mājasservera pārvaldītājam veikt atjauninājumus. Var turpināt, tomēr atsevišķas iespējas var nedarboties pareizi. + Novecojis mājasserveris + Ievadītais kods nav pareizs. Lūdzu, pārbaudiet. + Mēs tikko nosūtījām epastu uz %1$s. +\nLūdzu, noklikšķiniet uz saites epastā, lai turpinātu konta izveidi. + Lūdzu, pārbaudiet savu epastu + Pieņemt noteikumus, lai turpinātu + Lūdzu, veiciet CAPTCHA izaicinājumu + Izvēlēties pielāgotu mājasserveri + Izvēlēties Element Matrix Services + Izvēlēties matrix.org + Konts vēl nav izveidots. Vai pārtraukt reģistrēšanos\? + Lūdzu, izmantojiet starptautisko formātu. + Jānorāda tālruņa numurs, lai pēc izvēles ļauti sevi atklāt zināmiem cilvēkiem. + Iestatiet tālruņa numuru + Tālāk + E-pasta adrese (izvēles) + Jānorāda e-pasta adrese, lai atkoptu kontu. Vēlāk pēc izvēles var ļaut sevi atklāt zināmiem cilvēkiem pēc šīs adreses. + Iestatīt epasta adresi + Parole vēl nav nomainīta. +\n +\nPārtraukt paroles nomaiņu\? + Gatavs! + Nospiediet saiti, lai apstiprinātu savu jauno paroli. Kad esat sekojis saitei, noklikšķiniet zemāk. + Apstiprinājuma epasts tika nosūtīts uz %1$s. + Pārbaudiet ienākošos epastus + Šī e-pasta adrese nav piesaistīta nevienam kontam + Atiestatīt paroli uz %1$s + Šī e-pasta adrese nav piesaistīta nevienam kontam. + Lietotnei neizdodas izveidot kontu šajā mājasserverī. +\n +\nVai reģistrēties ar tīmekļa klientu\? + Atvainojiet, šis serveris nepieņem jaunus kontus. + Lietotnei neizdodas pieteikties šajā mājasserverī. Mājasserveris atbalsta šo(s) pieteikšanās veidu(s): %1$s. +\n +\nVai pieteikties tīmekļa klientā\? + Radās kļūda, ielādējot lapu: %1$s (%2$d) + Ievadiet servera adresi, kuru vēlaties izmantot + Ievadiet Modular Element vai servera adresi, kuru vēlaties izmantot + Premium hostings organizācijām + Adrese + Element Matrix Services adrese + Attīrīt vēsturi + Turpināt, izmantojot SSO + Pierakstīties uz %1$s + Pieslēgšanās pielāgotam serverim + Pieslēgšanās Element Matrix Services + Pieslēgšanās %1$s + vienotā pierakstīšanās + Pierakstīties ar %s + Reģistrēties ar %s + Turpināt ar %s + Pielāgoti un papildu iestatījumi + Uzzināt vairāk + Premium hostings organizācijām + Pievienojieties bez maksas miljoniem lietotāju lielākajā publiskajā serverī + Tāpat kā ar e-pastu, kontiem ir sava mājvieta, lai gan var sarunāties ar ikvienu + Izvēlieties serveri + Uzsākt + Paplašini un pielāgo savu pieredzi! + Paturiet saraksti privātu ar šifrēšanas palīdzību + Tērzēt ar cilvēkiem tieši vai grupās + Tā ir Tava sarakste. Tā pieder Tev. + Ilgs piespiediens uz istabas, lai redzētu vairāk iespēju + Tu neveici nekādas izmaiņas + %1$s neveica nekādas izmaiņas + Istabas iestatījumi + Pamest istabu + Izņemt no zemas prioritātes saraksta + Pievienot zemas prioritātes sarakstam + Izņemt no izlases + Pievienot izlasei + Uzlīme + Galerija + Kontakts + Fails + Pievienot attēlu no + QR kods + Nosaukums vai ID (#piemers:matrix.org) + Atvērt istabu katalogu + Sūtīt jaunu tiešo ziņu + Izveidot jaunu istabu + Nevarat atrast meklēto\? + Filtrēt sarakstes… + Istaba ir izveidota, bet daži ielūgumi nav nosūtīti šāda iemesla dēļ: +\n +\n%s + Jebkurš varēs pievienoties istabai + Izveidot jaunu istabu + Šeit tiks attēlotas istabas. Jāpiesit + apakšējā labajā stūrī, lai atrastu esošas vai izveidotu kādu jaunu. + Atkārtot + Tu neizmanto nevienu identitāšu serveri + Rezerves kopiju nevarēja atšifrēt ar šo atkopšanās atslēgu: lūdzu, pārbaudiet, vai ievadījāt pareizo atkopšanās atslēgu. + Kalkulē atkopšanās atslēgu… + Paroles vārdkopa ir pārāk vāja + Nosūta doto ziņu ar sniegu + Nosūta doto ziņu ar konfeti + Atbastīta tikai šifrētās istabās + Nosūta ziņu vienkāršā tekstā, nepielietojot markdown + Nosūta doto ziņu uzsvērti izkrāsotu varavīksnes krāsās + Nosūta doto ziņu izkrāsotu varavīksnes krāsās + Pievieno ¯\\_(ツ)_/¯ vienkārša teksta ziņas sākumā + Iespējo/atspējo markdown + Iestata istabas tematu + Pievienojas istabai ar norādīto adresi + Atceļ pieejas liegumu lietotājam ar norādīto id + Komandai \"%s\" nepieciešami vairāk parametri vai arī kāds no parametriem ir nepareizs. + Vai tiešām izdzēst visas nenosūtītas ziņas šajā istabā\? + Izdzēst nenosūtītās ziņas + Ziņas neizdevās nosūtīt + Vai vēlaties atcelt ziņu nosūtīšanu\? + Nosūtīta + Nosūta + Neizdevās autentificēties + Atmest izmaiņas + Te ir nesaglabātas izmaiņas. Atmest izmaiņas\? + Saite bija nepareizi veidota + QR kods nav noskenēts! + Nederīgs QR kods (nederīgs URI)! + Nevar atrast šo istabu. Pārliecinieties, ka tāda eksistē. + Brīdinājums! Pēdējais atlikušais mēģinājums pirms izrakstīšanās! + Atsaukt uzaicinājumu uz %1$s\? + Atsaukt uzaicinājumu + Meklēt kontaktus Matrix + Iegūst Tavus kontaktus… + UZZINĀT VAIRĀK + SAPRATU + Esam priecīgi paziņot, ka mēs esam mainījuši nosaukumu. Lietotne ir atjaunināta, un Tu esi pierakstījies savā kontā. + Riot tagad saucas Element! + Gaida šifrēšanas vēsturi + Tu veiksmīgi nomainīji istabas iestatījumus + Loma + Iestatīt lomu + Atvienoties no identitāšu servera %s\? + Atvērt %s noteikumus + Ar šo kodu ir jādalās ar citiem cilvēkiem, lai viņi varētu to nolasīt, lai pievienotu Tevi un uzsāktu tērzēt. + Mans kods + Dalīties ar manu kodu + Skenēt QR kodu + Tas nav derīgs matrix QR kods + Uzaicinājums nosūtīts uz %1$s + Uzaicina lietotājus… + UZAICINĀT + Pievienot cilvēkus + Pievienot dalībniekus + Saite %1$s ved uz citu vietni: %2$s. +\n +\nVai tiešām vēlaties turpināt\? + Pārbaudiet šo saiti + Interaktīvi verificēt ar emocijzīmēm + Verificējiet sesiju + Verificējiet jauno pierakstīšanos no sava konta: %1$s + Šifrēts ar neverificētu sesiju + sūta sniegu ❄️ + sūta konfeti 🎉 + Pieejams šifrēšanas atjauninājums + Ziņa… + Nepareizs lietotājvārds un/vai parole. Ievadītā parole sākas vai beidzas ar atstarpēm. Lūdzu, pārbaudiet to. + Gaida uz %s… + Gandrīz galā! Gaida apstiprinājumu… + Gandrīz galā! Vai otrā ierīcē redzams tas pats vairogs\? + "Temats: " + Pievienot tematu + Pabeigt + Ievadiet savu %s, lai turpinātu. + Apliecināšana tika atcelta. To var uzsākt atkārtoti. + Kaut kas no uzskaitītā var būt iesaistīts drošības pārkāpumā: +\n +\n- parole +\n- mājasserveris +\n- šī vai cita ierīce +\n- interneta savienojums kādā no izmantotajām ierīcēm +\n +\nMēs iesakām iestatījumos nekavējoties nomainīt paroli un atkopšanas atslēgu. + Atsvaidzināt + Vai vēlaties sūtīt šo pielikumu %1$s\? + Konta dati + Lidmašīnas režīms ir ieslēgts + Savienojums ar serveri ir zaudēts + Gandrīz galā! Vai %s redzams tas pats vairogs\? + Kamēr šis lietotājs nav padarījis šo sesiju uzticamu, ziņas uz un no tās ir iezīmētas ar brīdinājumiem. To var apliecināt arī pašrocīgi. + %1$s (%2$s) pierakstījās, izmantojot jaunu sesiju: + Lūgums ievadīt paroles vārdkopu + Paroles vārdkopa nesakrīt + Piekļuve istabai + Pārvaldīt ar Matrix kontu saistītās e-pasta adreses un tālruņa numurus + Epasti un tālruņa numuri + Parole nav derīga + Integrācija pārvaldnieks + Atļaut integrācijas + Deaktivizēt manu kontu + Sākotnējā sinhronizācija: +\nLejupielādē datus… + Sākotnējā sinhronizācija: +\nGaida servera atbildi… + Pievienojiet speciālu cilni priekš nelasītiem paziņojumiem galvenajā ekrānā. + Ieslēgt pavilkšanas žestu, lai atbildētu uz ziņu + Labojumi netika atrasti + Ziņu labojumi + Rādīt pilnu vēsturi šifrētajās istabās + Importējiet E2E atslēgas no faila \"%1$s\". + Kļūda radās vācot atslēgu dublējumu datus + Kļūda radās vācot uzticības informāciju + Mainīt tīklu + Nav tīkla. Lūdzu, pārbaudiet savu interneta savienojumu. + Malformēts notikums, nevar parādīt + Notikumu pārvalda administrators + Lietotājs izdzēsa notikumu + Rādīt vietu priekš izdzēstām ziņām + Rādīt izdzēstās ziņas + Apskatīt Reakcijas + Pievienot Reakciju + Piekrist + Šeit tiks attēlotas tiešās saziņas sarunas. Jāpiesit + apakšējā labajā stūrī, lai uzsāktu sarunu. + Viss panākts! + %s uzaicināja + Nezināma Kļūda + Paraksts + Visas atslēgas dublētas + Iestatiet Drošo Dublēšanu + Veido atslēgu rezerves kopiju. Tas var aizņemt vairākas minūtes… + Pārvaldīt Atslēgu Dublējumā + Jauna šifrēto ziņu atslēga + Izmantot Atslēgu Dublēšanu + Nekad nezaudējiet šifrētās ziņas + Izdzēst no servera savu šifrēšanas atslēgu rezerves kopiju\? Vairs nevarēs izmantot atkopšanas atslēgu, lai lasītu šifrēto ziņu vēsturi. + Izdzēst rezerves kopiju + Pārbauda dublējuma statusu + Izdzēš dublējumu… + Izdzēst rezerves kopiju + Dublējums Atgūts %s ! + Atbloķēt Vēsturi + Importē atslēgas… + Lejupielādē atslēgas… + Izmantojiet savu Atgūšanas Atslēgu, lai atbloķētu savu šifrēto ziņu vēsturi + izmantojiet savu atgūšanas atslēgu + Lietotāju ielūgšana, izmešana un aizliegšana tika neaizskarta. + Uzstādīt skaļos paziņojumus + Izslēgt ierobežojumus + Pārbaudīt fona ierobežojumus + Paziņojumam tika piesists! + Neizdevās reģistrēt FCM pilnvaru mājasserverī: +\n%1$s + FCM pilnvara veiksmīgi reģistrēta mājasserverī. + FCM žetons veiksmīgi saņemts: +\n%1$s + FCM žetons netika saņemts: +\n%1$s + Žetona Reģistrācija + ${app_name} izmanto Google Play pakalpojumus, lai piegādātu pašpiegādes ziņas, bet tas nešķiet pareizi konfigurēts: +\n%1$s + Jums pašlaik nav iespējotas uzlīmes. +\n +\nPievienojiet dažas tagad\? + Neizdevās izveidot reāllaika savienojumu. +\nLūgums vaicāt mājasservera pārvaldītājam uzstādīt TURN serveri, lai zvani varētu uzticami darboties. + Izmanto iekļaušanas pārvaldnieku, lai pārvaldītu robotprogrammatūru, tiltus, logrīkus un uzlīmju pakas. +\nIekļaušanas pārvaldnieks saņem konfigurācijas datus un var pārveidot logrīkus, sūtīt istabu uzaicinājumus un iestatīt spēka līmeņus Tavā vārdā. + Par ienākošajiem ziņojumiem netiks paziņots, kad lietotne darbojas fonā. + Bez fona sinhronizācijas + Optimizēts reālajam laikam + Fona Sinhronizācijas Režīms + Izvēlaites LED krāsu, vibrāciju, skaņu… + Uzstādīt klusos paziņojumus + Uzstādīt zvanu paziņojumus + Pakalpojums startēsies, kad ierīce būs restartēta. + Paziņojumu attēlošana + Google Play Servisu APK ir pieejams un atjaunināts. + Filtrēt aizliegtos lietotājus + Lūdzu palaidiet ${app_name} citā ierīcē, kas var atšifrēt ziņu, lai tā varētu nosūtīt šīs sesijas atslēgas. + Neautorizēts, trūkstošas autentifikācijas apliecības + Atvainojiet, nav atrasta ārēja aplikācija, lai pabeigtu šo darbību. + ${app_name} Zvans Neizdevās + Sūtīt atslēgu dalības vēsturi + Rādīt visas istabas istabu rādītājā, tostarp istabas ar vecumam ierobežotu saturu. + Rādīt istabas ar vecuma ierobežojumu + 🎉 Visi serveri ir aizliegti piedalīties! Šo istabu vairs nevar izmantot. + Nekas nemainīts. + • Serveri ar atbilstošu IP tagad ir aizliegti. + • Serveri ar atbilstošu IP ir atļauti. + • Serveri, kuri atbilst %s tika izņemti no atļauto saraksta. + • Serveri, kuri atbilst %s tagad ir atļauti. + • Serveri, kuri atbilst %s tika noņemti no aizliegto/nobanoto saraksta. + • Serveri, kuri atbilst %s tagad ir aizliegti. + Tu šai istabai nomainīji servera ACL. + %s nomainīja servera ACL šai istabai. + • Serveri ar vienādām IP ir aizliegti. + • Serveri ar vienādām IP ir atļauti. + • Serveri, kuri atbilst %s ir atļauti. + • Serveri, kuri atbilst %s ir nobanoti. + Tu šai istabai iestatīji servera ACL. + %s iestatīja servera ACL šai istabai. + Tu atjaunināji šeit. + %s atjaunināti šeit. + Sistēmas Brīdinājumi + Nepublicēt + Nolikt + Neizdevās noņemt logrīku + Neizdevās ielādēt logrīku + Ziņa aizsūtīta + Tu pārveidoji %1$s logrīku + %1$s modificēja %2$s logrīku + Tu noņēmi %1$s logrīku + %1$s noņēma %2$s logrīku + Tu pievienoji %1$s logrīku + %1$s pievienoja %2$s logrīku + Jāizmanto atkopšanas paroles vārdkopa, lai atslēgtu šifrēto ziņu vēsturi + Var zaudēt piekļuvi savām ziņām, ja notiks atteikšanās vai tiks pazaudēta šī ierīce. + Atgūšanas Atslēga + Lūdzu uztaisiet kopiju + Stop + Aizvietot + Rezerves kopija jau pastāv Tavā mājasserverī + Atkopšanas atslēgas tika saglabātas. + Saglabāt datnē + Saglabāt Atgūšanas Atslēgu + Es uztaisīju kopiju + Saglabājiet savu atgūšanas atslēgu kaut kur ļoti drošā vietā, piemēram, paroles pārvaldniekā (vai seifā) + Atkopšanas atslēga ir drošības tīkls - to var izmantot, lai atjaunotu piekļuvi šifrētajām ziņām, ja aizmirsta paroles vārdkopa. +\nAtkopšanas atslēga ir jāglabā kādā ļoti drošā vietā, piemēram, paroļu pārvaldniekā (vai seifā) + Tiek veidota atslēgu rezerves kopija. + Izdevās! + (Papildu) Uzstādīt ar atkopšanas atslēgu + Vai aizsargā rezerves kopiju ar atkopšanas atslēgu, saglabājot to drošā vietā. + Veido rezerves kopiju + Iestatīt paroles vārdkopu + Mēs saglabāsim šifrētu atslēgu kopiju Tavā mājasserverī. Lai rezerves kopija būtu droša, tā ir jāaizsargā ar paroles vārdkopu. +\n +\nLai nodrošinātu vislielāko drošību, tai jāatšķiras no konta paroles. + Aizsargā savu rezerves kopiju ar paroles vārdkopu! + Manuāli eksportēt atslēgas + (Advancēti) + Sākt izmantot Atslēgu Dublēšanu + Ziņojumi šifrētās istabās ir nodrošināti ar pilnīgu šifrēšanu. Tikai sarunas dalībniekiem ir atslēgas, lai izlasītu šos ziņojumus. +\n +\nAtslēgas jātur drošībā, lai izvairītos no to pazaudēšanas. + Nekad nepazaudējiet šifrētās ziņas + Šis mājasserveris ir sasniedzis savu ikmēneša aktīvo lietotāju ierobežojumu. + " Šis mājasserveris ir sasniedzis savu ikmēneša aktīvo lietotāju ierobežojumu, tādēļ <b>daži lietotāji nevarēs pieteikties</b>." + Šis mājasserveris ir pārsniedzis vienu no saviem resursu ierobežojumiem. + Šis mājasserveris ir pārsniedzis vienu no saviem resursu ierobežojumiem, tādēļ <b>daži lietotāji nevarēs pieteikties</b>. + jāsazinās ar pakalpojuma pārvaldītāju + Lūdzu ievadiet paroli. + Lūdzu ievadiet lietotājvārdu. + Lūdzu aizmirst visas ziņas, ko esmu nosūtījis, kad mans konts ir deaktivizēts (Brīdinājums: šis nākotnes lietotājiem neļaus redzēt visu sarunu kontekstu) + Tas padarīs kontu neizmantojamu. Nebūs iespējams pieteikties, un neviens nevarēs atkārtoti reģistrēties ar to pašu lietotāja identifikatoru. Tas liks kontam atstāt visas istabas, kurās piedalās, un tas noņems konta datus no identitātes servera. Šī darbība ir neatgriezeniska . +\n +\nKonta deaktivēšana pēc noklusējuma neliek mums aizmirst nosūtītās ziņas . Ja vēlme, lai mēs aizmirstu ziņas, lūgums atzīmēt zemāk esošo lodziņu. +\n +\nZiņu redzamība Matrix ir līdzīga e-pastam. Ziņu aizmiršana nozīmē, ka nosūtītās ziņas netiks rādītas jauniem vai nereģistrētiem lietotājiem, bet reģistrētiem lietotājiem, kuriem jau ir piekļuve šīm ziņām, joprojām būs piekļuve to kopijai. + Atslēgas Dalīšanās Pieprasījums + Nav aktīvu logrīku + Izmantot mikrofonu + Izmantot kameru + Bloķēt Visu + Atļaut + Šis logrīks vēlas izmantos tālāk norādītos resursus: + Pamest pašreizējo apspriedi un pārslēgties uz otru\? + Atvainojiet, konferences zvani ar Jitsi netiek atbalstīti vecās ierīces (ierīces ar Android OS zem 6.0) + Istabas ID + Logrīka ID + Tavs izskats + Tavs lietotāja Id + Tava iemiesojuma URL + Atsaukt piekļuvi man + Atvērt pārlūkprogrammā + Pārlādēt logrīku + Neizdevās ielādēt logrīku. +\n%s + Šis logrīks bija pievienots no: + Ielādēt Logrīku + Logrīks + Aktīvie logrīki + Pārvaldīt Atslēgu Dublējumu + Šifrētu Ziņu Atgūšana + Publicēt šo istabu uz %1$s istabu sadaļu\? + Nepublicēt šo adresi + Publicēt šo adresi + Nevienu citu publicētu adrešu nav. + Nav publicētu adrešu pagaidām, pievienojat vienu apakšā. + Nepublicēt adresi \"%1$s\"\? + Publicēt + Publicēt jaunu adresi manuāli + Šī ir galvenā adrese + ${app_name} apkopo anonīmu analītiku, lai ļautu mums uzlabot aplikāciju. + Šis aizvietos esošo atslēgu vai vārdkopu. + Izveidot jaunu drošības atslēgu vai iestatīt jaunu drošības vārdkopu esošajai rezerves kopijai. + Iestatīt uz šīs ierīces + Atiestatīt Drošo Dublējumu + Pievienot pogu ziņu ievades laukā priekš Emoji + Rādīt Emoji tastatūru + Tastatūras Enter poga sūtīs ziņu, tā vietā lai pievienotu jaunu rindkopu + Sūtīt ziņu ar Enter + Iekļauj avatara un parādāmā vārda izmaiņas. + Rādīt konta notikumus + Rādīt cilvēku pievienošanos vai iziešanu + Izmantojiet /konfeti komandu vai nosūtiet ziņu, kas satur ❄️ or 🎉 + Rādīt tērzēšanas iespaidus + Nospiediet izlasīšanas simbolu, priekš detalizētas informācijas. + Rādīt vai ziņa ir izlasīta/neizlasīta + Formatēt ziņas advancēti. Tas ļauj uzlabot formatējumu, piemēram, izmantojot zvaigznītes, lai parādītu slīprakstu tekstu. + Advancēts formatējums + Kriptogrāfijas Atslēgu Pārvaldība + Ļaut citiem lietotājiem zināt, ka Tu raksti. + Tu apskati paziņojumu. Klikšķini šeit! + Pievienot Kontu + Firebase Tokens + Salabot Play Servisus + Pārliecinieties, ka esat nospiedis uz saites e-pasta ziņojumā, ko esam nosūtījuši jums. + Optimizēts akumulatoram + ${app_name} sinhronizēsies fonā, tā lai ietaupītu telefona bateriju. +\nAtkarībā no ierīces baterijas stāvokļa, sinhronizāciju var atcelt operētājsistēma. + Ignorēt optimizāciju + ${app_name} neietekmē akumulatora optimizācija. + Akumulatora Optimizācija + Ieslēgt Aplikācijas palaišanu kopā ar telefonu + Play Servisu Pārbaude + Daži paziņojumi ir izslēgti pielāgotajos iestatījumos. + Ievērojiet, ka daži ziņojumi ir iestatīti kā klusi (paziņojumi pienāks bez skaņas). + Pielāgoti Iestatījumi. + Paziņojumi nav ieslēgti šai sesijai. +\nLūdzu, pārbaudiet ${app_name} iestatījumus. + Paziņojumi ir ieslēgti šai sesijai. + Sesijas Iestatījumi. + Konta paziņojumi ir atspējoti. +\nLūgums pārbaudīt konta iestatījumus. + Konta paziņojumi ir ieslēgti. + Konta iestatījumi. + Paziņojumi ir izslēgti sistēmas iestatījumos. +\nLūdzu, pārbaudiet sistēmas iestatījumus. + Paziņojumi ir ieslēgti sistēmas iestatījumos. + Sistēmas iestatījumi. + Viens vai vairāki testi nav izdevušies, lūdzu, iesniedziet kļūdu ziņojumu, lai palīdzētu mums izmeklēt. + Viens vai vairāki testi nav izdevušies, mēģiniet ieteiktos labojumus. + Pēc pamata pārbaudes ir labi. Ja joprojām netiek saņemti paziņojumi, lūgums iesniegt kļūdu ziņojumu, lai palīdzētu mums izpētīt cēloni. + Palaist Testus + Pārbaudes diagnostika + Paziņojumu pārbaude + Paziņojumu svarīgums + Paziņojumu papildu iestatījumi + Tu aizturēji zvanu + %s apturēja zvanu + Apturēt + Turpināt + Izvēlieties zvana signālu: + Ienākoša zvana signāls + Izmantot noklusējuma ${app_name} zvana signālu ienākošajiem zvaniem + Pirms zvana uzsākšanas lūgt apstiprinājumu + Novērst nejaušu zvanu + SSL kļūda: Peer identitāte nav pārbaudīta. + SSL kļūda. + Ar šo URL mājasserveris nav sasniedzams, lūgums pārbaudīt to + Šī nav derīga Matrix servera adrese + Lūgums pārskatīt un pieņemt šī mājasservera nosacījumus: + Ieslēgt HD + Izslēgt HD + Priekšējā + Pārslēgt kameru + Izvēlieties Skaņas Ierīci + Sanāksmes izmanto Jitsi drošības un atļauju nosacījumus. Visi cilvēki, kas pašlaik atrodas telpā, redzēs uzaicinājumu pievienoties, kamēr notiek sanāksme. + Sākt audio sanāksmi + Sākt video sanāksmi + Jums nav atļaujas sākt zvanu + Jums nav atļaujas sākt zvanu šajā istabā + Jums nav atļaujas sākt konferences zvanu + Uzsākt tērzēšanu + Tu zaudēsi piekļuvu savām šifrētajām ziņām, ja pirms atteikšanās neveiksi atslēgu rezerves kopēšanu. + Drošai atslēgu rezerves kopēšanai jābūt ieslēgtai visās sesijās, lai izvairītos no piekļuves zaudēšanas šifrētajām ziņām. + Dublēt + Dublē atslēgas… + Es nevēlos manas šifrētās ziņas + Notiek atslēgu rezerves kopēšana. Ja Tu tagad izrakstīsies, Tu zaudēsi piekļuvi savām šifrētajām ziņām. + Tu zaudēsi savas šifrētās ziņas, ja tagad atteiksies + Izmantot Atslēgu Dublējumu + Atslēgu Dublējums + Tu atjaunināji šo istabu. + %s atjaunināja šo istabu. + Atkopšanas paroles vārdkopa + Atbloķēt šifrēto ziņu vēsturi + ${app_name} Android + Atslēgas jau ir atjauninātas! + Pasākumu moderē telpas administrators, iemesls: %1$s + Lietotājs izdzēsa notikumu, iemesls: %1$s + Izdzēst %1$s veida konta datus\? +\n +\nJāizmanto piesardzīgi, jo tas var izraisīt neparedzētu uzvedību. + Izstrādātāj rīki + Nav pieejama kriptogrāfiska informācija + Mājasserveris pieņem pielikumus (datnes, multivides u.c.), kuru izmērs nepārsniedz %s. + Robeža nav zināma. + Servera failu augšupielādes ierobežojums + Servera versija + Servera nosaukums + Neizdoties-ātri + Kratīšana detektēta! + Kratiet telefonu, lai pārbaudītu detektēšanas slieksni + Detektēšanas slieksnis + Dusmu tricinājums + Izstrādātāja režīms aktivizē slēptās funkcijas un var arī padarīt lietojumprogrammu mazāk stabilu. Tikai izstrādātājiem! + Izstrādātāja režīms + Apraksts ir pārāk īss + Tiks zaudēta piekļuve šifrētām ziņām, kamēr nepieteiksies, lai atkoptu šifrēšanas atslēgas. + Skatīja + + Ir nosūtīts pārāk daudz pieprasījumu. Pēc %1$d sekundēm var mēģināt vēlreiz… + Ir nosūtīts pārāk daudz pieprasījumu. Pēc %1$d sekundes var mēģināt vēlreiz… + Ir nosūtīts pārāk daudz pieprasījumu. Pēc %1$d sekundēm var mēģināt vēlreiz… + + Ievadiet atslēgvārdus, lai atrastu reakciju. + Spoileris + Par šo saturu tika ziņots kā par nepiemērotu. +\n +\nJa vairs nevēlaties redzēt saturu no šī lietotāja, varat to ignorēt, lai paslēptu viņa ziņojumus. + Ziņots kā nepiemērots + Par šo saturu tika ziņots kā par spamu. +\n +\nJa vairs nevēlaties redzēt saturu no šī lietotāja, varat to ignorēt, lai paslēptu viņa ziņojumus. + Ziņots kā spams + Par šo saturu tika ziņots. +\n +\nJa vairs nevēlaties redzēt saturu no šī lietotāja, varat to ignorēt, lai paslēptu viņa ziņojumus. + Saturs ziņots + IGNORĒT LIETOTĀJU + Rotēšana un apgriešana + + %d lietotāju izlasīja + %d lietotājs izlasīja + %d lietotāji izlasīja + + Pāriet uz apakšu + Aizvērt atslēgu dublējuma baneri + Izveidot jaunu telpu + Lūgums mēģināt atkārtoti, tiklīdz esi piekritis sava mājasservera noteikumiem un nosacījumiem. + Pašlaik e-pasta adreses vai tālruņa numuri tiek kopīgoti identitātes serverī %1$s. Atkārtoti jāsavienojas ar %2$s, lai apturētu to kopīgošanu. + Izvēlētajam identitātes serverim nav pakalpojumu sniegšanas noteikumu. Turpināt ir ieteicams tikai tad, ja ir uzticēšanās pakalpojuma īpašniekam + Identitātes serverim nav pakalpojumu sniegšanas noteikumu + Lūdzu, ievadiet identitātes servera url + Ievadiet identitātes servera URL + Sniegt piekrišanu + Atsaukt manu piekrišanu + Ir dota piekrišana sūtīt e-pasta adreses un tālruņa numurus uz šo identitātes serveri, lai atklātu citus lietotājus no kontaktiem. + Sūtīt e-pastus un tālruņa numurus + Mēs nosūtījām apstiprinājuma e-pastu uz %s, lūgums vispirms pārbaudīt e-pasta iesūtni un noklikšķināt uz apstiprinājuma saites + Mēs nosūtījām apstiprinājuma e-pastu uz %s, jāpārbauda e-pasta iesūtne un jāklikšķina uz apstiprinājuma saites + Atrodamie tālruņa numuri + Atvienošanās no identitātes servera nozīmē, ka nebūsi atklājams citiem un nevarēsi uzaicināt citus, izmantojot e-pasta adresi vai tālruņa numuru. + Atklāšanas iespējas parādīsies tiklīdz būs pievienots tālruņa numurs. + Atklāšanas iespējas parādīsies tiklīdz būs pievienota e-pasta adrese. + Atklājamās e-pasta adreses + Pašlaik netiek izmantots identitātes serveris. To var norādīt zemāk, lai atklātu esošos kontaktus un būtu atklājams tiem. + Pašlaik izmantojat %1$s, lai atrastu un būtu atrodams esošajiem kontaktiem, kurus pazīstat. + Mainīt identitātes serveri + Izmanto robotprogrammatūru, tiltus, logrīkus un uzlīmju pakas + Esiet atrodams citiem + Pakalpojumu sniegšanas noteikumi + Skatīt labošanas vēsturi + Rādīt slēptos notikumus laika joslā + Reģistrēt žetonu + + Dublē %d atslēgu… + Dublē %d atslēgu… + Dublē %d atslēgas… + + Lai šajā sesijā izmantotu atslēgu rezerves kopēšanu, tagad jāatjauno ar savu paroles vārdkopu vai atkopšanas atslēgu. + Rezerves kopijai ir nederīgs paraksts no nepārbaudītas sesijas %s + Rezerves kopijai ir nederīgs paraksts no pārbaudītas sesijas %s + Rezerves kopijai ir derīgs paraksts no nepārbaudītas sesijas %s + Rezerves kopijai ir derīgs paraksts no pārbaudītas sesijas %s. + Rezerves kopijai ir derīgs šīs sesijas paraksts. + Rezerves kopijai ir paraksts no nezināmas sesijas ar ID %s. + Šīs sesijas atslēgām netiek veikta rezerves kopēšana. + Šajā sesijā Atslēgu Dublēšana nav aktīva. + Atslēgu Dublēšana šai sesijai ir pareizi iestatīta. + Atjaunot no Dublējuma + + Atjaunota rezerves kopija ar %d atslēgu. + Atjaunota rezerves kopija ar %d atslēgu. + Atjaunota rezerves kopija ar %d atslēgām. + + Lūdzu, ievadiet atgūšanas atslēgu + Rezerves kopijas atjaunošana: + Rezerves kopiju nevarēja atšifrēt ar šo paroles vārdkopu: lūgums pārbaudīt, vai ir ievadīta pareiza atkopšanas paroles vārdkopa. + Vai esat pazaudējis atgūšanas atslēgu\? Iestatījumos varat iestatīt jaunu. + Ievadiet Atgūšanas Atslēgu + Kopīgojiet atkopšanas atslēgu ar… + Lūdzu, %s, lai turpinātu izmantot šo pakalpojumu. + Lūdzu, %s, lai palielinātu šo limitu. + Palaidiet sistēmas kameru, nevis pielāgotās kameras ekrānu. + Lasīt DRM aizsargātu multividi + Izmantojot to, var kopīgot datus ar %s: + Izmantojot to, var iestatīt sīkfailus un kopīgot datus ar %s: + SKATĪT + + %d paziņojumu + %d paziņojums + %d paziņojumi + + + %1$s: %2$d ziņojumu + %1$s: %2$d ziņojums + %1$s: %2$d ziņojumi + + + %d uzaicinājumu + %d uzaicinājums + %d uzaicinājumi + + + %1$d/%2$d veiksmīgi importēta atslēgas. + %1$d/%2$d veiksmīgi importēta atslēga. + %1$d/%2$d veiksmīgi importēta atslēgas. + + Noklusējuma multivides avots + Mediji + Pārvaldiet atklāšanas iestatījumus. + Atklāšana + Priekšskatīt failu pirms nosūtīšanas + ${app_name} sinhronizēsies fonā periodiski, precīzi, noteiktā laikā (konfigurējams). +\nTas ietekmēs radio un akumulatora izmantošanu, tiks parādīts pastāvīgs paziņojums par to, ka ${app_name} klausās notikumus. + Ja lietotājs kādu laiku atstāj ierīci atvienotu no tīkla un nekustīgu, ar izslēgtu ekrānu, ierīcē tiek ieslēgts dīkstāves režīms. Tas neļauj lietotnēm piekļūt tīklam un atliek to darbu izpildi, sinhronizāciju un standarta brīdinājumus. + Pakalpojums nesāksies, kad ierīce tiks pārsāknēta, kamēr ${app_name} netiks atvērta vismaz vienreiz, netiks saņemti paziņojumi. + Lūdzu, noklikšķiniet uz paziņojuma. Ja paziņojums nav redzams, pārbaudiet sistēmas iestatījumus. + + %d izvēlēti + %d izvēlēts + %d izvēlēti + + Modificēt logrīku + Trūkst atļauju + Lai veiktu šo darbību, lūdzu, piešķiriet kamerai atļauju sistēmas iestatījumos. + Lai veiktu šo darbību, trūkst dažu atļauju. Lūdzu, sistēmas Iestatījumos piešķiriet atļaujas. + Vietnes + Ieteiktās istabas + Pievienoties tāpat + Pievienoties Telpai + Izveidot Telpu + Pagaidām izlaist + Pievienojies manai Telpai %1$s %2$s + Tie nebūs daļa no %s + Tikai uz šo istabu + Viņi varēs izpētīt %s + Uzaicināt uz %s + Kopīgot saiti + Ielūgt pēc lietotājvārda vai pa e-pastu + Ielūgt pa e-pastu + Šobrīd esi tikai tu. %s būs vēl labāk kopā ar citiem. + Uzaicināt uz %s + Uzaicināt cilvēkus + Uzaiciniet cilvēkus uz savu Telpu + Apraksts + Izveido Telpu… + Nejaušs + Vispārīgi + Izveidosim katram no tiem savu istabu. Vēlāk varat pievienot arī citas, tostarp jau esošās. + Pie kādām lietām strādājat\? + Nodrošiniet piekļuvi %s uzņēmumam pareizajiem cilvēkiem. Vēlāk varat uzaicināt vairāk. + Kas ir Tavi komandas biedri\? + Mēs izveidosim tām istabas. Vēlāk var pievienot arī citas. + Kādas ir dažas diskusijas, ko vēlaties apspriest %s\? + Dodiet tam nosaukumu, lai turpinātu. + Pievienojiet sīkāku informāciju, lai palīdzētu cilvēkiem to identificēt. Tās var mainīt jebkurā brīdī. + Pievienojiet dažas detaļas, lai tā izceltos. Tās var mainīt jebkurā brīdī. + Izveidot Telpu + Tikai uzaicinot, vislabāk priekš jums vai komandām + Atvērta ikvienam, vislabāk kopienām + Privāta + Publiska + Privāta Telpa jums un biedriem + Es un biedri + Pārliecinieties, ka piekļuve %s ir pareizajiem cilvēkiem. To var mainīt vēlāk. + Ar ko Tu strādā\? + Privāta vieta, kur sakārtot istabas + Tikai es + Lai pievienotos esošai Telpai, ir nepieciešams ielūgums. + To var mainīt vēlāk + Kādu Telpu vēlaties izveidot\? + Tava privātā vieta + Tava publiskā vieta + Pievienot Telpu + Privāta Telpa + Publiska Telpa + Pievienoties Telpai ar doto ID + Pievienot dotajai Telpai + Izveidot Telpu + Tips + Nav pieejams + Nav tiešsaistē + Tiešsaistē + Publiska istaba + Skatīt kuri izlasīja + Aizvērt emocijzīmju izvēlni + Atvērt emocijzīmju izvēlni + Izvēlēts + Video + Izdzēst iemiesojumu + Mainīt avatāru + Bilde + Atvērt logrīkus + Ekrānšāviņš + Velciet, lai pārtrauktu zvanu + Nezināma persona + Lietotāji + Savienoties + %1$s Pieskarieties, lai atgrieztos + Aktīvs zvans (%1$s) · + Aktīvs zvans (%1$s) + Tika pieļauta kļūda, meklējot tālruņa numuru + Zvanu taustiņi + Nav atbildes + Neatbildēts video zvans + Neatbildēts zvans + Video zvans atteikts + Zvans atteikts + Video zvans beidzās • %1$s + Balss zvans beidzās • %1$s + Aktīvs video zvans + Aktīvs zvans + Ienākošs video zvans + Ienākošs zvans + Piezvanīt atpakaļ + Zvans beidzās + %1$s atteica zvanu + Tu atteici šo zvanu + Telpa vēl nav izveidota. Atcelt telpas izveidi\? + Nevar sūtīt ziņas sev! + Nomainīt tagadējo PIN + Nomainīt PIN + Ieslēgt PIN + Jauns PIN + Attiestatīt PIN + Aizmirsāt PIN\? + Ievadiet savu PIN + Apstipriniet PIN + Izvēlaties PIN + Iestatīt avatāru + Ieslēgt kameru + Izslēgt kameru + Ieslēgt mikrofonu + Izslēgt mikrofonu + Jāievada identitātes servera URL + Var ievadīt arī jebkura cita identitātes servera URL + Izmantot %1$s + Mājasserveris (%1$s) ierosina identitātes serverim izmantot %2$s + Privātuma nolūkos ${app_name} nodrošina ar jaucējkodu slēptu lietotāja e-pasta adrešu un tālruņa numuru sūtīšanu. + Vispirms iestatījumos pieņemiet identitātes servera noteikumus. + Vispirms konfigurējiet identitātes serveri. + Šī darbība nav iespējama. Mājasserveris ir novecojis. + Ielādē pieejamās valodu… + Citas pieejamās valodas + Pašreizējā valoda + Uzaicinājumi nosūtīti uz %1$s un %2$s + 🔐️ Pievienojies ${app_name} + Sazinieties ar mani izmantojot ${app_name}: %s + Lūdzu, izvēlieties paroli. + Lūdzu, izvēlieties lietotājvārdu. + Nevarēja saglabāt multivides failu + Neatļaut ekrānšāviņus lietotnē + Izmantot failu + Ievadiet savu %s, lai turpinātu + Paziņojumu uzstādīšana + Neizdevās importēt atslēgas + %s, lai ļautu cilvēkiem uzzināt, par ko ir šī istaba. + Nokopējiet to uz personālās mākoņa krātuves + Saglabājiet uz USB vai rezerves diska + Izprintējiet un turiet to drošībā + Tavs %2$s un %1$s tagad ir iestatīti. +\n +\nTie ir jātur drošībā. Tie būs nepieciešami, lai atslēgtu šifrētus ziņojumus un aizsargātu informāciju, ja tiks zaudētas visas darbojošās sesijas. + Turiet to drošībā + Viss pabeigts! + Šis varētu aizņemt dažas sekundes. + Jāievada tikai sev zināma drošības vārdkopa, kas tiek izmantota, lai noslēpumus serverī padarītu drošus. + Neizmantojiet sava konta paroli. + Ziņu Atslēga + %1$s netiks apliecināts (%2$s), ja tagad atcelsi. Lietotāja profilā jāsāk no jauna. + Ja to atcelsiet, jaunajā ierīcē nevarēsiet lasīt šifrētos ziņojumus + Ja to atcelsiet, šajā ierīcē nevarēsiet lasīt šifrētus ziņojumus + Nosūtīt multividi ar sākotnējo izmēru + + %d aktīvu sesiju + %d aktīva sesiju + %d aktīvas sesiju + + Pārtrauc lietotāja ignorēšanu, rādot viņa ziņojumus + Ignorē lietotāju, slēpjot viņa ziņojumus no jums + Atvainojiet, mēģinot pievienoties konferencei, radās kļūda + Šis serveris jau ir iekļauts sarakstā + Nevar atrast šo serveri vai tā istabu sarakstu + Ievadiet jaunā servera nosaukumu, kuru vēlaties izpētīt. + Citas vietas vai istabas, kuras varētu būt zināmas + Telpa, kuru zināt, kas satur šo istabu + Izlemiet, kurš var atrast šo istabu un pievienoties tai. + Piesist, lai labotu vietas + Izvēlaties Telpas + Izlemiet, kuras Telpas var piekļūt šai istabai. Ja Telpa ir izvēlēta, tās dalībnieki varēs atrast istabas nosaukumu un pievienoties tai. + Telpas, kurām var piekļūt + Ļaujiet Telpas locekļiem atrast un piekļūt. + Telpas %s dalībnieki var atrast, apskatīt un pievienoties. + Ikviens, kas atrodas telpā, kurā ir šī telpa, var to atrast un pievienoties tai. Tikai šīs telpas administratori var to pievienot telpai. + Telpas dalībniekiem tikai + Mans redzamais vārds + Ikviens var atrast telpu un pievienoties + Ikviens var atrast istabu un pievienoties + Tikai ielūgtās personas var atrast un pievienoties + Privāts (tikai ielūgumiem) + Nav zināmi piekļuves iestatījumi (%s) + Ikviens var pieklauvēt istabai, dalībnieki var tad pieņemt vai noraidīt + Nav iespējams iegūt pašreizējās telpas direktorija redzamību (%1$s). + Skatiet un pārvaldiet adreses šajā telpā. + Kurš var piekļūt\? + Paziņojumus varat pārvaldīt sadaļā %1$s. + Lūgums ņemt vērā, ka šifrētu istabu pieminēšanas un atslēgvārdu paziņojumi nav pieejami viedierīcēs. + Maina attēlojamo segvārdu tikai pašreizējā istabā + Iestata istabas nosaukumu + Pievienot jaunu serveri + Tavs serveris + Publisks + Privāts + Telpas adrese + Ļaut viesiem pievienoties + Telpas piekļuve + Konta iestatījumi + + Nosūtīt video ar sākotnējo izmēru + Nosūtīt video ar sākotnējo izmēru + Nosūtīt video ar sākotnējo izmēru + + + Nosūtīt attēlus ar sākotnējo izmēru + Nosūtīt attēlu ar sākotnējo izmēru + Nosūtīt attēlus ar sākotnējo izmēru + + nestabila + stabila + Noklusējuma versija + Istabu versijas 👓 + Ziņu redaktors + Hronoloģija + Šī sesija nevar kopīgot šo verifikāciju ar citām sesijām. +\nVerifikācija tiks saglabāta lokāli un kopīgota kādā no nākamajām lietotnes versijām. + ${app_name} saskārās ar problēmu, atveidojot notikuma ar id \'%1$s\' saturu + ${app_name} neapstrādā \'%1$s\' tipa notikumus + Tā vietā pārbaudiet, salīdzinot emocijzīmes + Noskenēt ar šo ierīci + Noskenējiet kodu ar citu ierīci vai pārslēdziet un skenējiet ar šo ierīci + Balss + Šādam e-pasta domēnam nav ļauta reģistrēšanās šajā serverī + Izveido Telpu… + Telpas adrese + Pievieno ( ͡° ͜ʖ ͡°) parasta teksta ziņai + Rādīt kādu noderīgu informāciju, lai palīdzētu atkļūdošanas programmā + Parādīt atkļūdošanas informāciju ekrānā + ${app_name} var biežāk avarēt, ja rodas neparedzēta kļūda + Pašreizējā sesija ir lietotājam %1$s, un tiek sniegti lietotāja %2$s pieteikšanās dati. ${app_name} to nenodrošina. +\nLūgums vispirms notīrīt datus un pēc tam pieteikties vēlreiz citā kontā. + Izdzēst visus šajā ierīcē pašlaik saglabātos datus\? +\nPierakstieties vēlreiz, lai piekļūtu konta datiem un ziņojumiem. + Brīdinājums: šajā ierīcē joprojām tiek glabāti personīgie dati (tostarp šifrēšanas atslēgas). +\n +\nTie ir jānotīra, ja šī ierīce vairs netiks izmantota vai ir vēlēšanās pierakstīties citā kontā. + Pierakstieties, lai atgūtu šifrēšanas atslēgas, kas glabājas tikai šajā ierīcē. Jums tās ir nepieciešamas, lai lasītu visus savus drošos ziņojumus jebkurā ierīcē. + Mājasservera (%1$s) pārvaldītājs ir izrakstījis Tevi no konta %2$s (%3$s). + To var izraisīt dažādi iemesli: +\n +\n• Citā sesijā ir nomainīta parole. +\n +\n• Citā sesijā ir izdzēsta šī sesija. +\n +\n• Servera pārvaldītājs piekļuvi ir padarījis par spēkā neesošu drošības apsvērumu dēļ. + Neizskatās pēc derīgas e-pasta adreses + Nosūta doto ziņojumu kā pārsteigumu + %1$s pie %2$s + Šajā istabā nav multivides + Multivide + Nevarēja apstrādāt kopīgošanas datus + Fails ir pārāk liels, lai tos augšupielādētu. + + %1$s, %2$s un %3$d citi izlasīja + %1$s, %2$s un %3$d citi izlasīja + %1$s, %2$s un %3$d citi izlasīja + + Izveidot jaunu tiešo sarunu + Aizveriet telpas izveides izvēlni… + Atveriet izvēlni izveidot telpu + Atveriet navigācijas atvilktni + Izskatās, ka serveris pārāk ilgi neatbild, to var izraisīt slikts savienojums vai servera kļūda. Lūdzu, pēc brīža mēģiniet vēlreiz. + Identitātes serveris nesniedz nekādu politiku + Slēpt identitātes servera politiku + Parādīt identitātes servera politiku + Atvērt atklāšanas iestatījumus + Meklēt Vārdu + Meklēt pēc vārda, ID vai pasta + Kompresē video %d%% + Kompresē bildi… + Sniedziet atsauksmes + Atsauksmi neizdevās nosūtīt (%s) + Paldies, atsauksme tika veiksmīgi nosūtīta + Ja jums ir kādi papildjautājumi, varat sazināties ar mani + Tu izmanto vietu beta laidienu. Atsauksmes palīdzēs uzlabot nākamos laidienus. Izmantotā sistēma un lietotājvārds tiks pierakstīts, lai mēs varētu pēc iespējas labāk izmantot atsauksmes. + Atsauksmes + Atsauksmes par Telpām + Format: + Url: + Sesijas attēlojamais nosaukums: + Lietotnes attēlojamais nosaukums: + Iesūtīšanas atslēga: + Lietotnes identifikators: + Nav reģistrētu Palaišanas vārtu + Nav iestatīti Palaišanas Noteikumi + Palaišanas Noteikumi + Radīt jaunu Telpu + Izskatās, ka mēģini izveidot savienojumu ar citu mājasserveri. Vai atteikties\? + Paziņot mani priekš + Viedierīcēs netiks saņemti paziņojumi par pieminēšanu un atslēgvārdiem šifrētās istabās. + Istabu atjauninājumi + Ziņas no bota + Istabu ielūgumi + Atslēgvārdi + \@istaba + Šifrētās grupu ziņas + Grupu ziņas + Šifrētas tiešās ziņas + Tiešās ziņas + Mans lietotājvārds + Neizdevās iegūt jaunāko atjaunošanas atslēgu versiju (%s). + + %d jaunu atslēgu tika pievienotas šai sesijai. + %d jauna atslēgu tika pievienotas šai sesijai. + %d jaunas atslēgu tika pievienotas šai sesijai. + + Ja nav zināma atkopšanas paroles vārdkopa, tad var %s. + Iegūst rezerves kopiju… + Izveido atkošanas atslēgu, izmantojot paroles vārdkopu, tas var aizņemt vairākas sekundes. + Izskatās, ka jums jau ir izveidots atslēgas dublējums no citas sesijas. Vai vēlaties to aizstāt ar izveidoto\? + Lūgums izdzēst paroles vārdkopu, ja ir vēlams, lai ${app_name} izveidotu atkopšanas atslēgu. + Nav atrasts derīgs Google Play Services APK. Paziņojumi var nedarboties pareizi. + Marķēšana ir izslēgta. + Marķēšana ir ieslēgta. + Parāda informāciju par lietotāju + Lai salabotu Matrix Apps vadību + Maina Tavu iemiesojumu tikai šajā istabā + Nomaina šīs istabas avatāru + Kad istabas ir jauninātas + Fona ierobežojumi ir ieslēgti lietotnei ${app_name}. +\nDarbs, ko lietotne mēģina veikt, tiks agresīvi ierobežots, kamēr tā atrodas fonā, un tas var ietekmēt paziņojumus. +\n%1$s + Fona ierobežojumi ir izslēgti priekš ${app_name}. Šis tests jāveic, izmantojot mobilos datus (bez WIFI). +\n%1$s + Neizdevās saņemt palaišanu. Iespējams, vajag pārielādēt lietotni. + Lietotne saņem Palaišanu + Lietotne gaida Palaišanu + Pārbaudīt pašpiegādi + [%1$s] +\nŠī kļūda ir ārpus ${app_name} kontroles. Tālrunī nav Google konta. Lūdzu, atveriet kontu pārvaldnieku un pievienojiet Google kontu. + [%1$s] +\nŠī kļūda ir ārpus ${app_name} kontroles. Tā var rasties vairāku iemeslu dēļ. Iespējams, tā darbosies, ja vēlāk mēģināsiet vēlreiz, varat arī pārbaudīt, vai sistēmas iestatījumos nav ierobežota Google Play pakalpojuma datu izmantošana, vai ierīces pulkstenis ir pareizs, vai arī tā var notikt uz atsevišķām sistēmām. + [%1$s] +\nŠī kļūda nav kontrolējama ar ${app_name}, un saskaņā ar Google datiem šī kļūda norāda, ka ierīcē ir pārāk daudz lietotņu, kas reģistrētas FCM. Kļūda rodas tikai gadījumos, kad ir ārkārtīgi liels lietotņu skaits, tāpēc šim nevajadzētu ietekmēt parastu lietotāju. + Izpilda… (%1$d of %2$d) + Atslēgvārds nevar saturēt \'%s\' + Atslēgvārds nevar sākties ar \'.\' + Pievienot jaunu atslēgvārdu + Tavi atslēgvārdi + Paziņot mani par + Cits + Atsauces un Atslēgvārdi + Noklusējuma Paziņojumi + Ieslēgt e-pasta paziņojumus priekš %s + Lai saņemtu e-pasta paziņojumu, lūgums piesaistīt e-pasta adresi Matrix kontam + E-pasta paziņojumi + Nekas + Tikai Atsauces un Atslēgvārdi + Atjaunināt Telpu + Nomainīt Telpas nosaukumu + Ieslēgt Telpas šifrēšanu + Mainīt galveno Telpas adresi + Mainīt Telpas avatāru + Jums nav atļaujas atjaunināt lomas, kas nepieciešamas, lai mainītu dažādas šīs telpas daļas + Izvēlaties lomas, kas nepieciešamas, lai mainītu dažādas Telpas daļas + Skatiet un atjauniniet lomas, kas nepieciešamas, lai mainītu dažādas Telpas daļas. + Telpas atļaujas + Atceļot pievienošanās aizliegumu lietotājam, ļaus viņam atkal pievienoties Telpai. + Aizliedzot lietotājam pievienoties, viņš tiks izmests no šīs Telpas un vairs nevarēs tai pievienoties. + izmetot lietotāju, noņems viņu no šīs Telpas. +\n +\nLai novērstu viņu atkārtotu pievienošanos, jums tā vietā vajadzētu viņiem aizliegt pievienoties. + Beidz zvanu… + Nav atbildes + Lietotājs, kuram zvanījāt, ir aizņemts. + Lietotājs aizņemts + Zvans ar %s + Video zvans ar %s + + %d neatbildētu video zvanu + %d neatbildēts video zvans + %d neatbildēti zvans + + + %d neatbildētu zvanu + %d neatbildēts zvans + %d neatbildēti zvani + + Zvana… + Izvēlēties mājasserveri + Mājasservera API URL + Nevar sasniegt mājasserveri ar URL %s. Lūgums pārbaudīt saiti vai pašrocīgi izvēlieties mājasserveri. + Izmantot pēc noklusējuma un neprasīt atkal + Vienmēr prasīt + Lai sūtītu balss ziņojumus, piešķiriet Mikrofona atļauju. + Telpas + Uztver paziņojumus + Atvērt aptauju + Sniegt atgriezenisko saiti + Piesist augšējā labajā stūrī, lai redzētu iespēju sniegt atgriezenisko saiti. + Tu beidzi balss pārraidi. + %1$s izbeidza balss pārraidi. + Izmantot ierīci, kurā veikta pieteikšanās, lai nolasītu zemāk esošo kvadrātkodu: + Nolasīt zemāk esošo kvadrātkodu ar ierīci, kurā ir notikusi atteikšanās. + Pieteikties ar kvadrātkodu + Jāizmanto ierīces kamera, lai nolasītu citā ierīcē attēlotu kvadrātkodu: + Nolasīt kvadrātkodu + 3 + 2 + 1 + Izmēģināt + + %1$d atlasīti + %1$d atlasīts + %1$d atlasīti + + %1$s nomainīja attēlojamo vārdu uz %2$s + Nav ļauts pievienoties šai istabai + Mainīt vietu + Sākotnējais sinhronizēšanas pieprasījums + Visas tērzēšanas + Izpētīt istabas + Izvērst %s apakšvienumus + + %d servera ACL izmaiņu + %d servera ACL izmaiņa + %d servera ACL izmaiņas + + Sakļaut %s apakšvienumus + Uzsākt tērzēšanu + Izveidot istabu + ${app_name} ir nepieciešams veikt kešatmiņas tīrīšanu, lai būtu pašreizēja, šī iemesla dēļ: +\n%s +\n +\nJāņem vērā, ka šī darbība pārsāknēs lietotni, un tas var aizņemt kādu laiku. + - atsevišķi lietotāji atkal tiek ņemti vērā + Ne tagad + Skatīt pavedienus + Jā, apturēt + Pamest + h + Nākamais + Nepamest neko + Izmēģināt + Uzzināt vairāk + Skatīt istabā + Ievietot pavediena saiti starpliktuvē + Atspējot + Nekad nesūtīt šifrētas ziņas uz neapstiprinātām šīs istabas sesijām. + Izkārtojuma uzstādījumi + Rādīt nesenos + Kārtot pēc + Vienalga atteikties + Iespējot + Atlasīt visu + Noņemt visas atzīmes + Pamest istabu ar norādīto identifikatoru (vai pašreizējo istabu, ja tāda nav) + Pamest visu + Vai tiešām pamest %s\? + Mājasserveris nav sasniedzams. Ja vienalga tiks veikta atteikšanās, šī ierīce netiks izdzēsta no ierīču saraksta, tādēļ nepieciešamības gadījumā tā ir noņemama citā klientā. + Tu šeit esi vienīgais cilvēks. Ja pametīsi, neviens vairs nevarēs pievienoties, ieskaitot Tevi. + Aptauju vēsture + min. + sek. + Turpināt, lai atiestatītu + Skaidrs + Rādīt atlasītājus + Darbība + Jānosūta pirmā ziņa, lai tērzēšanā uzaicinātu %s + Šeit būs redzami jaunie pieprasījumi un uzaicinājumi. + No pavediena + Vēl nav vietu. + Uzaicinājumi + Uztur apspriedes sakārtotas ar pavedieniem + Mājiens: ilgi jāpiespiež ziņa un jāizmanto “%s”. + Rāda visus pavedienus, kuros ir notikusi iesaistīšanās + Kopīgot ekrānu + Izveidot tiešo ziņu tikai pēc pirmās ziņas + Izmēģināt bagātinātu teksta rakstīšanu (vienkārša teksta ievade būs drīzumā) + Nekā jauna. + %1$s, %2$s un citi + Visi pavedieni + Mājasserveris vēl neatbalsta pavedienu uzskaitīšanu. + Rādīt nesenās tērzēšanas sistēmas kopīgošanas izvēlnē + Mani pavedieni + A - Ž + Iespējot jauno izkārtojumu + Lai sarunas pieder Tev! + ${app_name} ir nepieciešama atļauja attēlot paziņojumus. Tajos var tikt attēlotas ziņas, uzaicinājumi utt.. +\n +\nLūgums atļaut piekļuvi nākamajos uznirstošajos logos, lai varētu skatīt paziņojumu. + Ziņas šajā tērzēšanā tiks pilnībā šifrētas. + %1$s un %2$s + Tiklīdz uzaicinātie lietotāji būs pievienojušies ${app_name}, būs iespējams tērzēt, un istaba būs pilnībā šifrēta + Vis vienā drošas tērzēšanas lietotne komandām, draugiem un apvienībām. Jāizveido tērzēšana vai jāpievienojas esošai istabai, lai uzsāktu. + Šifrēšanas konfigurācijā ir kļūmes, tādēļ nevar nosūtīt ziņas. Klikšķināt, lai atvērtu iestatījumus. + Atlasīt istabas pavedienus + Pavediens + Pavedieni + Rāda pašreizējās istabas visus pavedienus + Pavedieni palīdz viegli izsekot un noturēt sarunas par tēmu. + Citi lietotāji tiešajās ziņās un istabās, kurās pievienojies, var redzēt visu Tavu sesiju sarakstu. +\n +\nTas nodrošina viņiem pārliecību, ka viņi tiešām runā ar Tevi, bet tas arī nozīmē, ka viņi var redzēt šeit ievadītās sesijas nosaukumu. + Pavedieni tuvojas Beta 🎉 + Vienkāršots Element ar cilnēm pēc izvēles + Iespējot atliktās tiešās ziņas + Vietas ir jauns veids, kā apkopot istabas un cilvēkus. Jāizveido vieta, lai sāktu. + Šifrēšanas konfigurācijā ir kļūmes, tādēļ nevar nosūtīt ziņas. Lūgums sazināties ar pārvaldītāju, lai atjaunotu šifrēšanu derīgā stāvoklī. + Atlasīt + Apturēt ekrāna kopīgošanu + Jāpārbauda sevi un citus, lai uzturētu drošas tērzēšanas + Atvērt tērzēšanu + Ar ko ir tērzēts visvairāk\? + Iespējot bagātinātu teksta rakstīšanu + E-pasta adrese nav apliecināta, jāpārbauda iesūtne + Izpētīt istabas + Pievienot esošas istabas + Vietas ir jauns veids kā apkopot istabas un cilvēkus. + Pārvaldīt istabas + Pievienot esošas istabas un vietas + Šajā vietā nav istabu + Pavedieni Beta + Dažas istabas var būt paslēptas, jo tās ir privātas un ir nepieciešams uzaicinājums. + Visas istabas, kurās ir dalība, tiks rādītas sākumsadaļā. + 🔒 Drošības iestatījumos ir iespējota tikai apliecinātu sesiju šifrēšana visās istabās. + Mēs tuvojamies publiskai pavedienu Beta izlaišanai. +\n +\nTā kā mēs tam gatavojamies, mums ir jāveic dažas izmaiņas: pirms šī brīža izveidoti pavedieni tiks attēloti kā parastas atbildes. +\n +\nŠī būs tikai vienreizēja pāreja, jo pavedieni tagad ir Matrix specifikācijā. + Pievienot istabas + Pārvaldīt istabas un vietas + Sākumsadaļā rādīt visas istabas + Dažas istabas var būt paslēptas, jo tās ir privātas un ir nepieciešams uzaicinājums. +\nNav atļaujas pievienot istabas. + Šī sesija neatbalsta šifrēšana, tādēļ to nevar apliecināt. +\n +\nNebūs iespējams piedalīties istabās, kurās ir iespējota šifrēšana, kad tiks izmantota šī sesija. +\n +\nVislabākajai drošībai un privātumam ir ieteicams izmantot Matrix klientus, kas atbalsta šifrēšanu. + Vietas ir jauns veids, kā apkopot istabas un cilvēkus. Pievienot esošu istabu vai izveidot jaunu var ar apakšējā labajā stūrī esošo pogu. + Pavedieni palīdz uzturēt sarunas par tēmu un ir viegli izsekojami. %sPavedienu iespējošana atsvaidzinās lietotni. Dažiem kontiem tas var aizņemt vairāk laika. + Pavedieni Beta + %1$s un %2$s + Palīdzēt uzlabot ${app_name} + Atskaņot kustīgos laikjoslas attēlus, tiklīdz tie ir redzami + ${app_name} ir nepieciešama atļauja, lai parādītu paziņojumus. +\nLūgums piešķirt atļauju. + + %1$s un %2$d citu + %1$s un %2$d cits + %1$s un %2$d citi + + Iespējot tiešo kopīgošanu + Istaba ir pamesta. + Ir veikta izrakstīšanās no sesijas. + Pieņemamas izmantošanas nosacījums + Mājasserveris pagaidām nenodrošina pavedienus, tādēļ šī iespēja var nebūt uzticama. Dažas pavedienu ziņas var nebūt uzreiz pieejamas. %sVienalga iespējot pavedienus\? + Konts + Automātiski atskaņot kustīgos attēlus + Atgadījās kļūda paziņojumu uzstādījumu atjaunošanā. Lūgums mēģināt vēlreiz. + Piešķirt atļauju + Galapunkta reģistrācija + Galapunkts ir veiksmīgi reģistrēts mājasserverī. + Neizdevās mājasserverī reģistrēt galapunkta pilnvaru: +\n%1$s + Crypto laidiens + Konta informācija ir pārvaldāma atsevišķi %1$s. + Vietas %1$s attēls + Istabas %1$s attēls + Lietotāja %1$s profila attēls + Iespējots: + Atbildēt pavedienā + Sesijas identifikators: + Rezerves kopijai ir derīgs šī lietotāja paraksts. + Atjauno datus… + Kaut kas nogāja greizi. Lūgums pārbaudīt tīkla savienojumu un mēģināt vēlreiz. + Bezsaistē + Klātbūtne + šeit + Diemžēl šī istaba netika atrasta. +\nLūgums vēlāk mēģināt vēl.%s + Komanda \"%s\" tika atpazīta, bet to nevar izmantot pavedienos. + Aiziet + PIEVIENOT IZVĒLES IESPĒJU + Šis pavediens jau tiek skatīts. + Palīdzi mums atrast nepilnības un uzlabot ${app_name} daloties ar anonīmiem lietojuma datiem. Lai izprastu, kā cilvēki izmanto vairākas ierīces, mēs izveidosim nejaušu identifikatoru, ko kopīgo ierīces. +\n +\nVisus mūsu nosacījumus var izlasīt %s. + Mēs <b>nedalāmies</b> ar informāciju ar trešajām pusēm + Šo jebkurā brīdī var izslēgt iestatījumos + Mājasservera nosacījumi + Identitātes servera nosacījumi + Ja iespējots, citiem lietotājiem konts būs redzams kā bezsaistē esošs pat tad, kad tiek izmantota lietotne. + ⚠ Šajā istabā ir neapliecinātas ierīces, tās nevarēs atšifrēt nosūtītās ziņas. + Izvēlēties fonta izmēru + Iestatīt automātiski + Izvēlēties pašrocīgi + Atvērt izstrādātāja rīku skatu + Skatīt istabā + Izlasē + Cilvēki + Izveidot izvēles iespējas + Visas + Nelasītās + Mēs <b>neveicam</b> nekādu konta datu ierakstīšanu un profilēšanu + ${app_name} nosacījumi + Izmantot ierīces noklusējumu + Šis serveris nesniedz nekādus nosacījumus. + Atbild uz %s + Citē + Izvēles iespēja %1$d + + Ir nepieciešamas vismaz %1$s izvēles iespēju + Ir nepieciešama vismaz %1$s izvēles iespēja + Ir nepieciešamas vismaz %1$s izvēles iespējas + + Labo + Profila birka: + Lai vienkāršotu ${app_name}, cilnes tagad ir izvēles. Tās ir pārvaldāmas ar izvēlni augšējā labajā stūrī. + Trešo pušu bibliotēkas + Pavedienu Beta atsauksme + Droša ziņapmaiņa. + Ziņapmaiņa Tavai komandai. + Pavedieni šobrīd ir izstrādē ar jaunām, aizraujošām drīzumā sagaidāmām iespējām, piemēram, uzlabotiem paziņojumiem. Mums patiktu saņemt atsauksmes. + Droša un neatkarīga saziņa, kas dod tāda paša līmeņa privātumu kā aci pret aci saruna paša mājās. + Vienā reizē var uzaicināt tikai vienu e-pasta adresi + Kontakti ir privāti. Lai atklātu lietotājus no kontaktiem, mums ir nepieciešama atļauja nosūtīt saziņas informāciju uz identitātes serveri. + Pilnīga šifrēšana, un tālruņa numurs nav nepieciešams. Bez reklāmām un datu iegūšanas. + Sūtīt e-pasta adreses un tālruņa numurus uz %s + Pievienoties esošam serverim\? + Savienoties ar serveri + Citi var atrast Tevi ar %s + Kāda ir servera adrese\? + Element Matrix Services (EMS) ir noturīgs un uzticams izvietošanas pakalpojums ātrai, drošai un reāllaika saziņai. Vairāk var uzzināt <a href=\"${ftue_ems_url}\">element.io/ems</a> + Ievadīt e-pasta adresi + Jāseko norādēm, kas tika nosūtītas uz %s + Paroles atiestatīšana + Jāseko norādēm, kas tika nosūtītas uz %s + Izskatās labi. + Profilu jebkurā brīdī var atjaunot iestatījumos + Saglabāt un turpināt + Atjaunot šifrēšanu + Starpierīču parakstīšana ir iespējota +\nPrivātās atslēgas ierīcē. + Starpierīču parakstīšana ir iespējota +\nAtslēgas ir uzticamas. +\nPrivātās atslēgas nav zināmas + Starpierīču parakstīšana ir iespējota. +\nAtslēgas nav uzticamas + Starpierīču parakstīšana nav iespējota + Saņemt palīdzību ${app_name} izmantošanā + Sistēmas iestatījumi + Izveidot jaunu sarunu vai istabu + ${app_name} ir lielisks arī darba vietā. Tam uzticas visdrošākās pasaules apvienības. + Draugi un ģimene + Kur atradīsies sarunas + Kur atrodas sarunas + Laipni lūdzam atpakaļ! + %s nosūtīs apliecinājuma saiti + Jāpārbauda e-pasts. + Jāizvēlas jauna parole + Atiestatīt paroli + Atteikties visās ierīcēs + Atkārtoti nosūtīt e-pastu + Lietotājvārds / e-pasta adrese / tālruņa numurs + Sesijas + Atvērt vietu sarakstu + Kopienas + Aiziet! + Pāriet uz sākumsadaļu + Labot + Palīdzība un atbalsts + BETA + Laidieni + Lietotne atjaunināta + Juridiski + Tu uzraugi. + Vēl nav pārliecības\? %s + E-pasta adrese + Aizmirsta parole + Attēlojamais vārds + To vēlāk var mainīt + Lūgums sazināties ar pārvaldītāju, lai atjaunotu šifrēšanu derīgā stāvoklī. + Apstiprināt tālruņa numuru + Šo saiti nevar atvērt: kopienas tika aizstātas ar vietām + Uzsāka balss pārraidi + Izlaist šo jautājumu + Apliecina ar drošo atslēgu vai vārdkopu… + Šifrēšana ir kļūdaini uzstādīta. + Palīdzība + Izvēlies, kur tiks glabātas sarunas, sniedzot vadību un neatkarību. Savienots ar Matrix. + Izlaist šo soli + Pielāgot profilu + Sazināties + Aizvietot attēlojamā vārda krāsu + Kopīgoja atrašanās vietu + Izveidot kontu + Vai esi cilvēks\? + Lūgums izlasīt %s noteikumus un nosacījumus + Lai atklātu esošus kontaktus, ir nepieciešams nosūtīt kontaktinformāciju (e-pasta adreses un tālruņa numurus) uz identitātes serveri. Privātumam pirms sūtīšanas mēs pārveidojam datus ar jaucējkodu. + Jābūt vismaz 8 rakstzīmēm + Servera nosacījumi + Atkārtoti nosūtīt kodu + BETA + Man jau ir konts + Servera URL + Jauna parole + Nolasīt kvadrātkodu + Mēs palīdzēsim savienoties + Atrašanās vieta + Balss apraide + Komandas + Apsveicam! + Jāatlasa serveris + Vēlies izvietot pats savu serveri\? + Kods tika nosūtīts uz %s + Apliecināt e-pasta adresi + Jāizvēlas attēlojamais vārds + Nebija iespējams apliecināt šo ierīci + Vai + Atiestatīt paziņojumu veidu + Jāpārliecinās, ka tajā ir vismaz 8 rakstzīmes. + Ievadīt tālruņa numuru + Tālruņa numurs + E-pasts netika saņemts\? + Laiks vārdam pievienot seju + Kopīgoja atrašanās vietu tiešraidē + Starpierīču parakstīšana + %s nepieciešams apliecināt kontu + %s nepieciešams apliecināt kontu + Apstiprinājuma kods + Vai piekrīti šīs informācijas nosūtīšanai\? + Kas ir servera adrese\? Tas ir kā mājas visiem datiem + Sniegt atsauksmi + Izvērsti žurnāla ieraksti palīdzēs izstrādātājiem, nodrošinot vairāk ierakstu, kad tiek sūtīts RageShake. Pat ja iespējots, lietotne neieraksta ziņu saturu vai jebkādu citu privātu informāciju. + Konts %s tikai izveidots + Pievienot profila attēlu + Izveidot kontu + Pieturēt, lai ierakstītu, atlaist, lai nosūtītu + Aptauja + pievieno (╯°□°)╯︵ ┻━┻ pirms vienkārša teksta ziņas + Iespējot izvērstus žurnāla ierakstus. + Kamēr lietotājs neuzticas šai sesijai, tajā nosūtītās ziņas tiks iezīmētas ar brīdinājumiem. + Šis kvadrātkods izskatās bojāts. Lūgums mēģināt apliecināt citā veidā. + Gaida lietotājus pievienojamies ${app_name} + Izveido SSSS atslēgu no atkopšanas atslēgas + Glabā atslēgas rezerves kopēšanas atslēgu SSSS + Jāievada tikai sev zināma drošības vārdkopa, kas tiek izmantota, lai noslēpumus serverī padarītu drošus. + Publicēt izveidotās identitātes atslēgas + Iegūst līknes atslēgu + Atslēgu pieprasījumi + Izveido drošu atslēgu no paroles vārdkopas + Ja atcelsi tagad, vari zaudēt šifrētās ziņas un datus, ja pazaudēsi piekļuvi pieteikšanās informācijai. +\n +\nIr arī iespējams uzstādīt drošo rezerves kopēšanu un iestatījumos pārvaldīt atslēgas. + Pārbaude rezerves atslēgu (%s) + Lūgums sazināties ar mājasservera pārvaldītāju, lai uzzinātu vairāk + Iknakts būvējums + Netika atrasts apliecināšanas pieprasījums. Tas var būt atcelts vai to jau apstrādā cita sesija. + Sinhronizē pašparakstīšanas atslēgu + Izdzēst visas kļūdainās ziņas + Šifrēšana ir nepareizi uzstādīta + Nebūs iespējams piekļūt šifrēto ziņu vēsturei. Jāatiestata Drošo ziņu rezerves kopēšana un apliecinājuma atslēgas, lai sāktu no jauna. + Iegūt jaunāko būvējumu (piezīme: var būt sarežģījumi ar pieteikšanos) + Lūgums ņemt vērā: šī ir izmēģinājuma iespēja, kas izmanto pagaidu īstenojumu. Tas nozīmē, ka nebūs iespējams izdzēst atrašanās vietu vēsturi, un prasmīgi lietotāji varēs redzēt to pat tad, kad tiks pārtraukta atrašanās vietas tiešraides kopīgošana ar šo istabu. + Šī istaba darbojas ar istabu laidienu %s, ko šis mājasserveris ir atzīmējis kā nepastāvīgu. + Drošas ziņapmaiņas uzstādīšanā atgadījās drošības nepilnība. Kaut kas no šī var būt iesaistīts drošības pārkāpumā: mājasserveris; Interneta savienojums(i); ierīce(s); + Mājasserveris nenodrošina pieteikšanos ar kvadrātkodu. + Izveido SSSS atslēgu no paroles vārdkopas (%s) + Apliecinātas sesijas ir jebkur, kur tiek izmantots šis konts pēc paroles vārdkopas ievadīšanas vai identitātes apstiprināšanas ar citu apliecinātu sesiju. +\n +\nTas nozīmē, ka ir pieejamas visas nepieciešamās atslēgas, lai atslēgtu šifrētās ziņas un apstiprinātu citiem lietotājiem, ka šī sesija ir uzticama. + Apliecināt ar citu ierīci + Jāapliecina sava identitāte, lai piekļūtu šifrētajām ziņām un pierādītu citiem savu identitāti. + Izgūt pārbaudes ierakstus + Tika nosūtīts apliecinājuma pieprasījums. Jāatver viena no savām citām sesijām, lai apstiprinātu un uzsāktu apliecināšanu. + Pārbaude rezerves atslēgu + Ja nav zināma atslēgas rezerves kopēšanas paroles vārdkopa, tad var %s. + Šifrēts izdzēstā ierīcē + Izskatās, ka Tavs mājasserveris vēl nenodrošina vietas + Izdzēst ierakstu + Krātuvē nevar atrast noslēpumus + Atslēgas rezerves kopēšanas atkopšanas atslēga + jāizmanto atslēgas rezerves kopēšanas atkopšanas atslēga + Jāievada atslēgas rezerves kopēšanas paroles vārdkopa, lai turpinātu. + Izveido SSSS atslēgu no paroles vārdkopas + Lūgums ievadīt atkopšanas atslēgu + Tā nav derīga atkopšanas atslēga + Atkļūdot + Iestata atslēgu rezerves kopēšanu + Sinhronizē lietotāja atslēgu + Sinhronizē galveno atslēgu + Iestata atkopi. + Atiestatīt atslēgas + Uzsākt starpierīču parakstīšanu + Vēlreiz jāievada drošības vārdkopa, lai to apstiprinātu. + Jāievada tikai sev zināma slepena vārdkopa un jāizveido atslēga rezerves kopēšanai. + Izmantot drošības vārdkopu + Atsākt + Nosaka SSSS noklusējuma atslēgu + Šī iestatījuma iespējošana pievieno FLAG_SECURE visām darbībām. Jāpārsāknē lietotne, lai iedarbotos izmaiņas. + Slepenā tastatūra + Mājasserveris nepieņem lietotājvārdu, kas sastāv tikai no cipariem. + Lūgums turpināt tikai tad, ja ir pārliecība, ka ir pazaudētas visas citas ierīces un drošības atslēga. + Šīs šifrētās ziņas īstumu šajā ierīcē nevar nodrošināt. + ${app_name} iOS +\n${app_name} Android + Pieprasīt, lai tastatūra neatjauno nekādus personalizētos datus, piemēram, rakstīšanas vēsturi un vārdnīcu, vadoties pēc tā, kas ir rakstīts sarunās. Jāņem vērā, ka atsevišķas tastatūras šo iestatījumu var neievērot. + ${app_name} Web +\n${app_name} Desktop + Neizdevās piekļūt drošajai krātuvei + Izmantot atkopšanas atslēgu + Piespiež pašreizējās izejošās kopuma sesijas šifrētā istabā atmešanu + Jāatlasa sava atkopšanas atslēga vai jāievada tā pašrocīgi ierakstot vai ielīmējot no starpliktuves + Apliecināšanas atslēgu atiestatīšana ir neatgriezeniska. Pēc atiestatīšanas nevarēs piekļūt iepriekšējām šifrētajām ziņā, un visi draugi, kuri iepriekš ir Tevi apliecinājuši, redzēs drošības brīdinājumus līdz atkārtotai apliecināšanai. + Drošā ziņapmaiņa tika uzlabota jaunākajā atjauninājumā. Lūgums atkārtoti apliecināt ierīci. + Tās ir jāpārskata, lai nodrošinātu, ka konts ir drošs + Tev ir neapliecinātas sesijas + Neizdevās uzstādīt starpierīču parakstīšanu + Sasaiste neizdevās. + Jāapstiprina identitāte ar šīs pieteikšanās apliecināšanu, tādējādi nodrošinot piekļuvi šifrētajām ziņām. + + Uzaicinājums tika nosūtīts %1$s + Uzaicinājumi tika nosūtīti %1$s un vēl vienam + Uzaicinājumi tika nosūtīti %1$s un vēl %2$d + + Mēs nevarējām uzaicināt lietotājus. Lūgums pārbaudīt uzaicināmos lietotājus un mēģināt vēlreiz. + Šis identitāšu serveris ir novecojis. ${app_name} nodrošina tikai API V2. + Mēs nevarējām izveidot tiešās saziņas istabu. Lūgums pārbaudīt uzaicināmos lietotājus un mēģināt vēlreiz. + Šai ziņai nevar piekļūt, jo sūtītājs ar nolūku nenosūtīja atslēgas + Nav pašreizējas sasaistes ar šo identifikatoru. + Pašpiegādes paziņojumi + Saņemt pašpiegādes paziņojumus šajā sesijā. + Nav sniegta lietotāja piekrišana. + %1$s aizliedza piekļuvi + Adrešu grāmata ir tukša + Drošā rezerves kopija + Izmantot drošības atslēgu + Izveidot drošības atslēgu, ko glabāt kādā drošā vietā, piemēram, paroļu pārvaldniekā vai seifā. + Sava drošības atslēga ir jāglabā kādā drošā vietā, piemēram, paroļu pārvaldniekā vai seifā. + Šai ziņai nevar piekļūt, jo sūtītājs Tevi ir norobežojis + Šai ziņai nevar piekļūt, jo sūtītājs neuzticas Tavai sesijai + Neizdevās atsaukt lietotāja piekļuves aizliegumu + Pašpiegādes paziņojumi ir atspējoti + Jāpārskata iestatījumi, lai iespējotu pašpiegādes paziņojumus + Saglabāt atkopšanas atslēgu + Uzstādīt + \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-nn/strings.xml b/library/ui-strings/src/main/res/values-nn/strings.xml new file mode 100644 index 0000000000..37b159f21f --- /dev/null +++ b/library/ui-strings/src/main/res/values-nn/strings.xml @@ -0,0 +1,541 @@ + + + %s si innbjoding + %1$s inviterte %2$s + %1$s inviterte deg + %1$s kom inn + %1$s forlot rommet + %1$s sa nei til innbjodingi + %1$s sparka %2$s + %1$s slapp %2$s inn att + %1$s stengde %2$s ute + %1$s tok attende %2$s si innbjoding + %1$s byta avataren sin + %1$s sette visingsnamnet sitt som %2$s + %1$s byta visingsnamnet sitt frå %2$s til %3$s + %1$s tok burt visingsnamnet sitt (%2$s) + %1$s gjorde emnet til: %2$s + %1$s gjorde romnamnet til: %2$s + %s starta ei videosamtala. + %s starta ein talesamtale. + %s tok røyret. + %s la på røyret. + %1$s gjorde den framtidige romsoga synleg for %2$s + alle rommedlemmar, frå då dei vart invitert inn. + alle rommedlemmar, frå då dei kom inn. + alle rommedlemmar. + kven som heldst. + (avataren vart au byta) + %1$s tok burt romnamnet + %1$s tok burt romemnet + %1$s inviterte %2$s til rommet + %1$s sa ja til innbjodingi til %2$s + ** Fekk ikkje til å dekryptera: %s ** + Avsendareiningi hev ikkje sendt oss nyklane fyr denna meldingi. + Fekk ikkje til å senda meldingi + Noko gjekk gale med Matrix + Epostadresse + Telefonnummer + Rominnbjoding + %1$s og %2$s + Tomt rom + %s oppgraderte rommet. + %1$s forlot rommet. Grunn: %2$s + Lyst tema + Mørkt tema + Svart tema + Lyttar etter hendingar + Bråkete varsel + Stille varsel + Innstillingar + Feilrapport + Send eit klistremerke + Lastar… + Greitt + Avbryt + Lagra + Forlat + Send + Siter + Last ned + Del + Seinare + Permanent lenkje + Vis kjelde + Vis den dekrypterte kjelda + Slett + Gje nytt namn + Rapporter innhaldet + eller + Inviter + Logg av + Talesamtale + Videosamtale + Merk alle som lesne + Hurtigsvar + Opna + Lat att + Kopier til utklippstavla + Stadfesting + Åtvaring + Yndlingar + Folk + Rom + Filtrer romnamn + Invitasjonar + Låg prioritering + Samtalar + Berre Matrix-kontaktar + Ingen treff + Rom + Send loggar + Send krasjrapportar + Send skjermbilde + Rapporter om feil + Beskriv feilen. Kva gjorde du\? Kva forventa du skulle hende\? Kva hendte\? + Om mogleg, skriv beskrivelsen på engelsk. + Beskriv problemet ditt her + For å diagnostisere feil, vil loggar frå denne klienten bli sendt med i feilrapporten. Denne feilrapporten inklusiv loggar, skjermbilete vil ikkje vere offentleg. Fjern avkryssinga om du berre vil sende teksten ovanfor: + Det verkar som du ristar mobilen i vonbrot. Ønskjer du å opne skjerm for feilrapport \? + Programmet krasja sist gong. Ønskjer du å opne skjerm for feilrapport \? + Rist i sinne for å rapportera feil + Feilrapporten vart sendt + Fekk ikkje til å senda feilrapporten (%s) + Framgang (%s%%) + Gå inn i romet + Brukarnamn + Logg ut + Heimtenar-URL + Søk + Start talesamtale + Start videosamtale + Send tale + Er du sikker på at du vil starta ein ny talesamtale\? + Er du sikker på at du vil starta ein ny videosamtale\? + Send filer + Send klistremerke + Ta bilete eller video + Ta bilete + Ta video + Du har enno ingen klistremerkepakker skrudde på. Legg til nokre no\? + Beklagar, det vart ikkje funne nokon ekstern applikasjon som kan fullføre handlinga. + Logg inn + Send inn + Feil brukarnamn og/eller passord + Dette ser ikkje ut som ei gyldig e-postadresse + Denne e-postadressa er allereie i bruk. + Gløymt passord\? + Heimtenaren ynskjer å stadfeste at du ikkje er ein robot + Fekk ikkje til å stadfesta e-postadressa: sjå til at du klikka på lenken i e-posten + Skriv inn ein gyldig URL + Feilformatert JSON + Innehaldt ikkje ein gyldig JSON + For mange førespurnader vart sendt + Etterspør på nytt krypteringsnøkklar frå dei andre einingane dine. + Start ${app_name} på ein annan eining som kan dekryptere meldingen, slik at den kan sende nøkklane til denne sesjonen + + %d endring i medlemskap + %d endringar i medlemskap + + Original + Stor + Middels + Liten + Ring + Koplar saman samtalar… + Samtalen er avslutta + Innkommande videosamtale + Innkomande talesamtale + Samtalen er i gang… + Den andre parten tok ikkje samtalen. + Info + ${app_name} treng tilgang til mikrofonen din for å utføra talesamtalar. + ${app_name} treng tilgang til kameraet og mikrofonen din for å utføra videosamtalar. +\n +\nGjer vel og gjev tilgang på sprettvindauget som kjem for å utføra samtalen. + JA + NEI + Gå fram + Ta vekk + Bli med + Avvis + Medlemsoversikt + Hopp til første uleste melding. + + %d medlem + %d medlem + + Forlat rom + Er du sikker på at du vil forlata rommet\? + Folk + Inviter + Steng ute + Slepp inn att + Gøym alle meldingar frå denne brukaren + Syn alle meldingar frå denne brukaren + Nemn + Du vil ikkje kunne angre denne endringa, då du promoterar brukaren til å ha same tilgangsnivå som deg sjølv. +\nEr du sikker på dette\? + Er du trygg på at du vil stengja brukaren ute frå samtala\? + %s skriv… + %1$s og %2$s skriv… + %1$s, %2$s og andre skriv… + Du har ikkje løyve til å senda meldingar i dette rommet + + %d ny melding + %d nye meldingar + + Stol på + Ikkje stol på + Logg ut + Ignorer + Fingeravtrykk (%s): + Fekk ikkje til å stadfesta identiteten på den eksterne tenaren. + Detta kan vere teikn på at tilkoplinga blir avlytta eller at telefonen ikkje stolar på sertifikatet den eksterne tenaren brukar. + Om administratoren av tenaren har informert at dette er forventa, pass på at fingeravtrykket under samsvarar med fingeravtrykket han gav deg. + Sertifikatet har forandra seg frå det som var stolt på av mobilen din. Dette er SÆRS UVANLEG. Det er tilrådd å IKKJE GODKJENNA dette nye sertifikatet. + Sertifikatet har endra seg frå eit som tidlegare var stole på, til eit som ikkje er det. Det kan henda at tenaren har fornya sertifikatet. Snakk med administrator for å få det forventa fingeravtrykket. + Godkjenn BERRE sertifikatet viss tenaradministratoren har publisert eit fingeravtrykk som samsvarar med det over. + Søk + Filtrer rommedlemmar + Ingi treff + Alle meldingar + Legg til på heimskjermen + Profilbilete + Visingsnamn + Legg til e-postadresse + Legg til telefonnummer + Vis informasjon om appen i systeminnstillingane + Informasjon om applikasjonen + Varselljod + Skru på varslingar for denne kontoen + Aktiver varslingar for denne sesjonen + Meldingar som inneheld visingsnamnet mitt + Meldingar som inneheld brukarnamnet mitt + Meldingar i ein-og-ein-samtalar + Meldingar i gruppesamtalar + Når eg blir invitert til eit rom + Invitasjon til samtale + Meldingar frå botar + Køyr ved oppstart + Bakgrunnsamstilling + Samstillingsfyrespurnaden fekk tidsavbrot + Forsinkelse mellom kvar synkronisering + Versjon + olm versjon + Vilkår for bruk + Informasjon frå tredjepart + Opphavsrett + Personvern + Tøm buffer + Tøm mediabuffer + Behald mediefiler + Brukarinnstillingar + Varsel + Ignorerte brukarar + Anna + Avansert + Kryptografi + Varselmål + Lokale kontaktar + Kontakttilgang + Land for telefonbok + Startskjerm + Fest rom med tapte varslingar + Fest rom med uleste meldingar + Skru URL-førehandsvisingar i tekstfeltet på + Vis tidsspunkt for alle meldingar + Vis tidspunkt i 12-timarsformat + Rist ved nemning + Førehandsvis medium før avsending + Deaktiver konto + Deaktiver kontoen min + Statistikk + Send statistikkdata + ${app_name} samlar anonym statistikk inn for å forbetra applikasjonen. + ID + Offentleg namn + Oppdater offentleg namn + Sist sedd + %1$s @ %2$s + Stadfesting + Logga inn som + Heimtenar + Identitetstenar + Brukargrensesnitt + Språk + Vel språk + Ver venleg og sjekk eposten din og klikk på lenkja han inneheld. Når det er gjort, klikk gå fram. + E-postadressa er allereie i bruk + Telefonnummeret er allereie i bruk. + Forandr passordet + Gjeldande passord + Nytt passord + Fekk ikkje til å oppdatera passordet + Passordet ditt vart oppdatert + Vis alle meldingane frå %s\? Merk at denne handlinga gjer at applikasjonen startar på nytt og kan taka litt tid. + Vel eit land + 3 dagar + 1 veke + 1 månad + For alltid + Emne + Romhistoria si lesbarheit + Kven kan lesa historia? + Kven som helst + Berre medlemmar (frå då innstillinga er vald) + Berre medlemmar (frå då dei vart bodne inn) + Berre medlemmar (frå då dei kom inn) + Utestengde brukarar + Avansert + Rommet sin interne ID + Eksperimentelle funksjonar + Desse funksjonane er under utprøving og uventa vanskar kan dukka opp. Bruk med omhug. + Set som hovudadresse + Fjern som hovudadresse + Preg + Noko gjekk gale med dekrypteringa + Offentleg namn + Økt-ID + Sesjonsnøkkel + Eksporter E2E-romnøkklar + Eksporter romnøkklar + Hent nøkklane ut til ei lokal fil + Hent ut + Skriv passetning inn + Stadfest passetninga + Importer E2E-romnøkklar + Importer romnøkklar + Hent nøkklane inn frå ei lokal fil + Hent inn + Krypter berre til godkjende sesjonar + Aldri send krypterte meldingar til ikkje-godkjende sesjonar frå denne sesjonen + IKKJE Godkjend + Godkjend + Godkjenn + For å godkjenna at denne sesjonen er til å stola på, ver venleg og snakk med eigaren på ein anna måte (t.d. ansikt til ansikt eller på telefon) og spør han om nøkkelen han ser i Brukarinnstillingane for denne sesjonen samsvarar med nøkkelen under: + Viss det samsvarer, klikk Verifiser-knappen under. Viss det ikkje gjer det, avlyttar nokon andre denne sesjonen og du bør sannsynlegvis svarteliste den. I framtida vil denne verifikasjonsprosessen bli meir forbetra. + Vel ein romkatalog + Heimtenar-URL + Alle rom på %s-tenaren + + %d ulest varsla melding + %d uleste varsla meldingar + + + %d rom + %d rom + + %1$s i %2$s + Skriftstorleik + Bitteliten + Liten + Vanleg + Stor + Større + Størst + Enorm + Er du sikker på at du vil slette widgeten frå dette rommet\? + + %d widget på + %d widgetar på + + Klarte ikkje å laga widget. + Fekk ikkje til å senda førespurnad. + Tilgangsnivået må vere eit positivt heiltal. + Du er ikkje i dette rommet. + Du har ikkje tillating til å gjera det i dette rommet. + Vantande room_id i førespurnaden. + Vantande brukar_id i førespurnaden. + Rommet %s er ikkje synleg. + Ein krevd parameter vantar. + Legg til Matrix-applikasjonar + Du la til den nye sesjonen \'%s\', som etterspør krypteringsnøkklar. + Den ikkje-verifiserte sesjonen din \'%s\' etterspør krypteringsnøkklar. + Start verifikasjon + Noko gjekk gale med påbodet + Påbodet er uattkjend: %s + Viser handling + Stengjer brukarar med den gjevne IDen ute + Slepp utestengde brukarar med den gjevne IDen inn at + Definer tilgangsnivå for ein brukar + AvOPar brukarar med den gjevne IDen + Byd brukarar med den gjevne IDen inn til det noverande rommet + Vert med i rommet med det gjevne aliaset + Forlat rom + Set romemnet + Sparkar brukarar med gjeven ID + Forandrar visingsnamnet ditt + På/Av markdown + For å ordne opp i Matrix-App-administrasjon + Av + Bråket + Kryptert melding + Laga + Heim + Rom + Bodne inn + Du vart sparka frå %1$s av %2$s + Du var stengd ute frå %1$s av %2$s + Grunnlag: %1$s + Alle %s-rom på Matrix + Bruk det innebygde kameraet + Avatar + For å halda fram med å bruka %1$s-heimtenaren må du sjå over og seia deg einig i vilkåret og føresetnader. + Sjå over no + Deaktiver konto + Dette gjer at brukaren din vert ubrukeleg til evig tid. Du kjem ikkje til å kunna logga inn, og ingen andre kjem til å kunna melde seg inn med den gamle brukar-IDen din. Brukaren din forlét òg alle rom han er i, og brukardetaljane dine vil verta fjerna frå identitetstenaren. Denne handlinga kan ikkje gjerast om. + +Å avliva brukaren din gjer i utgangspunktet ikkje at vi gløymer meldingane du har send. Viss du vil at vi skal gløyma meldingane dine, ver venleg og kryss av i firkanten under. + +Meldingssynlegheit på Matrix liknar på epost. At vi gløymer meldingane dine tyder at meldingar du har send ikkje vil verta delt med nye, ikkje-innmeldte brukarar, men brukare som er meldt på som allereie har tilgang til desse meldingane vil fortsatt kunne sjå kopien deira. + Ver venleg og gløym alle meldingane eg har send når brukarkontoen min vert deaktivert (Åtvaring: dette gjer at framtidige brukarar ikkje får eit fullstendig oversyn av samtalene) + Deaktiver konto + Ver venleg og skriv passordet ditt inn. + Rommet har verta erstatta og er ikkje aktivt lenger + Samtala går vidare her + Rommet er ein vidareføring av ei anna samtale + Klikk her for å sjå gamle meldingar + Systemvarsel + + %d valt + %d valde + + kontakt tenesteadministratoren din + Heimtenaren har truffe ei av ressursgrensene sine so nokre brukarar vil ikkje kunna logga inn. + Heimtenaren har forbigått ei av ressursgrensene sine. + Heimtenaren har truffe den Månadlege Grensa si for Aktive Brukarar, so nokre brukarar vil ikkje kunna logga inn. + Heimtenaren har truffe den Månadlege Grensa si for Aktive Brukarar. + Ver venleg og %s for å heva grensa. + Ver venleg og %s for å halda fram med å bruka tenesten. + Aksepter + Feil + Hopp over + Ferdig + Ignorer + Sikker på at du vil logga ut\? + Merk som lest + Venligast sjå over og godta retningslinjene til heimtenaren: + Oppringingar + Bruk standard ${app_name}-ringetone for innkommande samtalar + Ringetone for innkommande samtalar + Vel ringetone for samtalar: + Ein videosamtale pågår… + Spark + Avanserte varslingsinnstillingar + Prioritet på varsel ut ifrå hendingar + Løys problem med varslingar + Diagnostikk for feilsøking + Køyr testar + Køyrer… (%1$d av %2$d) + Det grunnleggjande er i orden. Om du framleis ikkje får varsel, send inn ei feilmelding så vi kan undersøke dette. + Ein eller fleire testar har feila. Prøv føreslegne løysing(ar). + Éin eller fleire prøvar gjekk galne. Gjer vel og send inn ei feilmelding so me kann sjå nærare på det. + Systeminnstillingar. + Varsel er skrudde på i systeminnstillingane. + Varsel er skrudde av i systeminnstillingane. +\nGjer vel og sjå på systeminnstillingane. + Opna innstillingane + Brukarinnstillingar. + Varsel er skrudde på fyr brukaren din. + Varsel er skrudde av fyr brukaren din. +\nGjer vel og sjå på brukarinnstillingane. + Skru på + Sesjonsinnstillingar. + Varslingar er aktivert for denne sesjonen. + Varslingar er deaktivert for denne sesjonen. +\nSjekk ${app_name}-innstillingane. + Skru på + Sikkerheitskopi av nøkkel + Bruk sikkerheitskopiering av nøkkel + Om du loggar ut no, vil dine krypterte meldingar gå tapt + Sikkerheitskopi av nøklar pågår, viss du loggar ut no vil du miste tilgang til krypterte meldingar. + For å hindre tap av krypterte meldingar, bør sikkerheitskopiering av nøklar (Secure Key Backup) vere aktivert i alle sesjonar der du er innlogga. + Eg ønsker ikkje dei krypterte meldingane mine + Sikkerheitskopierar nøklar… + Er du sikker \? + Sikkerheitskopier + Du vil miste tilgang til dine krypterte meldingar, med mindre nøklane dine er sikkerheitskopierte før utlogging. + Ingen + Trekk tilbake + Koble frå + Avvis + Logg inn med SSO (single sign-on) + Dette er ikkje ei gyldig Matrix-tenaradresse + Klarar ikkje å nå ein heimetenar på denne URL\'en, sjekk at den er korrekt + Integrasjonar + Bruk ein integrasjonshandterar (Integration Manager) for å handtere botar, bruer, tillegg og klistermerkepakker. +\nIntegrasjonshandterarar hentar konfigurasjonsdata, og kan endra tillegg, senda rominvitasjonar og sette tilgangsnivå på vegne av deg. + Handtering av kryptografiske nøkklar + Anna informasjon frå tredjepart + Meldingar med denne brukaren er ende-til-ende kryptert, dei kan ikkje bli lesne av tredje part. + Set opp bråkete-varsel + Still inn samtale-varsel + Set opp stille-varsel + Set opp LED-farge, vibrasjon eller lyd… + Vis bli-med/forlat hendelsar + Invitasjonar, utkastingar og utestengingar gjeld ikkje dette. + Opna i nettlesar + Hentar sikkerheitskopiversjon… + Versjon + Matrix SDK versjon + Innstillingar + Tryggleik og personvern + Tale og video + Hjelp og om + Vis skjulte hendelsar i historikken + Aktiver swipe-for-å-svare i historikken + Forlat rommet + Uleste meldingar + Etter aktivering, så kan ikkje kryptering bli deaktivert. + Sikkerheit + Få meir info + Rominnstillingar + Forlat rom + Administratorar + Moderatorar + Tilpassa + Invitasjonar + Brukarar + Administrator i %1$s + Moderator i %1$s + Tilpassa (%1$d) i %2$s + Denne økta klarde ikkje å dele denne verifikasjonen med dine andre økter. +\nVerifikasjonsdata er lagra lokalt, og vil bli delt i ein framtidig versjon av programmet. + Historikk + Formater meldingar skrivne med Markdown-syntaksen før dei blir sendt. Dette gjer at ein kan t.d. bruke stjerne(*) for å vise tekst i kursiv. + Bruk Markdown-formatering + Still inn korleis e-postadresser og telefonnummer er knytta til Matrix-kontoen din + Still inn korleis kontoen din kan bli oppdaga. + E-postadresser og telefonnummer + Synlegheit + Avanserte innstillingar + Avanserte og tilpassa innstillingar + Generelt + Spel av + Dette telefonnummeret er allereie definert. + Skru HD av + Front + Trådlaus hovudtelefon + Høgtalar + Vel eining for lyd + ${app_name}-samtalen feila + Ingen fleire resultat + Suksess + Legg til + Legg på + Aksepter + Du kan ikkje starta ein talesamtale med deg sjølv, vent til at andre deltakarar aksepterer invitasjonen + Du kan ikkje starta ein talesamtale med deg sjølv + Møter nyttar Jitsi sine sikkerheit- og tilgangsreglar. Alle medlemmar av rommet vil sjå ei invitasjonslenkje så lenge møtet pågår. + Start møte med lyd + Start møte med video + Du har ikkje lov til å starta ein samtale + Du har ikkje lov til å starta ein samtale i dette rommet + Du har ikkje lov til å starta ein konferansesamtale + Du har ikkje lov til å starta ein konferansesamtale i dette rommet + Start samtale + Nullstill + Folk + Folk + \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-pl/strings.xml b/library/ui-strings/src/main/res/values-pl/strings.xml index 603265bd26..f4d89b0ebd 100644 --- a/library/ui-strings/src/main/res/values-pl/strings.xml +++ b/library/ui-strings/src/main/res/values-pl/strings.xml @@ -377,7 +377,7 @@ %1$s w %2$s Czy na pewno chcesz usunąć widżet z tego pokoju? Nie można utworzyć widżetu. - Nie udało się wysłać prośby. + Nie udało się wysłać żądania. Poziom uprawnień musi być liczbą dodatnią. Nie jesteś w tym pokoju. Nie masz uprawnień, aby zrobić to w tym pokoju. @@ -391,7 +391,7 @@ Błąd polecenia Nierozpoznane polecenie: %s Głośne - Strona startowa + Strona główna Pokoje Zaproszeni Dezaktywuj konto @@ -609,7 +609,7 @@ Importowanie kluczy… Odblokuj Historię Wprowadź klucz odzyskiwania - Kopia Przywrócona %s ! + Kopia przywrócona %s! dodano jeden nowy klucz do tej sesji. dodano %d nowe klucze do tej sesji. @@ -661,7 +661,7 @@ Pomoc i o aplikacji Wszystkie wiadomości (hałaśliwy) Wszystkie wiadomości - Tylko wspomnienia + Tylko wzmianki Wycisz Ustawienia Nie ignorujesz żadnych użytkowników @@ -801,9 +801,9 @@ Użyj kopii zapasowej klucza aby odblokować historię zaszyfrowanych wiadomości użyj klucza odzyskiwania Użyj Klucza Odzyskiwania aby odblokować historię zaszyfrowanych wiadomości - Kopia zapasowa nie może zostać zdeszyfrowana za pomocą tego hasła: proszę upewnij się, czy wprowadzone hasło jest poprawne. + Kopia zapasowa nie mogła zostać rozszyfrowana za pomocą tego Hasła: upewnij się, że wprowadzono prawidłowe Hasło bezpieczeństwa. Przywracanie kopii zapasowej: - Kopia zapasowa nie może zostać zdeszyfrowana za pomocą tego klucza odzyskiwania: proszę upewnij się, czy wprowadzony klucz odzyskiwania jest poprawny. + Kopia zapasowa nie mogła zostać rozszyfrowana za pomocą tego Klucza: upewnij się, że wprowadzono prawidłowy Klucz bezpieczeństwa. Kopia zapasowa klucza nie jest aktywna dla tej sesji. Twoje klucze nie są będą zapisywane w kopii zapasowej od tej sesji. Kopia zapasowa posiada sygnaturę od nieznanej sesji z ID %s. @@ -1127,7 +1127,7 @@ %d aktywnych sesji %d aktywnych sesji - Zweryfikuj te urządzenie + Weryfikuj to urządzenie Otwórz obecną sesję i użyj jej do zweryfikowania obecnej, przyznając jej dostęp do zaszyfrowanych wiadomości. Zweryfkuj Zweryfikowano @@ -1240,7 +1240,7 @@ Wpisz frazę bezpieczeństwa którą znasz tylko ty, będzie wykorzystywana do zabezpieczania sekretów na twoim serwerze. Przechowuj swój Klucz Bezpieczeństwa w chronionym miejscu takim jak menadżer haseł lub sejf. Zapisz Klucz Bezpieczeństwa - Użyj Frazy Bezpieczeństwa + Użyj hasła bezpieczeństwa Użyj klucza bezpieczeństwa Zabezpiecza przed utratą dostępu do zaszyfrowanych wiadomości poprzez zapisanie kluczy szyfrujących na twoim serwerze. Włącz aparat @@ -1384,7 +1384,7 @@ Niektóre znaki nie są dozwolone Podaj adres pokoju Ten adres jest już w użyciu - Możesz aktywować tę opcję jeżeli pokój będzie wykorzystywany jedynie do współpracy z wewnętrznymi zespołami na Twoim serwerze domowym. Ta opcja nie może być zmieniona później. + Możesz aktywować tę opcję, jeżeli pokój będzie wykorzystywany jedynie do współpracy z wewnętrznymi zespołami na Twoim serwerze domowym. Nie będzie można zmienić tej opcji. Zablokuj wszystkich nie będących członkami %s przed dołączeniem do tego pokoju Ukryj zaawansowane Pokaż zaawansowane @@ -1545,13 +1545,13 @@ Konfigurowanie odzyskiwania. Nie zweryfikujesz %1$s (%2$s) jeżeli przerwiesz w tym momencie. Zacznij ponownie w ich profilu użytkownika. ROZUMIEM - Fraza Bezpieczeństwa - Ustaw Frazę Bezpieczeństwa + Hasło bezpieczeństwa + Ustaw hasło bezpieczeństwa Wybierz nazwę użytkownika. Potwierdź swoją tożsamość poprzez zweryfikowanie tego logowania aby uzyskać dostęp do zaszyfrowanych wiadomości. Potwierdź swoją tożsamość poprzez zweryfikowanie tego logowania przy pomocy którejś z pozostałych sesji w celu przyznania dostępu do zaszyfrowanych wiadomości. - Interaktywna weryfikacja z wykorzystaniem emotikon - Zweryfikuj logowanie + Zweryfikuj interaktywnie za pomocą emoji + Weryfikuj logowanie Zweryfikuj nowe logowanie do swojego konta: %1$s Zaszyfrowano przez urządzenie niezweryfikowane Niezaszyfrowane @@ -1564,7 +1564,7 @@ Zaczniesz ponownie od zera, bez historii, bez wiadomości, bez zaufanych urządzeń bądź użytkowników Jeżeli zresetujesz wszystko Wykonaj tę akcję wyłącznie wówczas gdy nie masz żadnego innego urządzenia na którym możesz zweryfikować bieżące urządzenie. - Zresetuj wszystko + Resetuj wszystko Zapomniałeś(-łaś) albo straciłeś wszystkie opcje odzyskiwania\? Zresetuj wszystko Nie udało się uzyskać dostępu do bezpiecznego magazynu Sprawdzanie klucza kopii zapasowej @@ -1818,7 +1818,7 @@ Uprawnienia pokoju Odblokowanie użytkownika pozwoli mu na ponowne dołączenie do tej przestrzeni. Zablokowanie użytkownika usunie go z tego miejsca i uniemożliwi ponowne dołączenie. - Ten pokój jest prywatny. Nie będziesz w stanie dołączyć bez zaproszenia. + Ten pokój nie jest publiczny. Nie będziesz w stanie dołączyć bez zaproszenia. Zakańczanie połączenia… Brak odpowiedzi Użytkownik, do którego zadzwoniłeś jest zajęty. @@ -1947,15 +1947,15 @@ Wszystkie pokoje, w których jesteś będą pokazywane na ekranie domowym. Pokaż wszystkie pokoje w ekranie domowym Zarządzaj pokojami oraz przestrzeniami - Oznacz jako nie sugerowana - Oznacz jako sugerowana + Oznacz jako nie sugerowane + Oznacz jako sugerowane Sugerowane Zarządzaj pokojami Szukasz kogoś , kto nie jest w %s\? %s Cię zaprasza Zostałeś zaproszony Przestrzenie są nową metodą na grupowanie razem wielu pokoi i osób. - Dodaj przestrzeń do jakiejkolwiek przestrzeni którą zarządzasz. + Dodaj przestrzeń do jakiejkolwiek przestrzeni, którą zarządzasz. Dodaj istniejące przestrzenie Dodaj istniejące pokoje Dodaj istniejące pokoje i przestrzenie @@ -1974,7 +1974,7 @@ Dołącz pomimo to Dołącz do przestrzeni Utwórz przestrzeń - Na razie pomiń + Pomiń na razie Dołącz do mojej przestrzeni %1$s %2$s Nie będą częścią %s Tylko do tego pokoju @@ -1983,13 +1983,13 @@ Udostępnij link Zaproś przez nazwę użytkownika lub email Zaproś przez email - Aktualnie jesteś tu tylko ty. %s będzie jeszcze lepszą przestrzenią, gdy dołączą do niej inni. + Aktualnie jesteś tu tylko Ty. %s będzie jeszcze lepsze, gdy dołączą inni. Zaproś do %s Zaproś osoby Zaproś osoby do Twojej przestrzeni Opis Tworzenie przestrzeni… - Losowy + Losowe Ogólny Kim są Twoi znajomi \? Stworzymy dla nich pokoje. Możesz też dodać następne w późniejszym etapie. @@ -2000,9 +2000,9 @@ Prywatna Otwarta dla każdego, najlepsza dla społeczności Publiczna - Prywatna przestrzeń dla Ciebie i Twoich znajomych - Ja i moi znajomi - Prywatna przestrzeń do organizacji Twoich pokojów + Prywatna przestrzeń dla Ciebie i Twoich kolegów z drużyny + Ja i moi koledzy z drużyny + Prywatna przestrzeń do organizacji Twoich pokoi Tylko ja Upewnij się, że odpowiednie osoby mają dostęp do %s. Z kim pracujesz\? @@ -2069,7 +2069,7 @@ Przekaż opinię Nie udało się przesłać opinii (%s) Dziękujemy, Twoja opinia została wysłana - Pozwalam na kontakt ze mną w razie dodatkowych pytań + Możesz się ze mną skontaktować, jeśli masz jakiekolwiek pytania Używasz przestrzeni w wersji beta. Ta opinia pomoże nam w tworzeniu kolejnych wersji. Twoja platforma i nazwa użytkownika zostaną odnotowane, abyśmy mogli w pełni wykorzystać Twoje sugestie. Prześlij opinię o przestrzeniach Stwórz nową przestrzeń @@ -2089,7 +2089,7 @@ Twój serwer Wersja pokoju Inne przestrzenie lub pokoje, których możesz nie znać - Przestrzeń, o której wiesz, że zawiera ten pokój + Przestrzeń, którą znasz, że zawiera ten pokój Zdecyduj kto może odnaleźć i dołączyć do tego pokoju. Dotknij, aby edytować przestrzenie Wybierz przestrzenie @@ -2110,7 +2110,7 @@ Usuń nagranie Opinia użytkownika Synchronizacja klucza samopodpisującego (Self Signing key) - Weryfikacja ręczna poprzez tekst + Zweryfikuj ręcznie za pomocą tekstu lub innego klienta Matrix z krzyżową weryfikacją nowych sesji logowania Nie masz uprawnień do zmiany poziomu pokoju Oczekiwanie na historię szyfrowania @@ -2210,7 +2210,7 @@ Rozmowa głosowa zakończona • %1$s Oddzwoń Nie udało się skonfigurować logowania krzyżowego - Aktualizacja spowoduje utworzenie pokoju w nowej wersji. Wszystkie obecne wiadomości zostaną w zarchiwizowanym pokoju. + Aktualizacja spowoduje utworzenie pokoju w nowej wersji. Wszystkie bieżące wiadomości zostaną zarchiwizowane w tym pokoju. Nagrywanie wiadomości głosowej Zatrzymaj nagrywanie Wstrzymaj wiadomość głosową @@ -2242,7 +2242,7 @@ Dodaj do danej przestrzeni Stwórz przestrzeń Edytuj treść - Poznaj stan pokoju + Przeglądaj stan pokoju Narzędzia deweloperskie Nieobecny Pokój publiczny @@ -2295,7 +2295,7 @@ Nie udostępniamy informacji podmiotom trzecim Nie zbieramy i nie profilujemy danych użytkownika tutaj - Pomóż nam znaleźć błędy i ulepszyć ${app_name} poprzez udostępnianie anonimowych danych użytkowania. Aby lepiej zrozumieć jak użytkownicy wykorzystują wiele urządzeń wygenerujemy losowy identyfikator dzielony pomiędzy Twoimi urządzeniami. + Pomóż nam zidentyfikować problemy i ulepszyć ${app_name}, udostępniając anonimowe dane o użytkowaniu. Aby zrozumieć, w jaki sposób użytkownicy korzystają z wielu urządzeń, wygenerujemy losowy identyfikator dzielony pomiędzy Twoimi urządzeniami. \n \nWięcej informacji %s. Pomóż usprawnić ${app_name} @@ -2311,7 +2311,7 @@ Posiadam już konto Bezpieczna komunikacja. Masz wszystko pod kontrolą. - Przejmij swoje konwersacje. + Bądź właścicielem swoich konwersacji. By odkryć istniejące kontakty, musisz najpierw przesłać swoje dane kontaktowe (adresy e-mail i numer telefonu) do serwera tożsamości. Przed wysłaniem Twoje dane zostaną zaszyfrowane w celu zachowania prywatności. Uzyskaj pomoc w korzystaniu z ${app_name} Nie masz uprawnień by dołączyć do tego pokoju @@ -2350,7 +2350,7 @@ Uwaga: aplikacja zostanie uruchomiona ponownie Włącz wiadomości w wątkach Upewnij się, że odpowiednie osoby mają dostęp do firmy %s. Więcej osób możesz zaprosić później. - Wyślij niestandardowe zdarzenie stanowe + Wyślij własne wydarzenie stanu Wyślij zdarzenie stanowe Zdarzenia stanowe Zawartość zdarzenia @@ -2583,7 +2583,7 @@ min Pokoje w przestrzeni Dalej - Dostawca + Metoda Znaleziono %d dostawcę. Znaleziono %d dostawców. @@ -2632,7 +2632,7 @@ Kod został wysłany do %s Potwierdź swój numer telefonu Wyloguj wszystkie urządzenia - Zresetuj hasło + Resetuj hasło Upewnij się, że ma 8 lub więcej znaków. Wybierz nowe hasło Nowe hasło @@ -2670,7 +2670,7 @@ MSC3061: Współdzielenie kluczy pokoju dla wcześniejszych wiadomości Ten kod QR wygląda na niepoprawny. Spróbuj zweryfikować przy użyciu innej metody. Dostęp do wcześniejszych zaszyfrowanych wiadomości nie będzie możliwy. Zresetuj bezpieczną kopię zapasową wiadomości oraz klucze weryfikacyjne by zacząć od nowa. - Nie udało się zweryfikować tego urządzenia + Nie można zweryfikować tego urządzenia Zapoznaj się z warunkami i zasadami serwera %s Jaki jest adres twojego serwera\? Miejsce na twoje konwersacje @@ -3040,7 +3040,7 @@ Sprawdź, by upewnić się że Twoje konto jest bezpieczne Zaszyfrowano za pomocą usuniętego urządzenia Akceptowalna polityka użytkowania - Jak tylko zaproszeni użytkownicy dołączą do ${app_name}, będziesz mógł czatować w pokoju zaszyfrowanym end-to-end + Jak tylko zaproszeni użytkownicy dołączą do ${app_name}, będziesz mógł czatować w pokoju szyfrowanym end-to-end Czekanie aż użytkownicy dołączą do ${app_name} Żądanie weryfikacji nie zostało znalezione. Mogło zostać anulowane lub obsłużone przez inną sesję. Wznów @@ -3048,7 +3048,7 @@ Zdobądź najnowszą wersję (uwaga: mogą wystąpić problemy z logowaniem) Nightly build Zweryfikuj swoją tożsamość, aby uzyskać dostęp do wiadomości zaszyfrowanych i udowodnić swoją tożsamość innym. - Zweryfikuj za pomocą innego urządzenia + Weryfikuj innym urządzeniem Weryfikuję z Klucza bezpieczeństwa lub Frazy… Rozpoczął transmisje głosową Możesz zaprosić tylko jeden e-mail jednocześnie @@ -3068,4 +3068,21 @@ %1$d zaznaczono %1$d zaznaczono + %1$s zmienił swoją wyświetlaną nazwę na %2$s + Zdjęcie profilowe użytkownika %1$s + Awatar pokoju %1$s + Awatar przestrzeni %1$s + Bezpieczne wysyłanie wiadomości zostało usprawnione z najnowszą aktualizacją. Zweryfikuj swoje urządzenie ponownie. + Dopóki ten użytkownik nie zweryfikuje tej sesji, wysłane wiadomości będą zawierać ostrzeżenie. + Zaktualizowano aplikację + Wyloguj mimo to + Nie można skontaktować się z serwerem domowym. Jeśli mimo to się wylogujesz, urządzenie nie zostanie usunięte z listy urządzeń. Usuń je za pomocą innego klienta. + Nie można znaleźć profili dla poniższych ID Matrix. Czy chcesz rozpocząć czat mimo to\? +\n +\n%s + Zaproś mimo to + Rozpocznij czat mimo to + Nie można znaleźć profili dla poniższych ID Matrix. Czy chcesz zaprosić je mimo to\? +\n +\n%s \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-pt-rBR/strings.xml b/library/ui-strings/src/main/res/values-pt-rBR/strings.xml new file mode 100644 index 0000000000..ee6431ea3f --- /dev/null +++ b/library/ui-strings/src/main/res/values-pt-rBR/strings.xml @@ -0,0 +1,2912 @@ + + + Convite de %s + %1$s convidou %2$s + %1$s convidou você + %1$s entrou na sala + %1$s saiu da sala + %1$s recusou o convite + %1$s removeu %2$s + %1$s desbaniu %2$s + %1$s baniu %2$s + %1$s desfez o convite para %2$s + %1$s mudou seu avatar + %1$s definiu seu nome de exibição para %2$s + %1$s mudou seu nome de exibição de %2$s para %3$s + %1$s removeu seu nome de exibição (era %2$s) + %1$s mudou o tópico para: %2$s + %1$s mudou o nome da sala para: %2$s + %s começou uma chamada de vídeo. + %s começou uma chamada de voz. + %s atendeu a chamada. + %s encerrou a chamada. + %1$s tornou o histórico futuro da sala visível para %2$s + todos os membros da sala, a partir do ponto que foram convidados. + todos os membros da sala, a partir do ponto que entraram. + todos os membros da sala. + qualquer pessoa. + (avatar mudou também) + %1$s removeu o nome da sala + %1$s removeu o tópico da sala + %1$s enviou um convite para %2$s para se juntar à sala + %1$s aceitou o convite para %2$s + ** Incapaz de decriptar: %s ** + O dispositivo do/da enviador(a) não nos enviou as chaves para esta mensagem. + Não foi possível enviar mensagem + Erro de Matrix + Endereço de email + Número de telefone + Convite de Sala + %1$s e %2$s + Sala vazia + Seu convite + %1$s criou a sala + Você criou a sala + Você convidou %1$s + Você entrou na sala + Você saiu da sala + Você recusou o convite + Você removeu %1$s + Você desbaniu %1$s + Você baniu %1$s + Você desfez o convite para %1$s + Você mudou seu avatar + Você definiu seu nome de exibição para %1$s + Você mudou seu nome de exibição de %1$s para %2$s + Você removeu seu nome de exibição (era %1$s) + Você mudou o tópico para: %1$s + %1$s mudou o avatar da sala + Você mudou o avatar da sala + Você mudou o nome da sala para: %1$s + Você começou uma chamada de vídeo. + Você começou uma chamada de voz. + %s enviou dados para configurar a chamada. + Você enviou dados para configurar a chamada. + Você atendeu a chamada. + Você encerrou a chamada. + Você tornou o histórico futuro da sala visível para %1$s + %s fez o upgrade desta sala. + Você fez o upgrade desta sala. + Você removeu o nome da sala + Você removeu o tópico da sala + %1$s removeu o avatar da sala + Você removeu o avatar da sala + Você enviou um convite para %1$s para se juntar à sala + %1$s revogou o convite para %2$s para se juntar à sala + Você revogou o convite para %1$s para se juntar à sala + Você aceitou o convite para %1$s + %1$s adicionou widget %2$s + Você adicionou widget %1$s + %1$s removeu widget %2$s + Você removeu widget %1$s + %1$s modificou widget %2$s + Você modificou widget %1$s + Admin + Moderador(a) + Default + Personalizado (%1$d) + Personalizado + Você mudou o nível de poder de %1$s. + %1$s mudou o nível de poder de %2$s. + %1$s de %2$s para %3$s + Sincronização inicial: +\nImportando conta… + Sincronização inicial: +\nImportando criptografia + Sincronização inicial: +\nImportando salas + Sincronização inicial: +\nCarregando suas conversas +\nSe você entrou em muitas salas, isso pode demorar + Sincronização inicial: +\nImportando salas para as quais foi convidado + Sincronização inicial: +\nImportando salas das quais saiu + Sincronização inicial: +\nImportando dados de conta + Enviando mensagem… + Convite de %1$s. Motivo: %2$s + Seu convite. Motivo: %1$s + %1$s convidou %2$s. Motivo: %3$s + Você convidou %1$s. Motivo: %2$s + %1$s convidou você. Motivo: %2$s + %1$s entrou na sala. Motivo: %2$s + Você entrou na sala. Motivo: %1$s + %1$s saiu da sala. Motivo: %2$s + Você saiu da sala. Motivo: %1$s + %1$s rejeitou o convite. Razão: %2$s + Você rejeitou o convite. Razão: %1$s + %1$s expulsou %2$s. Razão: %3$s + Você expulsou %1$s. Razão: %2$s + %1$s desbaniu %2$s. Razão: %3$s + Você desbaniu %1$s. Razão: %2$s + %1$s baniu %2$s. Razão: %3$s + Você baniu %1$s. Razão: %2$s + %1$s aceitou o convite para %2$s. Razão: %3$s + Você aceitou o convite para %1$s. Razão: %2$s + %1$s retirou o convite de %2$s. Razão: %3$s + Você retirou o convite de %1$s. Razão: %2$s + + %1$s adicionou %2$s como um endereço para esta sala. + %1$s adicionou %2$s como endereços para esta sala. + + + Você adicionou %1$s como um endereço para esta sala. + Você adicionou %1$s como endereços para esta sala. + + + %1$s removeu %2$s como um endereço para esta sala. + %1$s removeu %2$s como endereços para esta sala. + + + Você removeu %1$s como um endereço para esta sala. + Você removeu %1$s como endereços para esta sala. + + %1$s adicionou %2$s e removeu %3$s como endereços para esta sala. + Você adicionou %1$s e removeu %2$s como endereços para esta sala. + %1$s definiu o endereço principal para esta sala para %2$s. + Você definiu o endereço principal para esta sala para %1$s. + %1$s removeu o endereço principal para esta sala. + Você removeu o endereço principal para esta sala. + %1$s tem permitido visitantes se juntarem à sala. + Você tem permitido visitantes se juntarem à sala. + %1$s tem prevenido visitantes de se juntarem à sala. + Você tem prevenido visitantes de se juntarem à sala. + %1$s ativou encriptação ponta-a-ponta. + Você ativou encriptação ponta-a-ponta. + %1$s ativou encriptação ponta-a-ponta (algoritmo irreconhecido %2$s). + Você ativou encriptação ponta-a-ponta (algoritmo irreconhecido %1$s). + Você tem prevenido visitantes de se juntarem à sala. + %1$s tem prevenido visitantes de se juntarem à sala. + Você tem permitido visitantes se juntarem aqui. + %1$s tem permitido visitantes se juntarem aqui. + Você saiu. Motivo: %1$s + %1$s saiu. Motivo: %2$s + Você entrou. Motivo: %1$s + %1$s entrou. Motivo: %2$s + Você revogou o convite para %1$s + %1$s revogou o convite para %2$s + Você convidou %1$s + %1$s convidou %2$s + Você fez o upgrade aqui. + %s fez o upgrade aqui. + Você tornou as mensagens futuras visíveis para %1$s + %1$s tornou as mensagens futuras visíveis para %2$s + Você saiu da sala + %1$s saiu da sala + Você entrou + %1$s entrou + Você criou a discussão + %1$s criou a discussão + Sala vazia (era %s) + + %1$s, %2$s, %3$s e %4$d outro + %1$s, %2$s, %3$s e %4$d outros + + %1$s, %2$s, %3$s e %4$s + %1$s, %2$s e %3$s + 🎉 Todos os servidores estão banidos de participar! Esta sala não pode mais ser usada. + Nenhuma mudança. + • Servidores correspondendo com literais de IP estão agora banidos. + • Servidores correspondendo com literais de IP estão agora permitidos. + • Servidores correspondendo com %s foram removidos da lista de permitidos. + • Servidores correspondendo com %s estão agora permitidos. + • Servidores correspondendo com %s foram removidos da lista de banimento. + • Servidores correspondendo com %s estão agora banidos. + Você mudou as LCAs do servidor para esta sala. + %s mudou as LCAs do servidor para esta sala. + • Servidores correspondendo com literais de IP estão banidos. + • Servidores correspondendo com literais de IP estão permitidos. + • Servidores correspondendo com %s estão permitidos. + • Servidores correspondendo com %s estão banidos. + Você definiu as LCAs do servidor para esta sala. + %s definiu as LCAs do servidor para esta sala. + Você mudou os endereços alternativos para esta sala. + %1$s mudou os endereços alternativos para esta sala. + + Você removeu o endereço alternativo %1$s para esta sala. + Você removeu os endereços alternativos %1$s para esta sala. + + + %1$s removeu o endereço alternativo %2$s para esta sala. + %1$s removeu os endereços alternativos %2$s para esta sala. + + + Você adicionou o endereço alternativo %1$s para esta sala. + Você adicionou os endereços alternativos %1$s para esta sala. + + + %1$s adicionou o endereço alternativo %2$s para esta sala. + %1$s adicionou os endereços alternativos %2$s para esta sala. + + Você mudou os endereços para esta sala. + %1$s mudou os endereços para esta sala. + Você mudou os endereços principal e alternativos para esta sala. + %1$s mudou os endereços principal e alternativos para esta sala. + Configurações + Aceitar + Declinar + Desligar + OK + Cancelar + Salvar + Sair + Enviar + Citar + Compartilhar + Mais Tarde + Permalink + Visualizar Fonte + Visualizar Fonte Decriptada + Deletar + Renomear + Reportar Conteúdo + ou + Convidar + Fazer signout + Chamar por Voz + Chamar por Vídeo + Marcar tudo como lido + Resposta rápida + Abrir + Fechar + Copiado para clipboard + Confirmação + Aviso + Favoritos + Pessoas + Salas + Filtrar nomes de salas + Convites + Prioridade baixa + Conversas + Contatos de Matrix somente + Nenhum resultado + Salas + Enviar logs + Enviar crash logs + Enviar screenshot + Reportar bug + Por favor descreva o bug. O que você fez\? O que você esperava que acontecesse\? O que na verdade aconteceu\? + Descreva seu problema aqui + A fim de diagnosticar problemas, logs deste cliente vão ser enviados com este reporte de bug. Este reporte de bug, incluindo os logs e o screenshot, não será visível publicamente. Se você prefere somente enviar o texto acima, por favor desmarque: + Você parece estar agitando o telefone em frustração. Você gostaria de abrir a tela de reporte de bug\? + O reporte de bug tem sido enviado com sucesso + O reporte de bug falhou para ser enviado (%s) + Progresso (%s%%) + O aplicativo tem crashado da última vez. Você gostaria de abrir a tela de reporte de crash\? + Juntar-Se a Sala + Nome de Usuária(o) + Fazer Signout + URL de Servidorcasa + Pesquisar + Começar Chamada de Voz + Começar Chamada de Vídeo + Enviar arquivos + Tirar foto ou vídeo + Fazer login + Submeter + Nome de usuária(o) e/ou senha incorreta(s) + Isto não parece com um endereço de email válido + Este endereço de email já está definido. + Esqueceu senha\? + Este servidorcasa gostaria de assegurar que você não é um robô + Falha para verificar endereço de email: assegure-se que clicou no link no email + Por favor entre um URL válido + JSON malformado + Não continha JSON válido + Requisições demais tem sido enviadas + Original + Grande + Médio + Pequeno + Chamada conectando… + Chamada terminada + Chamada de Vídeo Entrante + Chamada de Voz Entrante + Chamada Em Progresso… + O lado remoto falhou para atender. + Informação + ${app_name} precisa de permissão para acessar seu microfone para performar chamadas de áudio. + ${app_name} precisa de permissão para acessar sua câmera e seu microfone para performar chamadas de vídeo. +\n +\nPor favor permita acesso no próximo pop-up para ser capaz de fazer a chamada. + SIM + NÃO + Continuar + Remover + Juntar-se + Rejeitar + Pular para não-lida(s) + Sair de sala + Você tem certeza que você quer sair da sala\? + Mensagens Diretas + Convidar + Banir + Desbanir + Ignorar + Designorar + Mencionar + Você não vai ser capaz de desfazer esta mudança já que você está promovendo a(o) usuária(o) para ter o mesmo nível de poder que você. +\nVocê tem certeza\? + %s está digitando… + %1$s & %2$s estão digitando… + %1$s & %2$s & outras(os) estão digitando… + Você não tem permissão para postar nesta sala. + Confiar + Não confiar + Fazer logout + Ignorar + Impressão digital (%s): + Não foi possível verificar identidade de servidor remoto. + Isto poderia significar que alguém está maliciosamente interceptando seu tráfico, ou que seu celular não confia no certificado provido pelo servidor remoto. + Se o/a administrador(a) de servidor tem dito que isto é esperado, assegure que a impressão digital abaixo corresponde com a impressão digital provida por ele(a). + O certificado tem mudado de um que era confiado por seu telefone. Isto é ALTAMENTE INCOMUM. É recomendado que você NÃO ACEITE este novo certificado. + O certificado tem mudado de um previamente confiado para um que não é confiado. O servidor pode ter renovado seu certificado. Contacte o/a administrador(a) de servidor para a impressão digital esperada. + Somente aceite o certificado se o/a administrador(a) de servidor tem publicado uma impressão digital que corresponde com a acima. + Pesquisar + Filtrar membros de sala + Nenhum resultado + Imagem de Perfil + Nome de Exibição + Adicionar endereço de email + Adicionar número de telefone + Mostrar info de aplicativo nas configurações de sistema. + Info de aplicativo + Habilitar notificações para esta conta + Habilitar notificações para esta sessão + Mnsgns em chats um-a-um + Mnsgns em chats de grupo + Quando eu sou convidada(o) para uma sala + Convites de chamada + Mensagens enviadas por bot + Sincronização no background + Timeout de requisição de sinc + Delay entre casa Sinc + Versão + Versão de olm + Termos & condições + Notas de terceiros + Copyright + Política de privacidade + Limpar cache + Configurações de usuária(o) + Notificações + Usuárias(os) ignoradas(os) + Outras + Avançadas + Criptografia + Alvos de Notificação + Contatos locais + Permissão de acesso a contatos + País de livro de telefone + Dsiplay home + Fixar salas com notificações perdidas + Fixar salas com mensagens não-lidas + ID + Nome Público + Atualizar Nome Público + Visto por último + %1$s @ %2$s + Autenticação + Feito login como + Servidorcasa + Servidor de identidade + Por favor cheque seu email e clique no link que ele contém. Uma vez que isto for feito, clique em continuar. + Este endereço de email já está em uso. + Este número de telefone já está em uso. + Mudar senha + Senha atual + Senha nova + Falha para atualizar senha + Sua senha tem sido atualizada + Mostrar todas as mensagens de %s\? + Escolha um país + Tópico + Legibilidade de Histórico de Sala + Quem pode ler o histórico\? + Qualquer pessoa + Membros somente (desde o ponto no tempo de seleção desta opção) + Membros somente (desde que eles foram convidados) + Membros somente (desde que eles entraram) + Usuárias(os) banidas(os) + Avançadas + ID interno desta sala + Labs + Estes são recursos experimentais que podem quebrar de maneiras inesperadas. Use com cuidado. + Definir como endereço principal + Des-definir como endereço principal + Erro de decriptação + Nome público + ID de sessão + Chave de sessão + Exportar chaves de sala E2E + Exportar chaves de sala + Exportar as chaves para um arquivo local + Exportar + Entrar frasepasse + Confirmar frasepasse + Importar chaves de sala E2E + Importar chaves de sala + Importar as chaves de um arquivo local + Importar + Encriptar para sessões confirmadas somente + Nunca enviar mensagens encriptadas para sessões não-verificadas desta sessão. + Não Verificada + Verificada + Verificar + Confirme ao comparar o seguinte com as Configurações de Usuária(o) em sua outra sessão: + Se não correspondem, a segurança de sua comunicação pode estar comprometida. + Selecionar um diretório de salas + Nome de servidor + Todas as salas em servidor %s + Todas as salas nativas de %s + Começar em boot + Limpar cache de mídia + Manter mídia + Mostrar timestamps para todas as mensagens + Interface de usuária(o) + Língua + Escolher língua + 3 dias + 1 semana + 1 mês + Para sempre + Tema + Tamanho de fonte + Minúsculo + Pequeno + Normal + Grande + Maior + Ainda maior + Gigantesco + Tema Claro + Tema Escuro + Tema Preto + À escuta por eventos + Notificações barulhentas + Notificações silenciosas + Reporte de bug + Carregando… + Você tem certeza que você quer começar uma chamada de voz\? + Você tem certeza que você quer começar uma chamada de vídeo\? + Tirar foto + Tirar vídeo + Chamada + Banir usuária(o) vai removê-la(o) desta sala e preveni-la(o) de se juntar de novo. + Todas as mensagens + Adicionar a tela de Início + Som de notificação + Mnsgns contendo meu nome de exibição + Mnsgns contendo meu nome de usuária(o) + Previsualização de URL inline + Mostrar timestamps em formato de 12 horas + Vibrar ao mencionar um/uma usuário(a) + Analítica + Você tem certeza que você quer deletar o widget desta sala\? + Incapaz de criar widget. + Falha para enviar requisição. + Nível de poder deve ser um inteiro positivo. + Você não está nesta sala. + Você não tem permissão para fazer isso nesta sala. + room_id faltando em requisição. + user_id faltando em requisição. + Sala %s não está visível. + Adicionar apps Matrix + Usar câmera nativa + Você adicionou uma nova sessão \'%s\', que está requisitando chaves de encriptação. + Sua sessão não-verificada \'%s\' está requisitando chaves de encriptação. + Começar verificação + Erro de comando + Comando irreconhecido: %s + Desativada + Barulhenta + Mensagem encriptada + Criar + Home + Salas + Convidada(o) + Você foi expulsa(o) de %1$s por %2$s + Você foi banida(o) de %1$s por %2$s + Razão: %1$s + + %d membro + %d membros + + + %d nova mensagem + %d novas mensagens + + + %d mudança de filiação + %d mudanças de filiação + + Membros + + %d mensagem notificada não-lida + %d mensagens notificadas não-lidas + + + %d sala + %d salas + + %1$s em %2$s + + %d widget ativo + %d widgets ativos + + Avatar + Agitar com raiva para reportar bug + Enviar um sticker + Fazer Download + Alertas de Sistema + Se possível, por favor escreva a descrição em Inglês. + Enviar voz + Enviar sticker + Você não tem atualmente nenhum pacote de stickers habilitado. +\n +\nAdicionar alguns agora\? + Desculpe, nenhum aplicativo externo tem sido encontrado para completar esta ação. + Re-requisitar chaves de encriptação de suas outras sessões. + Por favor lance ${app_name} num outro dispositivo que possa decriptar a mensagem para que ele possa enviar as chaves para esta sessão. + + %d selecionada + %d selecionadas + + Previsualizar mídia antes de enviar + Desativar conta + Desativar minha conta + Enviar dados de analítica + ${app_name} coleta analítica anônima para nos permitir melhorar o aplicativo. + Um parâmetro requerido está faltando. + Exibe ação + Bane usuária(o) com id dada + Desbane usuária(o) com id dada + Define nível de poder de um/uma usuário(a) + Desopa usuária(o) com id dada + Convida usuária(o) com id dada para esta sala + Junta-se a sala com endereço dado + Sair de sala + Definir o tópico da sala + Expulsa a(o) usuária(o) com id dada + Muda seu apelido de exibição + Ativar/Desativar markdown + Para consertar gerenciamento de Apps Matrix + Para continuar usando o servidorcasa %1$s você deve revisar e aceitar os termos e condições. + Revisar agora + Desativar Conta + Isto vai fazer sua conta permanentemente inusável. Você não vai ser capaz de fazer login, e ninguém vai ser capaz de re-registrar a mesma ID de usuária(o). Isto vai causar sua conta sair de todas as salas em que ela está participando, e vai remover detalhes de sua conta de seu servidor de identidade. Esta ação é irreversível. +\n +\nDesativar sua conta não nos causa por default esquecer mensagens que você tem enviado. Se você gostaria que nós esqueçamos suas mensagens, por favor marque a caixa abaixo. +\n +\nVisibilidade de mensagem em Matrix é similar a email. Nós esquecermos suas mensagens significa que mensagens que você tem enviado não vão ser compartilhadas com nenhum usuária(o) nova(o) ou não-registrada(o), mas usuárias(os) registradas(os) que já têm acesso a estas mensagens vão ainda ter acesso à cópia delas(es). + Por favor esqueça todas as mensagens que eu tenho enviado quando minha conta for desativada (Aviso: isto vai causar usuárias/os futuras/os terem uma visualização incompleta de conversas) + Desativar Conta + Por favor entre sua senha. + Esta sala tem sido substituída e não está mais ativa. + A conversa continua aqui + Esta sala é uma continuação de uma outra conversa + Clique aqui para ver mensagens mais antigas + contacte o/a administrador(a) de seu serviço + Este servidorcasa tem excedido um de seus limites de recurso, então algumas(ns) usuária(os) não vão ser capazes de fazer login. + Este servidorcasa tem excedido um de seus limites de recurso. + Este servidorcasa tem atingido seu limite de Usuárias(os) Mensalmente Ativas(os) então algumas(ns) usuárias(os) não vão ser capazes de fazer login. + Este servidorcasa tem atingido seu limite de Usuárias(os) Mensalmente Ativas(os). + Por favor %s para ter este limite aumentado. + Por favor %s para continuar usando este serviço. + Por favor crie uma frasepasse para encriptar as chaves exportadas. Você vai precisar entrar a mesma frasepasse para ser capaz de importar as chaves. + Aceitar + Erro + Por favor revise e aceite as políticas deste servidorcasa: + Chamadas + Usar toque default de ${app_name} para chamadas entrantes + Toque de chamada entrante + Selecionar toque para chamadas: + Resolver Problemas de Notificação + Diagnóstico de resolução de problemas + Rodar Testes + Rodando… (%1$d of %2$d) + Diagnóstico básico está OK. Se você ainda não recebe notificações, por favor submita um reporte de bug para nos ajudar a investigar. + Um ou mais testes têm falhado, tente correção(ões) sugerida(s). + Um ou mais testes têm falhado, por favor submita um reporte de bug para nos ajudar a investigar. + Configurações de Sistema. + Notificações estão habilitadas nas configurações de sistema. + Notificações estão desabilitadas nas configurações do sistema. +\nPor favor cheque configurações de sistema. + Abrir Configurações + Configurações de Conta. + Notificações estão habilitadas para sua conta. + Notificações estão desabilitadas para sua conta. +\nPor favor cheque configurações de conta. + Habilitar + Configurações de Sessão. + Notificações estão habilitadas para esta sessão. + Expulsar + Notificações não estão habilitadas para esta sessão. +\nPor favor cheque as configurações de ${app_name}. + Habilitar + Checagem de Play Services + APK de Google Play Services está disponível e atualizado. + ${app_name} usa Google Play Services para entregar mensagens push mas não parece estar configurado corretamente: +\n%1$s + Consertar Play Services + Token de Firebase + Token FCM recuperado com sucesso: +\n%1$s + Falha para recuperar token do FCM: +\n%1$s + Registro de Token + Token FCM registrado com sucesso a servidorcasa. + Falha para registrar token FCM a servidorcasa: +\n%1$s + Começar em boot + Serviço vai começar quando o dispositivo for reiniciado. + O serviço não vai começar quando o dispositivo for recomeçado, você não vai receber notificações até que ${app_name} tenha sido aberto uma vez. + Habilitar Começar em boot + Checar restrições de background + Otimização de Bateria + ${app_name} não é afetado por Otimização de Bateria. + Desabilitar restrições + Ignorar Otimização + Previsualizar links dentro do chat quando seu servidorcasa suporta este recurso. + Enviar notificações de digitação + Deixar outras(os) usuárias(os) saberem que você está digitando. + Mostrar recibos de leitura + Clique nos recibos de leitura para uma lista detalhada. + Mostrar eventos de juntar-se e sair + Convites, remoções e bans são desafetados. + Mostrar eventos de conta + Inclui mudanças de avatar e nome de exibição. + Restrições de background estão desabilitadas para ${app_name}. Este teste devia ser rodado usando dados móveis (sem Wi-Fi). +\n%1$s + Restrições de background estão habilitadas para ${app_name}. +\nTrabalho que o app tenta fazer vai ser agressivamente restringido enquando ele está no background, e isto poderia afetar notificações. +\n%1$s + Formatação markdown + Formatar mensagens usando sintaxe markdown antes que elas são enviadas. Isto permite formatação avançada tal como usar asteriscos para exibir texto itálico. + Senha + Começar a câmera de sistema em vez da tela de câmera personalizada. + O comando \"%s\" precisa de mais parâmetros, ou alguns parâmetros estão incorretos. + Markdown tem sido habilitado. + Markdown tem sido desabilitado. + Desculpe, um erro ocorreu + expandir + colapsar + %1$s: %2$s + +%d + Nenhum APK de Google Play Services válido encontrado. Notificações podem não funcionar apropriadamente. + Se um/uma usuário(a) deixa um dispositivo despluggado e parado por um período de tempo, com a tela desligada, o dispositivo entra em modo Doze. Isto previne apps de acessar a rede e adia seus trabalhos, sincs e alarmes padrões. + Criar frasepasse + Frasepasse não corresponde + Chamada de Vídeo em Progresso… + Backup de Chave + Usar Backup de Chave + Você vai perder suas mensagens encriptadas se fizer signout agora + Backup de chave em progresso. Se você fizer signout agora você vai perder acesso a suas mensagens encriptadas. + Backup de Chave Seguro devia estar ativo em todas as suas sessões para evitar perder o acesso a suas mensagens encriptadas. + Eu não quero minhas mensagens encriptadas + Fazendo backup de chaves… + Você tem certeza\? + Fazer backup + Você vai perder acesso a suas mensagens encriptadas a menos que faça backup de suas chaves antes de fazer signout. + Assinatura + Pular + Feito + Você tem certeza que você quer fazer sign out\? + Configurações de Notificações Avançadas + Importância de notificação por evento + Configurações Personalizadas. + Observe que alguns tipos de mensagens estão definidos para serem silenciosos (vão produzir uma notificação sem nenhum som). + Algumas notificações estão desabilitadas em suas configurações personalizadas. + [%1$s] +\nEste erro está fora de controle de ${app_name} e de acordo com Google, este erro indica que o dispositivo tem apps demais registrados com FCM. O erro somente ocorre em casos onde há números extremos de apps, então isso não devia afetar a/o usuária(o) média(o). + Ignorar + Fazer sign-in com sign-on único + [%1$s] +\nEste erro está fora de controle de ${app_name}. Isto pode ocorrer por várias razões. Talvez vai funcionar se você retentar mais tarde, você também pode checar que Google Play Service não está restrito em uso de dados nas configurações de sistema, ou que o relógio do seu dispositivo está correto, ou ele pode acontecem em ROM personalizada. + [%1$s] +\nEste erro está fora de controle de ${app_name}. Não há uma conta de Google no celular. Por favor abra o gerenciador de contas e adicione uma conta de Google. + Adicionar Conta + Configurar Notificações Barulhentas + Configurar Notificações de Chamada + Configurar Notificações Silenciosas + Escolher cor de LED, vibração, som… + Gerenciamento de Chaves de Criptografia + Enviar mensagem com enter + Nenhum + Revogar + Desconectar + Declinar + Marcar como lida + Tocar + Descartar + Copiar + Sucesso + Notificações + Chamada ${app_name} Falhou + Falha para estabelecer conexão em tempo real. +\nPor favor peça ao/à administrador(a) de seu servidorcasa para configurar um servidor TURN a fim que chamadas funcionem confiavelmente. + Selecionar Dispositivo de Som + Celular + Falante + Auscultadores + Auscultadores Semfio + Trocar Câmera + Frontal + Traseira + Desativar HD + Ativar HD + Isto não é um endereço de servidor Matrix válido + Não é possível alcançar um servidorcasa neste URL, por favor cheque-o + Erro de SSL: a identidade da/do peer não tem sido verificada. + Erro de SSL. + Cancelar convite + Rebaixar-se\? + Você não vai pode desfazer esta mudança já que está se rebaixando, se você for a(o) última(o) usuária(o) privilegiada(o) na sala vai ser impossível recuperar privilégios. + Rebaixar + Ignorar usuária(o) + Ignorar esta(e) usuária(o) vai remover as mensagens dela(e) das salas que vocês compartilham. +\n +\nVocê pode reverter esta ação a qualquer momento nas configurações gerais. + Designorar usuária(o) + Designorar esta(e) usuária(o) vai mostrar todas as mensagens dela(e) de novo. + Cancelar convite + Você tem certeza que você quer cancelar o convite para esta(e) usuária(o)\? + Expulsar usuária(o) + Razão de expulsão + expulsar usuária(o) vai removê-la(o) desta sala. +\n +\nPara preveni-la(o) de se juntar de novo, você devia bani-la(o) em vez disso. + Banir usuária(o) + Razão de ban + Desbanir usuária(o) + Desbanir usuária(o) vai permitir-lhe se juntar à sala de novo. + Modo Sinc no Background + Optimizado para bateria + ${app_name} vai sincar em background de maneira que preserva recursos limitados do dispositivo (bateria). +\nDependendo do estado de recurso de seu dispositivo, a sinc pode ser adiada pelo sistema operacional. + Optimizado para tempo real + ${app_name} vai sincar em background periodicamente em tempo preciso (configurável). +\nIsto vai impactar uso de rádio e bateria, vai ter uma notificação permanente exibida declarando que ${app_name} está à escuta por eventos. + Sem sinc em background + Você não vai ser notificada(o) sobre mensagens entrantes quando o app está em background. + Integrações + Use um gerenciador de integrações para gerenciar bots, bridges, widgets e pacotes de stickers. +\nGerenciadores de integrações recebem dados de configuração, e podem modificar widgets, enviar convites de sala e definir níveis de poder em seu nome. + Botão enter do teclado suave vai enviar mensagem em vez de adicionar uma quebra de linha + Backup Seguro + Configurar Backup Seguro + Resettar Backup Seguro + Configurar neste dispositivo + Salvaguardar-se contra perda de acesso a mensagens & dados encriptados ao fazer backup de chaves de encriptação em seu servidor. + Gere uma nova Chave de Segurança ou defina uma nova Frase de Segurança para seu backup existente. + Isto vai substituir sua Chave ou Frase atual. + Descoberta + Gerenciar suas configurações de descoberta. + Permitir integrações + Gerenciador de integrações + Integrações estão desabilitadas + Habilite \'Permitir integrações\' em Configurações para fazer isto. + A senha não é válida + Mídia + Compressão default + Escolher + Fonte de mídia default + Escolher + Tocar som de obturador + + %d usuária(o) banida(o) + %d usuárias(os) banidas(os) + + Chaves exportadas com sucesso + Recuperação de Mensagens Encriptadas + Gerenciar Backup de Chave + ip desconhecido + + %1$s: %2$d mensagem + %1$s: %2$d mensagens + + + %d notificação + %d notificações + + Novo Evento + Sala + Novas Mensagens + Novo Convite + Eu + ** Falha para enviar - por favor abra sala + %1$s: %2$s + %1$s: %2$s %3$s + VISUALIZAR + Widgets ativos + Widget + Carregar Widget + Este widget foi adicionado por: + Usá-lo pode definir cookies e compartilhar dados com %s: + Usá-lo pode compartilhar dados com %s: + Falha para carregar widget. +\n%s + Recarregar widget + Abrir em browser + Revogar acesso para mim + Seu nome de exibição + URL de seu avatar + Sua ID de usuária(o) + Seu tema + ID de widget + ID de sala + Desculpe, chamadas de conferência com Jitsi não são suportadas em dispositivos antigos (dispositivos SO Android abaixo de 6.0) + Este wigdet quer usar os seguintes recursos: + Permitir + Bloquear Todos + Usar a câmera + Usar o microfone + Ler Mídia protegida por DRM + Para continuar você precisa aceitar os Termos deste serviço. + Uma nova sessão está requisitando chaves de encriptação. +\nNome de sessão: %1$s +\nVisto por último: %2$s +\nSe você não fez login numa outra sessão, ignore esta requisição. + Uma sessão não-verificada está requisitando chaves de encriptação. +\nNome de sessão: %1$s +\nVisto por último: %2$s +\nSe você não fez login numa outra sessão, ignore esta requisição. + Compartilhar + Requisição de Compartilhamento de Chaves + Ignorar + Silenciosa + Por favor entre um nome de usuária(o). + Por favor entre sua frasepasse + Frasepasse é fraca demais + Por favor delete a frasepasse se quiser que ${app_name} gere uma chave de recuperação. + Nunca perca mensagens encriptadas + Mensagens em salas encriptadas são asseguradas com encriptação ponta-a-ponta. Somente você e a(s)/o(s) recipiente(s) têm as chaves para ler estas mensagens. +\n +\nFaça seguramente backup de suas chaves para evitar perdê-las. + Começar a usar Backup de Chave + (Avançada) + Exportar chaves manualmente + Assegure seu backup com uma Frasepasse. + Nós vamos armazenar uma cópia encriptada de suas chaves em seu servidorcasa. Proteja seu backup com uma frasepasse para mantê-lo seguro. +\n +\nPara segurança máxima, esta deve ser diferente da senha de sua conta. + Definir Frasepasse + Criando Backup + Ou, assegure seu backup com uma Chave de Recuperação, salvando-a em algum lugar seguro. + (Avançada) Configurar com Chave de Recuperação + Sucesso ! + Backup de suas chaves está sendo feito. + Sua chave de recuperação é uma rede de segurança - você pode usá-la para restaurar acesso a suas mensagens encriptadas se você esquecer sua frasepasse. +\nMantenha sua chave de recuperação em algum lugar muito seguro, como um gerenciador de senhas (ou um cofre) + Mantenha sua chave de recuperação em algum lugar muito seguro, como um gerenciador de senhas (ou um cofre) + Feito + Eu tenho feito uma cópia + Salvar Chave de Recuperação + Compartilhar + Salvar como Arquivo + A chave de recuperação tem sido salva. + Um backup já existe em seu servidorcasa + Parece que você já tem configurado backup de chave de uma outra sessão. Você quer substituí-lo pelo que você está criando\? + Substituir + Parar + Por favor faça uma cópia + Compartilhar chave de recuperação com… + Gerando Chave de Recuperação usando a frasepasse, este processo pode levar muitos segundos. + Chave de Recuperação + Erro inesperado + Você tem certeza\? + Você pode perder acesso a suas mensagens se você fizer logout ou perder este dispositivo. + Obtendo versão de backup… + Use sua frasepasse de recuperação para destrancar seu histórico de mensagens encriptadas + use sua chave de recuperação + Não sabe sua frasepasse de recuperação, você pode %s. + Use a sua Chave de Recuperação para destrancar seu histórico de mensagens encriptadas + Entar Chave de Recuperação + Perdeu sua chave de recuperação\? Você pode configurar uma nova em configurações. + Backup não pôde ser decriptado com esta frasepasse: por favor verifique que você entrou a frasepasse de recuperação correta. + Restaurando backup: + Computando chave de recuperação… + Fazendo download de chaves… + Importando chaves… + Destrancar Histórico + Por favor entre uma chave de recuperação + Backup não pôde ser decriptado com esta chave de recuperação: por favor verifique que você entrou a chave de recuperação correta. + Backup Restaurado %s ! + + Restaurou um backup com %d chave. + Restaurou um backup com %d chaves. + + + %d nova chave tem sido adicionada a esta sessão. + %d novas chaves têm sido adicionadas a esta sessão. + + Falha para obter versão mais recente de chaves de recuperação (%s). + Restaurar de Backup + Deletar Backup + Backup de Chave tem sido corretamente configurado para esta sessão. + Backup de Chave não está ativo nesta sessão. + Backup de suas chaves não está sendo feito desta sessão. + Backup tem uma assinatura de sessão desconhecida com ID %s. + Backup tem uma assinatura válida desta sessão. + Backup tem uma assinatura válida de sessão verificada %s. + Backup tem uma assinatura válida de sessão não-verificada %s + Backup tem uma assinatura inválida de sessão verificada %s + Backup tem uma assinatura inválida de sessão não-verificada %s + Para usar Backup de Chave nesta sessão, restaure com sua frasepasse ou chave de recuperação agora. + Deletando backup… + Checando estado de backup + Deletar Backup + Deletar suas chaves de encriptação, das quais foi feito backup, do servidor\? Você não vai ser mais capaz de usar sua chave de recuperação para ler histórico de mensagens encriptadas. + Backup Seguro + Salvaguardar-se contra perda de acesso a mensagens & dados encriptados + Nunca perca mensagens encriptadas + Usar Backup de Chave + Novas chaves de mensagens seguras + Gerenciar em Backup de Chave + Fazendo backup de suas chaves. Isto pode levar muitos minutos… + Configurar Backup Seguro + Backup de todas as chaves foi feito + + Fazendo backup de %d chave… + Fazendo backup de %d chaves… + + Versão + Algoritmo + Verificada(o)! + Entendido + Requisição de Verificação + %s quer verificar sua sessão + Erro Desconhecido + Você não está usando nenhum servidor de identidade + Parece que você está tentando se conectar a um outro servidorcasa. Você quer fazer signout\? + Editar + Responder + Retentar + Te enviou um convite + Convidada(o) por %s + Você está em dia! + Você não tem mais nenhuma mensagem não-lida + Conversas + Suas conversas de mensagem direta vão ser exibidas aqui. Toque no + à direita fundo para começar algumas. + Salas + Suas salas vão ser exibidas aqui. Toque no + à direita fundo para encontrar umas existentes ou começar algumas propriamente suas. + Reações + Concordo + Adicionar Reação + Visualizar Reações + Reações + Mensagem removida + Mostrar mensagens removidas + Mostrar um placeholder para mensagens removidas + Evento deletado por usuária(o) + Evento moderado por admin da sala + Evento malformado, não dá para exibir + Criar Nova Sala + Sem rede. Por favor cheque sua conexão de Internet. + Mudar + Mudar rede + Por favor espere… + Esta sala não pode ser previsualizada + Salas + Mensagens Diretas + CRIAR + Nome + Pública + Qualquer pessoa poderá se juntar a esta sala + Um erro ocorreu ao obter info de confiança + Um erro ocorreu ao obter dados de backup de chaves + Importar as chaves e2e de arquivo \"%1$s\". + Versão de SDK de Matrix + Outras notas de terceiros + Você já está visualizando esta sala! + Geral + Preferências + Segurança & Privacidade + Regras de Push + Nenhuma regra de push definida + Nenhum gateway de push registrado + ID do App: + Chave Push: + Nome de Exibição do App: + Nome de Exibição da Sessão: + Url: + Formato: + Voz & Vídeo + Ajuda & Sobre + Registrar token + Fazer uma sugestão + Por favor escreva sua sugestão abaixo. + Descreva sua sugestão aqui + Obrigado, a sugestão tem sido enviada com sucesso + A sugestão falhou para ser enviada (%s) + Mostrar eventos escondidos em timeline + Mensagens Diretas + Esperando… + Encriptando thumbnail… + Enviando thumbnail (%1$s / %2$s) + Encriptando arquivo… + Enviando arquivo (%1$s / %2$s) + Download de arquivo %1$s foi feito! + (editada) + Edições de Mensagem + Nenhuma edição encontrada + Filtrar conversas… + Não consegue encontrar o que você está procurando\? + Criar uma nova sala + Enviar uma nova mensagem direta + Visualizar o diretório de salas + Nome ou ID (#exemplo:matrix.org) + Habilitar deslizar para responder em timeline + Adicionar uma aba dedicada para notificações não-lidas em tela principal. + Link copiado para clipboard + Criando sala… + Visualizar Histórico de Edição + Termos de Serviço + Ser descobertável por outras(os) + Usar bots, bridges, widgets e pacotes de stickers + Servidor de identidade + Desconectar servidor de identidade + Configurar servidor de identidade + Mudar servidor de identidade + Você está atualmente usando %1$s para descobrir e ser descobertável por contatos existentes que você conhece. + Você não está atualmente usando um servidor de identidade. Para descobrir e ser descobertável por contatos existentes que você conhece, configure um abaixo. + Endereços de email descobertáveis + Opções de descoberta vão aparecer uma vez que você tenha adicionado um endereço de email. + Opções de descoberta vão aparecer uma vez que você tenha adicionado um número de telefone. + Desconectar-se de seu servidor de identidade vai significar que você não vai ser descobertável por outras(os) usuárias(os) e você não vai ser capaz de convidar outras(os) por email ou telefone. + Números de telefone descobertáveis + Nós enviamos um email para %s, cheque seu email e clique no link de confirmação + Nós enviamos um email para %s, por favor primeiro cheque seu email e clique no link de confirmação + Entre um URL de servidor de identidade + Não foi possível conectar-se a servidor de identidade + Por favor entre o url de servidor de identidade + Servidor de identidade não tem termos de serviço + O servidor de identidade que você tem escolhido não tem quaisquer termos de serviço. Somente continue se você confia na/do proprietária(o) do serviço + Uma mensagem de texto tem sido enviada para %s. Por favor entre o código de verificação que ela contém. + O código de verificação não está correto. + Você está atualmente compartilhando endereços de email ou números de telefone no servidor de identidade %1$s. Você vai precisar reconectar-se a %2$s para parar de os compartilhar. + Concorde com os Termos de Serviço do servidor de identidade (%s) para permitir você mesma(o) ser descobertável por endereço de email ou número de telefone. + Habilitar verbose logs. + Verbose logs vão ajudar desenvolvedoras(es) ao prover mais logs quando você enviar uma RageShake. Mesmo quando habilitado, o aplicativo não registra conteúdos de mensagem ou quaisquer outros dados privados. + Por favor retente uma vez que você tenha aceitado os termos e condições de seu servidorcasa. + Parece que o servidor está demorando muito para responder, isto pode ser causado por ou má conectividade ou um erro com o servidor. Por favor tente de novo daqui a pouco. + Enviar anexo + Abrir a gaveta de navegação + Abrir o menu de criar sala + Fechar menu de criar sala… + Criar uma nova conversa direta + Criar uma nova sala + Fechar banner de backup de chaves + Pular para fundo + %1$s, %2$s e %3$s leram + %1$s e %2$s leram + %s leu + + %d usuária(o) leu + %d usuárias(os) leram + + Arquivo + Contato + Câmera + Galeria + Sticker + Não deu para lidar com compartilhar dados + MÍDIA + Não tem nenhuma mídia nesta sala + ARQUIVOS + %1$s a %2$s + Não tem nenhum arquivo nesta sala + É spam + É inapropriado + Reporte personalizado… + Reportar este conteúdo + Razão para reportar este conteúdo + REPORTAR + IGNORAR USUÁRIA(O) + Conteúdo reportado + Este conteúdo foi reportado. +\n +\nSe você não quer ver mais nada de conteúdo desta(e) usuária(o), você pode ignorá-la(o) para esconder mensagens dela(e). + Reportado como spam + Este conteúdo foi reportado como spam. +\n +\nSe você não quer ver mais nada de conteúdo desta(e) usuária(o), você pode ignorá-la(o) para esconder mensagens dela(e). + Reportado como inapropriado + Este conteúdo foi reportado como inapropriado. +\n +\nSe você não quer ver mais nada de conteúdo desta(e) usuária(o), você pode ignorá-la(o) para esconder mensagens dela(e). + Ignorar usuária(o) + Todas as mensagens (barulhento) + Todas as mensagens + Menções somente + Mutar + Configurações + Adicionar a favoritos + Remover de favoritos + Sair da sala + %1$s não fez nenhuma mudança + Você não fez nenhuma mudança + Envia a dada mensagem como um spoiler + Spoiler + Digite palavrachaves para encontrar uma reação. + Você não está ignorando nenhum(a) usuário(a) + Clique longo numa sala para ver mais opções + %1$s fez a sala pública para qualquer pessoa que sabe o link. + Você fez a sala pública para qualquer pessoa que sabe o link. + %1$s fez a sala somente convite. + Você fez a sala somente convite. + Mensagens não-lidas + É sua conversa. Tome-a como sua. + Faça chat com pessoas diretamente ou em grupos + Mantenha conversas privadas com encriptação + Extenda & personalize sua experiência + Começar agora + Selecione um servidor + Assim como email, contas têm uma casa, embora você pode falar com qualquer pessoa + Junte-se a milhões de graça no maior servidor público + Hospedagem premium para organizações + Saber mais + Outro + Configurações personalizadas & avançadas + Continuar + Conectar-se a %1$s + Conectar-se Element Matrix Services + Conectar-se a um servidor personalizado + Fazer signin a %1$s + Fazer Signup + Fazer Signin + Continuar com SOU + Endereço de Element Matrix Services + Endereço + Hospedagem premium para organizações + Entre o endereço do Modular Element ou Servidor que você quer usar + Entre o endereço do servidor que você quer usar + Um erro ocorreu quando carregando a página: %1$s (%2$d) + O aplicativo não é capaz de fazer signin a este servidorcasa. O servidorcasa suporta o(s) seguinte(s) tipo(s) de signin: %1$s. +\n +\nVocê quer fazer signing usando um cliente web\? + Desculpe, este servidor não está aceitando novas contas. + O aplicativo não é capaz de criar uma conta neste servidorcasa. +\n +\nVocê quer fazer signup usando um cliente web\? + Este endereço de email não está associado a nenhuma conta. + Resettar senha em %1$s + Um email de verificação vai ser enviado para sua inbox para confirmar definição de sua nova senha. + Próximo + Email + Nova senha + Aviso! + Mudar sua senha vai resettar quaisquer chaves de encriptação ponta-a-ponta em todas as suas sessões, fazendo histórico de chat encriptado ilegível. Configure Backup de Chave ou exporte suas chaves de sala de uma outra sessão antes de resettar sua senha. + Continuar + Este endereço de email não está linkado a nenhuma conta + Cheque sua inbox + Um email de verificação foi enviado para %1$s. + Toque no link para confirmar sua nova senha. Uma vez que você tenha seguido o link que ele contém, clique abaixo. + Eu tenho verificado meu endereço de email + Sucesso! + Sua senha tem sido resettada. + Você tem sido feito logout de todas suas sessões e você não vai mais receber notificações push. Para re-habilitar notificações, faça signin de novo em cada dispositivo. + Voltar para Fazer Signin + Aviso + Sua senha ainda não tem sido mudada. +\n +\nPara o processo de mudança de senha\? + Definir endereço de email + Defina um endereço de email para recuperar sua conta. Mais tarde, você pode opcionalmente permitir pessoas que você conhece descobrirem você por este endereço. + Email + Email (opcional) + Próximo + Definir número de telefone + Defina um número de telefone para opcionalmente permitir que pessoas que você conhece descubram você. + Por favor use o formato internacional. + Número de telefone + Número de telefone (opcional) + Próximo + Confirmar número de telefone + Nós acabamos de enviar um código para %1$s. Entre-o abaixo para verificar que é você. + Entrar código + Enviar de novo + Próximo + Números de telefone internacionais devem começar com \'+\' + Número de telefone parece inválido. Por favor cheque-o + Fazer signup a %1$s + Nome de usuária(o) ou email + Nome de usuária(o) + Senha + Próximo + Esse nome de usuária(o) está tomado + Aviso + Sua conta não foi criada ainda. Parar o processo de registro\? + Selecionar matrix.org + Selecionar Element Matrix Services + Selecionar um servidorcasa personalizado + Por favor performe o desafio de captcha + Aceite termos para continuar + Por favor cheque seu email + Nós acabamos de enviar um email para %1$s. +\nPor favor clique no link que ele contém para continuar a criação de conta. + O código entrado não está correto. Por favor cheque. + Servidorcasa desatualizado + + Requisições demais têm sido enviadas. Você pode retentar em %1$d segundo… + Requisições demais têm sido enviadas. Você pode retentar em %1$d segundos… + + Fazer signin com ID Matrix + Fazer signin com ID Matrix + Se você configurar uma conta em um servidorcasa, use sua ID Matrix (e.g. @usuarix:dominio.com) e senha abaixo. + ID Matrix + Se você não sabe sua senha, volte para resettá-la. + Este não é um identificador de usuária(o) válido. Formato esperado: \'@usuarix:servidorcasa.org\' + Incapaz de encontrar um servidorcasa válido. Por favor cheque seu identificador + Vista por + Você está com signout feito + Pode ser devido a várias razões: +\n +\n• Você tem mudado sua senha numa outra sessão. +\n +\n• Você tem deletado esta sessão de uma outra sessão. +\n +\n• O/a administrador(a) de seu servidor tem invalidado seu acesso por razão de segurança. + Fazer signin de novo + Você está com signout feito + Fazer signin + A/o admin de seu servidorcasa (%1$s) fez seu signout de sua conta %2$s (%3$s). + Faça signin para recuperar chaves de encriptação armazenadas exclusivamente neste dispositivo. Você precisa delas para ler todas suas mensagens seguras em qualquer dispositivo. + Fazer signin + Senha + Limpar dados pessoais + Aviso: Seus dados pessoais (incluindo chaves de encriptação) ainda estão armazenados neste dispositivo. +\n +\nLimpe-os quando você estiver terminado de usar este dispositivo, ou quiser fazer signin numa outra conta. + Limpar todos os dados + Limpar dados + Limpar todos os dados atualmente armazenados neste dispositivo\? +\nFaça signin de novo para acessar os dados e mensagens de sua conta. + Você vai perder acesso a mensagens seguras a menos que você faça signin para recuperar suas chaves de encriptação. + A sessão atual é para usuária(o) %1$s e você provê credenciais para usuária(o) %2$s. Isto não é suportado por ${app_name}. +\nPor favor primeiro limpe dados, então faça signin de novo em uma outra conta. + Seu link matrix.to foi malformado + A descrição é curta demais + Sinc Inicial… + Configurações avançadas + Modo desenvolvedor(a) + O modo desenvolvedor(a) ativa funcionalidades escondidas e também pode fazer o aplicativo menos estável. Para desenvolvedores(as) somente! + Rageshake + Limiar de detecção + Agite seu telefone para testar o limiar de detecção + Agitação detectada! + Configurações + Sessão atual + Outras sessões + Mostrando somente os primeiros resultados, digite mais letras… + Rápida-falha + ${app_name} pode crashar com mais frequência quando um erro inesperado ocorre + Prepende ¯\\_(ツ)_/¯ a uma mensagem de texto puro + Habilitar encriptação + Uma vez habilitada, encriptação não poder ser desabilitada. + Seu domínio de email não está autorizado a se registrar neste servidor + Signin desconfiado + Eles correspondem + Eles não correspondem + Não seguro + Um dos seguintes pode estar comprometido: +\n +\n - Seu servidorcasa +\n - O servidorcasa da/do usuária(o) ao qual você está verificando está conectada(o) +\n - A conexão de internet sua ou da/do outra(o) usuária(o) +\n - O dispositivo seu ou da/do outra(o) usuária(o) + Vídeo. + Imagem. + Áudio + Arquivo + Sticker + Esperando… + %s cancelou + Você cancelou + %s aceitou + Você aceitou + Verificação Enviada + Requisição de Verificação + Verificar esta sessão + Scanne o código com o dispositivo da/do outra(o) usuária(o) para verificar seguramente um/uma a/o outra(o) + Scannar código dela(e) + Não dá para scannar + Se você não está em pessoa, compare emoji em vez disso + Verificar ao comparar emojis + Verificar %s + Verificou %s + Esperando por %s… + Mensagens nesta sala não são encriptadas ponta-a-ponta. + Mensagens nesta sala são encriptadas ponta-a-ponta. +\n +\nSuas mensagens são asseguradas com cadeados e somente você e a/o recipente têm as chaves únicas para as destrancar. + Segurança + Saber mais + Mais + Ações de Admin + Configurações de sala + Notificações + + Uma pessoa + %1$d pessoas + + Uploads + Sair de Sala + Saindo da sala… + Admins + Moderadoras(es) + Personalizado + Convites + Usuárias(os) + Admin em %1$s + Moderador(a) em %1$s + Default em %1$s + Personalizado (%1$d) em %2$s + Pular para recibo de leitura + ${app_name} não lida com eventos de tipo \'%1$s\' + ${app_name} encontrou um problema ao render conteúdo de evento com id \'%1$s\' + Designorar + Esta sessão é incapaz de compartilhar essa verificação com suas outras sessões. +\nA confirmação vai ser salvada localmente e compartilhada numa versão futura do app. + Envia a dada mensagem colorida como um arco-íris + Envia o dado emote colorido como um arco-íris + Linha do tempo + Editor de mensagem + Habilitar encriptação ponta-a-ponta… + Habilitar encriptação\? + Uma vez habilitada, encriptação para uma sala não pode ser desabilitada. Mensagens enviadas numa sala encriptada não podem ser vistas pelo servidor, somente pelas(os) participantes da sala. Habilitar encriptação pode prevenir que muitos bots e bridges de funcionarem corretamente. + Habilitar encriptação + Para estar segura(o), verifique %s ao checar um código de única vez. + Para estar segura(o), faça isto em pessoa ou use uma outra forma de se comunicar. + Compare os emoji únicos, assegurando que eles apareçam na mesma ordem. + Compare o código com aquele exibido na tela da/do outra(o) usuária(o). + Mensagens com esta(e) usuária(o) são encriptadas ponta-a-ponta e não podem ser lidas por terceiros. + Sua nova sessão agora está confirmada. Ela tem acesso a suas mensagens encriptadas, e outras(os) usuárias(os) vão vê-la como confiada. + Assinatura Cruzada + Assinatura Cruzada está habilitada +\nChaves Privadas em dispositivo. + Assinatura Cruzada está habilitada +\nChaves são confiadas. +\nChaves privadas não são conhecidas + Assinatura Cruzada está habilitada. +\nChaves não são confiadas + Assinatura Cruzada não está habilitada + O/a administrador(a) de seu servidor tem desabilitado encriptação ponta-a-ponta por default em salas privadas & Mensagens Diretas. + Sessões Ativas + Mostrar Todas as Sessões + Gerenciar Sessões + Fazer signout desta sessão + Nenhuma informação criptográfica disponível + Esta sessão é confiada para mensageria segura porque você a verificou: + Verifique esta sessão para marcá-la como confiada & conceder-lhe acesso a mensagens encriptadas. Se você não fez signin a esta sessão sua conta pode estar comprometida: + + %d sessão ativa + %d sessões ativas + + Verificar este dispositivo + Use uma sessão existente para verificar esta aqui, concedendo-lhe acesso a mensagens encriptadas. + Verificar + Verificada(o) + Aviso + Falha para obter sessões + Sessões + Confiada + Não Confiada + Esta sessão está confiada para mensageria segura porque %1$s (%2$s) a verificou: + %1$s (%2$s) fez signin usando uma nova sessão: + Até que esta(e) usuária(o) confie nesta sessão, mensagens enviadas para e desde ela são etiquetadas com avisos. Alternativamente, você pode verificá-la manualmente. + Inicializar AssinaturaCruzada + Resettar Chaves + QR code + Quase lá! %s está mostrando um tick (✓)\? + Sim + Não + Conectividade ao servidor tem sido perdida + Modo avião está ligado + Ferramentas Dev + Dados de Conta + Use uma Chave ou a Frasepasse de Recuperação + Se você não pode acessar uma sessão existente + Não dá para encontrar segredos em armazenamento + Remover… + Você quer enviar este anexo para %1$s\? + + Enviar imagem com o tamanho original + Enviar imagens com o tamanho original + + Confirmar Remoção + Você tem certeza que você deseja remover (deletar) este evento\? Note que se você deletar um nome de sala ou mudança de tópico, isto poderia desfazer a mudança. + Incluir uma razão + Razão para redigir + Evento deletado por usuária(o), razão: %1$s + Evento moderado por admin de sala, razão: %1$s + Chaves já estão atualizadas! + ${app_name} Android + Requisições de Chave + Destrancar histórico de mensagens encriptadas + Recarregar + Novo login. Foi você\? + Use esta sessão para verificar sua nova, concedendo-lhe acesso a mensagens encriptadas. + Não foi eu + Sua conta pode estar comprometida + Se você cancelar, você não vai ser capaz de ler mensagens encriptadas neste dispositivo, e outras(os) usuárias(os) não vão confiar nele + Se você cancelar, você não vai ser capaz de ler mensagens encriptadas em seu novo dispositivo, e outras(os) usuárias(os) não vão confiar nele + Você não vai verificar %1$s (%2$s) se cancelar agora. Comece de novo no perfil de usuária(o) dela(e). + Um dos seguintes pode estar comprometido: +\n +\n- Sua senha +\n- Seu servidorcasa +\n- Este dispositivo, ou o outro dispositivo +\n- A conexão de internet que qualquer um dos dois dispositivos está usando +\n +\nNós recomendamos que você mude sua senha & chave de recuperação em Configurações imediatamente. + Verificação tem sido cancelada. Você pode começar verificação de novo. + Verificação Cancelada + Frasepasse de Recuperação + Chave de Mensagem + Entre sua %s para continuar. + Não use a senha de sua conta. + Entre uma frase de segurança que só você conheça, usada para assegurar segredos em seu servidor. + Isto pode levar muitos segundos, por favor seja paciente. + Configurando recuperação. + Tudo pronto! + Mantenha-a segura + Finalizar + Publicando chaves de identidade criadas + Gerando chave segura desde frasepasse + Definindo a Chave default SSSS + Sincronizando Master key + Sincronizando User key + Sincronizando Self Signing key + Configurando Backup de Chave + Suas %2$s & %1$s estão agora definidas. +\n +\nMantenha-as seguras! Você vai precisar delas para destrancar mensagens encriptadas e informação segura se você perder todas suas sessões ativas. + Imprima-a e armazene-a em algum lugar seguro + Salve-a em uma chave USB ou drive de backup + Copie-a para seu armazenamento nuvem pessoal + Encriptação habilitada + Encriptação não habilitada + Esperando por %s… + Configuração de notificações + Solucionar problemas + Mensagem… + Usar Arquivo + Checando Chave de backup + Se você cancelar agora, você pode perder mensagens & dados encriptados se você perder acesso a seus logins. +\n +\nVocê também pode configurar Backup Seguro & gerenciar suas chaves em Configurações. + Mensagens nesta sala são encriptadas ponta-a-ponta. Saiba mais & verifique usuárias(os) nos perfis delas(es). + A encriptação usada por esta sala não é suportada + %s criou e configurou a sala. + Você criou e configurou a sala. + Quase lá! O outro dispositivo está mostrando um tick (✓)\? + Quase lá! Esperando por confirmação… + Falha para importar chaves + Mensagens contendo @room + Mensagens encriptadas em conversas um-a-um + Mensagens encriptadas em chats de grupo + Quando é feito upgrade de salas + Envia uma mensagem como texto puro, sem interpretá-la como markdown + Nome de usuária(o) e/ou senha incorretos. A senha entrada começa ou termina com espaços, por favor cheque-a. + Esta conta tem sido desativada. + Upgrade de encriptação disponível + Verifique-se a si mesma(o) & outras(os) para manter seus chats seguros + Entre sua %s para continuar + Não é uma chave de recuperação válida + Por favor entre uma chave de recuperação + Checando Chave de backup (%s) + Obtendo chave de curva + Gerando chave SSSS a partir de frasepasse + Gerando chave SSSS a partir de frasepasse (%s) + Gerando chave SSSS a partir de chave de recuperação + Armazenando segredo de backup de chave em SSSS + Entre sua Frasepasse de Backup de Chave para continuar. + usar sua chave de recuperação da Chave do Backup + Se você não sabe sua Frasepasse de Backup de Chave, você pode %s. + Chave de recuperação de Backup de Chave + Prevenir screenshots do aplicativo + Habilitar esta configuração adiciona FLAG_SECURE a todas as Atividades. Recomece o aplicativo para que a mudança tenha efeito. + Não foi possível salvar arquivo de mídia + Definir uma nova senha de conta… + Use o ${app_name} mais recente em seus outros dispositivos, ${app_name} Web, ${app_name} Desktop, ${app_name} iOS, ${app_name} para Android, ou um outro cliente Matrix capaz de assinatura cruzada + ${app_name} Web +\n${app_name} Desktop + ${app_name} iOS +\n${app_name} Android + ou um outro cliente Matrix capaz de assinatura cruzada + Use o ${app_name} mais recente em seus outros dispositivos: + Força a atual sessão de grupo de saída em uma sala encriptada a ser descartada + Somente suportado em salas encriptadas + Use sua %1$s ou %2$s para continuar. + Usar Chave de Recuperação + Selecione sua Chave de Recuperação, ou faça manualmente input dela ao digitá-la ou colá-la desde seu clipboard + Falha para acessar armazenamento seguro + Não-encripada + Encriptada por um dispositivo não-verificado + Verifique o novo login acessando sua conta: %1$s + Verificar Manualmente por Texto + Verificar login + Verificar Interativamente por Emoji + Confirme sua identidade ao verificar este login desde uma de suas outras sessões, concedendo-lhe acesso a mensagens encriptadas. + Por favor escolha um nome de usuária(o). + Por favor escolha uma senha. + Cheque duplamente este link + O link %1$s está levando você para um outro site: %2$s. +\n +\nVocê tem certeza que você quer continuar\? + Nós não conseguimos criar sua DM. Por favor cheque as/os usuárias(os) que você quer convidar e tente de novo. + Adicionar membros + CONVIDAR + Convidando usuárias(os)… + Convidar Usuárias(os) + Convite enviado para %1$s + Convites enviados para %1$s e %2$s + + Convites enviados para %1$s e mais um/uma + Convites enviados para %1$s e mais %2$d + + Nós não conseguimos convidar usuárias(os). Por favor cheque as/os usuárias(os) que você quer convidar e tente de novo. + Língua atual + Outras línguas disponíveis + Carregando línguas disponíveis… + Abrir termos de %s + Desconectar-se do servidor de identidade %s\? + Este servidor de identidade está desatualizado. ${app_name} suporta somente API V2. + Esta operação não é possível. O servidorcasa está desatualizado. + Por favor primeiro configure um servidor de identidade. + Por favor primeiro aceite os termos do servidor de identidade nas configurações. + Para sua privacidade, ${app_name} somente suporta enviar endereços de email e números de telefone de usuária(o) hashados. + A associação tem falhado. + Não há nenhuma associação atual com este identificador. + Seu servidorcasa (%1$s) propõe usar %2$s para seu servidor de identidade + Usar %1$s + Alternativamente, você pode entrar qualquer outro URL de servidor de identidade + Entre o URL de um servidor de identidade + Submeter + Definir papel + Papel + Abrir chat + Mutar o microfone + Desmutar o microfone + Parar a câmera + Começar a câmera + Backup seguro + Salvaguardar-se contra perda de acesso a mensagens & dados encriptados ao fazer backup de chaves de encriptação em seu servidor. + Configurar + Usar uma Chave de Segurança + Gere uma chave de segurança para armazenar em algum lugar seguro como um gerenciador de senhas ou um cofre. + Usar uma Frase de Segurança + Entre uma frase secreta que somente você conhece, e gere uma chave para backup. + Salvar sua Chave de Segurança + Armazene sua Chave de Segurança em algum lugar seguro, como um gerenciador de senhas ou um cofre. + Definir uma Frase de Segurança + Entre uma frase de segurança que somente você conheça, usada para assegurar segredos em seu servidor. + Frase de Segurança + Entre sua Frase de Segurança de novo para confirmá-la. + Nome de Sala + Tópico + Você mudou configurações de sala com sucesso + Você não pode acessar esta mensagem + Esperando por esta mensagem, isto pode levar algum tempo + Devido a encriptação ponta-a-ponta, pode ser que você precise esperar para que a mensagem de alguém chegue porque as chaves de encriptação não foram enviadas apropriadamente para você. + Você não pode acessar esta mensagem porque você foi bloqueada(o) pelo(a) enviador(a) + Você não pode acessar esta mensagem porque sua sessão não é confiada pelo(a) enviador(a) + Você não pode acessar esta mensagem porque o/a enviador(a) propositalmente não enviou as chaves + Esperando por histórico de encriptação + Riot agora é Element! + Nós estamos animados em anunciar que nós temos mudado de nome! Seu app está atualizado e você está com signin feito a sua conta. + ENTENDI + SABER MAIS + Salvar chave de recuperação em + Recuperando seus contatos… + Seu livro de contatos está vazio + Livro de Contatos + Revogar convite + Revogar convite para %1$s\? + Banida(o) por %1$s + Falha para DesBanir usuária(o) + Notificações push estão desabilitadas + Revise suas configurações para habilitar notificações push + Escolha um PIN por segurança + Confirme PIN + Falha para validar PIN, por favor toque um novo. + Entre seu PIN + Esqueceu PIN\? + Resettar PIN + Novo PIN + Para resettar seu PIN, você vai precisar refazer login e criar um novo. + Habilitar PIN + Se você quer resettar seu PIN, toque em Esqueceu PIN para fazer logout e resettá-lo. + Prevenir chamada acidental + Pedir por confirmação antes de começar uma chamada + Você não tem permissão para começar uma chamada de conferência nesta sala + Começar reunião de vídeo + Começar reunião de áudio + Reuniões usam políticas de segurança e permissão de Jitsi. Todas as pessoas atualmente na sala vão ver um convite para se juntarem enquanto sua reunião estiver acontecendo. + Você não pode começar uma chamada com você mesma(o) + Você não pode começar uma chamada com você mesma(o), espere pelas(os) participantes aceitarem convite + Falha para adicionar widget + Falha para remover widget + + %1$d/%2$d chave importada com êxito. + %1$d/%2$d chaves importadas com êxito. + + Gerenciar Integrações + Nenhum widget ativo + A sala foi criada, mas alguns convites não foram enviados pelo seguinte motivo: +\n +\n%s + + %1$s, %2$s e %3$d outra(o) leu + %1$s, %2$s e %3$d outras(os) leram + + + Código errado, %d tentativa restante + Código errado, %d tentativas restantes + + Aviso! Última tentativa restante antes de logout! + Erros demais, você tem sido feito logout + Você não tem permissão para começar uma chamada nesta sala + Nenhum número de telefone tem sido adicionado a sua conta + Endereços de email + Nenhum endereço de email tem sido adicionado a sua conta + Números de telefone + Remover %s\? + Assegure-se que você tem clicado no link no email que enviamos para você. + + %d segundo + %d segundos + + Emails e números de telefone + Gerenciar endereços de email e números de telefone linkados a sua conta Matrix + Código + Por favor use o formato internacional (número de telefone deve começar com \'+\') + Confirme sua identidade ao verificar este login, concedendo-lhe acesso a mensagens encriptadas. + Não dá para abrir uma sala de onde você foi banida(o). + Não dá para encontrar esta sala. Assegure-se que ela existe. + O link foi malformado + Este número de telefone já está definido. + Sondagem + Reagiu com: %s + Conclusão de Verificação + Deletar os dados de conta de tipo %1$s\? +\n +\nUse com caução, pode levar a comportamento inesperado. + Código PIN é requerido toda vez que você abre ${app_name}. + Código PIN é requerido depois de 2 minutos de não usar ${app_name}. + Requerer PIN depois de 2 minutos + Somente mostrar número de mensagens não-lidas em uma notificação simples. + Mostrar detalhes como nomes de salas e conteúdo de mensagens. + Mostrar conteúdo em notificações + Código PIN é a única maneira de destrancar ${app_name}. + Habilitar biometria específica de dispositivo, como impressões digitais e reconhecimento de face. + Habilitar biometria + Configurar a proteção + Proteger acesso usando PIN e biometria. + Proteger acesso + + Mostrar o dispositivo com o qual você pode verificar agora + Mostrar %d dispositivos com os quais você pode verificar agora + + Você vai recomeçar com nada de histórico, mensagens, dispositivos confiados ou usuárias(os) confiadas(os) + Se você resetar tudo + Somente faça isto se você não tem nenhum outro dispositivo com o qual você pode verificar este dispositivo. + Resettar tudo + Esqueceu ou perdeu todas as opções de recuperação\? Resette tudo + Você entrou. + Mensagens neste chat são encriptadas ponta-a-ponta. + Sair + Configurações + Mensagens aqui são encriptadas ponta-a-ponta. +\n +\nSuas mensagens são asseguradas com cadeados e somente você e a/o recipiente têm as chaves únicas para as destrancar. + Mensagens aqui não são encriptadas ponta-a-ponta. + Este servidorcasa está rodando uma versão antiga. Peça à/ao admin de seu servidorcasa para fazer upgrade. Você pode continuar, mas algumas funcionalidades podem não funcionar corretamente. + Mostrar histórico completo em salas encriptadas + %1$s e %2$s + %1$s em %2$s e %3$s + A notificação tem sido clicada! + Por favor clique na notificação. Se você não vê a notificação, por favor cheque as configurações de sistema. + Exibição de Notificações + Você está visualizando a notificação! Clique em mim! + Falha para receber push. Solução podia ser reinstalar o aplicativo. + O aplicativo está recebendo PUSH + O aplicativo está esperando pelo PUSH + Você não tem permissão para começar uma chamada + Você não tem permissão para começar uma chamada de conferência + Resettar + %1$s fez isto somente convite. + Você fez isto somente convite. + %s entrou. + Filtrar usuárias(os) banidas(os) + Testar Push + + %d convite + %d convites + + Remover de prioridade baixa + Adicionar a prioridade baixa + Adicionar imagem de + Descartar mudanças + Existem mudanças não-salvas. Descartar as mudanças\? + A sala ainda não está criada. Cancelar a criação de sala\? + Rotar e recortar + Configurações de sala + Tópico + Tópico de sala (opcional) + Nome de sala + Enviar histórico de requisições de compartilhamento de chaves + Mais nenhum resultado + Exportar Auditoria + Mensagem direta + Mostrar avançadas + Esconder avançadas + %s para deixar pessoas saberem do que esta sala se trata. + Por favor proveja um endereço de sala + QR code não scannado! + QR code inválido (URI Inválido)! + Não dá para enviar DM para si mesma(o)! + Compartilhar por texto + Pesquisar por contatos na Matrix + Definir avatar + O consentimento de usuária(o) não tem sido provido. + Compartilhe este código com pessoas para que elas possam scanná-lo para adicionar você e começar a fazer chat. + Meu código + Compartilhar meu código + Scannar um QR code + Não é um QR code matrix válido + 🔐️ Junte-se a mim em ${app_name} + Hey, fale comigo em ${app_name}: %s + Convidar amigas(os) + Adicionar pessoas + "Tópico: " + Adicionar um tópico + Este é o começo de seu histórico de mensagem direta com %s. + Este é o começo desta conversa. + Este é o começo de %s. + Você não tem permissão para habilitar encriptação nesta sala. + Criando sala… + Alguns caracteres não são permitidos + Este endereço já está em uso + Você poderia habilitar isto se a sala vai somente ser usada para colaborar com times internos em seu servidorcasa. Isto não poder ser mudado mais tarde. + Bloquear qualquer pessoa que não é parte de %s de jamais se juntar a esta sala + %1$d de %2$d + Dar consentimento + Revogar meu consentimento + Você tem dado seu consentimento para enviar endereços de email e números de telefone para este servidor de identidade para descobrir outras(os) usuárias(os) de seus contatos. + Enviar emails e números de telefone + Sugestões + Usuárias(os) Conhecidas(os) + QR code + Adicionar por QR code + Aceitar permissão para acessar seus contatos. + Para scannear um QR code, você precisa permitir acesso a câmera. + Começar a Conversar + Publicar este endereço + Adicionar um endereço local + Esta sala não tem nenhum endereço local + Endereços Locais + Deletar o endereço \"%1$s\"\? + Publicar + Publicar um novo endereço manualmente + Outros endereços publicados: + Este é o endereço principal + Endereços publicados podem ser usados por qualquer pessoa em qualquer servidor para se junta a sua sala. Para publicar um endereço, ele precisa ser definido como um endereço local primeiro. + Endereços Publicados + Ver e gerenciar endereços desta sala, e sua visibilidade no diretório de salas. + Endereços de sala + Adicionar + Mudar seu PIN atual + Mudar PIN + Esta sala não pode ser previsualizada. Você quer se judar a ela\? + Esta sala não está acessível neste momento. +\nTente de novo mais tarde, ou peça a um/uma admin da sala para checar se você tem acesso. + Incapaz de recuperar a visibilidade atual de diretório de salas (%1$s). + Publicar esta sala ao público no diretório de salas de %1$s\? + Despublicar este endereço + Defina endereços para esta sala para que usuárias(os) possam encontrar esta sala através de seu servidorcasa (%1$s) + Novo endereço publicado (e.g. #alias:servidor) + Nenhum outro endereço publicado ainda. + Nenhum outro endereço publicado ainda, adicione um abaixo. + Despublicar o endereço \"%1$s\"\? + Acesso a sala + Mundaças de quem pode ler o histórico só se vão aplicar a mensagens futuras nesta sala. A visibilidade de histórico existente vai ser inalterada. + Despublicar + sign-on único + Adicionar um botão em compositor de mensagem para abrir teclado de emoji + Notificar todas as pessoas + envia queda de neve ❄️ + envia confetti 🎉 + Envia a dada mensagem com queda de neve + Envia a dada mensagem com confetti + Limpar histórico + Fazer signin com %s + Fazer signup com %s + Continuar com %s + Ou + Mostrar teclado de emoji + Use comando /confetti ou envie uma mensagem contendo ❄️ ou 🎉 + Mostrar efeitos de chat + Mudar tópico + Fazer upgrade da sala + Enviar eventos m.room.server_acl + Mudar permissões + Mudar nome de sala + Mudar visibilidade do histórico + Habilitar encriptação da sala + Mudar endereço principal para a sala + Mudar avatar da sala + Modificar widgets + Remover mensagens enviadas por outras(os) + Banir usuárias(os) + Expulsar usuárias(os) + Mudar configurações + Convidar usuárias(os) + Enviar mensagens + Papel default + Você não tem permissão para atualizar os papéis necessários para mudar várias partes da sala + Selecione os papéis requeridos para mudar várias partes da sala + Visualizar e atualizar os papéis requeridos para mudar várias partes da sala. + Permissões + Permissões de sala + Esta sala não é pública. Você não vai ser capaz de se rejuntar sem um convite. + Default de Sistema + Falha para autenticar + ${app_name} requer que você entre suas credenciais para performar esta ação. + Re-Autenticação Necessitada + Não autorizada(o), credenciais de autenticação válidas faltando + Usuárias(os) + Um erro ocorreu enquanto transferindo chamada + Transferir + Conectar + Consultar primeiro + Chamada ativa (%1$s) + Houve um erro ao procurar o número de telefone + Pad de disco + Chamar de volta + Esta chamada tem terminado + %1$s declinou esta chamada + Falha para configurar Asinatura Cruzada + Você pôs a chamada em espera + %s pôs a chamada em espera + Pôr em espera + Retomar + Nível de confiança default + Selecionada + Vídeo + Algumas mensagens não têm sido enviadas + Deletar avatar + Mudar avatar + Imagem + Importar chave desde arquivo + Abrir widgets + Screenshot + O limite é desconhecido. + Seu servidorcasa aceita anexos (arquivos, mídia, etc.) com um tamanho de até %s. + Versão do servidor + Nome do servidor + Configurações de sala + Sair da conferência atual e trocar para a outra\? + Versão da sala + Mostrar todas as salas no diretório de salas, incluindo salas com conteúdo explícito. + Mostrar salas com conteúdo explícito + Diretório de salas + Novo valor + Alterar + Sincronização inicial: +\nFazendo download de dados… + Sincronização inicial: +\nEsperando pela resposta do servidor… + Nível de confiança confiado + Nível de confiança alerta + Você tem certeza que você quer deletar todas as mensagens não-enviadas nesta sala\? + Deletar mensagens não-enviadas + Mensagens falharam para enviar + Você quer cancelar enviar mensagem\? + Deletar todas as mensagens falhadas + Falhou + Enviado + Enviando + Conteúdo de evento + Evento de estado enviado! + Evento enviado! + Evento malformado + Tipo de mensagem faltando + Sem conteúdo + Conteúdo de Evento + Chave de Estado + Tipo + Enviar Evento de Estado Personalizado + Editar Conteúdo + Eventos de Estado + Enviar Evento de Estado + Enviar Evento Personalizado + Explorar Estado de Sala + Ferramentas Dev + Visualizar recibos de leitura + Não notificar + Notificar sem som + Notificar com som + Mensagem não enviada devido a erro + Checado + Fechar Seletor de Emoji + Abrir seletor de Emoji + tem rascunho não-enviado + + %d entrada + %d entradas + + Limite de upload de arquivo do servidor + Qualquer pessoa num espaço com esta sala pode achá-la e se juntar a ela. Somente admins desta sala podem adicioná-la a um espaço. + Membros de espaço somente + Qualquer pessoa pode achar a sala e se juntar + Pública + Somente pessoas convidadas podem achar e se juntar + Privada + Configuração de acesso desconhecida (%s) + Qualquer pessoa pode bater na porta na sala, membros podem então aceitar ou rejeitar + Permitir visitantes se juntarem + Usar como default e não perguntar de novo + Sempre perguntar + Espaços + Salas Sugeridas + Mensagem enviada + O arquivo é grande demais para fazer upload. + Pesquisar Nome + Comprimindo vídeo %d%% + Comprimindo imagem… + Dar Feedback + O feedback falhou para ser enviado (%s) + Obrigado, seu feedback tem sido enviado com sucesso + Vocês podem me contactar se vocês tiverem quaisquer perguntas subsequentes + Você está usando uma versão beta de espaços. Seu feedback vai ajudar a informar as próximas versões. Sua plataforma e nome de usuária(o) vão ser anotados para nos ajudar a usar o seu feedback tanto quanto nós pudermos. + Feedback + Feedback de espaços + Desculpe, um erro ocorreu enquanto tentando se juntar à conferência + Juntar-se ao Espaço com a dada id + Sala pública + Não-checado + Pessoa desconhecida + Transferir para %1$s + Consultando com %1$s + Marcar como não sugerida(o) + Marcar como sugerida(o) + Sugerida(o) + Este alias não é acessível neste momento. +\nTente de novo mais tarde, ou peça a um/uma admin de sala para checar se você tem acesso. + Juntar-Se Mesmo Assim + Pular por enquanto + Elas não vão fazer parte de %s + Só a esta sala + Compartilhar link + Convidar por email + Convidar pessoas + Você está convidada(o) + %s convida você + Sala Não-Nomeada + Algumas salas podem estar escondidas porque elas são privadas e você precisa de um convite. + Algumas salas podem estar escondidas porque elas são privadas e você precisa de um convite. +\nVocê não tem permissão para adicionar salas. + Este espaço não tem nenhuma sala + Por favor contacte sua/seu admin de servidorcasa para mais informação + Parece que seu servidorcasa não suporta Espaços ainda + Se sentindo experimental\? +\nVocê pode adicionar espaços existentes a um espaço. + Gerenciar salas e espaços + Gerenciar salas + Procurando por alguém que não está em %s\? + Espaços são uma nova forma de agrupar salas e pessoas. + Adicionar salas e espaços existentes + Você é a/o única(o) admin deste espaço. Sair dele vai significar que ninguém tem controle sobre ele. + Você não vai ser capaz de se rejuntar a menos que você seja re-convidada(o). + Você é a única pessoa aqui. Se você sair, ninguém vai ser capaz de se juntar no futuro, incluindo você. + Sair + Adicionar salas + Explorar salas + + %d pessoa que você conhece já entrou + %d pessoas que você conhece já entraram + + Juntar-Se a Espaço + Criar espaço + Junte-se a meu espaço %1$s %2$s + Elas vão ser capazes de explorar %s + Convidar para %s + É só você no momento. %s vai ser ainda melhor com outras(os). + Convidar para %s + Convidar pessoas para seu espaço + Descrição + Criando Espaço… + Aleatório + Geral + Vamos criar uma sala para cada uma delas. Você pode adicionar outras mais tarde também, incluindo umas já existentes. + Em que coisas você está trabalhando\? + Nós vamos criar salas para elas. Você pode adicionar outras mais tarde também. + Quais são algumas discussões que você quer ter em %s\? + Dê-lhe um nome para continuar. + Adicione alguns detalhes para ajudar pessoas a identificá-lo. Você pode mudar isto a qualquer ponto. + Adicione alguns detalhes para ajudá-lo a se destacar. Você pode mudar isto a qualquer ponto. + Criar um espaço + Somente convite, o melhor para você mesma(o) ou equipes + Privado + Aberto para qualquer pessoa, o melhor para comunidades + Público + Um espaço privado para você & suas/seus colegas de equipe + Eu e minhas/meus colegas de equipe + Um espaço privado para organizar suas salas + Só eu + Assegure-se que as pessoas certas têm acesso a %s. + Com quem você está trabalhando\? + Para se juntar a um espaço existente, você precisa de um convite. + Você pode mudar isto mais tarde + Que tipo de espaço você quer criar\? + Seu espaço privado + Seu espaço público + Adicionar espaço + Espaço privado + Espaço público + Criar um Espaço + Sair de sala com dada id (ou sala atual se nula) + Este servidor já está presente na lista + Não dá para encontrar este servidor ou sua lista de salas + Entre o nome de um novo servidor que você quer explorar. + Adicionar um novo servidor + Seu servidor + Enviar mídia com o tamanho original + + Enviar vídeo com o tamanho original + Enviar vídeos com o tamanho original + + Desculpe, um erro ocorreu enquanto tentando se juntar: %s + Endereço de espaço + Ver e gerenciar endereços deste espaço. + Endereços de espaço + Fazer upgrade para a versão de sala recomendada + Esta sala está rodando versão de sala %s, que este servidorcasa tem marcado como instável. + Você precisa de permissão para fazer upgrade de uma sala + Fazer update de pai de espaço automaticamente + Convidar usuárias(os) automaticamente + Você vai fazer upgrade desta sala de %1$s para %2$s. + Fazer upgrade de uma sala é uma ação avançada e é geralmente recomendado quando uma sala está instável devido a bugs, funcionalidades faltando ou vulnerabilidades de segurança. +\nIsto geralmente só afeta como a sala é processada no servidor. + Fazer upgrade de sala privada + Fazer upgrade de sala pública + Fazer upgrade + Por favor seja paciente, pode levar algum tempo. + Juntar-se a sala de substituição + Faz upgrade de uma sala para uma nova versão + instável + estável + Versão Default + Versões de Sala 👓 + Verificar ao comparar emoji em vez disso + Scannar com este dispositivo + Scanne o código com seu outro dispositivo ou troque e scanne com este dispositivo + URL de API de Servidorcasa + Permissões faltando + Para performar esta ação, por favor conceda a permissão Câmera a partir das configurações de sistema. + Algumas permissões estão faltando para performar esta ação, por favor conceda as permissões a partir das configurações de sistema. + + Chamada de vídeo perdida + %d chamadas de vídeo perdidas + + + Chamada de áudio perdida + %d chamadas de áudio perdidas + + Por favor note que fazer upgrade vai fazer uma nova versão da sala. Todas as mensagens atuais vão ficar nesta sala arquivada. + Qualquer pessoa em um espaço pai vai ser capaz de achar e se juntar a esta sala - não precisa manualmente convidar todo mundo. Você vai ser capaz de mudar isto em configurações de sala a qualquer hora. + Qualquer pessoa em %s vai ser capaz de achar e se juntar a esta sala - não precisa manualmente convidar todo mundo. Você vai ser capaz de mudar isto em configurações de sala a qualquer hora. + Mensagem de Voz (%1$s) + Não dá para responder ou editar enquanto mensagem de voz está ativa + Não dá para gravar uma mensagem de voz + Não dá para tocar esta mensagem de voz + Toque em sua gravação para parar ou escutar + %1$ds restando + Segure para gravar, solte para enviar + Deletar gravação + Gravando mensagem de voz + Pausar Mensagem de Voz + Tocar Mensagem de Voz + Deslize para cancelar + Gravar Mensagem de Voz + Upgrade Requerido + Voz + Outros espaços ou salas que você poderia não saber + Espaço que você sabe que contém esta sala + Decida quem pode achar e se juntar a esta sala. + Toque para editar espaços + Selecionar espaços + Decida que espaços podem acessar esta sala. Se um espaço é selecionado seus membros vão ser capazes de achar e se juntar a Nome de sala. + Espaços que podem acessar + Permitir membros de espaço a encontrar e acessar. + Membros de Espaço %s podem achar, previsualizar e se juntar. + Privada (Convite Somente) + Para enviar mensagens de voz, por favor conceda a permissão Microfone. + Notifique-me para + Upgrades de sala + Mensagens por bot + Convites de sala + Mensagens de grupo encriptadas + Mensagens de grupo + Mensagens diretas encriptadas + Mensagens diretas + Meu nome de usuária(o) + Meu nome de exibição + Outras + Menções e Palavrachaves + Notificações Default + %s em Configurações para receber convites diretamente em ${app_name}. + Linkar este endereço de email com sua conta + Este convite para este espaço foi enviado para %s que não está associado com sua conta + Este convite para esta sala foi enviado para %s que não está associado com sua conta + Todas as salas em que você está vão ser mostradas em Home. + Mostrar todas as salas em Home + Deslize para terminar a chamada + %1$s Toque para retornar + Chamada ativa (%1$s) · + + Chamada ativa · + %1$d chamadas ativas · + + Sem resposta + Chamada de vídeo perdida + Chamada de voz perdida + Chamada de vídeo declinada + Chamada de voz declinada + Chamada de vídeo terminada • %1$s + Chamada de voz terminada • %1$s + Chamada de vídeo ativa + Chamada de voz ativa + Chamada de vídeo entrante + Chamada de voz entrante + Você declinou esta chamada + Configurações de conta + Você pode gerenciar notificações em %1$s. + Por favor note que notificações de menções & palavrachave não estão disponíveis em salas encriptadas no celular. + Notifique-me para + Você não vai ter notificações para menções & palavrachaves em salas encriptadas no celular. + Palavrachaves + \@room + Palavrachaves não podem conter \'%s\' + Palavrachaves não podem começar com \'.\' + Adicionar nova palavrachave + Suas palavachaves + Nenhuma + Menções & Palavrachaves somente + Terminando chamada… + Sem resposta + A/o usuária(o) que você chamou está ocupada(o). + Usuária(o) ocupada(o) + Chamada de áudio com %s + Chamada de vídeo com %s + Chamada tocando… + Espaços + Adicione um espaço a qualquer espaço que você gerencia. + Adicionar espaços existentes + Adicionar salas existentes + Você tem certeza que você quer sair de %s\? + Descoberta (%s) + Terminar configuração + Convidar por email, encontrar contatos e mais… + Termine de configurar descoberta. + Você não está atualmente usando um servidor de identidade. A fim de convidar colegas e ser descobertável por elas(es), configure um abaixo. + Convidar por nome de usuária(o) ou mail + Assegure que as pessoas certas têm acesso a companhia %s. Você pode convidar outras mais tarde. + Quem são suas/seus colegas\? + Adicionar ao dado Espaço + Criando espaço… + Mostrar certa info útil para ajudar a fazer debugging do aplicativo + Mostrar info de debug em tela + Não parece com um endereço de email válido + Abrir Configurações de Descoberta + Pesquisar por nome, ID ou mail + Criar Novo Espaço + Qualquer pessoa pode achar o espaço e se juntar + Acesso a espaço + Quem pode acessar\? + Habilitar notificações de email para %s + Para receber email com notificação, por favor associe um endereço de email a sua conta Matrix + Notificação de email + Fazer upgrade do espaço + Mudar nome de espaço + Habilitar encriptação de espaço + Mudar endereço principal para o espaço + Mudar avatar de espaço + Você não tem permissão para atualizar os papéis requeridos para mudar várias partes deste espaço + Selecione os papéis requeridos para mudar várias partes deste espaço + Veja e atualize os papéis requeridos para mudar várias partes do espaço. + Permissões de espaço + Desbanir usuária(o) vai permiti-la(o) se juntar ao espaço de novo. + Banir usuária(o) vai removê-la(o) deste espaço e preveni-la de se juntar de novo. + expulsar usuária(o) vai removê-la(o) deste espaço. +\n +\nPara preveni-la(o) de se juntar de novo, você devia bani-la(o) em vez disso. + Parar de Gravar + Prepende ( ͡° ͜ʖ ͡°) a uma mensagem de texto puro + Nenhuma política provida pelo servidor de identidade + Esconder política de servidor de identidade + Mostrar política de servidor de identidade + Exibe informação sobre um/uma usuário(a) + Muda seu avatar nesta sala atual somente + Muda o avatar da sala atual + Muda seu apelido de exibição na sala atual somente + Define o nome da sala + Para de ignorar um/uma usuário(a), mostrando as mensagens dele/dela de agora em diante + Ignora um/uma usuário(a), escondendo as mensagens dele/dela de você + Fora + Offline + Online + Escolher servidorcasa + Não dá para alcançar um servidorcasa na URL %s. Por favor cheque seu link ou escolha um servidorcasa manualmente. + À escuta por notificações + + Pelo menos %1$s opção é requerida + Pelo menos %1$s opções são requeridas + + Pergunta não pode estar vazia + CRIAR SONDAGEM + ADICIONAR OPÇÃO + Opção %1$d + Criar opções + Pergunta ou tópico + Sondar pergunta ou tópico + Criar Sondagem + Sondagem + Enviar endereços de email e números de telefone para %s + Seus contatos são privados. Para descobrir usuárias(os) de seus contatos, você precisa de permissão para enviar info de contato a seu servidor de identidade. + O signout desta sessão tem sido feito! + Esta sala tem sido saída! + Você concorda em enviar esta info\? + Para descobrir contatos existentes, você precisa enviar info de contato (endereços de email e números de telefone) para seu servidor de identidade. Nós hashamos seus dados antes de enviar por privacidade. + Não agora + Você tem certeza que você quer remover esta sondagem\? Você não vai ser capaz de recuperá-la uma vez removida. + Remover sondagem + Sondagem terminada + Voto lançado + Terminar sondagem + Isto vai parar pessoas de serem capazes de votar e vai exibir os resultados finais da sondagem. + Terminar esta sondagem\? + Terminar sondagem + + Resultado final baseado em %1$d voto + Resultado final baseado em %1$d votos + + + %1$d voto lançado. Vote para ver os resultados + %1$d votos lançados. Vote para ver os resultados + + + Baseado em %1$d voto + Baseado em %1$d votos + + + %1$d voto + %1$d votos + + Versões + Conseguir ajuda com uso de ${app_name} + Jurídicos + Este servidor não provê nenhuma política. + Bibliotecas de terceiros + A política do seu servidor de identidade + A política do seu servidor local + Política de ${app_name} + Nós não gravaremos nem criaremos um perfil dos dados de sua conta + Ajude-nos a identificar problemas e melhorar ${app_name} ao compartilhar dados de uso anônimos. Para entender como pessoas usam seus múltiplos dispositivos, nós vamos gerar um identificador aleatório, compartilhado por seus dispositivos. +\n +\nVocê pode ler todos os nossos termos %s. + Ajude a melhorar ${app_name} + Configurações de sistema + Ajuda e suporte + Ajuda + Você pode desativar isto a qualquer hora em configurações + Nós não compartilhamos informação com terceiros + aqui + Habilitar + Recomece o aplicativo para a mudançar tomar efeito. + Habilitar matemática LaTeX + Você não é permitida(o) se juntar a esta sala + Criar sondagem + Abrir contatos + Enviar sticker + Fazer upload de arquivo + Enviar imagens e vídeos + Abrir câmera + Seu sistema vai automaticamente enviar logs quando um erro incapaz de decriptar ocorre + Auto Reportar Erros de Decriptação. + Sobrepor cor de nome de exibição + Eu já tenho uma conta + Mensageria segura. + Você está em controle. + Tenha posse de suas conversas. + Compartilhar localização + Abrir com + ${app_name} não pôde acessar sua localização. Por favor tente de novo mais tarde. + ${app_name} não pôde acessar sua localização + Localização + Compartilhar localização + Resultados são somente revelados quando você termina a sondagem + Sondagem fechada + Votantes veem resultados assim que elas(es) têm votado + Sondagem aberta + Tipo de sondagem + Editar sondagem + Nenhum voto lançado + Encriptação está malconfigurada + Restaurar Encriptação + Por favor contacte um(a) admin para restaurar encriptação a um estado válido. + Compartilhou a localização dela(e) + Localização + Encriptação tem sido malconfigurada. + Criar conta + Mensageria para seu time. + Encriptado ponta-a-ponta e nenhum número de telefone requerido. Sem publicidade ou datamining. + Escolha onde suas conversas são mantidas, dando-lhe controle e independência. Conectado via Matrix. + Comunicação segura e independente que lhe dá o mesmo nível de privacidade que conversa face-a-face em sua própria casa. + Encriptação tem sido malconfigurada então você não pode enviar mensagens. Clique para abrir configurações. + Encriptação tem sido malconfigurada então você não pode enviar mensagens. Por favor contacte um(a) admin para restaurar encriptação a um estado válido. + Mostrar Bolhas de mensagem + Falha para carregar mapa + Mapa + Nota: app vai ser recomeçado + Habilitar mensagens com threads + Conectar a servidor + Procurando se juntar a um servidor existente\? + Pular esta pergunta + Não tem certeza ainda\? %s + Comunidades + Times + Amigas(os) e família + Nós vamos ajudá-la(o) a ficar conectada(o) + Com quem você vai fazer chat mais\? + Você já está visualizando esta thread! + Visualizar Em Sala + Responder em thread + O comando \"%s\" é reconhecido mas não suportado em threads. + De uma Thread + Dica: Toque longo numa mensagem e use “%s”. + Threads ajudam manter suas conversas em-tópico e fáceis de rastrear. + Mantenha discussões organizadas com threads + Mostra todas as threads nas quais você tem participado + Minhas Threads + Mostra todas as threads de sala atual + Todas as Threads + Filtrar + Threads + Thread + Filtrar Threads em sala + Copiar link para thread + Visualizar em sala + Visualizar Threads + Notificação de sala + Usuárias(os) + Notificar a sala toda + + %1$d mais + %1$d mais + + Mostrar menos + + %d mudança de ACLs de servidor + %d mudanças de ACLs de servidor + + %1$s, %2$s e outras(os) + %1$s e %2$s + Localização ao vivo habilitada + Compartilhar esta localização + Compartilhar esta localização + Compartilhar localização ao vivo + Compartilhar localização ao vivo + Compartilhar minha localização atual + Compartilhar minha localização atual + Zoom para localização atual + Pin de localização selecionada em mapa + Parar + Nós estamos ficando mais perto de lançar uma Beta pública para Threads. +\n +\nEnquanto nos preparamos para isso, nós precisamos fazer algumas mudanças: threads criadas antes deste ponto vão ser exibidas como respostas regulares. +\n +\nIsto vai ser uma transição única visto que Threads são agora parte da especificação Matrix. + Threads Aproximando-Se a Beta 🎉 + ${app_name} Localização ao Vivo + Compartilhamento de localização está em progresso + O servidorcasa não aceita nome de usuária(o) com somente dígitos. + Pular este passo + Salvar e continuar + Passe em configurações a qualquer momento para atualizar seu perfil + Tá com uma cara boa! + Vamo lá + Hora de colocar um rosto ao nome + Adicione uma imagem de perfil + Você pode mudar isto mais tarde + Nome de Exibição + Escolha um nome de exibição + Sua conta %s tem sido criada + Parabéns! + Me leve para casa + Personalizar perfil + Desabilitar + Carregando localização ao vivo… + 8 horas + 1 hora + 15 minutos + Compartilhar sua localização ao vivo por + (%1$s) + %1$s (%2$s) + Incapaz de tocar %1$s + Pausar %1$s + Tocar %1$s + %1$d minutos %2$d segundos + %1$s, %2$s, %3$s + Compartilhou a localização ao vivo dela(e) + ${app_name} também é ótimo para o lugar de trabalho. Ele é confiado pelas organizações mais seguras do mundo. + BETA + Threads são um trabalho em progresso com novas funcionalidades próximas emocionantes, tais como notificações melhoradas. Nós adoraríamos ouvir seu feedback! + Feedback de Threads Beta + Dar Feedback + BETA + Se habilitado, você sempre vai aparecer offline para outras(os) usuárias(os), mesmo quando usando o aplicativo. + Modo offline + Presença + Seu servidorcasa não atualmente suporta threads, então esta funcionalidade pode ser inconfiável. Algumas mensagens de thread podem não estar confiavelmente disponíveis. %sVocê quer habilitar threads mesmo assim\? + Threads Beta + Threads ajudam manThreads ajudam manter suas conversas em-tópico e fáceis de rastrear. %sHabilitar threads vai refrescar o app. Isto pode tomar mais tempo para algumas contas. + Threads Beta + Saber mais + Experimentar + Compartilhamento de tela está em progresso + ${app_name} Compartilhamento de Tela + Parar compartilhamento de tela + Compartilhar tela + - Algumas(ns) usuárias(os) têm sido designoradas(os) + ${app_name} precisa performar uma limpa de cache para estar atualizado, pela seguinte razão: +\n%s +\n +\nNote que esta ação vai recomeçar o app e pode levar algum tempo. + Requisição de sincronização inicial + Mostrar a info de perfil mais recente (avatar e nome de exibição) para todas as mensagens. + Mostrar info de usuária(o) mais recente + Ocupada(o) + Backup tem uma assinatura válida desta(e) usuária(o). + Atualizada %1$s atrás + Implementação tempoária: locais persistem em histórico de sala + Habilitar Compartilhamento de Localização Ao Vivo + %1$s restando + Ao vivo até %1$s + Ver localização ao vivo + Localização ao vivo terminou + Alguns resultados podem estar escondidos porque eles são privados e você precisa de um convite para eles. + Nenhum resultado encontrado + Sair de nenhum + Sair de todos + Coisas neste espaço + Tocar imagens animadas na timeline assim que elas estão visíveis + Auto-tocar imagens animadas + seg + min + h + Observação: esta é uma funcionalidade experimental usando uma implementação temporária. Isso significa que você não poderá deletar seu histórico de localização, e usuários avançados poderão ver seu histórico de localização mesmo depois que você parar de compartilhar sua localização em tempo real com esta sala. + Tag do perfil: + Falhou ao registrar o token do endpoint ao servidorcasa: +\n%1$s + Endpoint + Gateway + Ativar compartilhamento de localização + Compartilhamento de localização ao vivo + Gateway atual: %s + Não foi possível encontrar o endpoint. + Endpoint atual: %s + Usando %s atualmente. + Método + + %d método encontrado. + %d métodos encontrados. + + Nenhum outro método além da sincronização em plano de fundo encontrado. + Nenhum outro método além do Google Play Services encontrado. + Métodos disponíveis + Método de notificação + Sincronização em plano de fundo + Serviços do Google + Escolha como receber notificações + A verificação biométrica foi desativada porque um novo método de verificação biométrica foi adicionado recentemente. Você pode reativá-la nas Configurações. + Não foi possível ativar a verificação biométrica. + Redefinir método de notificação + Endpoint registrado com sucesso ao servidor casa. + Registro de Endpoint + Próximo + + %d mensagem removida + %d mensagens removidas + + Compartilhar localização + Você precisa ter as permissões certas a fim de compartilhar localização ao vivo nesta sala. + Você não tem permissão para compartilhar localização ao vivo + Resultados vão ser visíveis quando a sondagem estiver terminada + Ao convidar alguém para uma sala criptografada que compartilha o histórico de texto, ele será visível mesmo sendo criptografado. + MSC3061: Compartilhando chaves de sala para mensagens passadas + Envie sua primeira mensagem para convidar %s a fazer chat + Mensagens neste chat vão ser encriptadas ponta-a-ponta. + Não dá para abrir este link: comunidades têm sido substituídas por espaços + Nome de Usuária(o) / Email / Telefone + Você é um/uma humano(a)\? + Siga as instruções enviadas para %s + Senha resettada + Esqueceu senha + Reenviar email + Não recebeu um email\? + Siga as instruções enviadas para %s + Verifique seu email + Reenviar código + Um código foi enviado para %s + Confirmar seu número de telefone + Fazer signout de todos os dispositivos + Resettar senha + Garanta que seja 8 caracteres ou mais. + Escolher uma senha nova + Senha Nova + Checar seu email. + %s vai enviar para você um link de verificação + Código de confirmação + Número de Telefone + %s precisa verificar sua conta + Entrar seu número de telefone + Email + %s precisa verificar sua conta + Entrar seu email + Por favor leia todos os termos e políticas de %s + Políticas de servidor + Entrar em contato + Element Matrix Services (EMS) é um serviço de hospedagem robusto e confiável para comunicação rápida, segura e em tempo real. Descubra como em element.io/ems + Quer hospedar seu próprio servidor\? + URL de servidor + Qual é o endereço de seu servidor\? Isto é como uma casa para todos os seus dados + Selecionar seu servidor + Boas-vindas de volta! + Editar + Ou + Onde suas conversas vão viver + Deve ser 8 caracteres ou mais + Outras(os) podem descobrir você %s + Criar sua conta + Ir + Usar default de sistema + Escolher manualmente + Definir automaticamente + Encolher tamanho de fonte + Auto-aprovar widgets de Element Call e conceder acesso de câmera / mic + Habilitar atalhos de permissão de Element Call + Localização ao vivo + Este QR code parece malformado. Por favor tente verificar com um outro método. + Você não vai ser capaz de acessar histórico de mensagem encriptada. Resette seu Backup de Mensagem Seguro e chaves de verificação para começar do zero. + Incapaz de verificar este dispositivo + Qual é o endereço de seu servidor\? + Onde suas conversas vivem + Atualizando seus dados… + + %1$s e %2$d outro + %1$s e %2$d outros + + %1$s e %2$s + Email não verificado, cheque sua inbox + Incapaz de carregar mapa +\nEste servidor casa pode não estar configurado para exibir mapas. + Abrir configurações + Todos os Chats + Para a melhor segurança, verifique suas sessões e faça signout de qualquer sessão que você não reconhece ou usa mais. + Outras sessões + Sessões + Abrir lista de espaços + Criar uma nova conversa ou sala + Todas + Pessoas + Favoritas + Não-lidas + A - Z + Atividade + Ordenar por + Mostrar recentes + Mostrar filtros + Preferências de layout + Explorar Salas + Criar Sala + Começar Chat + Não-verificada · Última atividade %1$s + Verificada · Última atividade %1$s + Ver Todas (%1$d) + Visualizar Detalhes + Verificar Sessão + Sessão não-verificada + Sessão verificada + Tipo de dispositivo desconhecido + Desktop + Mobile + Web + Desculpe, esta sala não tem sido encontrada. +\nPor favor retente mais tarde.%s + Convites + Experimentar + Toque na direita topo para ver a opção para feedback. + Dê Feedback + Acesse seus Espaços (direita fundo) mais rápido e fácil que jamais antes. + Acesse Espaços + Para simplificar seu ${app_name}, abas são agora opcionais. Gerencie-as usando o menu direito topo. + Boas-vindas a uma nova visão! + Isto é onde suas mensagens não-lidas vão aparecer, quando você tiver algumas. + Nada para reportar. + O app de chat seguro tudo-em-um para equipes, amigas(os) e organizações. Crie um chat, ou junte-se a uma sala existe, para começar. + Boas-vindas a ${app_name}, +\n%s. + Espaços são uma nova maneira de agrupar salas e pessoas. Adicione uma sala existente, ou crie uma nova, usando o botão direito fundo. + %s +\nestá parecendo um pouco vazio. + + Considere fazer signout de sessões antigas (%1$d dia ou mais) que você não usa mais. + Considere fazer signout de sessões antigas (%1$d dias ou mais) que você não usa mais. + + Sessões inativas + Verificar ou fazer signout de sessões não-verificadas. + Sessões não-verificadas + Melhore a segurança de sua conta ao seguir estas recomendações. + Recomendações de segurança + + Inativa por %1$d+ dia (%2$s) + Inativa por %1$d+ dias (%2$s) + + Isto é onde suas novas requisições e convites vão estar. + Nada novo. + Espaços são uma nova maneira de agrupar salas e pessoas. Crie um espaço para começar. + Nenhum espaço ainda. + Colapsar filhos de %s + Expandir filhos de %s + Mudar Espaço + Não-verificadas + Verificadas + Não-verificadas + Verificadas + Inativas + + Inativas por %1$d dia ou mais longo + Inativas por %1$d dias ou mais longo + + Inativas + Endereço de IP + Última atividade + Nome de sessão + Informação de aplicativo, dispositivo, e atividade. + Detalhes de sessão + Limpar Filtro + Nenhuma sessão inativa encontrada. + Nenhuma sessão não-verificada encontrada. + Nenhuma sessão verificada encontrada. + + Considere fazer signout de sessões antigas (%1$d dia ou mais) que você não usa mais. + Considere fazer signout de sessões antigas (%1$d dias ou mais) que você não usa mais. + + Verifique suas sessões para mensageria segura melhorada ou faça signout daquelas que você não reconhece ou usa mais. + Para melhor segurança, faça signout de qualquer sessão que você não reconhece ou usa mais. + Filtrar + Pronta para mensageria segura + Não pronta para mensageria segura + Todas as sessões + Filtrar + Última atividade %1$s + Dispositivo + Sessão + Sessão atual + Verifique ou faça signout desta sessão para melhor segurança e fiabilidade. + Verifique sua sessão atual para mensageria segura melhorada. + Esta sessão está pronta para mensageria segura. + Sua sessão atual está pronta para mensageria segura. + Criar DM somente em primeira mensagem + Habilitar DMs diferidas + Um Element simplificado com abas opcionais + Habilitar novo layout + Outras(os) usuárias(os) em mensagens diretas e salas a que você se junta são capazes de visualizar uma lista completa de suas sessões. +\n +\nIsto as/os provê com confiança que elas(es) são estão realmente falando com você, mas também significa que elas(es) veem o nome da sessão que você entrar aqui. + Renomeando sessões + Sessões verificadas + Sessões não-verificadas são sessões que você tem feito login com suas credenciais mas não têm sido verificadas cruzado. +\n +\nVocê devia especialmente se certificar que você reconhece estas sessões já que elas podiam representar um uso não-autorizado de sua conta. + Sessões não-verificadas + Sessões inativas são sessões que você não tem usado em algum tempo, mas elas continuam a receber chaves de encriptação. +\n +\nRemover sessões inativas melhora segurança e performance, e torna mais fácil para você identificar se uma nova sessão é suspeita. + Sessões inativas + Por favor esteja ciente que nomes de sessões também são visíveis a pessoas com quem você se comunica. + Nomes de sessões personalizadas podem ajudar você a reconhecer seus dispositivos mais facilmente. + Nome da sessão + Renomear sessão + Fazer signout desta sessão + Não-verificada · Sua sessão atual + Começar um broadcast de voz + A autenticidade desta mensagem encriptada não pode ser garantida neste dispositivo. + Requisitar que o teclado não devia atualizar quaisquer dados personalizados tais como histórico de digitação e dicionário baseado no que você tem digitado em conversas. Note que alguns teclados podem não respeitar esta configuração. + Teclado incognito + Prepende (╯°□°)╯︵ ┻━┻ a uma mensagem de texto puro + Broadcast de Voz + Abrir tela de ferramentas de desenvolvedor(a) + 🔒 Você tem habilitado encriptar para sessões verificadas somente para todas as salas em Configurações de Segurança. + ⚠ Existem dispositivos não-verificados nesta sala, eles não vão ser capazes de decriptar mensagens que você enviar. + Nunca enviar mensagens encriptadas a sessões não-verificadas nesta sala. + Entendido + Aplicar formato tachar + Aplicar formato sublinhar + Aplicar formato itálico + Aplicar formato negrito + Gravar o nome de cliente, versão, e url para reconhecer sessões mais facilmente em gerenciador de sessão. + Habilitar gravação de info de cliente + Tenha visibilidade e controle maiores sobre todas suas sessões. + Habilitar novo gerenciador de sessão + Sistema operativo + Modelo + Browser + URL + Versão + Nome + Aplicativo + Receber notificações push nesta sessão. + Notificações push + Verifique sua sessão atual para revelar o status de verificação desta sessão. + Status de verificação desconhecido + Habilitado: + ID da Sessão: + Algo deu errado. Por favor cheque sua conexão de rede e tente de novo. + Conceder Permissão + ${app_name} precisa de permissão para mostrar notificações. +\nPor favor conceda a permissão. + ${app_name} precisa de permissão para exibir notificações. Notificações podem exibir suas mensagens, seus convites, etc. +\n +\nPor favor permita acesso nos próximos pop-ups para ser capaz de visualizar notificação. + Experimente o editor de texto rico (modo de texto puro vindo em breve) + Habilitar editor de texto rico + Por favor assegure que você sabe a origem deste código. Ao linkar dispositivos, você vai prover alguém com acesso completo a sua conta. + Confirmar + Tentar de novo + Nenhuma correspondência\? + Fazendo-lhe signin + Conectando a dispositivo + Scannar QR code + Fazendo signin com um dispositivo móvel\? + Mostrar QR code neste dispositivo + Selecione \'Scannar QR code\' + Comece na tela de signin + Selecione \'Fazer signin com QR code\' + Comece na tela de signin + Selecione \'Mostrar QR code\' + Vá para Configurações -> Segurança & Privacidade + Abra o app em seu outro dispositivo + A requisição foi negada no outro dispositivo. + A linkagem não foi completada no tempo requerido. + Linkagem com este dispositivo não é suportado. + Conexão malsucedida + Cheque seu dispositivo feito signin, o código abaixo deveria ser exibido. Confirme que o código abaixo corresponde com esse dispositivo: + Conexão segura estabelecida + Scanne o QR code abaixo com seu dispositivo que está feito signout. + Use seu dispositivo feito signin para scannar o QR code abaixo: + Fazer signin com QR code + Use a câmera neste dispositivo para scannar o QR code mostrado em seu outro dispositivo: + Scannar QR code + 3 + 2 + 1 + Você pode usar este dispositivo para fazer signin com um dispositivo móvel ou web com um QR code. Existem duas maneiras de fazer isto: + Fazer signin com QR Code + Scannar QR code + O servidorcasa não suporta sign in com QR code. + O sign in foi cancelado no outro dispositivo. + O QR code é inválido. + O outro dispositivo deve estar feito signin. + O outro dispositivo já está feito signin. + Um problema de segurança foi encontrado ao configurar mensageria segura. Um dos seguintes pode ter sido comprometido: Seu servidorcasa; Sua(s) conexão(ões) de internet; Seu(s) dispositivo(s); + A requisição falhou. + Seja capaz de gravar e enviar broadcast de voz em timeline de sala. + Broadcast de voz + Pré-carregando… + Pausar broadcast de voz + Tocar ou retomar broadcast de voz + Parar gravação de broadcast de voz + Pausar gravação de broadcast de voz + Retomar gravação de broadcast de voz + Ao vivo + Selecionar sessões + Contato + Câmera + Localização + Sondagens + Broadcast de voz + Anexos + Stickers + Biblioteca de fotos + Desselecionar todas(os) + Selecionar todas(os) + + %1$d selecionado(a) + %1$d selecionados(as) + + Alguma outra pessoa já está gravando um broadcast de voz. Espere que o broadcast de voz dela termine para começar um novo. + Alternar modo de tela cheia + Formatação de texto + Você já está gravando um broadcast de voz. Por favor termine seu broadcast de voz atual para começar um novo. + Você não tem as permissões requeridas para começar um broadcast de voz nesta sala. Contacte um/uma administrador(a) para fazer upgrade de suas permissões. + Não dá pra começar um novo broadcast de voz + Avançar rápido 30 segundos + Retroceder 30 segundos + Sessões verificadas são onde quer que você esteja usando esta conta depois de entrar sua frasepasse ou confirmar sua identidade com uma outra sessão verificada. +\n +\nIsto significa que você tem todas as chaves necessárias para destrancar suas mensagens encriptadas e confirmar a outras(os) usuárias(os) que você confia nesta sessão. + + Fazer signout de %1$d sessão + Fazer signout de %1$d sessões + + Fazer signout + %1$s restando + criou uma sondagem. + enviou um sticker. + enviou um vídeo. + enviou uma imagem. + enviou uma mensagem de voz. + enviou um arquivo de áudio. + enviou um arquivo. + Em resposta a + Esconder endereço de IP + Mostrar endereço de IP + Citando + Respondendo a %s + Editando + Mostrar chats recentes no menu de compartilhar do sistema + Habilitar compartilhar direto + Esta sessão não suporta encriptação, então ela não pode ser verificada. +\n +\nVocê não vai ser capaz de participar em salas onde encriptação está habilitada quando usando esta sessão. +\n +\nPara a melhor segurança e privacidade, é recomendado usar cliente Matrix que suportam encriptação. + Fazer signout de todas as outras sessões + Esta sessão não suporta encriptação e assim não pode ser verificada. + Revise para assegurar que sua conta está segura + Você tem sessões não-verificadas + Obtenha a build mais recente (note: você pode ter problema para fazer signin) + Build nightly + Broadcast ao vivo + Você terminou um broadcast de voz. + %1$s terminou um broadcast de voz. + Editar link + Criar um link + Link + Texto + Definir link + Tem certeza que você quer parar seu broadcast ao vivo\? Isto vai terminar o broadcast e a gravação completa vai estar disponível na sala. + Parar de fazer broadcasting ao vivo\? + Sim, Parar + Avatar da sala %1$s + Avatar do espaço %1$s + Os detalhes da sua conta são gerenciados separadamente em %1$s. + Conta + Termos de Uso Aceitável + Um erro ocorreu ao atualizar suas preferências de notificação. Por favor, tente novamente. + Seu servidorcasa ainda não suporta threads. + Continuar com o reset + %1$s mudou seu nome de exibição para %2$s + Incapaz de reproduzir esse broadcast de voz. + Incapaz de decriptar esse broadcast de voz. + Erro de conexão - Gravação pausada + Aplicação actualizada + Versão criptográfica + Não foi possível contactar o servidor doméstico. Se ainda assim terminar sessão, este dispositivo não será apagado da sua lista de dispositivos, poderá querer removê-lo utilizando outro cliente. + Imagem de perfil do utilizador %1$s + Iniciou uma emissão de voz + Histórico da sondagem + Verificar com outro dispositivo + Verifique a sua identidade para aceder a mensagens encriptadas e provar a sua identidade a outros. + Foi enviado um pedido de verificação. Abra uma das suas outras sessões para aceitar e iniciar a verificação. + Só é possível convidar um email de cada vez + Terminar sessão ainda assim + Verificação a partir de Chave ou Frase Segura… + Até que este utilizador confie nesta sessão, as mensagens enviadas para e a partir dela são marcadas com avisos. + \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-ru/strings.xml b/library/ui-strings/src/main/res/values-ru/strings.xml new file mode 100644 index 0000000000..dad51116e5 --- /dev/null +++ b/library/ui-strings/src/main/res/values-ru/strings.xml @@ -0,0 +1,3063 @@ + + + приглашение %s + %1$s пригласил(а) %2$s + %1$s пригласил(а) вас + %1$s вошёл(шла) в комнату + %1$s покинул(а) комнату + %1$s отклонил(а) приглашение + %1$s выгнал %2$s + %1$s разблокировал(а) %2$s + %1$s заблокировал(а) %2$s + %1$s отозвал(а) приглашение %2$s + %1$s изменил(а) свой аватар + %1$s установил(а) имя %2$s + %1$s изменил(а) имя с %2$s на %3$s + %1$s удалил(а) свое имя (%2$s) + %1$s изменил(а) тему на: %2$s + %1$s изменил(а) название комнаты: %2$s + %s начал(а) видеовызов. + %s начал(а) голосовой вызов. + %s ответил(а) на звонок. + %s завершил(а) вызов. + %1$s сделал(а) будущую историю комнаты видимой %2$s + всем участникам, с момента их приглашения. + всем участникам, с момента присоединения. + всем участникам. + всем. + (аватар также был изменен) + %1$s удалил(а) название комнаты + %1$s удалил(а) тему комнаты + %1$s отправил(а) приглашение %2$s присоединиться к комнате + %1$s принял(а) приглашение от %2$s + ** Невозможно расшифровать: %s ** + Устройство отправителя не предоставило нам ключ для расшифровки этого сообщения. + Не удалось отправить сообщение + Ошибка Matrix + Адрес электронной почты + Номер телефона + Приглашение в комнату + %1$s и %2$s + Пустая комната + Начальная синхронизация: +\nИмпорт учётной записи… + Начальная синхронизация: +\nИмпорт криптографии + Начальная синхронизация: +\nИмпорт комнат + Начальная синхронизация: +\nВаши беседы загружаются +\nЕсли вы присоединились к большому количеству комнат, это может занять некоторое время + Начальная синхронизация: +\nИмпорт приглашенных комнат + Начальная синхронизация: +\nИмпорт покинутых комнат + Начальная синхронизация: +\nИмпорт данных учётной записи + %s обновил эту комнату. + Отправка сообщения… + %1$s отозвал приглашение %2$s присоединиться к комнате + Приглашение %1$s. Причина: %2$s + %1$s приглашен %2$s. Причина: %3$s + %1$s пригласил вас. Причина: %2$s + %1$s присоединился(лась) к комнате. Причина: %2$s + %1$s покинул(а) комнату. Причина: %2$s + %1$s отклонил приглашение. Причина: %2$s + %1$s выгнали %2$s. Причина: %3$s + %1$s разблокировано %2$s. Причина: %3$s + %1$s забанил %2$s. Причина: %3$s + %1$s принял приглашение для %2$s. Причина: %3$s + %1$s отозвал приглашение %2$s. Причина: %3$s + %1$s создал(а) комнату + + %1$s добавил(а) %2$s в качестве адреса для этой комнаты. + %1$s добавил(а) %2$s в качестве адресов для этой комнаты. + %1$s добавил(а) %2$s в качестве адресов для этой комнаты. + + + %1$s удалил(а) адрес %2$s для комнаты. + %1$s удалил(а) адреса %2$s для комнаты. + %1$s удалил(а) адреса %2$s для комнаты. + + %1$s добавил(а) адреса %2$s и удалил(а) %3$s для комнаты. + %1$s сделал(а) %2$s главным адресом комнаты. + %1$s удалил(а) главный адрес комнаты. + %1$s разрешил(а) гостям входить в комнату. + %1$s запретил(а) гостям входить в комнату. + %1$s включил(а) сквозное шифрование. + %1$s включил(а) сквозное шифрование (неизвестный алгоритм %2$s). + Ваше приглашение + Вы создали комнату + Вы пригласили %1$s + Вы вошли в комнату + Вы покинули комнату + Вы отклонили приглашение + Вы выгнали %1$s + Вы разбанили %1$s + Вы забанили %1$s + Вы отозвали приглашение %1$s + Вы сменили свой аватар + Вы сменили отображаемое имя на %1$s + Вы сменили отображаемое имя с %1$s на %2$s + Вы удалили отображаемое имя (%1$s) + Вы сменили тему на: %1$s + Вы сменили название комнаты на: %1$s + Вы начали видеозвонок. + Вы начали звонок. + Вы ответили на звонок. + Вы закончили звонок. + Вы сделали будущую историю комнаты видимой для %1$s + Вы обновили эту комнату. + Вы удалили название комнаты + Вы удалили тему комнаты + Вы отправили %1$s приглашение в эту комнату + Вы отозвали у %1$s приглашение в эту комнату + Вы приняли приглашение для %1$s + %1$s добавил(а) виджет %2$s + Вы добавили виджет %1$s + %1$s удалил(а) виджет %2$s + Вы удалили виджет %1$s + %1$s изменил(а) виджет %2$s + Вы изменили виджет %1$s + Администратор + Модератор + По умолчанию + Пользовательский (%1$d) + Пользовательский + Вы изменили уровни доступа %1$s. + %1$s изменил(а) уровни доступа %2$s. + %1$s с %2$s на %3$s + Ваше приглашение. Причина: %1$s + Вы пригласили %1$s. Причина: %2$s + Вы вошли в комнату. Причина: %1$s + Вы покинули комнату. Причина: %1$s + Вы отклонили приглашение. Причина: %1$s + Вы выгнали %1$s. Причина: %2$s + Вы разбанили %1$s. Причина: %2$s + Вы забанили %1$s. Причина: %2$s + Вы приняли приглашение для %1$s. Причина: %2$s + Вы отозвали приглашение %1$s. Причина: %2$s + + Вы добавили адрес %1$s для этой комнаты. + Вы добавили %1$s в качестве адресов для этой комнаты. + Вы добавили %1$s в качестве адресов для этой комнаты. + + + Вы удалили адрес этой комнаты: %1$s. + Вы удалили адреса этой комнаты: %1$s. + Вы удалили адреса этой комнаты: %1$s. + + Вы добавили адреса %1$s и удалили %2$s для этой комнаты. + Вы задали главный адрес этой комнаты %1$s. + Вы удалили главный адрес этой комнаты. + Вы разрешили гостям входить в комнату. + Вы запретили гостям входить в комнату. + Вы включили сквозное шифрование. + Вы включили сквозное шифрование (неизвестный алгоритм %1$s). + %1$s изменил(а) аватар комнаты + Вы изменили аватар комнаты + %s отправил(а) данные для начала звонка. + Вы отправили данные для начала звонка. + %1$s удалил(а) аватар комнаты + Вы удалили аватар комнаты + Вы запретили гостям входить в комнату. + %1$s запретил(а) гостям входить в комнату. + Вы разрешили гостям присоединяться сюда. + %1$s разрешил(а) гостям присоединиться сюда. + Вы вышли. Причина: %1$s + %1$s вышел(-ла). Причина: %2$s + Вы вошли. Причина: %1$s + %1$s вошел(-ла). Причина: %2$s + Вы отозвали приглашение %1$s + %1$s отозвал(а) приглашение %2$s + Вы пригласили %1$s + %1$s пригласил(а) %2$s + Вы сделали будущие сообщения видимыми для %1$s + %1$s сделал(а) будущие сообщения видимыми для %2$s + Вы покинули комнату + %1$s покинул(а) комнату + Вы вошли + %1$s вошел(ла) + Вы создали обсуждение + %1$s создал(а) обсуждение + Вы обновили эту комнату. + %s обновил(а) эту комнату. + + %1$s, %2$s, %3$s и %4$d другой + %1$s, %2$s, %3$s и %4$d других + %1$s, %2$s, %3$s и %4$d другие + %1$s, %2$s, %3$s и %4$d другие + + %1$s, %2$s, %3$s и %4$s + %1$s, %2$s и %3$s + 🎉 Всем серверам запрещено участвовать! Эта комната больше не может быть использована. + Без изменений. + Пустая комната (без %s) + • Соответствующие серверы %s заблокированы. + • Серверы, соответствующие буквальным IP-адресам, теперь запрещены. + • Серверы, соответствующие буквальным IP-адресам, теперь разрешены. + • Серверы, соответствующие %s, теперь запрещены. + • Серверы, соответствующие %s, теперь разрешены. + • Серверы, соответствующие %s, были удалены из списка блокировки. + • Серверы, соответствующие буквальным IP-адресам, запрещены. + • Серверы, соответствующие буквальным IP-адресам, разрешены. + • Серверы, соответствующие %s, разрешены. + • Серверы, соответствующие %s, были удалены из разрешённого списка. + Вы изменили права доступа сервера (ACL) для этой комнаты. + %s изменил права доступа сервера (ACL) для этой комнаты. + Вы настроили права доступа сервера (ACL) для этой комнаты. + %s устанавливает права доступа сервера (ACL) для этой комнаты. + Вы изменили адреса этой комнаты. + %1$s изменил(а) адреса этой комнаты. + Вы изменили основной и альтернативный адреса этой комнаты. + %1$s изменил(а) основной и альтернативный адреса этой комнаты. + Вы изменили альтернативные адреса для этой комнаты. + %1$s изменил(а) альтернативные адреса для этой комнаты. + + Вы удалили альтернативный адрес %1$s для этой комнаты. + Вы удалили альтернативные адреса %1$s для этой комнаты. + Вы удалили альтернативные адреса %1$s для этой комнаты. + Вы удалили альтернативные адреса %1$s для этой комнаты. + + + %1$s удалил(а) альтернативный адрес %2$s для этой комнаты. + %1$s удалил(а) альтернативные адреса %2$s для этой комнаты. + %1$s удалил(а) альтернативные адреса %2$s для этой комнаты. + %1$s удалил(а) альтернативные адреса %2$s для этой комнаты. + + + Вы добавили альтернативный адрес %1$s для этой комнаты. + Вы добавили альтернативные адреса %1$s для этой комнаты. + Вы добавили альтернативные адреса %1$s для этой комнаты. + Вы добавили альтернативные адреса %1$s для этой комнаты. + + + %1$s добавил(а) альтернативный адрес %2$s для этой комнаты. + %1$s добавил(а) альтернативные адреса %2$s для этой комнаты. + %1$s добавил(а) альтернативные адреса %2$s для этой комнаты. + %1$s добавил(а) альтернативные адреса %2$s для этой комнаты. + + Настройки + Принять + Отклонить + Завершить звонок + OK + Отмена + Сохранить + Покинуть + Отправить + Цитировать + Поделиться + Позже + Постоянная ссылка + Просмотр исходного кода + Просмотр расшифрованного исходного кода + Удалить + Переименовать + Пожаловаться на содержимое + или + Пригласить + Выйти из учётной записи + Голосовой вызов + Видео вызов + Пометить все как прочитанное + Быстрый ответ + Открыть + Закрыть + Скопировано в буфер + Подтверждение + Предупреждение + Избранные + Люди + Комнаты + Фильтр названий комнат + Приглашения + Маловажные + Личные сообщения + Только Matrix контакты + Нет результатов + Комнаты + Отправить логи + Отправить журналы ошибок + Отправить снимок экрана + Сообщить об ошибке + Пожалуйста опишите ошибку. Что вы делали\? Что вы хотели получить\? Что на самом деле произошло\? + Опишите проблему здесь + Для диагностики проблемы журналы работы приложения будут приложены к отчету об ошибке. Этот отчет, включая журналы и скриншот, не будет доступен публично. Если вы предпочитаете отправить только текст, то снимите отметку: + Вы, наверное, трясете телефон в отчаянии. Хотите открыть экран отчета об ошибке\? + Отчет об ошибке успешно отправлен + Сбой отправки отчета об ошибке (%s) + Прогресс (%s%%) + В прошлый раз приложение некорректно завершило работу. Хотите отправить отчёт о сбое\? + Войти в Комнату + Псевдоним + Выйти + URL домашнего сервера + Поиск + Начать голосовой вызов + Начать видеовызов + Отправить файлы + Камера + Вход + Подать + Неверный псевдоним и/или пароль + Это не похоже на действительный адрес электронной почты + Этот адрес электронной почты уже используется. + Забыли пароль? + Этот домашний сервер хочет убедиться, что вы не робот + Не удалось проверить адрес электронной почты: убедитесь, что вы перешли по ссылке из сообщения + Пожалуйста, введите корректный URL + Неверный формат JSON + Не содержит допустимого JSON + Отправлено слишком много запросов + Оригинал + Крупный + Средний + Мелкий + Устанавливается соединение… + Вызов завершен + Входящий видеовызов + Входящий голосовой вызов + Идёт разговор… + Вызываемый абонент не смог ответить. + Информация + ${app_name} необходимы разрешения на доступ к микрофону, чтобы выполнять звонки. + ${app_name} необходимы разрешения на доступ к камере и микрофону для видеовызовов. +\n +\nПожалуйста дайте разрешение в следующем окне для звонка. + ДА + НЕТ + Продолжить + Удалить + Присоединиться + Отклонить + Перейти к непрочитанному + Покинуть комнату + Вы уверены, что хотите выйти из комнаты\? + Личные сообщения + Пригласить + Забанить + Разбанить + Скрыть все сообщения этого пользователя + Отобразить все сообщения этого пользователя + Упомянуть + Вы не сможете отменить это действие, поскольку пользователь получит такой же уровень доступа, как и у вас. +\nВы уверены\? + %s печатает… + %1$s & %2$s печатают… + %1$s & %2$s & и другие печатают… + У вас нет разрешения писать сообщения в этой комнате. + Доверять + Не доверять + Выйти + Игнорировать + Отпечаток (%s): + Не удалось проверить сертификат удаленного сервера. + Это может означать, что кто-то злонамеренно перехватывает ваш трафик или что ваш телефон не доверяет сертификату, предоставленному удаленным сервером. + Если администратор сервера сказал, что это ожидалось, убедитесь, что отпечаток сертификата ниже совпадает с отпечатком сертификата предоставленным администратором. + Сертификат был изменен с того, которому доверял ваш телефон. Это ОЧЕНЬ НЕОБЫЧНО. Рекомендуется НЕ ПРИНИМАТЬ этот новый сертификат. + Сертификат изменился с ранее доверенного на недействительный. Возможно, сервер обновил свой сертификат. Свяжитесь с администратором сервера для получения ожидаемого отпечатка сертификата. + Примите сертификат только если администратор сервера опубликовал отпечаток сертификата, который соответствует указанному выше. + Поиск + Фильтр списка пользователей + Нет результатов + Аватар + Отображаемое имя + Добавить электронный адрес + Добавить телефон + Системные настройки приложения. + Сведения о приложении + Уведомления для этой учётной записи + Уведомления для этого сеанса + В персональных чатах + В групповых чатах + Когда меня приглашают в комнату + Вызовы + Сообщения от бота + Фоновая синхронизация + Таймаут синхронизации + Задержка между каждой синхронизацией + Версия + Версия OLM + Правила и условия + Прочие уведомления + Авторские права + Политика конфиденциальности + Очистить весь кэш + Параметры пользователя + Уведомления + Игнорируемые + Другое + Дополнительно + Криптография + Устройства для уведомлений + Локальные контакты + Доступ к контактам + Страна контактов + Домашний экран + Прикрепить комнаты с отключенными уведомлениями + Прикрепить комнаты с непрочитанными сообщениями + ID + Публичное название + Обновить публичное название + Недавно + %1$s @ %2$s + Аутентификация + Авторизован как + Домашний сервер + Сервер обнаружения + Проверьте электронную почту и перейдите по высланной ссылке. Затем нажмите продолжить. + Этот адрес электронной почты уже занят. + Этот номер телефона уже используется. + Смена пароля + Текущий пароль + Новый пароль + Не удалось обновить пароль + Пароль был обновлен + Показать все сообщения %s\? + Выберите страну + Тема + Доступ к истории комнаты + Кто может читать историю? + Все + Только участники (с момента выбора этой опции) + Только участники (с момента приглашения) + Только участники (с момента присоединения) + Заблокированные пользователи + Дополнительно + Внутренний ID комнаты + Лаборатория + Это экспериментальные функции, которые могут повести себя неожиданным образом. Используйте с осторожностью. + Установить как основной адрес + Сбросить основной адрес + Ошибка дешифровки + Публичное название + ID сеанса + Ключ сеанса + Экспорт E2E ключей + Экспорт ключей + Экспорт ключей в локальный файл + Экспорт + Введите мнемоническую фразу + Подтвердите мнемоническую фразу + Импорт E2E ключей + Импорт ключей + Импортировать ключи из локального файла + Импорт + Шифровать только для заверенных сеансов + Не отправлять зашифрованные сообщения незаверенным сеансам из этого сеанса. + Не заверено + Заверено + Подтвердить + Чтобы убедиться, что этой сессии можно доверять, обратитесь к ее владельцу, используя другие способы (например, лично или по телефону), и спросите, соответствует ли ключ, который он видит в настройках для этой сессии: + Если они не совпадают, безопасность вашего общения может быть поставлена под угрозу. + Выбор каталога комнат + Название сервера + Все комнаты на сервере %s + Все местные комнаты %s + Пользовательский интерфейс + Язык + Выберите язык + Запускать при загрузке + Метки времени для всех сообщений + 3 дня + 1 неделя + 1 месяц + Навсегда + Очистить медиа кэш + Тема + Размер шрифта + Очень мелкий + Малый + Нормальный + Крупный + Большой + Самый большой + Огромный + Сохранить медиа + Светлая тема + Тёмная тема + Чёрная тема + Звук уведомлений + Показывать метки времени в 12-часовом формате + Вы уверены, что хотите удалить виджет из этой комнаты? + Не удалось создать виджет. + Не удалось отправить запрос. + Уровень доступа должен быть числом больше 0. + Вы не состоите в этой комнате. + У вас нет разрешений делать это в данной комнате. + В запросе отсутствует room_id. + В запросе отсутствует user_id. + Комната %s невидима. + Добавить приложения Matrix + Мониторинг событий + Вызов + Сообщения, содержащие мое имя пользователя + Вы добавили новою сессию \'%s\', запрашивающую ключи шифрования. + Ваш незаверенный сеанс \'%s\' запрашивает ключи шифрования. + Сообщения, содержащие моё отображаемое имя + Начать проверку + Звуковые уведомления + Беззвучные уведомления + Сделать фото + Снять видео + Аналитика + Использовать встроенную камеру + Сообщить об ошибке + Ошибка команды + Нераспознанная команда: %s + Выкл + Громко + Зашифрованное сообщение + Загрузка… + Вы уверены, что хотите начать голосовой вызов? + Вы уверены, что хотите начать видеовызов? + Блокировка пользователя удалит его из этой комнаты и не позволит ему присоединиться вновь. + Все сообщения + Добавить на главный экран + Предпросмотр встроенных URL-адресов + Вибрация при упоминании пользователя + Создать + Начало + Комнаты + Приглашен + Вас выгнал %2$s из %1$s + Вас заблокировал %2$s в %1$s + Причина: %1$s + Встряхните устройство, чтобы сообщить об ошибке + Участники + + %d комната + %d комнаты + %d комнат + + + %1$s в %2$s + + %d активный виджет + %d активных виджета + %d активных виджетов + + + Аватар + + %d участник + %d участника + %d участников + + + + %d новое сообщение + %d новых сообщения + %d новых сообщений + + + + %d изменение членства + %d изменения членства + %d изменений членства + + + + %d непрочитанное уведомление + %d непрочитанных уведомления + %d непрочитанных уведомлений + + + Отправить наклейку + Отправить наклейку + У вас сейчас нет доступных наклеек. +\n +\nДобавить сейчас\? + Деактивация учётной записи + Деактивировать мою учётную запись + Отправка аналитических данных + ${app_name} собирает анонимную аналитику для улучшения приложения. + Обязательный параметр отсутствует. + Для продолжения использования %1$s вы должны ознакомиться и согласиться с условиями и правилами использования этого домашнего сервера. + Посмотреть сейчас + Деактивировать учётную запись + Пожалуйста, удалите все сообщения, которые я отправил, после деактивации моего аккаунта (Предупреждение: будущие участники увидят неполную историю разговоров) + Деактивировать учётную запись + Это действие сделает вашу учетную запись навсегда непригодной для дальнейшего использования. Вы не сможете войти в систему и никто другой не сможет заново зарегистрировать учетную запись с вашим идентификатором. Также, это приведет к тому, что вы покинете все комнаты, в которых участвовали и данные о вашей учетной записи будут удалены с сервера идентификации. Это действие необратимо. +\n +\nПо умолчанию, деактивация вашей учетной записи не удаляет отправленные вами сообщения. Если вы хотите, чтобы мы удалили все ваши сообщения - поставьте отметку в поле ниже. +\n +\nВидимость сообщений в Matrix похожа на электронную почту. Удаление ваших сообщений означает, что отправленные вами сообщения не будут показаны новым или не зарегистрированным пользователям, но те пользователи, которые уже получили эти сообщения - по прежнему будут видеть их копии. + Скачать + Перезапросить ключи шифрования у других ваших сессий. + Запустите ${app_name} на другом устройстве, которое может расшифровать сообщение, для отправки ключа на эту сессию. + Отправить голосовое сообщение + К сожалению, внешнее приложение для выполнения этого действия не найдено. + Пожалуйста, введите ваш пароль. + Если возможно, добавьте описание на английском языке. + Предварительный просмотр медиа перед отправкой + Отображает действие + Блокирует пользователя с данным ID + Разблокирует пользователя с данным ID + Определение уровня доступа пользователя + Сбросить уровень доступа для пользователя с данным ID + Пригласить пользователя с данным ID в текущую комнату + Покинуть комнату + Задать тему комнаты + Выгнать пользователя с заданным ID из этой комнаты + Изменить ваше отображаемое имя + Вкл/выкл markdown + Эта комната была заменена и больше не активна. + Беседа продолжается здесь + Эта комната — продолжение другой беседы + Нажмите здесь для просмотра старых сообщений + Присоединиться к комнате с указанным адресом + Для исправления управления приложениями Matrix + + %d выбран + %d выбрано + %d выбраны + + + Системные оповещения + Ошибка + Создать мнемоническую фразу + Мнемонические фразы не совпадают + свяжитесь с вашим администратором + Превышен один из ресурсных лимитов сервера, по этому некоторые пользователи не смогут авторизоваться. + Превышен один из ресурсных лимитов сервера. + Пожалуйста, придумайте парольную фразу для шифрования экспортируемых ключей. Вам нужно будет ввести ту же самую фразу для импорта ключей. + Из-за ежемесячного ограничения активных пользователей сервера некоторые из пользователей не смогут авторизоваться. + Сервер достиг ежемесячного ограничения активных пользователей. + Пожалуйста %s для увеличения этого лимита. + Пожалуйста, %s, чтобы продолжить пользоваться этим сервисом. + Извините, произошла ошибка + развернуть + свернуть + Пароль + Пожалуйста, ознакомьтесь и примите правила этого домашнего сервера: + Вызовы + Использовать стандартную мелодию ${app_name} для входящих звонков + Мелодия входящего вызова + Выберите мелодию звонка: + Идёт видеозвонок … + Удалить из комнаты + Поиск проблем с уведомлениями + Оправлять уведомления о наборе текста + Markdown форматирование + Команде \"%s\" нужно либо больше параметров, либо некоторые из них неверны. + Markdown включен. + Markdown выключен. + Принимаю + Результаты диагностики + Запустить тесты + Выполняется… (%1$d из %2$d) + В основном, всё в порядке. Если вы по-прежнему не получаете уведомления, пожалуйста, отправьте отчет об ошибке, чтобы помочь нам разобраться. + Один или несколько тестов не пройдены, попробуйте предлагаемые решения. + Один или несколько тестов не пройдены, пожалуйста, отправьте отчет об ошибке, чтобы помочь нам исследовать проблему. + Настройки системы. + Уведомления включены в настройках системы. + Уведомления отключены в настройках системы. +\nПожалуйста, проверьте настройки системы. + Открыть настройки + Настройки аккаунта. + Уведомления включены для вашей учетной записи. + Уведомления отключены для вашей учетной записи. +\nПожалуйста, проверьте настройки аккаунта. + Включить + Настройки сеанса. + Уведомления включены для этой сессии. + Уведомления не включены для этого сеанса. +\nПожалуйста, проверьте настройки ${app_name}. + Включить + Проверка сервисов Play + APK Google Play сервисов доступен и обновлён. + ${app_name} использует сервисы Google Play для доставки push-сообщений, но не похоже что он настроен правильно: +\n%1$s + Исправить сервисы Play + Токен Firebase + Токен FCM успешно получен: +\n%1$s + Не удалось получить токен FCM: +\n%1$s + Регистрация токена + Токен FCM успешно зарегистрирован на домашнем сервере. + Не удалось зарегистрировать токен FCM на домашнем сервере: +\n%1$s + Запуск при загрузке + Служба будет запущена после перезапуска устройства. + При перезагрузке устройства служба не будет запущена , вы не будете получать уведомления, пока ${app_name} не будет открыт один раз. + Включить запуск при загрузке + Проверьте фоновые ограничения + Фоновые ограничения отключены для ${app_name}. Этот тест должен быть запущен с использованием мобильных данных (без WIFI). +\n%1$s + Фоновые ограничения включены для ${app_name}. +\nРабота приложения будет жестко ограничена, пока оно находится в фоновом режиме, и это может повлиять на уведомления. +\n%1$s + Отключить ограничения + Оптимизация батареи + Оптимизация батареи не влияет на ${app_name}. + Если пользователь оставляет устройство в отключенном от сети и в неподвижном состоянии в течение некоторого времени при выключенном экране, устройство переходит в режим Doze. Это предотвращает доступ приложений к сети и откладывает выполнение заданий, синхронизацию и передачу стандартных аварийных сигналов. + Игнорировать оптимизацию + Предпросмотр ссылок в чате, когда ваш домашний сервер поддерживает эту функцию. + Показывать другим пользователям, что вы печатаете. + Форматировать сообщения, используя markdown. Например, позволяет использовать звёздочки для выделения текста курсивом. + Уведомления о прочтении + Нажмите на уведомление о прочтении для подробного списка. + События о вступлении/выходе + События учётной записи + Включает изменения аватара и отображаемого имени. + Использовать системную камеру вместо камеры Element. + %1$s: %2$s + +%d + Не найден APK сервисов Google Play. Уведомления могут работать неправильно. + Не влияет на приглашения, изгнания и блокировки. + Резервное копирование ключей + Используйте резервную копию ключа + Пропустить + Готово + Расширенные настройки уведомлений + Значение уведомления по событию + Пользовательские настройки. + Обратите внимание, для некоторых типов сообщений выбран беззвучный режим (уведомление будет, но без звука). + Некоторые уведомления отключены в настройках. + Добавить аккаунт + Настроить шумные уведомления + Настроить уведомления о вызовах + Настроить беззвучные уведомления + Выбрать цвет светодиода, вибрацию, звук… + Управление криптографическими ключами + Управление резервным копированием ключей + Беззвучный + Введите мнемоническую фразу + Мнемоническая фраза слишком проста + Пожалуйста, удалите мнемоническую фразу, если хотите, чтобы ${app_name} сгенерировал бумажный ключ. + Никогда не теряйте зашифрованных сообщений + Сообщения в зашифрованных комнатах защищены сквозным шифрованием. Ключи для прочтения этих сообщений есть только у вас и получателя(ей). +\n +\nНадёжно сохраните резервную копию ключей, чтобы не потерять их. + Задайте мнемоническую фразу + Сохранить бумажный ключ + Готово + Сохранить как файл + Пожалуйста, сделайте копию + Поделиться бумажным ключом с… + Бумажный ключ + Непредвиденная ошибка + Уверены? + Удалить резервную копию ключей шифрования с сервера\? Вы больше не сможете использовать бумажный ключ для чтения истории зашифрованных сообщений. + Удалить резервную копию + Удаление резервной копии… + Чтобы использовать резервное копирование ключей в этом сеансе, восстановите их с помощью мнемонической фразы или бумажного ключа. + Резервная копия имеет недействительную подпись из подтвержденной сессии %s + Резервная копия имеет действительную подпись из неподтвержденной сессии %s + Резервная копия имеет действительную подпись из подтверждённой сессии %s. + Резервная копия имеет действительную подпись с этой сессии. + Резервная копия подписана сессией с идентификатором %s. + Резервные копии ключей этой сессии не сохраняются. + Резервное копирование ключей не активировано в этом сеансе. + Резервное копирование ключей успешно настроено для этого сеанса. + Удалить резервную копию + Восстановить из резервной копии + Пожалуйста, введите бумажный ключ + Разблокировать историю + Восстановление резервной копии: + Введите бумажный ключ + Используйте бумажный ключ для разблокировки зашифрованных сообщений + Если забыли свою мнемоническую фразу, вы можете %s. + используйте бумажный ключ + Вы можете потерять доступ к сообщениям, если выйдете из системы или потеряете это устройство. + Получение версии резервной копии… + Используйте мнемоническую фразу для разблокировки зашифрованных сообщений + Потеряли бумажный ключ\? В настройках вы можете создать новый. + Резервная копия восстановлена %s ! + Резервная копия имеет недействительную подпись из неподтвержденной сессии %s + Не удалось получить последнюю версию ключей восстановления (%s). + + %d новый ключ был добавлен к этому устройству. + %d новых ключа были добавлены к этим устройствам. + %d новых ключей были добавлены к этим устройствам. + %d новых ключей были добавлены к этим устройствам. + + + Восстановлена резервная копия с %d ключом. + Восстановлены резервные копии с %d ключами. + Восстановлены резервные копии с %d ключами. + + Невозможно расшифровать резервную копию с помощью этого бумажного ключа: пожалуйста, убедитесь, что вы ввели правильный бумажный ключ. + Невозможно расшифровать резервную копию с помощью этой мнемонической фразы: пожалуйста, убедитесь, что вы ввели правильную мнемоническую фразу. + Создание бумажного ключа с использованием мнемонической фразы может занять несколько секунд. + [%1$s] +\nЭта ошибка вне контроля ${app_name}. На телефоне нет учетной записи Google. Пожалуйста, добавьте аккаунт Google. + [%1$s] +\nЭта ошибка вне контроля ${app_name}. Причины могут быть разными. Возможно, это будет работать, если вы повторите попытку позже, вы также можете проверить, что службы Google Play не ограничены в использовании данных в настройках системы, или что часы вашего устройства установлены правильно, или это может произойти на модифицированных прошивках. + [%1$s] +\nЭта ошибка вне контроля ${app_name}, и, по словам Google, эта ошибка означает, что на устройстве слишком много приложений, зарегистрированных в FCM. Ошибка возникает только в тех случаях, когда существует огромное количество приложений, поэтому она не должна влиять на обычного пользователя. + Ваши зашифрованные сообщения будут потеряны, если выйдете сейчас + Выполняется резервное копирование ключа. Если выйти сейчас, Вы потеряете доступ к Вашим зашифрованным сообщениям. + Мне не нужны мои зашифрованные сообщения + Выполняется резервное копирование ключей… + Уверены? + Создание резервной копии + Сделайте резервную копию ваших ключей или потеряете доступ к вашим зашифрованным сообщениям. + Уверены, что хотите выйти? + Пожалуйста, введите псевдоним. + (Расширенный) + Ручной экспорт ключей + Создание резервной копии + Успех! + Подпись + Алгоритм + Версия + + Резервное копирование %d ключа… + Резервное копирование %d ключей… + Резервное копирование %d ключей… + + + Все ключи сохранены + Резервное копирование ключей… + Никогда не теряйте зашифрованные сообщения + Поделиться + Я сделал(а) копию + Храните бумажный ключ в очень надёжном месте, например, в менеджере паролей (или в сейфе) + Защитите резервную копию мнемонической фразой. + Восстановление зашифрованных сообщений + Начать использовать резервное копирование ключей + Использовать резервное копирование ключей + Управление резервным копированием ключей + Новые ключи зашифрованных сообщений + Ваши ключи копируются. + (Дополнительно) Настройка с ключом восстановления + Или защитите резервную копию бумажным ключом, сохранив его в надёжном месте. + Безопасная резервная копия ключей должна быть активирована на всех ваших сессиях, чтобы не потерять доступ к зашифрованным сообщениям. + Зашифрованная копия ключей будет храниться на вашем сервере. Для безопасности защитите её мнемонической фразой. +\n +\nДля максимальной безопасности мнемоническая фраза должна отличаться от пароля вашей учётной записи. + Бумажный ключ — это подстраховка: вы можете использовать его для восстановления доступа к своим зашифрованным сообщениям, если забудете свою мнемоническую фразу. +\nХраните свой бумажный ключ в очень надёжном месте, например, в менеджере паролей (или в сейфе) + Импортирование ключей… + Скачивание ключей… + Вычисление бумажного ключа… + Игнорировать + Отметить как прочитанное + Войти с помощью единого входа + Отправить сообщение нажав ввод + Пароль не действителен + Медиа + Сжатия по умолчанию + Выберите + Источник медиа по умолчанию + Выберите + + %1$s: %2$d сообщение + %1$s: %2$d сообщения + %1$s: %2$d сообщений + %1$s: %2$d сообщений + + + %d оповещение + %d оповещения + %d оповещений + + Новое событие + Комната + Новые сообщения + Новое приглашение + Мне + Клавиша Ввод отправит сообщение вместо переноса строки + Воспроизвести звук затвора + неизвестный IP + ** Отправить не удалось — пожалуйста, откройте комнату + К сожалению, конференц-звонки с Jitsi не поддерживаются на старых устройствах (ниже Android OS - 6.0) + Новый сеанс запрашивает ключи шифрования. +\nНазвание сеанса: %1$s +\nПоследний раз в сети: %2$s +\nЕсли вы не входили в другой сеанс, проигнорируйте этот запрос. + Незаверенный сеанс запрашивает ключи шифрования. +\nНазвание сеанса: %1$s +\nПоследний раз в сети: %2$s +\nЕсли вы не входили в другой сеанс, проигнорируйте этот запрос. + Поделиться + Запрос поделится ключом + Игнорировать + Проверено! + Понял + Запрос на подтверждение + %s желает подтвердить вашу сессию + Неизвестная ошибка + Резервная копия существует на домашнем сервере + Похоже, у вас уже есть резервная копия ключа настройки из другой сессии. Хотите заменить его новым\? + Заменить + Стоп + Проверка состояния резервного копирования + Изменить + Ответить + Повторить + Отправил вам приглашение + Приглашен %s + Вы в теме! + У вас больше нет непрочитанных сообщений + Беседы + Здесь будут отображаться ваши личные сообщения. Нажмите «+» в правом нижнем углу, чтобы начать беседу. + Комнаты + Здесь будут отображаться ваши комнаты. Нажмите + в правом нижнем углу, чтобы найти существующие комнаты или создать свою. + Реакции + Принять + Отреагировать + Просмотреть реакции + Менеджер интеграции + Реакции + Событие удалено пользователем + Событие модерируется администратором комнаты + Некорректное событие, не могу отобразить + Создать комнату + Нет сети. Пожалуйста, проверьте подключение к Интернету. + Изменить + Изменить сервер + Пожалуйста, подождите… + Эту комнату нельзя предварительно просмотреть + Комнаты + Личные сообщения + СОЗДАТЬ + Название + Публичная + Каждый сможет присоединиться к этой комнате + Произошла ошибка при получении информации о доверии + Произошла ошибка при получении ключей резервного копирования данных + Импорт ключей сквозного шифрования из файла \"%1$s\". + Версия Matrix SDK + Другие уведомления третьих лиц + Вы уже просмотрели эту комнату! + Общее + Предпочтения + Безопасность + Правила push-уведомлений + ID приложения: + Ключ Push: + Отображаемое название приложения: + Отображаемое название сеанса: + Url: + Формат: + Голос и видео + Помощь и информация + Регистрационный токен + Оставить отзыв + Пожалуйста, напишите ваше предложение ниже. + Опишите ваше предложение здесь + Спасибо, предложение было успешно отправлено + Не удалось отправить предложение (%s) + Показать скрытые события в ленте сообщений + Личные сообщения + Ждите… + Шифрование миниатюры… + Отправка миниатюр (%1$s / %2$s) + Файл шифруется… + Файл отправляется (%1$s / %2$s) + Файл %1$s был загружен! + (изменено) + Изменение сообщения + Изменения не найдены + Отфильтровать беседы… + Не можете найти нужное\? + Создать комнату + Отправить личное сообщение + Каталог комнат + Название или ID (#example:matrix.org) + Жест смахивания для ответа в ленте сообщений + Ссылка скопирована в буфер обмена + Создаем комнату… + История изменений + Отклонить + Для продолжения Вам необходимо принять Условия этого сервиса. + Правила push-уведомлений не определены + Нет зарегистрированных push-шлюзов + Условия использования + Быть видимым для других + Используйте ботов, мосты, виджеты и наклейки + Никто + Отмена + Отключить + Не удается связаться с домашним сервером по этому URL, пожалуйста, проверьте его + Оптимизирован для батареи + Оптимизирован для работы в реальном времени + Без фоновой синхронизации + Обнаружение + Режим фоновой синхронизации + ${app_name} будет синхронизироваться в фоновом режиме таким образом, чтобы сохранить ограниченные ресурсы устройства (батарея). +\nВ зависимости от состояния ресурса вашего устройства, синхронизация может быть отложена операционной системой. + ${app_name} будет синхронизироваться в фоновом режиме периодически в точное время (настраивается). +\nЭто повлияет на использование радио и батареи, появится постоянное уведомление о том, что ${app_name} прислушивается к событиям. + Вы не будете уведомлены о входящих сообщениях, когда приложение находится в фоновом режиме. + Изменить настройки обнаружения. + Вы не используете какой-либо сервер обнаружения + Похоже, вы пытаетесь подключиться к другому домашнему серверу. Вы хотите выйти\? + Сервер обнаружения + Отключить сервер обнаружения + Настроить сервер обнаружения + Изменить сервер обнаружения + В настоящее время вы используете %1$s для обнаружения и доступны для обнаружения существующими знакомыми вам контактам. + Вы в настоящее время не используете сервер обнаружения. Чтобы обнаружить и быть найденным вашими существующими контактами, настройте один из них ниже. + Видимые адреса электронной почты + Видимые номера телефонов + Введите адрес сервера обнаружения + Не удалось подключиться к серверу обнаружения + Пожалуйста, введите URL сервера обнаружения + Сервер обнаружения не имеет условий использования + Параметры обнаружения появятся после добавления адреса электронной почты. + Параметры поиска появятся после добавления номера телефона. + Отключение от сервера обнаружения будет означать, что другие пользователи не смогут обнаружить вас, и вы не сможете приглашать других по электронной почте или по телефону. + Мы отправили вам электронное письмо на %s, проверьте вашу электронную почту и нажмите на ссылку для подтверждения + Выбранный сервер обнаружения не имеет условий использования. Продолжайте, только если вы доверяете его владельцу + Текстовое сообщение отправлено %s. Введите код проверки, который он содержит. + В настоящее время вы делитесь адресами электронной почты или телефонными номерами на сервере обнаружения %1$s. Вам нужно повторно подключиться к %2$s, чтобы прекратить делиться ими. + Примите Условия использования сервера обнаружения (%s), чтобы разрешить обнаружение по адресу электронной почты или номеру телефона. + Включить подробные логи. + Отправить вложение + Откройте панель навигации + Откройте меню создания комнаты + Это недействительный адрес сервера Matrix + Интеграции + Разрешить интеграции + Виджет + Загрузить виджет + Перезагрузить виджет + Открыть в браузере + ID виджета + Позволить + Этот виджет был добавлен: + Ваша тема + ID комнаты + Используйте менеджер интеграций чтобы управлять ботами, мостами, виджетами и наборами стикеров. +\nМенеджеры интеграций получают данные о конфигурации, могут изменять виджеты, отправлять приглашения в комнаты и устанавливать права от вашего имени. + Использование может оставить cookie на вашем устройстве и отправить данные в %s: + Использование может отправить данные в %s: + Не удалось загрузить виджет. +\n%s + Отозвать доступ для меня + Ваше отображаемое имя + URL вашего аватара + Ваш ID + Данный виджет запрашивает доступ к следующим ресурсам: + Запретить все + Использовать камеру + Использовать микрофон + Получать доступ к медиа, защищённым DRM + Создать комнату + Файл + Камера + Галерея + Это спам + Игнорировать пользователя + Все сообщения + Только упоминания + Настройки + Покинуть комнату + %1$s сделал(а) комнату доступной для всех, у кого есть ссылка. + %1$s сделал(а) комнату доступной только по приглашению. + Подробные логи помогут разработчикам, предоставив больше информации, когда вы отправляете \"Яростное встряхивание\". Даже когда они разрешены, приложение не записывает ваши сообщения и другие приватные данные. + Закройте меню создание комнаты… + Вниз + Контакт + Наклейка + Причина жалобы на это содержимое + ЖАЛОБА + ИГНОРИРОВАТЬ ПОЛЬЗОВАТЕЛЯ + Все сообщения (громко) + Заглушить + Отправить данное сообщение под спойлером + Спойлер + Введите ключевые слова, чтобы найти реакцию. + Долгий клик по комнате покажет дополнительные опции + Непрочитанные сообщения + Это ваша переписка. Контролируйте её. + Общайтесь с людьми напрямую или в группах + Начнем + Выберите сервер + Как и у электронной почты, у учётных записей один дом, не смотря на это вы можете общаться с кем угодно + Премиум-хостинг для организаций + Узнать больше + Другой + Пользовательские и расширенные настройки + Продолжить + Подключиться к %1$s + Подключиться к Element Matrix Services + Подключиться к пользовательскому серверу + Зарегистрироваться + Войти в систему + Продолжить с SSO + Element Matrix Services Адрес + Адрес + Премиум-хостинг для организаций + Введите адрес Modular Element или Сервер, который вы хотите использовать + Произошла ошибка при загрузке страницы: %1$s (%2$d) + Приложение не может войти на этот домашний сервер. Домашний сервер поддерживает следующие типы входа: %1$s. +\n +\nВы хотите войти с помощью веб-клиента\? + Извините, этот сервер не принимает новые учётные записи. + Приложение не может создать учётную запись на этом домашнем сервере. +\n +\nХотите зарегистрироваться через веб-клиент\? + Этот адрес электронной почты не связан ни с одной учетной записью. + Сбросить пароль на %1$s + Далее + Электронная почта + Новый пароль + Предупреждение! + Смена пароля приведёт к сбросу всех сквозных ключей шифрования во всех ваших сессиях, что сделает зашифрованную историю разговоров нечитаемой. Настройте резервное копирование ключей или экспортируйте ключи от комнаты из другой сессии, прежде чем сбрасывать пароль. + Продолжить + Данный адрес электронной почты не связан ни с одним аккаунтом + Проверьте свою почту + Письмо с подтверждением было отправлено на %1$s. + Нажмите на ссылку, чтобы подтвердить свой новый пароль. Как только вы перейдете по ссылке нажмите ниже. + Успешно! + Ваш пароль был сброшен. + Вы вышли из всех сессий и больше не будете получать push-уведомления. Чтобы возобновить уведомления, войдите снова на каждом устройстве. + Назад, чтобы войти в систему + Предупреждение + Ваш пароль еще не изменен. +\n +\nОстановить процесс смены пароля\? + Задать адрес электронной почты + Электронная почта + Электронная почта (необязательно) + Далее + Установить номер телефона + Укажите номер своего телефона, чтобы разрешить людям найти вас. + Пожалуйста, используйте международный формат. + Номер телефона + Номер телефона (необязательно) + Далее + Подтвердить номер телефона + Мы только что отправили код на %1$s. Введите его ниже, чтобы подтвердить, что это вы. + Введите код + Отправить повторно + Далее + Международные телефонные номера должны начинаться с \'+\' + Номер телефона выглядит недействительным. Пожалуйста, проверьте его + Зарегистрироваться в %1$s + Псевдоним или электронная почта + Псевдоним + Пароль + Далее + Этот псевдоним уже занят + Предупреждение + Ваш аккаунт еще не создан. Остановить процесс регистрации\? + Выбрать matrix.org + Выбрать Element Matrix Services + Выбрать другой сервер + Пожалуйста, пройдите проверку капчей + Примите условия для продолжения + Пожалуйста, проверьте свою электронную почту + Мы только что отправили письмо на %1$s. +\nПожалуйста, нажмите на содержащуюся в нём ссылку, чтобы продолжить создание аккаунта. + Домашний сервер устарел + + Отправлено слишком много запросов. Вы сможете повторить попытку через %1$d секунду… + Отправлено слишком много запросов. Вы сможете повторить попытку через %1$d секунды… + Отправлено слишком много запросов. Вы сможете повторить попытку через %1$d секунд… + + Вы вышли из системы + Это могло произойти по разным причинам: +\n +\n• Вы сменили пароль в другой сессии. +\n +\n• Вы удалили эту сессию из другой сессии. +\n +\n• Администратор вашего сервера заблокировал вам доступ из соображений безопасности. + Войти снова + Вы вышли из системы + Войти + Администратор вашего домашнего сервера (%1$s) вывел вас из вашего аккаунта %2$s (%3$s). + Войдите, чтобы восстановить ключи шифрования, хранящиеся только на этом устройстве. Они нужны для чтения всех ваших защищённых сообщений на любом устройстве. + Войти + Пароль + Очистить личные данные + Внимание: Ваши личные данные (включая ключи шифрования) всё ещё хранятся на этом устройстве. +\n +\nУдалите их, если вы закончили использовать это устройство или хотите войти в другую учётную запись. + Очистить все данные + Очистить данные + Очистить все данные, хранящиеся в данный момент на этом устройстве\? +\nВойдите заново, чтобы получить доступ к данным своей учётной записи и сообщениям. + Вы потеряете доступ к защищённым сообщениям, если не войдёте в систему для восстановления ключей шифрования. + Текущая сессия предназначена для пользователя %1$s, а вы предоставляете учётные данные для пользователя %2$s. Это не поддерживается в ${app_name}. +\nПожалуйста, сначала очистите данные, а затем снова войдите под другим аккаунтом. + Ваша ссылка на matrix.to была испорчена + Описание слишком короткое + Дополнительные настройки + Режим разработчика + Режим разработчика активирует скрытые функции, а также может сделать приложение менее стабильным. Только для разработчиков! + Настройки + Текущий сеанс + Другие сеансы + Включить шифрование + Недоверенный вход + Вложения + Интерактивная проверка со смайлами + Пожалуйста, выберите псевдоним. + Пожалуйста, выберите пароль. + Удалить… + Просмотрено + Узнать больше + Настройки комнаты + Уведомления + + Один участник + %1$d участника + %1$d участников + + Покинуть комнату + Администраторы + Модераторы + Пользователи + Сообщение удалено + МЕДИА + В этой комнате нет медиафайлов + ФАЙЛЫ + В этой комнате нет файлов + Это неуместно + Другая причина… + Пожаловаться на это содержимое + Безопасность + Ещё + QR-код + Соединение с сервером потеряно + Используйте мнемоническую фразу или бумажный ключ + Разблокировать историю зашифрованных сообщений + Проверка была отменена. Вы можете начать проверку снова. + Мнемоническая фраза + Введите %s, чтобы продолжить. + Не переиспользуйте пароль учётной записи. + Это может занять несколько секунд, пожалуйста, наберитесь терпения. + %s создал(а) и настроил(а) комнату. + Сообщение… + Доступно обновление шифрования + Проверьте себя и других для защиты ваших бесед + Заверьте сеанс + Подтвердите свою личность и получите доступ к зашифрованным сообщениям, сверив этот сеанс с другим вашим сеансом. + Лента сообщений + Ключ сообщения + Распечатайте его и храните в безопасном месте + Шифрование включено + Шифрование не включено + %1$s: %2$s + %1$s: %2$s %3$s + Удалённые сообщения + Показывать заглушку на месте удалённых сообщений + Мы отправили письмо на %s, пожалуйста проверьте почту и нажмите на ссылку для подтверждения + Код подтверждения неверный. + Попробуйте снова после принятия условий обслуживания на вашем домашнем сервере. + Похоже, сервер долгое время не отвечает, что может быть вызвано плохим соединением или ошибкой на сервере. Попробуйте снова через некоторое время. + Сменить пароль учётной записи… + Поддерживается только в зашифрованных комнатах + Создать новый диалог + %1$s, %2$s и %3$s прочли + %1$s и %2$s прочли + %1$s %2$s + Жалоба отправлена + Жалоба на контент отправлена. +\n +\nЕсли вы больше не хотите видеть от этого пользователя любого содержимого, вы можете его игнорировать, чтобы скрыть его сообщения. + Отмечено как спам + Это содержимое было отмечен как спам. +\n +\nЕсли вы больше не хотите видеть любое содержимое этого пользователя, вы можете его игнорировать, чтобы скрыть его сообщения. + Жалоба на неуместное содержание отправлена + Этот контент был отмечен как неприемлемый. +\n +\nЕсли вы больше не хотите видеть от этого пользователя любого содержимого, вы можете его игнорировать, чтобы скрыть его сообщения. + Они совпадают + Они не совпадают + Закрыть окно резервного копирования ключей + %s прочитано + Не удалось обработать данные + Воспроизвести + Копировать + Удачно + Уведомления + Звонок не состоялся + Не удалось установить соединение реального времени. +\nПопросите администратора вашего сервера настроить сервер TURN, чтобы звонки работали надёжно. + Выберите звуковое устройство + Телефон + Динамик + Гарнитура + Беспроводная гарнитура + Переключить камеру + Передняя + Задняя + Выключить HD + Включить HD + Ошибка SSL: не удалось идентифицировать другого абонента. + Ошибка SSL. + Отменить приглашение + Снизить собственные полномочия\? + Отклонить + Вы не сможете отменить это изменение, поскольку вы понижаете собственный полномочия, а если вы последний привилегированный пользователь в комнате, то восстановить привилегии будет невозможно. + Понизить + Игнорировать пользователя + Игнорирование этого пользователя приведет к удалению его сообщений из общих комнат. +\n +\nВы можете отменить это действие в любое время в общих настройках. + Перестать игнорировать пользователя + Если вы перестанете игнорировать этого пользователя, то вы увидите все его сообщения снова. + Отменить приглашение + Вы уверены, что хотите отменить приглашение для этого пользователя\? + Выгнать пользователя + Причина гонения + Пользователь будет выгнан из этой комнаты. +\n +\nЧтобы предотвратить его повторное присоединение, вы должны заблокировать его. + Заблокировать пользователя + Причина блокировки + Разблокировать пользователя + Разблокирование пользователя позволит ему присоединиться к комнате опять. + Безопасное резервное копирование + Настройка безопасного резервного копирования + Сброс безопасного резервного копирования + Настроить на этом устройстве + Защитите себя от потери доступа к зашифрованным сообщениям и данным, создав резервные копии ключей шифрования на вашем сервере. + Создайте новый бумажный ключ или задайте новую мнемоническую фразу для существующей резервной копии. + Это заменит ваш текущий ключ или фразу. + Интеграции отключены + Включите «Управление интеграциями» в настройках, чтобы сделать это. + + %d пользователь заблокирован + %d пользователей заблокировано + %d пользователей заблокировано + + Ключи успешно экспортированы + ОБЗОР + Активные виджеты + Бумажный ключ сохранён. + Безопасное резервное копирование + Защита от потери доступа к зашифрованным сообщениям и данным + Настроить безопасное резервное копирование + Добавьте отдельную вкладку для непрочитанных уведомлений на главном экране. + + Прочитал %d пользователь + Прочитано %d пользователями + Прочитано %d пользователями + Прочитано %d пользователями + + Добавить в избранное + Убрать из избранного + %1$s не внес никаких изменений + Вы не внесли никаких изменений + Вы не игнорируете никаких пользователей + Вы сделали комнату доступной для всех, у кого есть ссылка. + Вы сделали комнату только по приглашению. + Храните тайну переписки с помощью шифрования + Расширьте и персонализируйте свой опыт использования + Присоединяйтесь к миллионам бесплатно на крупнейшем публичном сервере + Войти в %1$s + Введите адрес сервера, который вы хотите использовать + На ваш почтовый ящик будет отправлено письмо для подтверждения установки нового пароля. + Я подтвердил свою электронную почту + Укажите адрес электронной почты для восстановления вашей учетной записи. Потом вы сможете, при желании, разрешить людям, которых вы знаете, обнаружить вас по адресу электронной почты. + Введенный код неверен. Пожалуйста, проверьте. + Войти с Matrix ID + Войти с Matrix ID + Если вы создаёте учётную запись на домашнем сервере, используйте свой матричный идентификатор (например, @user:domain.com) и пароль ниже. + Matrix ID + Если вы не знаете свой пароль, вернитесь, чтобы сбросить его. + Это недопустимый идентификатор пользователя. Ожидаемый формат: \'@user:homeserver.org\' + Не удалось найти действительный домашний сервер. Пожалуйста, проверьте свой идентификатор + Начальная синхронизация… + Яростное встряхивание + Порог обнаружения + Встряхните телефон, чтобы проверить порог обнаружения + Обнаружено встряхивание! + Показываем только первые результаты, наберите больше букв… + Раннее падение + ${app_name} может падать чаще, когда происходит непредвиденная ошибка + Добавляет ¯\\_(ツ)_/¯ в начало сообщения + После включения шифрования его нельзя отключить. + Ваш почтовый домен не имеет права регистрироваться на этом сервере + Не безопасно + Одно из следующих условий может быть скомпрометировано: +\n +\n— Ваш домашний сервер +\n— Домашний сервер, к которому подключен пользователь, которого вы проверяете +\n— Ваше подключение к интернету или других пользователей +\n— Ваше устройство или других пользователей + Видео. + Изображение. + Аудио + Файл + Наклейка + Ожидание… + %s отменено + Вы отменили + %s принято + Вы приняли + Подтверждение отправлено + Запрос на подтверждение + Заверьте этот сеанс + Сканируйте код с помощью устройства другого пользователя, чтобы безопасно проверить друг друга + Сканировать их код + Невозможно сканировать + Если вы не можете лично, сравните вместо этого эмодзи + Подтвердить при помощи сравнения эмодзи + Подтверждено %s + Подтверждённых %s + Ожидаем %s… + Сообщения в этой комнате не защищены сквозным шифрованием. + Сообщения в этой комнате защищены сквозным шифрованием. +\n +\nВаши сообщения защищены замками и только вы и получатель имеете уникальные ключи для их разблокировки. + Действия Администратора + Покидаем комнату… + Пользовательский + Приглашения + Администратор в %1$s + Модератор в %1$s + По умолчанию в %1$s + Пользовательский (%1$d) в %2$s + Перейти к последнему прочтённому им сообщению + ${app_name} не обрабатывает события типа \'%1$s\' + ${app_name} столкнулся с проблемой при отображении содержимого события с идентификатором \'%1$s\' + Перестать игнорировать + Эта сессия не может поделиться подтверждением с другими сессиями. +\nПодтверждение будет сохранено локально и отправится в будущей версии приложения. + Посылает сообщение, окрашенное в цвет радуги + Посылает данную эмоцию, окрашенную в цвет радуги + Редактор сообщений + Включить сквозное шифрование… + Включить шифрование\? + После включения шифрование для комнаты нельзя отключить. Сообщения отправленные в зашифрованной комнате не будут видны серверу, только участникам комнаты. Включение шифрования может помешать правильной работе многих ботов и мостов. + Включить шифрование + В целях безопасности, подтвердите %s, проверив одноразовый код. + В целях безопасности, сделайте это лично или используйте другой способ общения. + Сравните уникальные эмодзи, убедившись, что они появились в том же порядке. + Сравните код с тем, который отображается на экране другого пользователя. + Сообщения от этого пользователя зашифрованы сквозным шифрованием и не смогут быть прочитаны третьими лицами. + Ваш новый сеанс заверен. Он имеет доступ к вашим зашифрованным сообщениям, и другие пользователи будут воспринимать его как заверенный. + Перекрёстная подпись + Перекрёстная подпись включена +\nЛичные ключи хранятся на устройстве. + Перекрестная подпись включена +\nКлючи являются доверенными. +\nЛичные ключи неизвестны + Перекрестная подпись включена. +\nКлючи не являются доверенными + Перекрестная подпись выключена + Администратор вашего сервера отключил сквозное шифрование по умолчанию в приватных комнатах и личных сообщениях. + Активные сеансы + Показать все сеансы + Управление сеансами + Выйти из этого сеанса + Нет доступной криптографической информации + + %d сессия активна + %d сессии активны + %d сессий активно + + Заверьте этот сеанс + Используйте существующую сессию для подтверждения этой, предоставив ей доступ к зашифрованным сообщениям. + Инструменты для разработчиков + Данные учётной записи + Если вы не можете получить доступ к существующей сессии + Запросы ключей + Используйте эту сессию для подтверждения новой сессии, предоставляя ей доступ к зашифрованным сообщениям. + Ваши %2$s и %1$s установлены. +\n +\nДержите их в безопасности! Они понадобятся для разблокировки зашифрованных сообщений и защиты информации, если у вас не останется активных сессий. + Если вы отмените сейчас, вы можете потерять зашифрованные сообщения и данные, если потеряете доступ к своим логинам. +\n +\nВы также можете настроить безопасное резервное копирование и управлять своими ключами в настройках. + Сообщения в этой комнате зашифрованы сквозным шифрованием. Посмотрите подробности и подтвердите пользователей в их профиле. + Параметры уведомлений + Сообщения, содержащие @room + Отладка + Используйте последнюю версию ${app_name} на других ваших устройствах, веб-клиент ${app_name}, ${app_name} для ПК, ${app_name} для iOS, ${app_name} для Android или другой клиент Matrix, поддерживающий перекрестную подпись + Используйте последнюю версию ${app_name} на других ваших устройствах: + Подтвердите новую сессию вашей учетной записи: %1$s + Безопасное резервное копирование + Эта сессия является надежной для безопасного обмена сообщениями, поскольку вы подтвердили ее: + Подтвердите эту сессию, чтобы пометить её доверенной и предоставить ей доступ к зашифрованным сообщениям. Если вы не входили в эту сессию, ваша учетная запись может быть скомпрометирована: + Заверить + Заверено + Предупреждение + Не удалось получить список сессий + Сеансы + Заверенная + Незаверенная + Эта сессия является доверенной для безопасного обмена сообщениями, так как %1$s (%2$s) проверил(а) его: + %1$s (%2$s) вошел(ла), используя новую сессию: + Пока этот пользователь не доверяет этой сессии, сообщения, отправленные в обе стороны, помечаются предупреждениями. Вы также можете подтвердить эту сессию вручную. + Начать перекрестную подпись + Сбросить ключи + Почти готово! Показывает ли %s галочку\? + Да + Нет + Активирован режим \"В самолёте\" + Не удалось найти данные в хранилище + Вы хотите отправить это вложение в %1$s\? + + Отправить изображение в оригинальном размере + Отправить изображения в оригинальном размере + Отправить изображения в оригинальном размере + + Подтвердите удаление + Вы уверены, что хотите скрыть (удалить) это событие\? Обратите внимание, что если вы удалите название комнаты или измените тему, это может отменить изменение. + Укажите причину + Причина редактирования + Событие удалено пользователем, Причина: %1$s + Событие модерируется администратором комнаты, Причина: %1$s + Ключи успешно обновлены! + ${app_name} для Android + Обновить + Новый вход в вашу учётную запись. Это были Вы\? + Это был не я + Ваш аккаунт может оказаться под угрозой + Если вы прервёте процедуру, то не сможете читать зашифрованные сообщения на этом устройстве, а другие пользователи не захотят доверять ему + Если вы прервёте процедуру, то не сможете читать зашифрованные сообщения на своем новом устройстве, а другие пользователи не захотят доверять ему + Если вы прервёте процедуру, пользователь %1$s (%2$s) не будет подтверждён. Начните заново в профиле этого пользователя. + Что-то из этого может быть поставлено под угрозу: +\n +\n- Ваш пароль +\n- Ваш домашний сервер +\n- Это устройство или другое устройство +\n- Интернет-соединение, используемое этим или другим устройством +\n +\nМы рекомендуем вам немедленно изменить свой пароль и ключ восстановления в настройках. + Подтверждение отменено + Создание бумажного ключа из мнемонической фразы + Создание ключа SSSS из мнемонической фразы + Создание ключа SSSS из мнемонической фразы (%s) + Чтобы продолжить работу, введите парольную фразу для резервного копирования ключа. + Если вы не знаете вашу парольную фразу для резервного копирования ключей, вы можете %s. + Задать роль + Введите мнемоническую фразу, известную только вам, которая используется для защиты данных на вашем сервере. + Настройка восстановления. + Готово! + Храните его в надёжном месте + Завершить + Публикация созданных ключей идентификации + Определение ключа SSSS по умолчанию + Синхронизация мастер-ключа + Синхронизация ключа пользователя + Синхронизация ключа самоподписи + Настройка резервного копирования ключей + Сохраните на USB-ключ или резервное хранилище + Скопируйте в персональное облачное хранилище + Шифрование этой комнаты не поддерживается + Вы создали и настроили комнату. + Почти готово! Показывает ли другое устройство галочку\? + Почти готово! Ожидание подтверждения… + Ожидание для %s… + Не удалось импортировать ключи + Зашифрованные сообщения в персональных чатах + Зашифрованные сообщения в групповых чатах + При обновлении комнат + Посылает сообщение в виде простого текста, не интерпретируя его как разметку + Неверный псевдоним и/или пароль. Введённый пароль начинается или заканчивается пробелами, пожалуйста, проверьте его. + Эта учётная запись была деактивирована. + Введите %s, чтобы продолжить + Использовать файл + Этот бумажный ключ недействителен + Пожалуйста, введите бумажный ключ + Проверка ключа резервного копирования + Проверка ключа резервного копирования (%s) + Получение кривой ключа + Генерация ключа SSSS из бумажного ключа + Сохранение резервной копии ключа в SSSS + используйте ваш ключ восстановления ключа резервной копии + Ключ восстановления ключа резервной копии + Блокировать скриншоты в приложении + Включение этого параметра добавляет FLAG_SECURE ко всем действиям. Перезапустите приложение, чтобы изменения вступили в силу. + Не удалось сохранить медиафайл + Веб-${app_name} +\n${app_name} для ПК + ${app_name} для iOS +\n${app_name} для Android + или другой клиент Matrix поддерживающий перекрестную подпись + Принудительно отбрасывает текущую групповую сессию для отправки сообщений в зашифрованную комнату + Чтобы продолжить, используйте %1$s или %2$s. + Используйте бумажный ключ + Выберите бумажный ключ или введите его вручную, введя или вставив из буфера обмена + Не удалось получить доступ к защищенному хранилищу данных + Не зашифровано + Зашифровано неподтверждённой сессией + Ручная проверка с помощью текста + Перепроверьте эту ссылку + Ссылка %1$s перенаправит вас на другой сайт: %2$s. +\n +\nВы уверены, что хотите продолжить\? + Мы не смогли создать эту беседу. Пожалуйста, проверьте пользователей, которых вы приглашаете, и попробуйте ещё раз. + Добавить участников + ПРИГЛАСИТЬ + Приглашаем пользователей… + Пригласить пользователей + Приглашение для %1$s отправлено + Приглашения для %1$s и %2$s отправлены + + Приглашения отправлены %1$s и еще одному пользователю + Приглашения отправлены %1$s и еще %2$d пользователям + Приглашения отправлены %1$s и еще %2$d пользователям + + Мы не могли пригласить этих пользователей. Пожалуйста, проверьте пользователей, которых вы хотите пригласить, и повторите попытку. + Текущий язык + Другие доступные языки + Загрузка доступных языков… + Посмотреть условия %s + Отключиться от сервера идентификации %s\? + Этот сервер идентификации устарел. ${app_name} поддерживает только API V2. + Эта операция невозможна. Домашний сервер устарел. + Пожалуйста, настройте сначала сервер идентификации. + Пожалуйста, примите сначала условия сервера идентификации в настройках. + Для вашей приватности, ${app_name} поддерживает отправку адреса электронной почты и номеров телефонов только в хэшированном виде. + Привязка не удалась. + Текущая взаимосвязь с этим идентификатором отсутствует. + Ваш домашний сервер (%1$s) предлагает использовать %2$s для вашего сервера обнаружения + Использовать %1$s + Кроме того, вы можете ввести любой другой URL-адрес сервера идентификации + Введите URL-адрес сервера идентификации + Отправить + Роль + Открыть чат + Заглушить микрофон + Включить звук микрофона + Отключить камеру + Включить камеру + Защитите себя от потери доступа к зашифрованным сообщениям и данным, создав резервные копии ключей шифрования на вашем сервере. + Настроить + Используйте ключ безопасности + Создайте ключ безопасности для хранения в надежном месте, например в менеджере паролей или сейфе. + Использовать мнемоническую фразу + Введите мнемоническую фразу, известную только вам, и создайте ключ для резервного копирования. + Сохраните свой ключ безопасности + Храните бумажный ключ в надёжном месте, например, в менеджере паролей или в сейфе. + Задайте мнемоническую фразу + Введите мнемоническую фразу, известную только вам, которая используется для защиты данных на вашем сервере. + Мнемоническая фраза + Введите мнемоническую фразу ещё раз, чтобы подтвердить её. + Название комнаты + Тема + Вы успешно изменили настройки комнаты + У вас нет доступа к этому сообщению + Расшифровка этого сообщения может занять некоторое время + Из-за сквозного шифрования вам, возможно, придется ждать прибытие чьего-либо сообщения, потому что ключи шифрования не были отправлены вам должным образом. + Вы не можете получить доступ к этому сообщению, потому что вы были заблокированы отправителем + Нет доступа к этому сообщению, так как отправитель не доверяет вашей сессии + Вы не можете получить доступ к этому сообщению, потому что отправитель намеренно не отправил ключи + Ожидание истории шифрования + Riot теперь Element! + Мы рады сообщить, что сменили имя! Ваше приложение обновлено, и вы вошли в свою учетную запись. + ПОНЯТНО + УЗНАТЬ БОЛЬШЕ + Сохранить бумажный ключ в + Получаем ваши контакты… + Ваша контактная книга пуста + Книга контактов + Отозвать приглашение + Отозвать приглашение для %1$s\? + Забанен %1$s + Не удалось разбанить пользователя + Push-уведомления отключены + Просмотрите свои настройки, чтобы включить push-уведомления + Выберите PIN-код для обеспечения безопасности + Подтвердите PIN-код + Не удалось установить PIN-код, Пожалуйста, введите новый. + Введите ваш PIN-код + Забыли PIN-код\? + Сброс PIN-кода + Новый PIN-код + Чтобы сбросить свой PIN-код, вам нужно будет повторно войти в аккаунт и создать новый PIN-код. + Включить PIN-код + Для сброса PIN-кода нажмите Забыл(а) PIN-код, чтобы выйти из сессии и сбросить его. + Предотвращение случайных звонков + Запрашивать подтверждение перед началом звонка + У вас нет разрешения на запуск конференции в этой комнате + Начать видеовстречу + Начать аудиовстречу + На встречах используются политики безопасности и разрешения Jitsi. Все люди, находящиеся в данный момент в комнате, увидят приглашение присоединиться во время вашей встречи. + Вы не можете позвонить самому себе + Вы не можете позвонить самому себе, дождитесь, пока участники примут приглашение + Не удалось добавить виджет + Не удалось удалить виджет + + %1$d/%2$d ключ успешно импортирован. + %1$d/%2$d ключа успешно импортированы. + %1$d/%2$d ключей успешно импортированы. + %1$d/%2$d ключей успешно импортированы. + + Управление интеграциями + Нет активных виджетов + Комната создана, но некоторые приглашения не отправлены по следующей причине: +\n +\n%s + + %1$s, %2$s и %3$d читает + %1$s, %2$s и %3$d других читают + %1$s, %2$s и %3$d других читают + + + Неверный код, осталась %d попытка + Неверный код, осталось %d попытки + Неверный код, осталось %d попыток + + Предупреждение! Последняя оставшаяся попытка перед выходом из системы! + Слишком много ошибок, вы вышли из системы + Этот номер телефона уже используется. + В ваш аккаунт не добавлен номер телефона + Адрес электронной почты + В вашу учётную запись не добавлен адрес электронной почты + Телефонные номера + Удалить %s\? + Убедитесь, что вы перешли по ссылке в электронном письме, которое мы вам отправили. + Электронная почта и номера телефонов + Управляйте адресами электронной почты и номерами телефонов, привязанными к вашей учётной записи Matrix + Код + Используйте международный формат (номер телефона должен начинаться с \'+\') + Подтвердите свою личность, проверив этот логин, предоставив ему доступ к зашифрованным сообщениям. + Невозможно открыть комнату, в которую вам запрещён доступ. + Невозможно найти эту комнату. Убедитесь, что она существует. + + %d секунда + %d секунды + %d секунд + + Опрос + Отреагировал(а): %s + Результат проверки + Ссылка была искажена + У вас нет разрешения на запуск звонка в этой комнате + Удалить данные учетной записи типа %1$s\? +\n +\nИспользуйте с осторожностью, это может привести к неожиданному поведению. + ПИН-код потребуется каждый раз, когда вы откроете ${app_name}. + ПИН-код потребуется через 2 минуты неиспользования ${app_name}. + Требовать PIN-код через 2 минуты + Отображать только количество непрочитанных сообщений в простом уведомлении. + Показывать подробности, такие как названия комнат и содержание сообщений. + Показывать содержимое в уведомлениях + PIN-код - единственный способ разблокировать ${app_name}. + Включить биометрические данные устройства, такие как отпечатки пальцев и распознавание лиц. + Включить биометрию + Настроить защиту + Защитите доступ с помощью PIN-кода и биометрии. + Защита доступа + Вы перезапустите приложение без истории, сообщений, доверенных устройств или доверенных пользователей + Если сбросить всё + Делайте это только в том случае, если у вас нет другого устройства, с которого вы можете проверить это устройство. + Сбросить всё + Забыли или потеряли все варианты восстановления\? Сбросить всё + Вы вошли. + %s вошёл(шла). + Сообщения в этой переписке защищены сквозным шифрованием. + Покинуть + Настройки + Сообщения здесь защищены сквозным шифрованием. +\n +\nВаши сообщения защищены замками, и только у вас и получателя есть уникальные ключи для их разблокировки. + Сообщения здесь не прошли сквозного шифрования. + На этом домашнем сервере работает старая версия. Попросите администратора вашего домашнего сервера выполнить обновление. Вы можете продолжить, но некоторые функции могут работать некорректно. + Вы сделали доступ только по приглашению. + %1$s сделал(а) доступ только по приглашению. + Показать полную историю в зашифрованных комнатах + %1$s и %2$s + %1$s в %2$s и %3$s + + %d приглашение + %d приглашения + %d приглашений + %d приглашений + + Фильтр заблокированных пользователей + У вас нет разрешения на запуск звонка + У вас нет разрешения на запуск конференции + Сброс + + Показать устройство, которое вы можете проверить сейчас + Показать %d устройства, которые вы можете проверить сейчас + Показать %d устройств, которые вы можете проверить сейчас + Показать %d устройств, которые вы можете проверить сейчас + + Уведомление нажато! + Пожалуйста, нажмите на уведомление. Если вы не видите уведомления, проверьте настройки системы. + Отображение уведомления + Вы видите уведомление! Нажмите сюда! + Не удалось получить push-уведомление. Переустановка приложения может быть возможным решением. + Приложение получило push-уведомление + Приложение ожидает push-уведомление + Тестирование push-уведомлений + Есть несохраненные изменения. Отменить изменения\? + Удалить из маловажного + Повернуть и обрезать + Настройки комнаты + Тема комнаты (необязательно) + Отменить изменения + Комната ещё не создана. Отменить создание комнаты\? + Добавить к маловажному + Добавить изображение из + Тема + Название комнаты + Вы дали свое согласие на отправку адресов электронных почт и телефонных номеров на этот сервер идентификации для обнаружения других пользователей из ваших контактов. + Добавить по QR-коду + Разрешить доступ к вашим контактам. + Чтобы отсканировать QR-код, вам нужно разрешить доступ к камере. + QR-код не отсканирован! + Недействительный QR-код (недопустимый URI)! + Нельзя отправлять сообщения самому себе! + Поделиться по тексту + Поиск контактов в Matrix + Установить аватар + Согласие пользователя не предоставлено. + Поделитесь этим кодом с людьми, чтобы они могли отсканировать его, добавить вас и начать общение. + Мой код + Поделиться моим кодом + Сканировать QR-код + Это недействительный QR-код matrix + 🔐️ Присоединяйтесь ко мне в ${app_name} + Привет, поговори со мной в ${app_name}: %s + Пригласить друзей + Добавить людей + "Тема: " + Добавьте тему + Это начало беседы. + Это начало %s. + У вас нет разрешения на включение шифрования в этой комнате. + Создание комнаты… + Некоторые символы не разрешены + Укажите адрес комнаты + Этот адрес уже используется + Вы можете включить это, если комната будет использоваться только для совместной работы с внутренними командами на вашем домашнем сервере. Это не может быть изменено позже. + Запретить кому-либо, не входящему в %s, когда-либо присоединяться к этой комнате + Скрыть дополнительные настройки + Показать дополнительные настройки + %1$d из %2$d + Дать согласие + Отозвать моё согласие + Больше никаких результатов + Предложения + Известные пользователи + QR-код + Отправить историю запросов на обмен ключами + Начать беседу + %s чтобы люди знали, о чём эта комната. + Это начало вашей переписки с %s. + Экспорт аудита + Личное сообщение + Отправить электронную почту и номера телефонов + Изменить текущий PIN-код + Изменить PIN-код + Предварительный просмотр этой комнаты невозможен. Вы хотите к ней присоединиться\? + Доступ в эту комнату в настоящее время закрыт. +\nПовторите попытку позже или попросите администратора комнаты проверить, есть ли у вас доступ. + Не удалось получить текущую видимость каталога комнаты (%1$s). + Опубликовать эту комнату для всех в каталоге комнат %1$s\? + Отменить публикацию этого адреса + Опубликовать этот адрес + Добавить локальный адрес + У этой комнаты нет локальных адресов + Задайте адреса для этой комнаты, чтобы пользователи могли найти эту комнату через ваш домашний сервер (%1$s) + Локальные адреса + Новый опубликованный адрес (например, #alias:server) + Других опубликованных адресов пока нет. + Других опубликованных адресов пока нет, добавьте первый ниже. + Удалить адрес \"%1$s\"\? + Отменить публикацию адреса \"%1$s\"\? + Опубликовать + Опубликовать новый адрес вручную + Другие опубликованные адреса: + Это основной адрес + Опубликованные адреса могут быть использованы кем угодно на любом сервере, чтобы присоединиться к вашей комнате. Чтобы опубликовать адрес, сначала его нужно настроить как локальный. + Опубликованные адреса + Просматривайте и управляйте адресами этой комнаты, а также её видимостью в каталоге комнат. + Адреса комнаты + Доступ в комнату + Изменение того, кто может читать историю, будет применяться только к будущим сообщениям в этой комнате. Видимость существующей истории не изменится. + Отменить публикацию + Добавить + отправляет снегопад ❄️ + отправляет конфетти 🎉 + Отправляет данное сообщение со снегопадом + Отправляет данное сообщение с конфетти + Очистить историю + Единая точка входа + Зарегистрироваться через %s + Войти через %s + Продолжить с %s + Или + Добавить кнопку в редактор сообщений, чтобы открыть клавиатуру эмодзи + Показать клавиатуру эмодзи + Используйте команду /confetti или отправьте сообщение, содержащее ❄️ или 🎉 + Эффекты + Изменить тему + Обновить комнату + Отправить событие m.room.server_acl + Изменить разрешения + Изменить название комнаты + Изменить видимость истории + Включить шифрование комнаты + Изменить основной адрес комнаты + Изменить аватар комнаты + Изменить виджеты + Уведомить всех + Удалить сообщения, отправленные другими + Блокировка пользователей + Выгнать пользователей + Изменить настройки + Пригласить пользователей + Отправить сообщения + Роль по умолчанию + У вас нет права доступа на обновление ролей, необходимых для изменения различных параметров комнаты + Выберите роли, которые смогут менять различные параметры комнаты + Просматривайте и обновляйте роли, необходимые для изменения различных параметров комнаты. + Разрешения + Разрешения комнаты + Эта комната не публичная. Вы не сможете повторно присоединиться без приглашения. + Системная тема + Не удалось пройти аутентификацию + ${app_name} требует от вас ввести свои учетные данные для выполнения этого действия. + Требуется повторная аутентификация + Не удалось настроить перекрестную подпись + Активный звонок (%1$s) + При поиске номера телефона произошла ошибка + Панель набора номера + Перезвонить + Этот вызов закончился + %1$s отменил(а) этот вызов + Вы поставили вызов на удержание + %s поставил вызов на удержание + Удерживать + Возобновить + Пользователи + Произошла ошибка при переводе вызова + Перевод + Подключиться + Сначала посоветуйтесь + Нет учётных данных, неправильная учётная запись пользователя и/или пароль + Вы уверены, что хотите удалить все неотправленные сообщения в этой комнате\? + Удалить неотправленные сообщения + Сообщения не удалось отправить + Вы хотите отменить отправку сообщения\? + Удалить все неудачные сообщения + Не удалось + Отправлено + Отправка + Содержание события + Событие статуса отправлено! + Событие отправлено! + Некорректное событие + Отсутствует тип сообщения + Нет содержания + Содержание события + Ключ статуса + Тип + Отправить пользовательское событие статуса + Редактировать содержание + События статуса + Исследовать статус комнаты + Отправить событие статуса + Отправить пользовательское событие + Инструменты для разработчиков + Смотреть подтверждение получения + Не уведомлять + Уведомить без звука + Уведомить со звуком + Сообщение не отправлено из-за ошибки + Проверено + Закрыть выбор эмодзи + Открыть выбор эмодзи + Доверенный уровень доверия + Предостерегающий уровень доверия + Уровень доверия по умолчанию + Выбрано + Видео + есть неотправленный черновик + Некоторые сообщения не были отправлены + Удалить аватар + Сменить аватар + Изображение + Импорт ключа из файла + Открытые виджеты + Снимок экрана + + %d запись + %d записи + %d записей + %d записей + + Предел неизвестен. + Ваш домашний сервер принимает вложения (файлы, медиа и т.д.) размером до %s. + Лимит загрузки файла сервера + Версия сервера + Название сервера + Настройки комнаты + Покинуть текущую конференцию и перейти к другой\? + Версия комнаты + Показать все комнаты в списке комнат, в том числе с откровенным содержанием. + Комнаты с непристойным содержанием + Каталог комнат + Новое значение + Сменить + Начальная синхронизация: +\nЗагрузка данных… + Начальная синхронизация: +\nОжидание ответа сервера… + Сообщение отправлено + Отзыв о пространствах + Адреса пространства + Извините, при попытке присоединиться произошла ошибка: %s + Обновить до рекомендованной версии комнаты + В этой комнате запущена версия комнаты %s, которую этот домашний сервер пометил как нестабильную. + Для обновления комнаты необходимо разрешение + Автоматическое обновление родительского пространства + Автоматическое приглашение пользователей + Вы обновили эту комнату с %1$s до %2$s. + Обновление комнаты - это расширенное действие, которое обычно рекомендуется, когда комната работает нестабильно из-за ошибок, отсутствующих функций или уязвимостей безопасности. +\nОбычно это влияет только на то, как комната обрабатывается на сервере. + Модернизировать приватную комнату + Модернизировать публичную комнату + Обновление + Пожалуйста, будьте терпеливы, это может занять некоторое время. + Присоединиться к замещенной комнате + Безымянная Комната + Некоторые комнаты могут быть скрыты, потому что они приватные, и вам нужно приглашение. + Некоторые комнаты могут быть скрыты, потому что они приватные, и вам нужно приглашение. +\nУ вас нет разрешения на добавление комнат. + В этом пространстве нет комнат + Для получения дополнительной информации обратитесь к администратору домашнего сервера + Похоже, что ваш домашний сервер пока не поддерживает Пространства + Чувствуете себя экспериментатором\? +\nВы можете добавить существующие пространства в пространство. + Управление комнатами и пространствами + Отметить как не рекомендуется + Отметить как рекомендуется + Предложено + Управление комнатами + Ищете кого-то не в %s\? + %s приглашает вас + Вы приглашены + Пространства — это новый способ организации комнат и людей. + Добавить существующие комнаты и пространство + Вы единственный администратор этого пространства. Если вы его покинете, то никто не сможет управлять им. + Вы сможете присоединиться только после повторного приглашения. + Вы здесь единственный человек. Если вы уйдёте, никто не сможет присоединиться в будущем, включая вас. + Покинуть + Добавить комнаты + Обзор комнат + + %d человек, которого вы знаете, уже присоединился + %d людей, которых вы знаете, уже присоединились + %d людей, которых вы знаете, уже присоединились + %d людей, которых вы знаете, уже присоединились + + В данный момент этот псевдоним недоступен. +\nПовторите попытку позже или попросите администратора комнаты проверить, есть ли у вас доступ. + Присоединиться в любом случае + Присоединиться к пространству + Создать пространство + Пока пропустить + Присоединяйтесь к моему пространству %1$s %2$s + Они не будут участвовать в %s + Только в эту комнату + Они смогут изучить %s + Пригласить в %s + Поделиться ссылкой + Пригласить по электронной почте + На данный момент здесь только вы. С другими в %s будет ещё лучше. + Пригласить в %s + Пригласить людей + Пригласите людей в свое пространство + Описание + Создание пространства… + Случайный + Общие + Давайте создадим комнату для каждого из них. Позже можно добавить и другие, в том числе уже существующие. + Над чем вы работаете\? + Мы создадим для них комнаты. Позже вы сможете добавить и другие. + Какие обсуждения вы хотите провести в %s\? + Дайте ему название, чтобы продолжить. + Добавьте некоторые детали, чтобы помочь людям распознать его. Вы сможете изменить их в любой момент. + Добавьте некоторые детали, чтобы помочь ему выделиться. Вы сможете изменить их в любой момент. + Создание пространства + Только по приглашениям, лучше для себя или команды + Приватное + Открыто для всех, лучше всего подходит для сообществ + Публичное + Приватное пространство для вас и членов команды + Приватное пространство для организации ваших комнат + Я и члены команды + Только я + Убедитесь, что нужные люди имеют доступ к %s. + С кем вы работаете\? + Чтобы присоединиться к существующему пространству, вам необходимо получить приглашение. + Вы сможете изменить это позже + Какой тип пространства вы хотите создать\? + Ваше приватное пространство + Ваше публичное пространство + Добавить пространство + Приватное пространство + Публичное пространство + Обновляет комнату до новой версии + Покинуть комнату с заданным id (или текущую комнату, если null) + Присоединитесь к пространству с заданным id + Создать пространство + Публичная комната + Непроверенные + Неизвестное лицо + Перевести на %1$s + Консультация с %1$s + + Отправить видео в исходном размере + Отправить видео в исходном размере + Отправить видео в исходном размере + Отправить видео в исходном размере + + Отправить медиафайлы в исходном размере + нестабильная + стабильная + Версия по умолчанию + Версии комнаты 👓 + Проверьте, сравнив эмодзи + Сканирование с помощью этого устройства + Сканируйте код с помощью другого устройства или переключитесь и сканируйте с помощью этого устройства + Адрес пространства + Файл слишком большой для загрузки. + Поиск по названию + Сжатие видео %d%% + Сжатие изображения… + Оставить отзыв + Не удалось отправить отзыв (%s) + Спасибо, ваш отзыв успешно отправлен + Вы можете связаться со мной, если у вас есть дополнительные вопросы + Вы используете бета-версию пространств. Ваши отзывы помогут при разработке следующих версий. Ваша платформа и имя пользователя будут отмечены, чтобы мы могли максимально использовать ваш отзыв. + Отзыв + Извините, при попытке присоединиться к конференции произошла ошибка + Этот сервер уже присутствует в списке + Не удается найти этот сервер или список его комнат + Введите имя нового сервера, который вы хотите исследовать. + Добавить новый сервер + Ваш сервер + Любой человек в пространстве с этой комнатой может найти её и присоединиться к ней. Только администраторы этой комнаты могут добавить её в пространство. + Только участники пространства + Каждый может найти комнату и присоединиться + Публичный + Только приглашенные люди могут найти и присоединиться + Приватный + Неизвестная настройка доступа (%s) + Любой может постучаться в комнату, а участники могут принять или отклонить его + Просмотреть и управлять адресами этого пространства. + Разрешить гостям присоединяться + + Пропущенный видеозвонок + %d пропущенных видеозвонка + %d пропущенных видеозвонков + %d пропущенных видеозвонков + + + Пропущенный аудиовызов + %d пропущенных аудиовызова + %d пропущенных аудиовызовов + %d пропущенных аудиовызовов + + Использовать по умолчанию и больше не спрашивать + Всегда спрашивать + URL API домашнего сервера + Пространства + Предлагаемые комнаты + Отсутствующие разрешения + Для выполнения этого действия, пожалуйста, предоставьте разрешение Камеры в настройках системы. + Для выполнения этого действия отсутствуют некоторые разрешения, пожалуйста, предоставьте разрешения в настройках системы. + Обратите внимание, что при обновлении будет создана новая версия комнаты. Все текущие сообщения останутся в этой архивной комнате. + Любой человек в родительском пространстве сможет найти и присоединиться к этой комнате - нет необходимости вручную приглашать всех. Вы сможете изменить это в настройках комнаты в любое время. + Любой человек в %s сможет найти и присоединиться к этой комнате - нет необходимости вручную приглашать всех. Вы сможете изменить это в настройках комнаты в любое время. + Голосовое сообщение (%1$s) + Вы не можете отвечать или редактировать, пока активно голосовое сообщение + Не удалось записать голосовое сообщение + Не удалось воспроизвести это голосовое сообщение + Нажмите на запись, чтобы остановить или прослушать ее + %1$d осталось + Удерживайте для записи, отпустите для отправки + Удалить запись + Запись голосового сообщения + Приостановить голосовое сообщение + Прослушать голосовое сообщение + Проведите для отмены + Запись голосового сообщения + Требуется обновление + Голосовое сообщение + Другие пространства или комнаты, которые вы могли не знать + Пространство, которое вы знаете, содержит эту комнату + Решите, кто может найти и присоединиться к этой комнате. + Нажмите для изменения пространств + Выбрать пространства + Определите, какие пространства могут получить доступ к этой комнате. Если пространство выбрано, его участники смогут найти и присоединиться к комнате. + Пространства с доступом + Разрешить участникам пространства находить и получать доступ. + Участники пространства %s могут находить, просматривать и присоединяться. + Приватная (только по приглашению) + Обновлениях комнаты + Сообщениях от бота + Приглашениях в комнату + Зашифрованных групповых сообщениях + Групповых сообщениях + Зашифрованных диалогах + Диалогах + Мой псевдоним + Моё отображаемое имя + Уведомлять меня о + Другое + Упоминания и ключевые слова + Уведомления по умолчанию + Чтобы отправлять голосовые сообщения, предоставьте разрешение на Микрофон. + %s в настройках, чтобы получать приглашения непосредственно в ${app_name}. + Свяжите этот адрес электронной почты с вашей учетной записью + Приглашение в эту комнату было отправлено на %s, который не связан с вашей учетной записью + Приглашение в это пространство было отправлено на %s, который не связан с вашей учетной записью + Все комнаты, в которых вы находитесь, будут отображаться в Начале. + Показать все комнаты в Начале + Проведите для завершения вызова + %1$s Нажмите, чтобы вернуться + Активный вызов (%1$s) · + + %1$d Активный вызов · + %1$d активных вызова · + %1$d активных вызовов · + %1$d активных вызовов · + + Нет ответа + Пропущенный выдеовызов + Пропущенный голосовой вызов + Видеовызов отклонен + Голосовой вызов отклонен + Выдеовызов завершен • %1$s + Голосовой вызов завершен • %1$s + Активный видеовызов + Активный голосовой вызов + Входящий видеовызов + Входящий голосовой вызов + Вы отклонили этот вызов + Настройки учётной записи + Вы можете управлять уведомлениями в %1$s. + Обратите внимание, что уведомления об упоминаниях и ключевых словах недоступны в зашифрованных комнатах на мобильных устройствах. + Уведомлять меня о + Вы не будете получать уведомления об упоминаниях и ключевых словах в зашифрованных комнатах на мобильных устройствах. + Ключевые слова + \@room + Ключевые слова не могут содержать \'%s\' + Ключевые слова не могут начинаться с \'.\' + Добавить новое ключевое слово + Ваши ключевые слова + Отсутствует + Только упоминания и ключевые слова + Завершение вызова… + Нет ответа + Пользователь, которого вы вызвали, занят. + Пользователь занят + Аудиовызов с %s + Видеовызов с %s + Вызов… + Пространства + Добавьте пространство в любое пространство, которым вы управляете. + Добавить существующие пространства + Добавить существующие комнаты + Вы уверены, что хотите покинуть %s\? + Обнаружение (%s) + Завершение настройки + Приглашение по электронной почте, поиск контактов и многое другое… + Завершите настройку обнаружения. + В настоящее время вы не используете сервер обнаружения. Чтобы приглашать членов команды и быть доступным для них, настройте один из них ниже. + Приглашение по имени пользователя или по почте + Убедитесь, что нужные люди имеют доступ к %s. Вы можете пригласить больше людей позже. + Кто ваши члены команды\? + Добавить в данное пространство + Создание пространства… + Показать некоторую полезную информацию для помощи в отладке приложения + Показать отладочную информацию на экране + Не похоже на действительный адрес электронной почты + Открыть настройки обнаружения + Поиск по имени, ID или почте + Создать новое пространство + Каждый может найти это пространство и присоединиться + Доступ к пространству + Кто имеет к этому доступ\? + Включить уведомления по электронной почте для %s + Чтобы получать уведомления по электронной почте, пожалуйста, привяжите адрес электронной почты к своей учётной записи Matrix + Уведомление по эл. почте + Обновить пространство + Изменить название пространства + Включить шифрование пространства + Изменить основной адрес для пространства + Изменить аватар пространства + У вас нет разрешения на обновление ролей, необходимых для изменения различных параметров этого пространства + Выберите роли, необходимые для изменения различных параметров этого пространства + Просмотр и обновление ролей, необходимых для изменения различных частей пространства. + Разрешения пространства + Разблокирование пользователя позволит ему присоединиться к пространству опять. + Блокировка пользователя удалит его из этого пространства и не позволит ему присоединиться вновь. + Пользователь будет выгнан из этого пространства. +\n +\nЧтобы предотвратить его повторное присоединение, вы должны заблокировать его. + Остановить запись + Добавляет ( ͡° ͜ʖ ͡°) в начало сообщения + Нет правил, предоставляемых сервером обнаружения + Скрыть правила сервера обнаружения + Показать правила сервера обнаружения + Отображает информацию о пользователе + Изменяет ваш аватар только в этой текущей комнате + Меняет аватар текущей комнаты + Изменяет ваше отображаемое имя только в текущей комнате + Устанавливает имя комнаты + Прекращение игнорирования пользователя, показывает его сообщения в дальнейшем + Игнорирует пользователя, скрывая его сообщения от вас + Недоступен + Не в сети + В сети + Поделиться местоположением + Создать опрос + Открыть контакты + Отправить наклейку + Загрузить файл + Отправить изображения и видео + Открыть камеру + Открыть с помощью + ${app_name} не смог получить доступ к вашему местоположению. Пожалуйста, повторите попытку позже. + ${app_name} не смог получить доступ к вашему местоположению + Местоположение + Поделиться местоположением + Результаты отображаются только после завершения опроса + Закрытый опрос + Открытый опрос + Проголосовавшие увидят результаты сразу после голосования + Тип опроса + Редактировать опрос + Вы уверены, что хотите удалить этот опрос\? Вы не сможете восстановить его после удаления. + Удалить опрос + Опрос завершен + Проголосовано + Завершить опрос + Это лишит людей возможности голосовать и отобразит окончательные результаты опроса. + Завершить этот опрос\? + Завершить опрос + + Окончательный результат на основании %1$d голоса + Окончательный результат на основании %1$d голосов + Окончательный результат на основании %1$d голосов + Окончательный результат на основании %1$d голосов + + + %1$d голос. Проголосуйте, чтобы увидеть результаты + %1$d голоса. Проголосуйте, чтобы увидеть результаты + %1$d голосов. Проголосуйте, чтобы увидеть результаты + %1$d голосов. Проголосуйте, чтобы увидеть результаты + + Голосов нет + + На основании %1$d голоса + На основании %1$d голосов + На основании %1$d голосов + На основании %1$d голосов + + + %1$d голос + %1$d голоса + %1$d голосов + %1$d голосов + + + Требуется минимум %1$s вариант + Требуется минимум %1$s варианта + Требуется минимум %1$s вариантов + Требуется минимум %1$s вариантов + + Вопрос не может быть пустым + СОЗДАТЬ ОПРОС + ДОБАВИТЬ ВАРИАНТ + Вариант %1$d + Создать варианты + Вопрос или тема + Вопрос или тема опроса + Опрос + Создать опрос + Перезапустите приложение, чтобы изменения вступили в силу. + Математика LaTeX + Ваша система будет автоматически отправлять журналы при возникновении ошибки невозможности расшифровки + Автоматически сообщать об ошибках расшифровки. + Шифрование неправильно настроено + Изменить цвет имени + Восстановить шифрование + Обратитесь к администратору, чтобы восстановить шифрование до рабочего состояния. + Шифрование настроено неправильно. + Поделился(лась) местоположением + У меня уже есть учётная запись + Создать учётную запись + Обмен сообщениями для вашей команды. + Сквозное шифрование не требующее номера телефона. Нет рекламы или сбора данных. + Решайте самостоятельно и независимо, где хранить беседы. Благодаря Matrix. + Безопасное и независимое общение, обеспечивающее вам такой же уровень конфиденциальности, как при личном общении в вашем собственном доме. + Безопасный обмен сообщениями. + Ваше управление. + Контролируйте свою переписку. + Местоположение + Вы согласны отправить эту информацию\? + Чтобы обнаружить существующие контакты, необходимо отправить контактную информацию (электронную почту и номера телефонов) на сервер обнаружения. Мы хешируем ваши данные перед отправкой для обеспечения конфиденциальности. + Отправить адреса электронных почт и номера телефонов %s + Ваши контакты приватны. Чтобы обнаружить пользователей из ваших контактов, нам необходимо ваше разрешение на отправку контактной информации на ваш сервер обнаружения. + Системные настройки + Версии + Получите помощь в использовании ${app_name} + Помощь и поддержка + Помощь + Правовые положения + Этот сервер не предоставляет никакой политики. + Сторонние библиотеки + Политика сервера обнаружения + Политика домашнего сервера + Политика ${app_name} + Вы можете отключить это в любое время в настройках + Мы не передаем информацию третьим лицам + Мы не записываем и не профилируем любые данные учетной записи + тут + Помогите нам выявить проблемы и улучшить ${app_name}, поделившись анонимными данными об использовании. Чтобы понять, как люди используют несколько устройств, мы сгенерируем случайный идентификатор, общий для всех ваших устройств. +\n +\nВы можете ознакомиться со всеми нашими условиями %s. + Помогите улучшить ${app_name} + Сеанс завершён! + Комната покинута! + Шифрование неправильно настроено, поэтому вы не можете отправлять сообщения. Нажмите, чтобы открыть настройки. + Шифрование настроено неправильно, поэтому вы не можете отправлять сообщения. Пожалуйста, обратитесь к администратору, чтобы восстановить работу шифрования. + Выберите домашний сервер + Не могу связаться с домашним сервером на URL %s. Пожалуйста, проверьте вашу ссылку или выберите домашний сервер вручную. + Не сейчас + Включить + Ожидание уведомлений + Вам не разрешено подключаться к этой комнате + Организуйте обсуждения с помощью обсуждений + Показать все обсуждения, в которых вы участвуете + Все обсуждения + Посмотреть обсуждения + Посмотреть в комнате + Сообщения в пузырях + Не удалось загрузить карту + Карта + Примечание: приложение будет перезапущено + Включить обсуждения сообщений + Подключиться к серверу + Хотите присоединиться к существующему серверу\? + Пропустить вопрос + Пока не уверены\? %s + Сообщества + Команды + Друзья и семья + Мы поможем вам подключиться + С кем вы будете общаться чаще всего\? + Вы уже просматриваете это обсуждение! + Просмотр в Комнате + Обсудить + Команда «%s» распознаётся, но не поддерживается в обсуждениях. + Из обсуждения + Совет: нажмите и удерживайте сообщение и используйте «%s». + Обсуждения помогают поддерживать и легко отслеживать тематику бесед. + Мои обсуждения + Показать все обсуждения этой комнаты + Фильтр + Обсуждения + Обсуждение + Фильтровать Обсуждения в комнате + Скопировать ссылку на обсуждение + Уведомления комнаты + Пользователи + Оповестить всю комнату + + И ещё %1$d + И ещё %1$d + И ещё %1$d + И ещё %1$d + + Свернуть + %1$s, %2$s и другие + %1$s и %2$s + + %d изменение ACL сервера + %d изменения ACL сервера + %d изменений ACL сервера + %d изменений ACL сервера + + Поехали! + Его можно изменить позже + Добавить аватар + Вы сможете изменить это позже + Отображаемое имя + Выберите отображаемое имя + Ваша учётная запись %s создана + Поздравляем! + Домой + Персонализировать + БЕТА + Отзыв на бета-версию Обсуждений + Оставить отзыв + БЕТА + Если включено, для других вы всегда будете выглядеть, как в офлайне, даже при использовании приложения. + Офлайн-режим + Бета-версия Обсуждений + Бета-версия Обсуждений + Обсуждения почти в бете 🎉 + Остановить демонстрацию экрана + Демонстрировать экран + Узнать больше + Попробуйте + Отключить + - Несколько пользователей больше не игнорируются + Начальный запрос на синхронизацию + Обсуждения помогают поддерживать и легко отслеживать тематику бесед.%sВключение обсуждений обновит приложение. Может занять продолжительное время. + Идёт отправка местоположения + Осталось %1$s + Обновлено %1$s назад + Функция \"Поделиться трансляцией местоположения\" + ${app_name} Трансляция местоположения + Транслировать до %1$s + Трансляция завершена + Трансляция местоположения включена + Текущим местоположением + Загрузка трансляции местоположения… + Поделиться трансляцией местоположения на + Трансляцией местоположения + Поделился(лась) трансляцией местоположения + Трансляцией местоположения + Некоторые результаты могут быть скрыты, поскольку они являются приватными и для их просмотра необходимо приглашение. + мин + ч + ${app_name} нуждается в очистке кэша для обновления по следующей причине: +\n%s +\n +\nОбратите внимание, что это действие приведёт к перезапуску приложения и может занять некоторое время. + Временная реализация: местоположения сохраняются в истории комнат + Остановить + 8 часов + 1 час + 15 минут + Поделиться этим местоположением + Поделиться этим местоположением + Увеличить масштаб до текущего местоположения + Текущим местоположением + Закрепить выбранное место на карте + Отображать последнюю информацию о профиле (аватар и отображаемое имя) для всех сообщений. + Последняя информация о пользователе + Не найдено + Занят + Домашний сервер не принимает псевдонимы, состоящие только из цифр. + Пропустить этот шаг + Сохранить и продолжить + Ваши предпочтения были сохранены + Выглядит хорошо! + ${app_name} также отлично подходит для работы. Ему доверяют самые надёжные организации в мире. + Резервная копия имеет действительную подпись для данного пользователя. + Воспроизводить анимированные изображения, как только они попадают в поле зрения + Анимированные изображения + сек + Обсуждения — это незавершенная работа с новыми интересными функциями, такими как улучшенные уведомления. Мы будем рады услышать ваши отзывы! + Ваш домашний сервер в настоящее время не поддерживает обсуждения, поэтому эта функция может быть ненадёжной. Некоторые сообщения из обсуждений могут быть недоступны. %sВы хотите включить обсуждения в любом случае\? + Мы приближаемся к выпуску публичной бета-версии Обсуждений. +\n +\nГотовясь к этому, мы должны внести некоторые изменения: обсуждения, созданные до этого момента, будут отображаться как обычные ответы. +\n +\nЭто будет однократный переход, поскольку Обсуждения теперь являются частью спецификации Matrix. + Невозможно воспроизвести %1$s + Пауза %1$s + Играть %1$s + (%1$s) + %1$s (%2$s) + %1$d минут %2$d секунд + %1$s, %2$s, %3$s + Не выходить + Выйти из всех + Присутствие + ${app_name} Демонстрация экрана + Идёт демонстрация экрана + Посмотреть трансляцию местоположения + Текущий шлюз: %s + Шлюз + Сервисы Google + Не удалось включить вход по биометрии. + Вход по биометрии был отключён, так как недавно был добавлен новый метод входа по биометрии. Вы можете снова включить его в настройках. + Метка профиля: + Разрешить отправку местоположения + Трансляция местоположения + Обратите внимание: это временная реализация функции. Это означает, что вы не сможете удалить свою историю местоположений, а опытные пользователи смогут просмотреть вашу историю местоположений даже после того, как вы перестанете делиться своим местоположением в этой комнате. + Сейчас используется %s. + Способ + + Найден %d способ. + Найдено %d способа. + Найдено %d способов. + Найдено %d способов. + + Другого способа, кроме фоновой синхронизации, не найдено. + Другого способа, кроме Google Play Service, не найдено. + Доступные способы + Способ оповещения + Выберите способ получения уведомлений + Сбросить способ оповещения + Фоновая синхронизация + Далее + Не удалось зарегистрировать токен конечной точки на домашнем сервере: +\n%1$s + Конечная точка успешно зарегистрирована на домашнем сервере. + Регистрация конечной точки + Не удалось найти конечную точку. + Текущая конечная точка: %s + Конечная точка + Вещи в этом пространстве + Поделиться местоположением + MSC3061: Предоставление ключей от прошлых сообщений + Вперёд + Убедитесь, что он состоит из 8 или более символов. + Выбрать вручную + Выбор размера шрифта + + Удалено %d сообщение + Удалено %d сообщения + Удалено %d сообщений + Удалено %d сообщений + + Выйти из учётной записи на всех устройствах + Трансляция местоположения + Сообщения в этой переписке будут защищены сквозным шифрованием. + Обновление данных… + Повторно отправить письмо + Следуйте инструкциям, отправленным на %s + Подтвердите свою электронную почту + Проверьте электронную почту. + Пожалуйста, ознакомьтесь с условиями и правилами %s + Хотите разместить собственный сервер\? + Какой адрес у вашего сервера\? + Какой адрес у вашего сервера\? Это что-то вроде дома для всех ваших данных + Выберите свой сервер + Установить автоматически + Почта не подтверждена, проверьте почтовый ящик + Изменить + Где хранятся ваши переписки + Где будут храниться ваши переписки + Должно быть 8 или более символов + Не удалось заверить этот сеанс + Невозможно открыть эту ссылку: сообщества были заменены пространствами + Псевдоним / Почта / Телефон + Следуйте инструкциям, отправленным на %s + Забыли пароль + Не получили письмо\? + Вы человек\? + Повторно отправить код + Код отправлен на %s + Подтвердите номер телефона + Сбросить пароль + Новый пароль + Код подтверждения + Номер телефона + Введите номер телефона + Электронная почта + Введите адрес электронной почты + Правила сервера + URL-адрес сервера + С возвращением! + Или + Создайте учётную запись + %1$s и %2$s + Открыть настройки + Не удалось загрузить карту +\nВозможно, этот домашний сервер не настроен для отображения карт. + Все беседы + Для лучшей защиты заверьте свои сеансы и выйдите из тех, которые более не признаёте или не используете. + Другие сеансы + Сеансы + Создать беседу или комнату + ЛС + Настройки вида + Фильтры + Недавние + Избранные + Непрочитанные + Все + А - Я + Активности + Сортировать по + Обзор комнат + Отправить ЛС + Создать комнату + Посмотреть все (%1$d) + Повысьте безопасность учётной записи, следуя этим рекомендациям. + Заверенный · Последняя активность %1$s + Незаверенный сеанс + Заверенный сеанс + Неизвестный тип устройства + Компьютер + Мобильный + Незаверенный · Последняя активность %1$s + Рекомендации по безопасности + Незаверенные сеансы + Неактивные сеансы + Добро пожаловать в ${app_name}, +\n%s. + Оставить отзыв + Название сеанса + Неактивные + IP-адрес + Последняя активность + Сведения о сеансе + Для лучшей безопасности выйдите из всех сеансов, которые более не признаёте или не используете. + Заверенные + Все сеансы + Последняя активность %1$s + Устройство + Сеанс + Текущий сеанс + Заверить сеанс + Подробности + Этот сеанс готов к защищенной переписке. + Текущий сеанс готов к защищенной переписке. + Веб-браузер + Пространства — это новый способ организации комнат и людей. Создайте пространство, чтобы начать. + Новый вид + Нечего отображать. + Здесь будут отображаться непрочитанные сообщения, когда таковые будут. + Как в системе + Смена пространства + Упрощённый Element с дополнительными вкладками + Добро пожаловать в новый вид! + %s +\nвыглядит слегка пустовато. + Попробовать + Информация о приложении, устройстве и активности. + Заверьте текущий сеанс для усиления защиты переписки. + Пока нет пространств. + Заверьте свои сеансы для усиления защиты переписки или выйдите из тех, которые более не признаёте или не используете. + Заверьте или выйдите из незаверенных сеансов. + Заверьте или выйдите из этого сеанса для лучшей безопасности и надёжности. + Ничего нового. + Заверенных сеансов не обнаружено. + Незаверенных сеансов не обнаружено. + Неактивных сеансов не обнаружено. + Очистить фильтр + Не готовы к защищенной переписке + Готовы к защищенной переписке + + Неактивны %1$d день или дольше + Неактивны %1$d дня или дольше + Неактивны %1$d дней или дольше + Неактивны %1$d дней или дольше + + Незаверенные + Фильтр + Незаверенный · Текущий сеанс + Переименовать сеанс + Название сеанса + Заверенные + Выйти из этого сеанса + Неактивные + Незаверенные + Пожалуйста, имейте в виду, что названия сеансов также видны людям, с которыми вы общаетесь. + Заверенные сеансы + Незаверенные сеансы + Неактивные сеансы + Добавляет (╯°□°)╯︵ ┻━┻ в начало сообщения + Приватная клавиатура + Запрещает клавиатуре обновлять персональные данные, такие как история набора текста и словарь, на основе того, что вы набрали при общении. Обратите внимание, что некоторые клавиатуры могут не соблюдать эту настройку. + Понятно + 🔒 В настройках безопасности вы включили шифрование только для заверенных сессий во всех комнатах. + Не отправлять зашифрованные сообщения незаверенным сеансам в этой комнате. + Неактивные сеансы — это сеансы, которыми вы не пользовались определённое время, но они продолжают получать ключи шифрования. +\n +\nУдаление неактивных сеансов повышает безопасность и производительность, а также облегчает выявление подозрительных новых сеансов. + Переименование сеансов + Другие пользователи в личных сообщениях и комнатах, к которым вы присоединились, могут просматривать весь перечень ваших сеансов. +\n +\nЭто даёт им уверенность в том, что они действительно общаются с вами, но это также означает, что они могут видеть название сеанса, которое вы ввели здесь. + Наглядный текстовый редактор + ID сеанса: + Уведомления + Получать push-уведомления в этой сессии. + URL-адрес + Приложение + Название + Версия + Веб-браузер + Модель + Операционная система + Новый менеджер сеансов + + Рассмотрите возможность выхода из старых сеансов (%1$d день или дольше), которые вы более не используете. + Рассмотрите возможность выхода из старых сеансов (%1$d дня или дольше), которые вы более не используете. + Рассмотрите возможность выхода из старых сеансов (%1$d дней или дольше), которые вы более не используете. + Рассмотрите возможность выхода из старых сеансов (%1$d дней или дольше), которые вы более не используете. + + Результаты будут видны после завершения опроса + Доступ к пространствам (внизу справа) быстрее и проще, чем когда-либо прежде. + Доступ к пространствам + + Рассмотрите возможность выхода из старых сеансов (%1$d день или дольше), которые вы более не используете. + Рассмотрите возможность выхода из старых сеансов (%1$d дня или дольше), которые вы более не используете. + Рассмотрите возможность выхода из старых сеансов (%1$d дней или дольше), которые вы более не используете. + Рассмотрите возможность выхода из старых сеансов (%1$d дней или дольше), которые вы более не используете. + + Голосовая трансляция + Включить голосовые трансляции + Записывает название клиента, версию и URL-адрес для более лёгкого распознавания сеансов в менеджере сеансов. + Записывать информацию о клиенте + Галерея + Наклейки + Вложения + Голосовая трансляция + Опрос + Местоположение + Камера + Контакт + ${app_name} нуждается в разрешении для отображения оповещений. +\nПожалуйста, дайте разрешение. + + %1$s и %2$d другой + %1$s и %2$d другие + %1$s и %2$d других + %1$s и %2$d других + + ${app_name} нуждается в резрешении для отображения оповещений. Оповещения могут показывать ваши сообщения, приглашения и тому подобное. +\n +\nПожалуйста разрешите доступ при следующем всплывающем сообщении, чтобы иметь возможность видеть оповещения. + Здесь будут появляться новые запросы и приглашения. + Приглашения + Попробуйте расширенный текстовый редактор (режим набора обычного текста скоро появится) + Создавать личные сообщения только при отправке первого сообщения + Включить отложенные личные сообщения + Отменить выбор всего + Выбрать всё + Свернуть дочерние элементы %s + Развернуть дочерние элементы %s + + Выбрано %1$d + Выбраны %1$d + Выбраны %1$d + Выбраны %1$d + + Войти в полноэкранный режим + Применить форматирование подчёркиванием + Применить форматирование перечёркиванием + Применить форматирование курсивом + Применить форматирование жирным + Пожалуйста удостоверьтесь в том, что вы знаете откуда этот код. При соединении устройств, вы даёте кому-то полный доступ к вашей учётной записи. + Подтвердить + Попробовать снова + Не сходится\? + Вход + Соединение с устройством + Сканировать QR-код + Входите с мобильного устройства\? + Показать QR-код на этом устройстве + Выберите «Сканировать QR-код» + Начните с экрана входа + Выберите «Войти по QR-коду» + Начните с экрана входа + Выберите «Показать QR-код» + Зайдите в Настройки -> Безопасность и Приватность + Откройте приложение с другого устройства + Домашний сервер не поддерживает вход по QR-коду. + Вход был отменён с другого устройства. + Этот QR-код не работает. + Другое устройство должно войти в учётную запись. + Другое устройство уже выполнило вход. + Во время установки безопасной переписки возникла проблема с безопасностью. Одно из следующего является скомпроментированным: Ваш домашний сервер; Ваше интернет-соединение; Ваше устройство; + Запрос не выполнен. + Запрос был отклонён на другом устройстве. + Соединение не было выполнено за нужное время. + Соединение с этим устройством не поддерживается. + Неудачное соединение + Проверьте устройство, с которого вы вошли в учётную запись. На его экране должен появиться код снизу. Подтвердите, что код снизу такой же, как и на том устройстве: + Безопасное соединение установлено + Сканируйте QR-код снизу при помощи устройства, с которого вы вышли с учётной записи. + Используйте устройство, с которого вы вошли в учётную запись, чтобы сканировать QR-код снизу: + Войти по QR-коду + Используйте камеру на этом устройстве, чтобы сканировать QR-код, отображённый на вашем другом устройстве: + Сканировать QR-код + 3 + 2 + 1 + Нажмите слева сверху, чтобы увидеть опцию отзыва. + Чтобы упростить ${app_name}, вкладки теперь опциональные. Управляйте ими при помощи меню справа сверху. + Универсальное безопасное приложение для переписок с командами, друзьями и организациями. Создайте переписку или присоеденитесь к уже существующей, чтобы начать. + Пространства — новый способ групировать комнаты и людей. Добавьте существующую комнату или создайте новую, используя кнопку слева снизу. + Возможность записывать и отправлять голосовые трансляции в ленту комнаты. + Получите лучший надзор и контроль над всеми вашими сессиями. + Заверенные сеансы есть везде, где вы используете эту учётную запись после ввода своей мнемонической фразы или подтверждения своей личности с помощью другого заверенного сеанса. +\n +\nЭто означает, что у вас есть все ключи, необходимые для разблокировки ваших зашифрованных сообщений и подтверждения другим пользователям, что вы доверяете этому сеансу. + Незаверенные сеансы — это сеансы, которые вошли в систему с вашими учётными данными, но не были перекрёстно заверены. +\n +\nВы должны быть особенно уверены, что признаёте эти сеансы, поскольку они могут представлять собой несанкционированное использование вашей учётной записи. + Вы можете использовать это устройство для входа с телефона или веб-устройства при помощи QR-кода. Для этого есть два способа: + Войти по QR-коду + Собственные названия сессий помогут вам легче распознать свои девайсы. + + Выйти из %1$d сеанса + Выйти из %1$d сеансов + Выйти из %1$d сеансов + Выйти из %1$d сеансов + + Выйти + Выбрать сеансы + Фильтр + + Неактивен %1$d+ день (%2$s) + Неактивен %1$d+ дней (%2$s) + Неактивен %1$d+ дня (%2$s) + Неактивен %1$d+ дня (%2$s) + + Подтвердите текущую сессию, чтобы посмотреть её состояние подтверждения. + Неизвестное состояние проверки + Автоматически принимать виджеты Element Call и давать доступ к микрофону/камере + Включить ярлыки разрешений Element Call + Форматирование текста + Начать новую голосовую трансляцию + Вам необходимо иметь нужные разрешения, чтобы делиться местоположением в реальном времени в этой комнате. + У вас нет разрешения делиться местоположением в реальном времени + При приглашении кого-то в зашифрованную комнату, которая делится историей, зашифрованная история будет видимой. + Вы уже записываете голосовую трансляцию. Пожалуйста закончите текущую голосовую трансляцию, чтобы начать новую. + Кто-то другой уже записывает голосовую трансляцию. Подождите пока их голосовая трансляция закончится, чтобы начать новую. + У вас нет необходимых разрешений для начала голосовой трансляции в этой комнате. Свяжитесь с администратором комнаты, чтобы получить разрешения. + Не получилось начать новую голосовую трансляцию + Перемотать вперёд на 30 секунд + Перемотать назад на 30 секунд + Буферизация… + Приостановить голосовую трансляцию + Проиграть или продолжить голосовую трансляцию + Остановить запись голосовой трансляции + Приостановить запись голосовой трансляции + Продолжить запись голосовой трансляции + Прямая трансляция + Подлинность этого зашифрованного сообщения не может быть гарантирована на этом устройстве. + Сканировать QR-код + Отправьте ваше первое сообщение, чтобы пригласить %s в переписку + Этот QR-код выглядит неправильно. Пожалуйста, попробуйте подтвердить другим способом. + Вы не сможете получить доступ к истории зашифрованных сообщений. Сбросьте вашу защищённую резевную копию и ключи подтверждения, чтобы начать заново. + Сброс пароля + Выберите новый пароль + %s пришлёт вам ссылку для подтверждения + %s нуждается в подтверждении вашей учётной записи + %s нуждается в подтверждении вашей учётной записи + Связаться + Element Matrix Services (EMS) — надёжная хостинговая служба для быстрой и безопасной связи в режиме реального времени. Узнайте больше на <a href=\"${ftue_ems_url}\">element.io/ems</a> + Открыть список пространств + Включено: + Что-то пошло не так. Пожалуйста, проверьте соединение и попробуйте ещё раз. + Открыть экран инструментов для разработчика + Простите, эта комната не была найдена. +\nПожалуйста, попробуйте снова позже.%s + ⚠ В этой комнате есть неподтверждённые устройства, они не смогут расшифровывать сообщения, отправленные вами. + Дать разрешение + Другие пользователи могут найти вас по %s + Осталось %1$s + создал опрос. + отправил наклейку. + отправил видео. + отправил изображение. + отправил голосовое сообщение. + отправил аудиофайл. + отправил файл. + В ответ на + Скрыть IP-адрес + Показать IP-адрес + Цитируя + В ответ на %s + Редактирование + Показывать последние беседы в системном меню распостранения + Включить прямое распостранение + Выйти из всех других сеансов + У вас есть незаверенные сеансы + Ночная сборка + Этот сеанс не поддерживает шифрование, поэтому его невозможно заверить. +\n +\nПри использовании этого сеанса вы не сможете участвовать в комнатах, где включено шифрование. +\n +\nДля лучшей защиты и приватности рекомендуется использовать клиенты Matrix, поддерживающие шифрование. + Этот сеанс не поддерживает шифрование и поэтому не может быть заверен. + %1$s завершил(а) голосовую трансляцию. + Вы завершили голосовую трансляцию. + + Нет активных опросов за %1$d день. +\nЗагрузите больше чтобы показать опросы за прошедшие дни. + Нет активных опросов за %1$d дней. +\nЗагрузите больше чтобы показать опросы за прошедшие дни. + Нет активных опросов за %1$d дней. +\nЗагрузите больше чтобы показать опросы за прошедшие дни. + Нет активных опросов за %1$d дней. +\nЗагрузите больше чтобы показать опросы за прошедшие дни. + + + Нет завершённых опросов за день %1$d. +\nЗагрузите больше чтобы показать опросы за предыдущие дни. + Нет завершённых опросов за %1$d дней +\nЗагрузите больше чтобы показать опросы за предыдущие дни. + Нет завершённых опросов за %1$d дней +\nЗагрузите больше чтобы показать опросы за предыдущие дни. + Нет завершённых опросов за %1$d дней +\nЗагрузите больше чтобы показать опросы за предыдущие дни. + + Токен доступа даёт полный доступ к аккаунту. Не делитесь им ни с кем. + Токен доступа + Завершённый опрос + Опрос + завершённый опрос. + Изменить ссылку + Создать ссылку + Ссылка + Текст + Список + Пронумерованный список + Ссылка + Ошибка считывания опросов. + Загрузить больше опросов + Показываем опросы + Нет завершённых опросов + Завершённые опросы + Нет активных опросов + Активные опросы + Из-за ошибок расшифровки, некоторые голоса могут быть не засчитаны + Опрос завершён. + Вы уверены что хотите завершить голосовую трансляцию\? Это завершит трансляцию и полная запись будет доступна в чате. + Завершить голосовую трансляцию\? + Ошибка подключения - Запись приостановлена + Невозможно прослушать голосовую трансляцию. + Голосовая трансляция + Вы не можете записать голосовое сообщение, потому-что Вы записываете голосовую трансляцию. Завершите голосовую трансляцию, чтобы записать голосовое сообщение + Не удалось записать голосовое сообщение + Убедиться что Ваш аккаунт в безопасности + Получить последнюю сборку (у вас могут быть проблемы со входом) + Опросы + Голосовая трансляция начата + Ваш домашний сервер не поддерживает список обсуждений. + Остановить + Всё равно выйти + Подтвердить сброс + Аватар пространства %1$s + Аватар комнаты %1$s + Сообщение от %s + Сообщение в %s + Сообщение в комнате + Комната/Пространство + Учётная запись + Аватар профиля пользователя %1$s + Продолжайте, только если вы уверены, что ваш ключ утерян, а доступ к другим активным устройствам отсустствует. + Пока пользователь не верифицировал эту сессию, отправленные и полученные сообщения отмечаются предупреждениями. + Запрос на верификацию отправлен. Откройте приложение на одном из активных устройств и подтвердите эту сессию. + Можно пригласить один email за раз + Приложение обновлено + Верификация секретной фразы или ключа… + Подтвердите ваш сеанс для доступа к зашифрованным сообщениям и верификации для других пользователей. + Не удается подключиться к серверу. Если вы подтвердите выход сейчас, это устройство не будет удалено из списка активных сеансов. Удалить этот сеанс можно будет с другого устройства. + Ожидание подключения пользователей к ${app_name} + При изменении настроек уведомлений произошла ошибка. Попробуйте ещё раз. + Когда приглашенные пользователи присоединятся к ${app_name}, вы сможете писать им с использованием сквозного шифрования + Сброс ваших ключей верификации не может быть отменен. После сброса, вы не будете иметь доступа к старым зашифрованным сообщениям, а все ваши контакты, верифицировавшие вас ранее, увидят предупреждение о повторной верификации. + Зашифровано прерванным сеансом + В последнем обновлении улучшили защищённую переписку. Пожалуйста, перезаверьте свой сеанс. + Не удается расшифровать голосовое сообщение. + Обзор опроса во времени + Сообщение + Сверить с другим сеансом + Возобновить + %1$s изменил(а) имя на %2$s + Запрос на верификацию не найден. Возможно, он был отменен или обработан другим сеансом. + Цитата + Версия шифрования + Блок кода + Подпункт + Пункт + \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-sk/strings.xml b/library/ui-strings/src/main/res/values-sk/strings.xml index 6f95e6428b..c60927d578 100644 --- a/library/ui-strings/src/main/res/values-sk/strings.xml +++ b/library/ui-strings/src/main/res/values-sk/strings.xml @@ -3009,4 +3009,21 @@ Zásady prijateľného používania Pokračovať v obnovení Krypto verzia + %1$s zmenil/a svoje zobrazované meno na %2$s + Profilový obrázok používateľa %1$s + Obrázok miestnosti %1$s + Obrázok priestoru %1$s + Najnovšou aktualizáciou sa zlepšilo bezpečné zasielanie správ. Overte prosím znova svoje zariadenie. + Pokiaľ tento používateľ tejto relácii nedôveruje, správy odoslané do nej a z nej sú označené varovaním. + Aplikácia bola aktualizovaná + Aj tak sa odhlásiť + Nie je možné sa spojiť s domovským serverom. Ak sa aj tak odhlásite, toto zariadenie nebude vymazané zo zoznamu zariadení, môžete ho odstrániť pomocou iného klienta. + Nie je možné nájsť profily pre nižšie uvedené Matrix ID. Chceli by ste napriek tomu začať konverzáciu\? +\n +\n%s + Spustiť konverzáciu aj tak + Nie je možné nájsť profily pre nižšie uvedené Matrix ID. Chcete ich aj tak pozvať\? +\n +\n%s + Napriek tomu pozvať \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-sl/strings.xml b/library/ui-strings/src/main/res/values-sl/strings.xml new file mode 100644 index 0000000000..3e392ca5a0 --- /dev/null +++ b/library/ui-strings/src/main/res/values-sl/strings.xml @@ -0,0 +1,78 @@ + + + Ime + Prijava hrošča + Pošlji ekransko sliko + Pošlji + Pridružil si se v sobi + %1$s te je povabil + Odgovorili ste na klic. + %s je odgovoril na klic. + Spremenil si ime sobe v: %1$s + %1$s je spremenil ime sobe v: %2$s + Zavrnil si povabilo + %1$s je zavrnil povabilo + Zapustil si sobo + %1$s je zapustil sobo + Zapustil si sobo + %1$s je zapustil sobo + %1$s se je pridružil + %1$s se je pridružil v sobi + Ustvaril si sobo + %1$s je ustvaril sobo + Ni omrežja. Preveri internetno povezavo. + Ustvari novo sobo + Ustvaril si razpravo + %1$s je povabil %2$s + Pridružil si se + %1$s je izključil %2$s + Preklical si povabilo %1$s + %1$s je spremenil svojega avatarja + %1$s je spremenil svoje prikazno ime v %2$s + Svoje prikazno ime si spremenil v %1$s + %1$s je spremenil svoje prikazno ime iz %2$s v %3$s + %1$s je odstranil svoje prikazno ime (bilo je %2$s) + Tvoje povabilo + Odstranil si %1$s + %1$s je preklical povabilo %2$s + %1$s je spremenil temo v: %2$s + %1$s je spremenil avatarja sobe + Spremenil si avatarja sobe + Začel si video klic. + %s je začel video klic. + Začeli ste video klic. + %s je končal klic. + Končali ste klic. + %1$s je %2$s omogočil ogled prihodnje zgodovine sobe + Omogočili ste ogled prihodnje zgodovine sobe %1$s + + %1$d izbran + %1$d izbrana + %1$d izbranih + %1$d izbranih + + %1$s je ustvaril razpravo + Povabil si %1$s + %1$s je odstranil %2$s + %1$s je izključil %2$s + Izključil si %1$s + Spremenil si svojega avatarja + %1$s je spremenil svoje prikazno ime v %2$s + Svoje prikazno ime si spremenil iz %1$s v %2$s + Odstranil si svoje prikazno ime (bilo je %1$s) + Temo si spremenil v: %1$s + %s je začel video klic. + %1$s je omogočil %2$s ogled prihodnjih sporočil + %1$s ste omogočili ogled prihodnjih sporočil + vsi člani sobe, od trenutka povabila. + Povabilo uporabnika %s + %s je poslal(a) podatke za začetek klica. + Poslali ste podatke za začetek klica. + Tu ste izvedli nadgradnjo. + vsi člani te sobe od trenutka ko so se pridružili. + vsi člani sobe. + kdorkoli. + %s je nadgradil to sobo. + Vi ste nadgradili to sobo. + %s je tu izvedel(a) nadgradnjo. + \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-sq/strings.xml b/library/ui-strings/src/main/res/values-sq/strings.xml index 39a67b3b72..f79d418453 100644 --- a/library/ui-strings/src/main/res/values-sq/strings.xml +++ b/library/ui-strings/src/main/res/values-sq/strings.xml @@ -2935,4 +2935,14 @@ Rregulla të Pranueshme Përdorimi Vazhdo me rikthimin te parazgjedhjet Version kriptografie + %1$s ndërroi emrin e vet në ekran në %2$s + Foto profili i përdoruesit %1$s + Avatar i dhomës %1$s + Avatar i hapësirës %1$s + Shkëmbimi i siguruar i mesazheve është përmirësuar me përditësimin më të ri. Ju lutemi, riverifikoni pajisjen tuaj. + Rimerre + Deri kur ky përdorues të besojë këtë sesion, mesazhet dërguar për të dhe nga ai etiketohem me sinjalizime. + Aplikacioni u përditësua + Dil, sido qoftë + S’kapet dot shërbyesi Home. Nëse keni dalë, sido qoftë, kjo pajisje s’do të fshihet te lista e pajisjeve tuaja, mund të doni ta hiqni duke përdorur klient tjetër. \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-sv/strings.xml b/library/ui-strings/src/main/res/values-sv/strings.xml index 744c4c4e0f..3ec7b60778 100644 --- a/library/ui-strings/src/main/res/values-sv/strings.xml +++ b/library/ui-strings/src/main/res/values-sv/strings.xml @@ -2949,4 +2949,13 @@ Kryptoversion Ett fel uppstod när du uppdaterade dina aviseringsinställningar. Var god försök igen. Fortsätt till återställning + Profilbild för användaren %1$s + Avatar för rummet %1$s + Avatar för utrymmet %1$s + %1$s bytte sitt visningsnamn till %2$s + Säker meddelandehantering har förbättrats med den senaste uppdateringen. Vänligen verifiera din enhet igen. + Tills den här användaren litar på den här sessionen märks meddelanden som skickas till och från den med varningar. + App uppdaterad + Kan inte nå hemservern. Om du ändå loggar ut kommer den här enheten inte att raderas från din enhetslista, du kanske vill ta bort den med en annan klient. + Logga ut ändå \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-sw/strings.xml b/library/ui-strings/src/main/res/values-sw/strings.xml new file mode 100644 index 0000000000..dc03bffa60 --- /dev/null +++ b/library/ui-strings/src/main/res/values-sw/strings.xml @@ -0,0 +1,44 @@ + + + umeondoa %1$s + %1$s kuondolewa %2$s + Ulikataa mwaliko + %1$s alikataa mwaliko + Ulijiunga + %1$s alijiunga + %1$s Amekualika + + %1$d Iliyochaguliwa + %1$d Ziliyochaguliwa + + %1$s Andaa chumba + Umeandaa chumba + %1$s anzisha mjadala + Ulianzisha mjadala + %1$s Walioalikwa %2$s + %1$s jiunge na mjadala + %1$s Acha mjadala + Umetoka kwenye mjadala + %1$s Acha mjadala + Umeacha mjadala + %1$s hujazuiliwa %2$s + Hujazuiliwa %1$s + %1$s huruhusiwi %2$s + Huruhusiwi %1$s + Sitisha %1$s\'s mwaliko + %s\'s Mwaliko + Umejiunga na mjadala + %1$s sitisha %2$s\'s mmwaliko + Mwaliko wako + Umealika %1$s + %1$s wamebadilisha avatar + Umebadilisha avatar yako + Unaweka jina lako la kuonyesha %1$s + ulibadilisha jina lako la kuonyesha kutoka %1$s kwenda %2$s + Umeondoa jina lako la kuonyesha(lilikuwa %1$s) + %1$s alibadilisha mada kuwa: %2$s + %1$s weka jina lao la kuonyesha %2$s + %1$s badilisha majina yao kuonyesha yalitoka %2$s kwenda %3$s + %1$s badilisha majina yao kwenda %2$s + %1$s wameondoa ma jina yao yaliyonyeshwa (yalikuwa %2$s) + \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-uk/strings.xml b/library/ui-strings/src/main/res/values-uk/strings.xml index 0ba658abd7..a621db40b6 100644 --- a/library/ui-strings/src/main/res/values-uk/strings.xml +++ b/library/ui-strings/src/main/res/values-uk/strings.xml @@ -3069,4 +3069,13 @@ Політика прийнятного користування Перейти до скидання Криптоверсія + %1$s змінює своє ім\'я на %2$s + Зображення профілю користувача %1$s + Аватар кімнати %1$s + Аватар простору %1$s + В останньому оновленні було вдосконалено захищений обмін повідомленнями. Перевірте свій пристрій ще раз. + Поки користувач не довіряє цьому сеансу, повідомлення, надіслані до нього та від нього, позначаються попередженнями. + Застосунок оновлено + Усе одно вийти + Не вдалося зв\'язатися з домашнім сервером. Якщо ви все одно вийдете з системи, цей пристрій не буде видалено з вашого списку пристроїв, можливо, ви захочете видалити його за допомогою іншого клієнта. \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-vi/strings.xml b/library/ui-strings/src/main/res/values-vi/strings.xml index 34cbdd6afc..d7f2c07a08 100644 --- a/library/ui-strings/src/main/res/values-vi/strings.xml +++ b/library/ui-strings/src/main/res/values-vi/strings.xml @@ -1,5 +1,5 @@ - + Lắc điện thoại để báo cáo lỗi Có vẻ bạn đang lắc điện thoại một cách tức giận. Bạn có muốn mở màn hình báo cáo lỗi không\? Miêu tả vấn đề của bạn ở đây @@ -84,7 +84,7 @@ Bạn có chắc không\? Đang sao lưu khoá… Tôi không muốn các tin nhắn của tôi được mã hoá - Sao lưu Khoá Bảo mật nên được kích hoạt trên tất cả các phiên để tránh mất các tin nhắn được mã hoá. + Sao lưu bảo mật khoá nên được kích hoạt trên tất cả các phiên để tránh mất các tin nhắn được mã hoá. Đang sao lưu khoá. Nếu bạn đăng xuất bây giờ bạn sẽ không thể xem các tin nhắn được mã hoá. Bạn sẽ mất các tin nhắn được mã hoá nếu bạn đăng xuất ngay bây giờ Sử dụng Sao lưu Khóa @@ -99,7 +99,7 @@ Chủ đề tối Chủ đề sáng Quên mật khẩu\? - Đấy không giống một địa chỉ email hợp lệ + Đấy không giống một địa chỉ thư điện tử hợp lệ Tên người dùng hoặc mật khẩu không đúng Đăng nhập Xin lỗi, không có ứng dụng nào được tìm thấy có thể hoàn thành hành động này. @@ -196,7 +196,7 @@ Đã gửi Đang gửi Số điện thoại - Địa chỉ email + Địa chỉ thư điện tử Lỗi Matrix %1$s đã thay đổi cấp độ quyền lực của %2$s. Bạn đã thay đổi cấp độ quyền lực của %1$s. @@ -234,12 +234,12 @@ (ảnh đại diện cũng được thay đổi) 🎉 Tất cả máy chủ bị cấm không được tham gia! Phòng này không thể được sử dụng nữa. Không có thay đổi. - Bạn đã thay đổi ACL máy chủ cho phòng này. - %s đã thay đổi ACL máy chủ cho phòng này. + Bạn đã thay đổi danh sách máy chủ truy cập máy chủ cho phòng này. + %s đã thay đổi danh sách máy chủ truy cập máy chủ cho phòng này. • Những máy chủ khớp với %s được cho phép. • Những máy chủ khớp với %s bị cấm. - Bạn đã đặt ACL máy chủ cho phòng này. - %s đã đặt ACL máy chủ cho phòng này. + Bạn đã đặt danh sách máy chủ truy cập cho phòng này. + %s đã đặt danh sách máy chủ truy cập cho phòng này. Bạn đã nâng cấp ở đây. %s đã nâng cấp ở đây. Bạn đã nâng cấp phòng này. @@ -256,16 +256,16 @@ %1$s đã cấm %2$s Bạn đã bỏ cấm %1$s %1$s đã bỏ cấm %2$s - Bạn đã xoá tên hiển thị (nó đã là %1$s) - %1$s đã xoá tên hiển thị (nó đã là %2$s) + Bạn đã xoá tên hiển thị (từng là %1$s) + %1$s đã xoá tên hiển thị (từng là %2$s) Bạn đã đổi tên hiển thị từ %1$s thành %2$s %1$s đã đổi tên hiển thị từ %2$s thành %3$s Bạn đã đặt tên hiển thị thành %1$s %1$s đã đặt tên hiển thị thành %2$s Bạn đã thay đổi ảnh đại diện %1$s đã thay đổi ảnh đại diện - Bạn đã rút lại lời mời của %1$s - %1$s đã rút lại lời mời của %2$s + Bạn đã hủy lời mời của %1$s + %1$s đã hủy lời mời của %2$s Chủ đề của bạn Chủ đề Bạn đã kết thúc cuộc gọi. @@ -286,8 +286,8 @@ Bạn đã thay đổi chủ đề thành: %1$s Xoá các tin nhắn chưa được gửi Bạn có chắc bạn muốn xoá tất cả tin nhắn chưa được gửi trong phòng này không\? - Bạn đã kick %1$s - %1$s đã kick %2$s + Bạn đã loại bỏ %1$s + %1$s đã loại bỏ %2$s Bạn đã từ chối lời mời %1$s đã từ chối lời mời Bạn đã rời phòng @@ -329,7 +329,7 @@ %1$s đã rời phòng. Lý do: %2$s Máy chủ nhà này muốn chắc chắn bạn không phải rô bốt Số điện thoại này đã được định nghĩa rồi. - Địa chỉ email này đã được định nghĩa rồi. + Địa chỉ thư điện tử này đã được sử dụng rồi. Đăng nhập bằng đăng nhập một lần Sử dụng làm mặc định và không hỏi lại Luôn hỏi @@ -341,8 +341,8 @@ Xoá tiện ích thất bại Thêm tiện ích thất bại Chuyển - Đã xác minh - Chưa xác minh + Đã xác thực + Chưa xác thực Nhập %1$d/%2$d mã khoá thành công. @@ -359,9 +359,9 @@ Nhập các mã khoá phòng E2E Quản lý bản sao lưu mã khoá ip không xác định - Nếu chúng không khớp, sự bảo mật của việc giao tiếp của bạn có thể bị can thiệp. - Xác nhận bằng cách so sánh những điều sau đây với Cài đặt người dùng trong phiên làm việc kia của bạn: - Xác minh + Nếu chúng không khớp, bảo mật của việc giao tiếp của bạn có thể bị can thiệp. + Xác thực bằng cách so sánh những thứ sau với Cài đặt người dùng trong phiên làm việc kia của bạn: + Xác thực URL máy chủ nhà Bạn có chắc bạn muốn rời khỏi phòng không\? Rời khỏi phòng @@ -402,14 +402,14 @@ %d thay đổi thành viên Vui lòng khởi chạy ${app_name} trên một thiết bị khác mà có thể giải mã tin nhắn để nó có thể gửi các mã khoá vào phiên làm việc này. - Yêu cầu lại các mã khoá mã hoá từ các phiên làm việc khác của bạn. + Yêu cầu lại các mã khoá mã hoá từ các phiên khác của bạn. Quá nhiều yêu cầu đã được gửi Đã không chứa JSON hợp lệ Không được uỷ quyền, thiếu thông tin xác thực hợp lệ Không thể kết nối đến máy chủ nhà tại URL này, vui lòng kiểm tra nó Vui lòng nhập URL hợp lệ Vui lòng xem xét và chấp nhận chính sách của máy chủ nhà này: - Xác minh địa chỉ email thất bại: hãy chắc chắn là bạn đã nhấn vào liên kết trong email + Xác nhận địa chỉ thư điện tử thất bại: hãy chắc chắn là bạn đã nhấn vào liên kết trong email Hiện tất cả phòng trong thư mục phòng, bao gồm cả các phòng có nội dung phản cảm. Hiện các phòng có nội dung phản cảm Danh sách phòng @@ -517,8 +517,8 @@ Lời mời vào phòng • Những máy chủ khớp với IP bây giờ sẽ bị cấm. • Những máy chủ khớp với IP bây giờ sẽ được cho phép. - • Những máy chủ khớp với IP bị cấm. - • Những máy chủ khớp với IP được cho phép. + • Những máy chủ chỉ có địa chỉ Internet (IP) bị cấm. + • Những máy chủ chỉ có địa chỉ Internet (IP) được cho phép. Hủy bỏ qua người dùng Bỏ qua Bỏ qua người dùng này sẽ xóa những tin nhắn của họ khỏi những phòng bạn chia sẻ. @@ -593,7 +593,7 @@ Hủy các giới hạn Hủy tài khoản Xem lại ngay - Chìa khóa phiên + Khóa phiên Mã phiên Tên công khai Lỗi giải mã @@ -669,7 +669,7 @@ Phòng chat của bạn được hiển thị ở đây. Bạn có thể tạo mới phòng chat hoặc tham gia các phòng cộng đồng hiện có. Chọn một máy chủ Hãy bắt đầu - Mở rộng và hiệu chỉnh trải nghiệm của bạn + Mở rộng và tùy chỉnh trải nghiệm của bạn Giữ cho hội thoải riêng tư với bảo mật đầu cuối Chat với một người hoặc chat nhóm Đây là hội thoại của bạn. Bạn sở hữu nó. @@ -754,7 +754,7 @@ Cấu hình máy chủ định danh Ngắt kết nối máy chủ định danh Máy chủ định danh - Sử dụng Bot, cầu nối, widget hoặc sticker + Sử dụng Bot, cầu nối, widget hoặc gói sticker Được khám phá bởi người khác Điều khoản Dịch vụ Xem lịch sử chỉnh sửa @@ -789,8 +789,8 @@ Nén dữ liệu mặc định Media Chọn quốc gia - Quản lý email và số điện thoại liên kết với tài khoản Matrix - Email và số điện thoại + Quản lý địa chỉ thư điện tử và số điện thoại liên kết với tài khoản Matrix + Địa chỉ thư điện tử và số điện thoại Hiện tất cả tin nhắn từ %s\? Mật khẩu của bạn vừa được cập nhật Mật khẩu này không hợp lệ @@ -800,7 +800,7 @@ Đổi mật khẩu Mật khẩu Số điện thoại này đã được sử dụng. - Địa chỉ Email này đã được sử dụng. + Địa chỉ thư điện tử này đã được sử dụng. Chọn ngôn ngữ Ngôn ngữ Giao diện người dùng @@ -878,9 +878,9 @@ Thời gian chờ giữa 2 lần đồng bộ Mã nhập vào không hợp lệ. Vui lòng kiểm tra. - Chúng tôi vừa gửi email tới %1$s. -\nClick vào đường link trong email để tiếp tục quá trình tạo tài khoản. - Hãy kiểm tra email của bạn + Chúng tôi vừa gửi thư điện tử tới %1$s. +\nNhấp vào liên kết trong thư để tiếp tục quá trình tạo tài khoản. + Hãy kiểm tra hòm thư của bạn Chấp nhận điều khoản để tiếp tục Hãy thực hiện thách thức captcha Chọn một máy chủ khác @@ -892,7 +892,7 @@ Tiếp Mật khẩu Tên đăng nhập - Username hoặc email + Tên người dùng hoặc thư điện tử Đăng ký với %1$s Số điện thoại có vẻ không hợp lệ. Hãy kiểm tra lại Số điện thoại quốc tế phải bắt đầu với dấu \'+\' @@ -908,11 +908,11 @@ Vui lòng sử dụng mẫu quốc tế. Thêm số điện thoại để tùy chọn cho phép người khác tìm bạn qua số điện thoại. Thêm số điện thoại - Tiếp - Email (tùy chọn) - Email - Thêm địa chỉ email để phục hồi tài khoản. Sau này bạn có thể tùy chọn cho phép người khác tìm mình qua email. - Thêm địa chỉ email + Tiếp tục + Địa chỉ thư điện tử (tùy chọn) + Địa chỉ thư điện tử + Thêm địa chỉ thư điện tử để có thể phục hồi tài khoản. Sau này bạn có thể tùy chọn cho phép người khác tìm mình qua thông tin này. + Thêm địa chỉ thư điện tử Mật khẩu chưa được thay đổi. \n \nBạn muốn ngừng tiến trình đổi mật khẩu\? @@ -921,20 +921,20 @@ Bạn vừa đăng xuất tất cả phiên đăng nhập và không còn nhận được thông báo đẩy. Đăng nhập lại để nhận thông báo trên thiết bị. Mật khẩu của bạn đã được đặt lại. Thành công! - Tôi đã xác minh địa chỉ email + Tôi đã xác nhận địa chỉ email Nhấp vào đường dẫn để xác nhận mật khẩu mới. Sau khi bạn nhâp vào đường dẫn, hãy nhấp vào bên dưới. - Email xác thực đã được gửi tới %1$s. + Thư xác nhận đã được gửi tới %1$s. Kiểm tra mailbox - Email này không gắn với tài khoản nào + Địa chỉ thư điện tử này không được liên kết với tài khoản nào Tiếp tục Đổi mật khẩu sẽ đặt lại tất cả khóa bảo mật trên tất cả phiên của bạn, làm cho lịch sử chat mã hóa không đọc được. Vui lòng Sao lưu Khóa hoặc xuất khẩu tất cả khóa bảo mật các phòng từ một phiên đăng nhập khác trước khi đặt lại mật khẩu. Cảnh báo! Mật khẩu mới - Email + Địa chỉ thư điện tử Tiếp - Email xác thực thông tin đã được gửi tới bạn để xác nhận đặt lại mật khẩu mới. + Email xác nhận đã được gửi tới bạn để xác nhận đặt lại mật khẩu mới. Đặt lại mật khẩu ở %1$s - Địa chỉ email này không có trong hệ thống. + Địa chỉ thư điện tử này không được liên kết với tài khoản nào. Địa chỉ Địa chỉ Dịch vụ Element Matrix Xóa lịch sử @@ -954,7 +954,7 @@ Thiết lập tùy chỉnh và nâng cao Khác Xem thêm - Giống như email, tài khoản cần có nhà riêng, dù bạn có thể nói chuyện với bất kỳ ai + Giống như tài khoản thư điện tử, tài khoản cần có nhà riêng, dù bạn có thể nói chuyện với bất kỳ ai Thiết lập tùy chỉnh. Khả dụng Thông báo không được bật cho phiên này. @@ -982,16 +982,16 @@ Thông báo mặc định Mức quan trọng của thông báo theo sự kiện Thiết lập Thông báo nâng cao - Đảm bảo rằng bạn nhấp vào đường link trong email được gửi tới bạn. + Đảm bảo rằng bạn nhấp vào đường link trong thư điện tử được gửi tới bạn. Loại bỏ %s\? Số điện thoại - Không có địa chỉ email nào trong tài khoản của bạn - Địa chỉ email + Không có địa chỉ thư điện tử nào trong tài khoản của bạn + Địa chỉ thư điện tử Hiển thị thông tin ứng dụng trong thiết lập hệ thống. Thông tin ứng dụng Thêm số điện thoại Chưa có số điện thoại trong tài khoản của bạn - Thêm địa chỉ email + Thêm địa chỉ thư điện tử Tên hiển thị Hình đại diện Thêm vào màn hình Home @@ -1027,7 +1027,7 @@ Chọn vai trò được yêu cầu để thay đổi thiết lập của phòng Quyền hạn Việc này có thể có nghĩa là ai đó đang can thiệp vào lưu lượng của bạn, hoặc điện thoại của bạn không tin cậy chứng chỉ được máy chủ trên mạng cung cấp. - Không thể xác minh danh tính của máy chủ trên mạng. + Không thể xác thực danh tính của máy chủ trên mạng. Mã kiểm tra (%s): Bỏ qua Đăng xuất @@ -1060,7 +1060,7 @@ Ai có thể tìm và tham gia không gian Truy cập không gian Ai có quyền truy cập\? - Vui lòng kiểm tra email và bấm vào liên kết trong đó. Một khi xong, bấm tiếp tục. + Vui lòng kiểm tra thư điện tử và bấm vào liên kết trong đó. Một khi xong, bấm tiếp tục. Sử dụng trình quản lý chung để quản lý bot, các cầu nối, widget và các gói nhãn dán. \nTrình quản lý chung sẽ nhận được dữ liệu hiệu chỉnh, và sẽ có thể điều chỉnh các widget, gửi lời mời vào phòng và thiết lập các mốc quyền lợi theo ý bạn. ${app_name} sẽ đồng bộ hóa dưới nền trong một khoảng thời gian nhất định (có thể điều chỉnh thời gian). @@ -1115,9 +1115,9 @@ Đang chạy… (%1$d of %2$d) Chạy thử Chuẩn đoán khắc phục sự cố - Bật thông báo qua email cho %s - Để được nhận thông báo qua email, hãy liên kết một địa chỉ mail với tài khoản Matrix của bạn - Thông báo qua email + Bật thông báo qua thư điện tử cho %s + Để được nhận thông báo qua thư điện tử, hãy liên kết một địa chỉ thư điện tử với tài khoản Matrix của bạn + Thông báo qua thư điện tử Nâng cấp không gian Thay đổi tên không gian Bật mã hóa không gian @@ -1148,10 +1148,10 @@ Các lời mời đã gửi tới %1$s và %2$d người nữa - Hiển thị %d thiết bị bạn có thể xác minh ngay bây giờ + Hiển thị %d thiết bị bạn có thể xác thực ngay bây giờ - %d phiên đang hoạt động + %d phiên hoạt động %1$d người @@ -1203,7 +1203,7 @@ Câu hỏi hoặc chủ đề thăm dò ý kiến Tạo Cuộc thăm dò ý kiến %s trong Cài đặt để nhận lời mời trực tiếp trong ${app_name}. - Liên kết email này với tài khoản của bạn + Liên kết địa chỉ thư điện tử này với tài khoản của bạn Lời mời này đến Space này đã được gửi đến %s không được liên kết với tài khoản của bạn Lời mời này đến phòng này đã được gửi đến %s không được liên kết với tài khoản của bạn Xin lưu ý nâng cấp sẽ tạo ra một phiên bản mới của căn phòng. Tất cả các tin nhắn hiện tại sẽ ở trong phòng lưu trữ này. @@ -1271,15 +1271,15 @@ Khám phá phòng Khám phá (%s) Hoàn tất cài đặt - Mời qua email, tìm liên hệ và hơn thế nữa… + Mời qua thư điện tử, tìm liên hệ và hơn thế nữa… Hoàn tất việc cài đặt khám phá. - Hiện tại bạn không sử dụng máy chủ xác thực. Để mời đồng đội và có thể khám phá bởi họ, hãy cấu hình một bên dưới. + Hiện tại bạn không sử dụng máy chủ định danh. Để mời đồng đội và có thể khám phá bởi họ, hãy cấu hình một bên dưới. Tham gia Space Tạo space Bỏ qua ngay bây giờ Gia nhập Space của tôi %1$s %2$s Mời theo tên người dùng hoặc thư - Mời qua email + Mời qua thư điện tử Chỉ có anh lúc này thôi. %s sẽ còn tốt hơn với những người khác. Mời đến %s Mời mọi người @@ -1424,19 +1424,19 @@ Quyền Đặt quyền Xác nhận - Nhập URL của máy chủ xác thực - Ngoài ra, bạn có thể nhập bất kỳ URL máy chủ xác thực nào khác + Nhập URL của máy chủ định danh + Ngoài ra, bạn có thể nhập bất kỳ URL máy chủ định danh nào khác Dùng %1$s - Homeerver của bạn (%1$s) đề xuất sử dụng %2$s cho máy chủ xác thực của bạn + Máy chủ nhà của bạn (%1$s) đề xuất sử dụng %2$s cho máy chủ định danh của bạn Sự đồng ý của người dùng chưa được cung cấp. - Không có mối liên hệ hiện tại với mã định danh này. - Sự kết hợp đã thất bại. - Đối với quyền riêng tư của bạn, ${app_name} chỉ hỗ trợ gửi email và số điện thoại của người dùng băm. - Trước tiên, vui lòng chấp nhận các điều khoản của máy chủ nhận dạng trong cài đặt. - Trước tiên, vui lòng cấu hình máy chủ nhận dạng. - Hoạt động này là không thể. Homeerver đã lỗi thời. - Máy chủ nhận dạng này đã lỗi thời. ${app_name} chỉ hỗ trợ API V2. - Ngắt kết nối khỏi máy chủ nhận dạng %s\? + Không có mối liên hệ hiện tại với định danh này. + Không thể liên kết. + Để đảm bảo quyền riêng tư cho bạn, ${app_name} chỉ hỗ trợ gửi địa chỉ thư điện tử và số điện thoại của người dùng khi đã được băm. + Trước tiên, vui lòng chấp nhận các điều khoản của máy chủ định danh trong cài đặt. + Trước tiên, vui lòng cấu hình máy chủ định danh. + Hoạt động này là không thể. Máy chủ nhà đã lỗi thời. + Máy chủ định danh này đã lỗi thời. ${app_name} chỉ hỗ trợ API V2. + Ngắt kết nối khỏi máy chủ định danh %s\? Mở các điều khoản của %s Tải các ngôn ngữ có sẵn… Các ngôn ngữ có sẵn khác @@ -1466,12 +1466,12 @@ Vui lòng chọn tên người dùng. Thất bại trong việc thiết lập Xác thực chéo Xác nhận danh tính của bạn bằng cách xác minh đăng nhập này, cấp cho nó quyền truy cập vào các tin nhắn được mã hóa. - Xác nhận danh tính của bạn bằng cách xác minh đăng nhập này từ một trong các phiên khác của bạn, cấp cho nó quyền truy cập vào các tin nhắn được mã hóa. - Xác minh tương tác bằng Emoji - Xác minh đăng nhập - Xác minh thủ công bằng Văn bản - Xác minh thông tin đăng nhập mới truy cập vào tài khoản của bạn: %1$s - Được mã hóa bởi một thiết bị chưa được xác minh + Xác thực danh tính của bạn bằng cách xác nhận đăng nhập này từ một trong các phiên khác của bạn, cấp cho nó quyền truy cập vào các tin nhắn được mã hóa. + Xác thực tương tác bằng Emoji + Xác thực đăng nhập + Xác thực thủ công bằng Văn bản + Xác thực thông tin đăng nhập mới truy cập vào tài khoản của bạn: %1$s + Được mã hóa bởi một thiết bị chưa được xác thực Không được mã hóa gửi tuyết rơi ❄️ gửi hoa giấy 🎉 @@ -1479,7 +1479,7 @@ Gửi tin nhắn đã cho với hoa giấy Bạn sẽ khởi động lại mà không có lịch sử, không có tin nhắn, thiết bị đáng tin cậy hoặc người dùng đáng tin cậy Nếu bạn đặt lại mọi thứ - Chỉ làm điều này nếu bạn không có thiết bị nào khác mà bạn có thể xác minh thiết bị này. + Chỉ làm điều này nếu bạn không có thiết bị nào khác mà bạn có thể xác thực thiết bị này. Đặt lại mọi thứ Quên hoặc mất tất cả các tùy chọn phục hồi\? Đặt lại mọi thứ Không truy nhập được dung lượng lưu trữ an toàn @@ -1514,7 +1514,7 @@ Nó không phải là một khóa phục hồi hợp lệ Sử dụng Tệp Nhập %s của bạn để tiếp tục - Xác minh bản thân và người khác để giữ an toàn cho cuộc trò chuyện của bạn + Xác thực bản thân và người khác để giữ an toàn cho cuộc trò chuyện của bạn Nâng cấp mã hóa có sẵn Tin nhắn… Tài khoản này đã bị vô hiệu hóa. @@ -1560,7 +1560,7 @@ Mã hóa được sử dụng bởi phòng này không được hỗ trợ Mã hóa không được bật Tin nhắn trong phòng này được mã hóa đầu cuối. - Tin nhắn trong phòng này được mã hóa đầu cuối. Tìm hiểu thêm và xác minh người dùng trong hồ sơ của họ. + Tin nhắn trong phòng này được mã hóa đầu cuối. Tìm hiểu thêm và xác thực người dùng trong hồ sơ của họ. Mã hóa được bật Nếu bạn hủy ngay bây giờ, bạn có thể mất tin nhắn và dữ liệu được mã hóa nếu bạn mất quyền truy cập vào thông tin đăng nhập của mình. \n @@ -1579,9 +1579,9 @@ Phiên bản máy chủ Tên máy chủ Đăng xuất khỏi phiên này - Quản lý Phiên - Hiện Tất cả Phiên - Phiên Hoạt động + Quản lý phiên + Hiện tất cả phiên + Phiên hoạt động Người quản trị máy chủ của bạn đã vô hiệu hóa mã hóa đầu cuối theo mặc định trong phòng riêng và Tin nhắn trực tiếp. Xác thực chéo không được kích hoạt Xác thực chéo được kích hoạt. @@ -1592,12 +1592,12 @@ Xác thực chéo được kích hoạt \nKhóa riêng trên thiết bị. Xác thực chéo - Phiên mới của bạn hiện đã được xác minh. Nó có quyền truy cập vào các tin nhắn được mã hóa của bạn và những người dùng khác sẽ thấy nó đáng tin cậy. + Phiên mới của bạn hiện đã được xác thực. Nó có quyền truy cập vào các tin nhắn được mã hóa của bạn và những người dùng khác sẽ thấy nó đáng tin cậy. Tin nhắn với người dùng này được mã hóa đầu cuối và không thể được đọc bởi các bên thứ ba. So sánh mã với mã được hiển thị trên màn hình của người dùng khác. So sánh biểu tượng cảm xúc độc đáo, đảm bảo chúng xuất hiện theo cùng một thứ tự. Để được an toàn, hãy làm điều này trực tiếp hoặc sử dụng một cách khác để giao tiếp. - Để an toàn, hãy xác minh %s bằng cách kiểm tra mã một lần. + Để an toàn, hãy xác thực %s bằng cách kiểm tra mã một lần. Bật mã hóa Sau khi được bật, mã hóa cho một căn phòng không thể bị vô hiệu hóa. Tin nhắn được gửi trong một căn phòng được mã hóa không thể được nhìn thấy bởi máy chủ, chỉ bởi những người tham gia của căn phòng. Cho phép mã hóa có thể ngăn nhiều bot và cầu hoạt động chính xác. Bật mã hóa\? @@ -1607,8 +1607,8 @@ Dòng thời gian Gửi emote đã cho màu cầu vồng Gửi tin nhắn đã cho có màu cầu vồng - Phiên này không thể chia sẻ xác minh này với các phiên khác của bạn. -\nViệc xác minh sẽ được lưu cục bộ và chia sẻ trong phiên bản tương lai của ứng dụng. + Phiên này không thể chia sẻ xác thực này với các phiên khác của bạn. +\nViệc xác thực sẽ được lưu cục bộ và chia sẻ trong phiên bản tương lai của ứng dụng. Hủy bỏ qua ${app_name} gặp sự cố khi hiển thị nội dung sự kiện với id \'%1$s\' ${app_name} không xử lý các sự kiện thuộc loại \'%1$s\' @@ -1643,17 +1643,17 @@ Tin nhắn ở đây không được mã hóa đầu cuối. Tin nhắn trong phòng này không được mã hóa đầu cuối. Đang chờ %s… - Đã xác minh %s - Xác minh %s - Xác minh bằng cách so sánh biểu tượng cảm xúc - Thay vào đó, xác minh bằng cách so sánh biểu tượng cảm xúc + Đã xác thực %s + Xác thực %s + Xác thực bằng cách so sánh biểu tượng cảm xúc + Thay vào đó, xác thực bằng cách so sánh biểu tượng cảm xúc Nếu bạn không trực tiếp, hãy so sánh biểu tượng cảm xúc thay thế Không thể quét Quét bằng thiết bị này Quét mã của họ Quét mã bằng thiết bị khác của bạn hoặc chuyển đổi và quét bằng thiết bị này - Quét mã bằng thiết bị của người dùng khác để xác minh lẫn nhau một cách an toàn - Xác minh phiên này + Quét mã bằng thiết bị của người dùng khác để xác thực lẫn nhau một cách an toàn + Xác thực phiên này Yêu cầu xác minh Xác minh đã gửi Bạn đã chấp nhận @@ -1672,15 +1672,15 @@ Video. Một trong những điều sau đây có thể bị xâm phạm: \n -\n - Homeserver của bạn -\n - Homeserver mà bạn đang xác minh được kết nối với +\n - Máy chủ nhà của bạn +\n - Máy chủ nhà mà người bạn đang xác thực được kết nối với \n - Kết nối internet của bạn hoặc của người dùng khác \n - Thiết bị của bạn hoặc thiết bị của người dùng khác Không bảo mật Chúng không phù hợp Chúng phù hợp Đăng nhập không tin cậy - Tên miền email của bạn không được phép đăng ký trên máy chủ này + Tên miền địa chỉ thư điện tử của bạn không được phép đăng ký trên máy chủ này Tạo Space… Tạo phòng… Một số ký tự không được phép @@ -1749,7 +1749,7 @@ Đăng nhập bằng Matrix ID Homeerver này đang chạy một phiên bản cũ. Yêu cầu người quản trị homeerver của bạn nâng cấp. Bạn có thể tiếp tục, nhưng một số tính năng có thể không hoạt động chính xác. Homeerver lỗi thời - Không giống như một địa chỉ email hợp lệ + Không giống một địa chỉ thư điện tử hợp lệ Ứng dụng không thể tạo tài khoản trên homeerver này. \n \nBạn có muốn đăng ký bằng máy khách web không\? @@ -1769,8 +1769,8 @@ Vui lòng thử lại một khi bạn đã chấp nhận các điều khoản và điều kiện của homeserver của bạn. Nhật ký verbose sẽ giúp các nhà phát triển bằng cách cung cấp thêm nhật ký khi bạn lắc mạnh thiết bị. Ngay cả khi được bật, ứng dụng không ghi lại nội dung tin nhắn hoặc bất kỳ dữ liệu riêng tư nào khác. Bật nhật ký verbose. - Đồng ý với điều khoản dịch vụ của máy chủ xác thực (%s) để cho phép bản thân có thể khám phá bằng địa chỉ email hoặc số điện thoại. - Bạn hiện đang chia sẻ địa chỉ email hoặc số điện thoại trên máy chủ xác thực %1$s. Bạn sẽ cần kết nối lại với %2$s để ngừng chia sẻ chúng. + Đồng ý với điều khoản dịch vụ của máy chủ định danh (%s) để cho phép bản thân có thể khám phá bằng địa chỉ email hoặc số điện thoại. + Bạn hiện đang chia sẻ địa chỉ thư điện tử hoặc số điện thoại trên máy chủ định danh %1$s. Bạn sẽ cần kết nối lại với %2$s để ngừng chia sẻ chúng. Mã xác minh không chính xác. Có lỗi tra cứu số điện thoại Bàn phím số @@ -1790,26 +1790,26 @@ %1$s đã từ chối cuộc gọi này Bạn đã từ chối cuộc gọi này - Thư văn bản đã được gửi đến %s. Vui lòng nhập mã xác minh mà nó chứa. - Máy chủ xác thực bạn đã chọn không có bất kỳ điều khoản dịch vụ nào. Chỉ tiếp tục nếu bạn tin tưởng chủ sở hữu dịch vụ - Máy chủ xác thực không có điều khoản dịch vụ - Vui lòng nhập url máy chủ xác thực - Không thể kết nối với máy chủ xác thực - Nhập URL máy chủ xác thực + Tin nhắn văn bản đã được gửi đến %s. Vui lòng nhập mã xác minh mà nó chứa. + Máy chủ định danh bạn đã chọn không có bất kỳ điều khoản dịch vụ nào. Chỉ tiếp tục nếu bạn tin tưởng chủ sở hữu dịch vụ + Máy chủ định danh không có điều khoản dịch vụ + Vui lòng nhập đường dẫn máy chủ định danh + Không thể kết nối với máy chủ định danh + Nhập URL máy chủ định danh Bạn có đồng ý gửi thông tin này không\? - Để khám phá các liên hệ hiện có, bạn cần gửi thông tin liên hệ (email và số điện thoại) đến máy chủ nhận dạng của mình. Chúng tôi băm dữ liệu của bạn trước khi gửi cho quyền riêng tư. - Gửi email và số điện thoại đến %s + Để khám phá các liên hệ hiện có, bạn cần gửi thông tin liên hệ (địa chỉ thư điện tử và số điện thoại) đến máy chủ định danh của mình. Chúng tôi băm dữ liệu của bạn trước khi gửi để đảm bảo quyền riêng tư. + Gửi địa chỉ thư điện tử và số điện thoại đến %s Đồng ý Thu hồi sự đồng ý của tôi - Các liên hệ của bạn là riêng tư. Để khám phá người dùng từ danh bạ của bạn, chúng tôi cần sự cho phép của bạn để gửi thông tin liên hệ đến máy chủ xác thực của bạn. - Bạn đã đồng ý gửi email và số điện thoại đến máy chủ xác thực này để khám phá những người dùng khác từ danh bạ của bạn. - Gửi email và số điện thoại - Chúng tôi đã gửi cho bạn một email xác nhận đến %s, trước tiên vui lòng kiểm tra email của bạn và nhấp vào liên kết xác nhận - Chúng tôi đã gửi cho bạn một email xác nhận đến %s, kiểm tra email của bạn và nhấp vào liên kết xác nhận + Các liên hệ của bạn là riêng tư. Để khám phá người dùng từ danh bạ của bạn, chúng tôi cần sự cho phép của bạn để gửi thông tin liên hệ đến máy chủ định danh của bạn. + Bạn đã đồng ý gửi địa chỉ thư điện tử và số điện thoại đến máy chủ định danh này để khám phá những người dùng khác từ danh bạ của bạn. + Gửi thư điện tử và số điện thoại + Chúng tôi đã gửi một thư đến %s, trước tiên vui lòng kiểm tra hòm thư của bạn và nhấp vào liên kết xác nhận + Chúng tôi đã gửi một thư đến %s, kiểm tra hòm thư của bạn và nhấp vào liên kết xác nhận Số điện thoại có thể khám phá - Ngắt kết nối khỏi máy chủ xác thực của bạn sẽ có nghĩa là bạn sẽ không thể khám phá bởi những người dùng khác và bạn sẽ không thể mời người khác qua email hoặc điện thoại. + Ngắt kết nối khỏi máy chủ định danh của bạn sẽ có nghĩa là bạn sẽ không thể khám phá bởi những người dùng khác và bạn sẽ không thể mời người khác qua thư điện tử hoặc điện thoại. Tùy chọn Khám phá sẽ xuất hiện khi bạn đã thêm số điện thoại. - app_id: + Định danh ứng dụng (ID): Không có cổng Push đã đăng ký Không có quy tắc Push nào được xác định Quy tắc Push @@ -1842,7 +1842,7 @@ Vui lòng chờ… Thay đổi mạng Thay đổi - Không có mạng. Vui lòng kiểm tra kết nối Internet. + Không có mạng. Kiểm tra kết nối Internet. Tạo Space mới Tạo phòng mới Sự kiện bị hỏng, không thể hiển thị @@ -1860,12 +1860,12 @@ Các cuộc hội thoại tin nhắn trực tiếp của bạn sẽ được hiển thị tại đây. Nhấp vào dấu + dưới cùng bên phải để bắt đầu. Các cuộc hội thoại Có vẻ như bạn đang cố gắng kết nối với một homeserver khác. Bạn có muốn đăng xuất không\? - Bạn không sử dụng bất kỳ máy chủ xác thực nào + Bạn không sử dụng bất kỳ máy chủ định danh nào Lỗi không xác định - %s muốn xác minh phiên của bạn - Yêu cầu xác minh + %s muốn xác thực phiên của bạn + Yêu cầu xác thực Đã nhận được - Đã xác minh! + Đã xác thực! Chữ ký Thuật toán Phiên bản @@ -1882,16 +1882,16 @@ Xóa Sao lưu Kiểm tra trạng thái sao lưu Đang xóa bản sao lưu… - Để sử dụng Sao lưu Chính trong phiên này, hãy khôi phục bằng cụm mật khẩu hoặc khóa khôi phục của bạn ngay bây giờ. - Sao lưu có chữ ký không hợp lệ từ phiên chưa được xác minh %s - Sao lưu có chữ ký không hợp lệ từ phiên đã xác minh %s - Sao lưu có chữ ký hợp lệ từ phiên chưa được xác minh %s - Sao lưu có chữ ký hợp lệ từ phiên đã xác minh %s. + Để sử dụng Sao lưu khóa trong phiên này, hãy khôi phục bằng cụm mật khẩu hoặc khóa khôi phục của bạn ngay bây giờ. + Sao lưu có chữ ký không hợp lệ từ phiên chưa được xác thực %s + Sao lưu có chữ ký không hợp lệ từ phiên đã xác thực %s + Sao lưu có chữ ký hợp lệ từ phiên chưa được xác thực %s + Sao lưu có chữ ký hợp lệ từ phiên đã xác thực %s. Sao lưu có chữ ký hợp lệ từ phiên này. - Sao lưu có chữ ký từ phiên không xác định với ID %s. + Sao lưu có chữ ký từ phiên không xác định với định danh %s. Khóa của bạn không được sao lưu từ phiên này. - Sao lưu chính không hoạt động trong phiên này. - Key Backup đã được thiết lập chính xác cho phiên này. + Sao lưu khóa không hoạt động trong phiên này. + Sao lưu khóa đã được thiết lập chính xác cho phiên này. Xóa Sao lưu Khôi phục từ Sao lưu Thất bại trong việc nhận được phiên bản khóa khôi phục mới nhất (%s). @@ -1963,22 +1963,22 @@ Nhập %s của bạn để tiếp tục. Chìa khóa tin nhắn Cụm mật khẩu phục hồi - Xác minh bị hủy bỏ - Xác minh đã bị hủy bỏ. Bạn có thể bắt đầu xác minh lại. + Xác thực đã bị hủy bỏ + Xác thực đã bị hủy bỏ. Bạn có thể bắt đầu xác thực lại. Một trong những điều sau đây có thể bị xâm phạm: \n \n- Mật khẩu của bạn -\n- Người ở nhà của anh -\n- Thiết bị này hoặc thiết bị khác +\n- Máy chủ nhà của bạn +\n- Thiết bị này hoặc thiết bị kia \n- Kết nối internet mà một trong hai thiết bị đang sử dụng \n \nChúng tôi khuyên bạn nên thay đổi mật khẩu và khóa khôi phục trong Cài đặt ngay lập tức. - Bạn sẽ không xác minh %1$s (%2$s) nếu bạn hủy ngay. Bắt đầu lại trong hồ sơ người dùng của họ. + Bạn sẽ không xác thực %1$s (%2$s) nếu bạn hủy ngay. Bắt đầu lại trong hồ sơ người dùng của họ. Nếu bạn hủy, bạn sẽ không thể đọc tin nhắn được mã hóa trên thiết bị mới của mình và những người dùng khác sẽ không tin tưởng nó Nếu bạn hủy, bạn sẽ không thể đọc tin nhắn được mã hóa trên thiết bị này và những người dùng khác sẽ không tin tưởng nó Tài khoản của bạn có thể bị xâm phạm Không phải tôi - Sử dụng phiên này để xác minh phiên mới của bạn, cấp cho nó quyền truy cập vào các tin nhắn được mã hóa. + Sử dụng phiên này để xác thực phiên mới của bạn, cấp cho nó quyền truy cập vào các tin nhắn được mã hóa. Đăng nhập mới. Đây có phải là bạn không\? Làm tươi Mở khóa lịch sử tin nhắn được mã hóa @@ -2011,20 +2011,20 @@ Mã QR Đặt lại khóa Khởi tạo xác thực chéo - Cho đến khi người dùng này tin tưởng phiên này, tin nhắn được gửi đến và đi từ nó được dán nhãn cảnh báo. Ngoài ra, bạn có thể xác minh thủ công. + Cho đến khi người dùng này tin tưởng phiên này, tin nhắn được gửi đến nó và từ nó đều mang nhãn cảnh báo. Ngoài ra, bạn có thể xác thực thủ công. %1$s (%2$s) đã đăng nhập bằng phiên mới: - Phiên này được tin cậy để nhắn tin an toàn vì %1$s (%2$s) đã xác minh: + Phiên này được tin cậy để nhắn tin an toàn vì %1$s (%2$s) đã xác thực: Không tin cậy Tin cậy Phiên Không nhận được phiên Cảnh báo - Đã xác minh - Xác minh - Sử dụng phiên hiện có để xác minh phiên này, cấp cho nó quyền truy cập vào các thư được mã hóa. - Xác minh đăng nhập này - Xác minh phiên này để đánh dấu nó là đáng tin cậy và cấp cho nó quyền truy cập vào các thư được mã hóa. Nếu bạn không đăng nhập vào phiên này, tài khoản của bạn có thể bị xâm phạm: - Phiên này được tin cậy để nhắn tin an toàn vì bạn đã xác minh nó: + Đã xác thực + Xác thực + Sử dụng phiên hiện có để xác thực phiên này, cấp cho nó quyền truy cập vào các tin nhắn được mã hóa. + Xác thực thiết bị này + Xác thực phiên này để đánh dấu nó là đáng tin cậy và cấp cho nó quyền truy cập vào các thư được mã hóa. Nếu bạn không đăng nhập vào phiên này, tài khoản của bạn có thể bị xâm phạm: + Phiên này được tin cậy để nhắn tin an toàn vì bạn đã xác thực nó: Không có thông tin mật mã sẵn dùng bất ổn định ổn định @@ -2058,9 +2058,9 @@ Vui lòng nhập tên người dùng. Hủy kích hoạt Tài khoản Vui lòng quên tất cả các tin nhắn tôi đã gửi khi tài khoản của tôi bị vô hiệu hóa (Cảnh báo: điều này sẽ khiến người dùng trong tương lai thấy chế độ xem cuộc hội thoại không đầy đủ) - Điều này sẽ làm cho tài khoản của bạn vĩnh viễn không thể sử dụng được. Bạn sẽ không thể đăng nhập và không ai có thể đăng ký lại cùng một ID người dùng. Điều này sẽ khiến tài khoản của bạn rời khỏi tất cả các phòng mà nó đang tham gia và nó sẽ xóa chi tiết tài khoản của bạn khỏi máy chủ nhận dạng của bạn. Điều này là không thể đảo ngược. + Điều này sẽ làm cho tài khoản của bạn vĩnh viễn không thể sử dụng được. Bạn sẽ không thể đăng nhập và không ai có thể đăng ký lại cùng một ID người dùng. Điều này sẽ khiến tài khoản của bạn rời khỏi tất cả các phòng mà nó đang tham gia và nó sẽ xóa chi tiết tài khoản của bạn khỏi máy chủ định danh của bạn. <b>Điều này là không thể đảo ngược</b>. \n -\nHủy kích hoạt tài khoản của bạn does không theo mặc định khiến chúng tôi quên tin nhắn bạn đã gửi. Nếu bạn muốn chúng tôi quên tin nhắn của bạn, vui lòng đánh dấu vào hộp bên dưới. +\nHủy kích hoạt tài khoản của bạn <b>does không theo mặc định khiến chúng tôi quên tin nhắn bạn đã gửi</b>. Nếu bạn muốn chúng tôi quên tin nhắn của bạn, vui lòng đánh dấu vào hộp bên dưới. \n \nKhả năng hiển thị tin nhắn trong Matrix tương tự như email. Chúng tôi quên tin nhắn của bạn có nghĩa là tin nhắn bạn đã gửi sẽ không được chia sẻ với bất kỳ người dùng mới hoặc chưa đăng ký nào, nhưng người dùng đã đăng ký đã có quyền truy cập vào các tin nhắn này vẫn sẽ có quyền truy cập vào bản sao của họ. Để tiếp tục sử dụng homeserver %1$s, bạn phải xem xét và đồng ý với các điều khoản và điều kiện. @@ -2102,11 +2102,11 @@ Lệnh không được nhận ra: %s Lỗi lệnh Yêu cầu Chia sẻ Khóa - Một phiên chưa được xác minh đang yêu cầu khóa mã hóa. + Một phiên chưa được xác thực đang yêu cầu khóa mã hóa. \nTên phiên: %1$s \nLần nhìn thấy lần cuối: %2$s \nNếu bạn không đăng nhập vào phiên khác, hãy bỏ qua yêu cầu này. - Phiên chưa được xác thực của bạn \'%s\' đang yêu cầu khóa mã hóa. + Phiên chưa được xác thực \'%s\' đang yêu cầu khóa mã hóa. Một phiên mới đang yêu cầu các khóa mã hóa. \nTên phiên: %1$s \nLần nhìn thấy lần cuối: %2$s @@ -2182,13 +2182,13 @@ Tất cả các phòng trên %s server Tên máy chủ Chọn thư mục phòng - Không bao giờ gửi tin nhắn được mã hóa đến các phiên chưa được xác minh từ phiên này. - Chỉ mã hóa cho các phiên đã xác minh + Không bao giờ gửi tin nhắn được mã hóa đến các phiên chưa được xác thực từ phiên này. + Chỉ mã hóa cho các phiên đã xác thực Bỏ đặt làm địa chỉ chính Đặt làm địa chỉ chính Máy chủ này không cung cấp bất kỳ chính sách nào. Thư viện bên thứ ba - Chính sách máy chủ xác thực của bạn + Chính sách máy chủ định danh của bạn Chính sách homeerver của bạn Chính sách ${app_name} Bạn có thể tắt tính năng này bất cứ lúc nào trong cài đặt @@ -2199,19 +2199,19 @@ \n \nBạn có thể đọc tất cả các thuật ngữ của chúng tôi %s. Giúp cải thiện ${app_name} - Thiết bị đã bị đăng xuất! + Phiên đã bị đăng xuất! Căn phòng đã bị bỏ lại! Chọn homeerver Không thể kết nối đến một homeserver tại URL %s. Vui lòng kiểm tra liên kết của bạn hoặc chọn homeerver thủ công. Không phải bây giờ Kích hoạt Nghe thông báo - Tùy chọn Khám phá sẽ xuất hiện sau khi bạn đã thêm email. - Địa chỉ email có thể khám phá - Hiện tại bạn không sử dụng máy chủ xác thực. Để khám phá và có thể khám phá bởi các liên hệ hiện có mà bạn biết, hãy cấu hình một danh bạ dưới đây. - Không có chính sách được cung cấp bởi máy chủ xác thực - Ẩn chính sách máy chủ xác thực - Hiện chính sách máy chủ xác thực + Tùy chọn Khám phá sẽ xuất hiện sau khi bạn đã thêm địa chỉ thư điện tử. + Địa chỉ thư điện tử có thể khám phá + Hiện tại bạn không sử dụng máy chủ định danh. Để khám phá và có thể khám phá bởi các liên hệ hiện có mà bạn biết, hãy cấu hình một danh bạ dưới đây. + Máy chủ định danh không cung cấp chính sách nào + Ẩn chính sách máy chủ định danh + Hiện chính sách máy chủ định danh Mở Cài đặt Khám phá Thêm tab dành riêng cho các thông báo chưa đọc trên màn hình chính. Tìm kiếm theo tên, ID hoặc thư @@ -2253,8 +2253,8 @@ Âm thanh & Hình ảnh Format: Url: - session_name: - app_display_name: + Tên hiển thị của phiên: + Tên hiển thị của ứng dụng: push_key: Gửi video với kích thước gốc @@ -2320,4 +2320,238 @@ %d thay đổi về danh sách truy cập + Mã hóa bị thiết đặt sai. + Đã chia sẻ vị trí + Không mở được liên kết: cộng đồng đã được thay bằng spaces + Quét mã QR + Tôi đã có tài khoản + Tạo tài khoản + Bỏ qua bước này + Lưu và tiếp tục + Vào cài đặt mỗi khi cần cập nhật hồ sơ + Trông rất tuyệt! + Thêm ảnh hồ sơ + Bạn có thể đổi lại sau + Tên hiển thị + Chọn tên hiển thị + Tên người dùng / Địa chỉ thư điện tử / Số điện thoại + Bạn có phải con người\? + Làm theo chỉ dẫn gửi tới %s + Đặt lại mật khẩu + Quên mật khẩu + Gửi lại thư + Không nhận được thư\? + Làm theo chỉ dẫn gửi tới %s + Xác nhận địa chỉ thư điện tử + Gửi lại mã + Một mã đã được gửi tới %s + Xác nhận số điện thoại + Đăng xuất mọi thiết bị + Đặt lại mật khẩu + Đặt mật khẩu chữa ít nhất 8 ký tự. + Chọn mật khẩu mới + Mật khẩu mới + Kiểm tra hòm thư. + Mã xác nhận + Số điện thoại + Nhập số điện thoại + Địa chỉ thư điện tử + Nhập địa chỉ thư điện tử + Sửa + Hay + Nơi các cuộc trò chuyện được đặt + Nơi các cuộc trò chuyện được đặt + Phải chứa ít nhất 8 ký tự + Tạo tài khoản + Tài khoản %s đã được tạo + Chúc mừng! + Về trang chủ + Cá nhân hóa hồ sơ + Kết nối tới máy chủ + Bỏ qua câu hỏi + Cộng đồng + Nhóm + Bạn bè và gia đình + Nhắn tin bảo mật. + Gửi phản hồi + Đã bật: + Thẻ hồ sơ: + Định danh phiên: + Đi + Đang cập nhật dữ liệu của bạn… + Mọi người + Yêu thích + Chưa đọc + Tất cả + Xem trong phòng + Đang trả lời %s + Sửa + Sao lưu có con dấu hợp lệ từ người dùng này. + Lệnh \"%s\" không được hỗ trợ ở chủ đề. + Xin lỗi, phòng này không được tìm thấy +\nHãy thử lại.%s + Dùng của hệ thống + Chọn thủ công + Thiết đặt tự động + Chọn cỡ chữ + Bạn đã bật chỉ mã hóa với các phiên đã xác thực trong tất cả các phòng ở Cài đặt bảo mật. + Trong phòng có các thiết bị chưa được xác thực, chúng sẽ không thể giải mã tin nhắn mà bạn gửi. + Không gửi tin nhắn được mã hóa cho các phiên chưa xác thực trong phòng này. + Thông tin tài khoản của bạn được quản lý riêng rẽ tại %1$s. + Tài khoản + Tự động phát các ảnh động + Phiên bản thuật toán + Cấp quyền + + %1$s và %2$d người khác + + %1$s và %2$s + Mẹo: Nhấn giữ một tin nhắn và dùng “%s”. + Space là một cách mới để nhóm các phòng và mọi người. Tạo một space để bắt đầu. + Chưa có space nào. + %1$s đã đổi tên hiển thị thành %2$s + Cứ đăng xuất + Không thể kết nối tới máy chủ nhà. Nếu bạn cứ đăng xuất, thiết bị này sẽ không được xóa khỏi danh sách, bạn có thể muốn xóa nó bằng thiết bị khác. + Giao tiếp độc lập và bảo mật cho bạn mức độ riêng tư ngang với trò chuyện trực tiếp trong nhà. + Được mã hóa đầu cuối và không yêu cầu số điện thoại. Không quảng cáo hay khai thác dữ liệu. + Rời tất cả + Đặt lại các khóa xác thực không thể được hoàn tác. Sau khi đặt lại, bạn không thể truy cập vào các tin nhắn đã được mã hóa cũ, và tất cả bạn bè đã xác thực bạn trước đó sẽ thấy các cảnh báo cho đến khi nào bạn xác thực lại với họ. + Hiện thông tin hồ sơ mới nhất (ảnh đại diện và tên hiển thị) cho tất cả các tin nhắn. + Đăng xuất khỏi mọi phiên khác + Các phiên chưa được xác thực là các phiên đã đăng nhập bằng thông tin của bạn nhưng chưa được xác thực chéo. +\n +\nBạn cần đặc biệt chắc chắn là bạn nhận ra các phiên này vì chúng có thể đang sử dụng trái phép tài khoản của bạn. + Những người dùng khác trong tin nhắn trực tiếp và các phòng bạn tham gia có thể xem danh sách các phiên của bạn. +\n +\nNhư vậy giúp họ chắc chắn họ đang thực sự nói chuyện với bạn, nhưng vì thế mà họ cũng có thể thấy tên phiên bạn nhập ở đây. + Bật trình soạn thảo văn bản phong phú + Thử trình soạn thảo văn bản phong phú (sẽ có chế độ văn bản thuần) + Đây là nơi chứa các yêu cầu và lời mời mới. + Ảnh đại diện cho space %1$s + Ảnh đại diện cho phòng %1$s + Ảnh đại diện cho người dùng %1$s + Mở màn hình công cụ cho nhà phát triển + Thư viện ảnh + Đăng ký điểm cuối + Có một lỗi đã xảy ra. Kiểm tra kết nối mạng và thử lại. + Đang thử nghiệm + Địa chỉ máy chủ của bạn là gì\? Đó như là nhà của tất cả dữ liệu của bạn + Gửi ảnh và phim + Hiện tất cả (%1$d) + ${app_name} cũng là nơi tốt cho nơi làm việc. Được tin cậy bởi những tổ chức bảo mật nhất thế giới. + Tùy chọn bố cục + Mọi phiên + Sử dụng bố cục mới + Điểm cuối đã được đăng ký với máy chủ nhà. + Vị trí + Dịch vụ của Google + Hệ thống sẽ tự động gửi nhật ký khi nào xảy ra lỗi giải mã tin nhắn + + Đăng xuất khỏi %1$d phiên + + Các phiên đã được xác thực là phiên mà bạn đăng nhập bằng mật khẩu hay xác thực danh tính bằng một phiên khác +\n +\nNghĩa là bạn đã có tất cả các khóa cần thiết để mở khóa các tin nhắn đã được mã hóa và xác nhận với những người khác là bạn tin cậy phiên này. + Hiển thị và kiểm soát các phiên của bạn tốt hơn. + Ứng dụng nhắn tin bảo mật tất cả-trong-một cho nhóm, bạn bè và tổ chức. Tạo một cuộc trò chuyện, hay tham gia vào một phòng, để bắt đầu. + Chọn nơi lưu trữ các cuộc trò chuyện của bạn, cho bạn quyền kiểm soát và độc lập. Kết nối qua giao thức Matrix. + Chỉ tiếp tục nếu bạn chắc chắn là bạn đã mất tất cả các thiết bị và khóa bảo mật. + Đóng %s mục + Mở %s mục + Bạn chỉ có thể mời một địa chỉ thư điện tử một lần + Mở danh sách space + Chọn máy chủ của bạn + Bạn nắm quyền kiểm soát. + Muốn chạy một máy chủ của mình\? + %s cần xác nhận tài khoản của bạn + Đi thôi + Bạn sẽ trò chuyện với ai nhiều nhất\? + Chưa chắc chắn\? %s + URL Máy chủ + Đến lúc để thêm khuôn mặt vào tên + Nhắn tin với đồng đội. + Đã chia sẻ vị trí hiện tại + Tạo một cuộc trò chuyện hay phòng mới + Phát thanh + Những người khác có thể tìm thấy bạn %s + Chính sách máy chủ + %s sẽ gửi bạn một liên kết xác nhận + Làm chủ cuộc trò chuyện. + %s cần xác thực tài khoản của bạn + Chào mừng trở lại! + Địa chỉ máy chủ của bạn là gì\? + Chúng tôi sẽ giúp bạn kết nối + Tìm để tham gia một máy chủ sẵn có\? + Đã bắt đầu phát thanh + Xác thực bằng khóa bảo mật hay chuỗi từ bảo mật… + Vui lòng liên hệ một quản trị viên để khôi phục mã hóa về trạng thái hợp lệ. + Khôi phục mã hóa + Bản dựng hằng ngày + Xác thực với thiết bị khác + Lịch sử bỏ phiếu + Các phiên + Bạn không thể truy cập vào các tin nhắn được mã hóa. Đặt lại sao lưu tin nhắn bảo mật và các khóa xác thực để bắt đầu lại. + Không thể xác thực thiết bị này + Ứng dụng được cập nhật + Trước khi người dùng này tin tưởng phiên này, các tin nhắn gửi đến phiên và từ phiên đều mang nhãn cảnh báo. + Xác thực danh tính để truy cập vào các tin nhắn được mã hóa và chứng minh danh tính của bạn với những người khác. + Tải bản dựng mới nhất (ghi chú: bạn có thể gặp vấn đề khi đăng nhập) + + Xem lại để chắc chắn rằng tài khoản bạn an toàn + %1$d phút %2$d giây + Hoạt động lần cuối + Tên phiên + Mã hóa bởi một thiết bị đã xóa + Mã hóa bị thiết lập sai + Chọn các phiên + Hủy bộ lọc + Thông báo đẩy + Tên + Địa chỉ + Phiên không hoạt động + Phiên chưa xác thực + Yêu cầu bàn phím không được phép cập nhật các dữ liệu cá nhân hóa như lịch sử nhập và từ điển dựa trên những gì bạn nhắn trong trò chuyện. Tuy vậy một số bàn phím sẽ không tuân theo cài đặt này. + Tính xác thực của tin nhắn đã mã hóa này không thể được đảm bảo trên thiết bị này. + Bạn có các phiên chưa xác thực + %1$s, %2$s, %3$s + Đăng xuất + Đăng xuất khỏi phiên này + Chi tiết phiên + Thông tin phần mềm, thiết bị, và hoạt động. + Phiên bản + Trình duyệt + Mẫu mã + Đổi tên phiên + Hiện địa chỉ Internet (IP) + Phần mềm + Địa chỉ Internet (IP) + Tên phiên + Gửi tin nhắn đầu tiên để mời %s vào cuộc trò chuyện + Bàn phím ẩn danh + Ẩn địa chỉ Internet (IP) + Phiên đã xác thực + Hệ điều hành + Bộ lọc + Bộ lọc các chủ đề trong phòng + Sao chép liên kết vào cuộc trò chuyện + Các chủ đề + Bản Beta của Chủ đề + Bản Beta của Chủ đề + Các chủ đề đã chuyển sang Beta 🎉 + Hiển thị tất cả chủ đề trong phòng + Tất cả chủ đề + Sắp xếp các cuộc thảo luận với các chủ đề + Chủ đề + Hiển thị tất cả chủ đề bạn đã tham gia + Element đã được đơn giản hóa với các mục tùy chọn + Chỉ tạo cuộc trò chuyện riêng cho tin nhắn đầu tiên + Bật trì hoãn cho các tin nhắn riêng + Các chủ đề của tôi + Từ một chủ đề + \'\'Chủ đề\'\' giúp giữ cho các cuộc trò chuyện của bạn theo chủ đề và dễ theo dõi. + Máy chủ nhà của bạn chưa hỗ trợ cho việc liệt kê các chủ đề. + \'\'Chủ đề\'\' giúp giữ cho các cuộc trò chuyện của bạn theo chủ đề và dễ theo dõi. %sBật chủ đề sẽ làm mới ứng dụng. Quá trình này có thể mất nhiều thời gian hơn đối với một số tài khoản. + Phiên + Thiết bị + Hoạt động cuối %1$s \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-zh-rCN/strings.xml b/library/ui-strings/src/main/res/values-zh-rCN/strings.xml new file mode 100644 index 0000000000..9abc3b25e4 --- /dev/null +++ b/library/ui-strings/src/main/res/values-zh-rCN/strings.xml @@ -0,0 +1,2868 @@ + + + %s 的邀请 + %1$s 邀请了 %2$s + %1$s 邀请了你 + %1$s 加入了房间 + %1$s 离开了房间 + %1$s 拒绝了邀请 + %1$s 移除了 %2$s + %1$s 解封了 %2$s + %1$s 封禁了 %2$s + %1$s 更换了其头像 + %1$s 将他们的显示名称设置为 %2$s + %1$s 将其显示名称从 %2$s 更改为 %3$s + %1$s 移除了他们的显示名称(%2$s) + %1$s 将话题更改为:%2$s + %1$s 将房间名称更改为:%2$s + %s 发起了一次视频通话。 + %s 发起了一次语音通话。 + %s 已接听通话。 + %s 已结束通话。 + 所有房间成员,从他们被邀请开始。 + 所有房间成员,从他们加入开始。 + 所有房间成员。 + 任何人。 + (头像也被更改) + %1$s 移除了房间名称 + %1$s 移除了房间话题 + ** 无法解密:%s ** + 发送者的设备没有向我们发送此消息的密钥。 + 无法发送消息 + Matrix 错误 + 电子邮件地址 + 手机号码 + %1$s 撤回了对 %2$s 的邀请 + %1$s 让未来的房间历史记录对 %2$s 可见 + %1$s 向 %2$s 发送了加入房间的邀请 + %1$s 接受了 %2$s 的邀请 + 空房间 + 房间邀请 + %1$s 和 %2$s + 初始化同步: +\n正在导入账户… + 初始化同步: +\n正在导入加密数据 + 初始化同步: +\n正在导入房间 + 初始化同步: +\n正在加载对话 +\n如果你加入了很多论房间,这可能需要一段时间 + 初始化同步: +\n正在导入已邀请的房间 + 初始化同步: +\n正在导入已离开的房间 + 初始化同步: +\n正在导入账户数据 + %s 升级了此房间。 + 正在发送消息…… + %1$s 撤回了对 %2$s 加入房间的邀请 + %1$s 的邀请。理由:%2$s + %1$s 邀请了 %2$s。理由:%3$s + %1$s 邀请了你。理由:%2$s + %1$s 加入了房间。理由:%2$s + %1$s 离开了房间。理由:%2$s + %1$s 已拒绝邀请。理由:%2$s + %1$s移除了%2$s。理由:%3$s + %1$s 解封了 %2$s。理由:%3$s + %1$s 封禁了 %2$s。理由:%3$s + %1$s 接受 %2$s 的邀請。理由:%3$s + %1$s 撤回了对 %2$s 的邀请。理由:%3$s + + %1$s 新增了 %2$s 为此房间的地址。 + + + %1$s 移除了 %2$s 作为此房间额地址。 + + %1$s 为此房间新增了 %2$s 并移除 %3$s 地址。 + %1$s 将此房间的主要地址设为了 %2$s。 + %1$s 为此房间移除了主要地址。 + %1$s 已允许访客加入房间。 + %1$s 已禁止访客加入房间。 + %1$s 已开启端到端加密。 + %1$s 已开启端到端加密(无法识别的算法 %2$s)。 + %1$s 创建了房间 + 你的邀请 + 你创建了房间 + 你邀请了 %1$s + 你加入了房间 + 你离开了房间 + 你拒绝了邀请 + 你移除了 %1$s + 你解封了 %1$s + 你封禁了 %1$s + 你撤回了对 %1$s 的邀请 + 你更换了你的头像 + 你将你的显示名称设置为 %1$s + 你将显示名称从 %1$s 更改为 %2$s + 你移除了你的显示名称(%1$s) + 你将话题更改为:%1$s + %1$s 更改了房间头像 + 你更改了房间头像 + 你将房间名称更改为:%1$s + 你发起了一次视频通话。 + 你发起了一次语音通话。 + %s 发送了数据以建立通话。 + 你发送了数据以建立通话。 + 你已接听通话。 + 你已结束通话。 + 你已让未来的房间历史对 %1$s 可见 + 你升级了此房间。 + 你移除了房间名称 + 你移除了房间话题 + %1$s 移除了房间头像 + 你移除了房间头像 + 你向 %1$s 发送了加入房间的邀请 + 你已撤回了对 %1$s 加入房间的邀请 + 你接受了 %1$s 的邀请 + %1$s 添加了 %2$s 小部件 + 你添加了 %1$s 小部件 + %1$s 移除了 %2$s 小部件 + 你移除了 %1$s 小部件 + %1$s 修改了 %2$s 小部件 + 你修改了 %1$s 小部件 + 管理员 + 协管员 + 默认 + 自定义(%1$d) + 自定义 + 你更改了 %1$s 的权限等级。 + %1$s 更改了 %2$s 的权限等级。 + %1$s 从 %2$s 到 %3$s + 你的邀请。理由:%1$s + 你邀请了 %1$s。理由:%2$s + 你加入了房间。理由:%1$s + 你离开了房间。理由:%1$s + 你拒绝了邀请。理由:%1$s + 你移除了%1$s。理由:%2$s + 你解封了 %1$s。理由:%2$s + 你封禁了 %1$s。理由:%2$s + 你接受了 %1$s 的邀请。理由:%2$s + 你撤回了 %1$s 的邀请。理由:%2$s + + 你新增了 %1$s 为此房间的地址。 + + + 你移除了此房间的 %1$s 地址。 + + 你为此房间新增了 %1$s 并移除了 %2$s 地址。 + 你将此房间的主要地址设为了 %1$s。 + 你移除了此房间的主要地址。 + 你已允许访客加入房间。 + 你已禁止访客加入房间。 + 你已开启端到端加密。 + 你已开启端到端加密(无法识别的算法 %1$s)。 + 你已离开。理由:%1$s + %1$s 已离开。理由:%2$s + 你已加入。理由:%1$s + %1$s 已加入。理由:%2$s + 你撤回了对 %1$s 的邀请 + %1$s 撤回了对 %2$s 的邀请 + 你邀请了 %1$s + %1$s 邀请了 %2$s + 你在此处升级。 + %s 是升级后的房间。 + 你使未来的消息对 %1$s 可见 + %1$s 使未来的消息对 %2$s 可见 + 你离开了房间 + %1$s 离开了房间 + 你已加入 + %1$s 已加入 + 你创建了讨论 + %1$s 创建了讨论 + 你已阻止访客加入房间。 + %1$s 已阻止访客加入房间。 + 你已允许访客加入这里。 + %1$s 已允许访客加入这里。 + 接受 + 拒绝 + 挂断 + 引用 + 分享 + 语音通话 + 视频通话 + 全部标记为已读 + 快速回复 + 已复制到剪贴板 + 发送日志 + 发送屏幕截图 + 加入房间 + 用户名 + 登出 + 搜索 + 发送文件 + 通话已结束 + 继续 + 加入 + 拒绝 + 离开房间 + 确定要离开房间吗? + %s正在输入…… + 设置 + 保存 + 离开 + 发送 + 查看源代码 + 查看解密后的源代码 + + 登出 + 警告 + 请描述你遇到的问题。你做了什么?你期望发生什么?实际上发生了什么? + 在这里描述你的问题 + 进度(%s%%) + 家服务器 URL + 登录 + 提交 + 错误的用户名和/或密码 + 此电子邮件地址似乎无效 + 此电子邮件地址已被使用。 + 忘记密码? + 请输入有效的 URL + 没有包含有效的 JSON + 发送了过多的请求 + + + + + + 搜索 + 过滤房间成员 + 没有结果 + 添加电子邮件地址 + 添加手机号码 + 版本 + olm 版本 + 高级 + 加密 + 本地联系人 + 更新公开名称 + 修改密码 + 新密码 + 密码更新失败 + 你的密码已更新 + 解密错误 + 公开名称 + 会话 ID + 会话密钥 + 导入 + 已验证 + 取消 + 删除 + 打开 + 关闭 + 确认 + 发送崩溃日志 + 上次启动后本应用发生了崩溃。是否打开崩溃报告页面? + 开始语音通话 + 开始视频通话 + 拍摄照片或视频 + 此家服务器想确认你不是机器人 + 电子邮件地址验证失败:请确保你已点击邮件中的链接 + 原始 + 通话正在连接…… + ${app_name} 需要权限以访问你的麦克风来进行语音通话。 + 私聊 + 邀请 + 封禁 + 解除封禁 + 忽略 + 取消忽略 + 提及 + %1$s和%2$s正在输入…… + %1$s和 %2$s及其他人正在输入…… + 你没有在这个房间发帖的权限。 + 信任 + 不信任 + 登出 + 忽略 + 指纹(%s): + 无法验证远程服务器的身份。 + 应用信息 + 启用这个账户的通知 + 启用这个会话的通知 + 来自私聊的消息 + 来自群聊的消息 + 当我被邀请加入房间时 + 来自机器人的消息 + 后台同步 + 同步请求超时 + 每次同步请求之间的间隔 + 版权 + 隐私政策 + 清空缓存 + 用户设置 + 通知 + 已忽略的用户 + 通讯录权限 + 身份认证 + 当前密码 + 显示所有来自 %s 的消息? + 选择国家 + 话题 + 房间历史可见性 + 谁可以阅读历史消息? + 任何人 + 仅成员(从选中此项的时间点开始) + 仅成员(从他们被邀请开始) + 仅成员(从他们加入开始) + 被封禁的用户 + 高级 + 此房间的内部 ID + 这些是实验性功能,可能会出现不可预料的错误。请谨慎使用。 + 导出端到端房间密钥 + 导出房间密钥 + 导出密钥到本地文件 + 导出 + 输入口令词组 + 确认口令词组 + 导入端到端房间密钥 + 导入房间密钥 + 从本地文件导入密钥 + 仅向已验证的会话发送加密消息 + 从不从此会话向未验证的会话发送加密消息。 + 未验证 + 验证 + 稍后再说 + 永久链接 + 重命名 + 举报内容 + 问题反馈 + 为分析此问题,本客户端的日志将会随此问题反馈发送。本问题反馈,包括日志与截图,将不会被公开显示。若你希望仅发送上面的文字,请取消选择: + 问题反馈发送成功 + 问题反馈发送失败(%s) + 异常的 JSON + 呼入的视频通话 + 呼入的语音通话 + 通话中…… + 远端未能接听。 + 信息 + ${app_name} 需要权限以访问你的摄像机和麦克风来进行视频通话。 +\n +\n请在接下来的弹出窗口中授权允许访问,以便进行通话。 + 移除 + 你将无法撤消此更改,因为你正在将用户提升为与你相同的权限级别。 +\n你确定吗? + 这可能意味着有人正在恶意劫持你的流量,或者你的手机不信任远程服务器提供的数字证书。 + 如果服务器管理员说这是预期的情况,请确保下面的指纹与管理员提供的指纹相匹配。 + 显示名称 + 显示系统设置中的应用程序信息。 + 通话请求 + 使用条款 + 其它 + 通知目标 + 登录为 + 请检查你的电子邮件并点击里面包含的链接。完成时请点击继续。 + 此电子邮件地址已被使用。 + 此手机号码已被使用。 + 设置为主要地址 + 取消设置为主要地址 + 确认 + 你似乎沮丧地摇了摇手机。你想打开问题反馈界面吗? + 证书已从一个先前受你的手机信任的证书更改为另一个。这高度反常。建议你不要接受此新证书。 + 证书已从曾受信任的证书更改为不受信任的证书。服务器可能已更新其证书,请联系管理员并核对服务器的指纹。 + 请仅在服务器管理员发布了与上述指纹匹配的指纹的情况下接受该证书。 + 用户资料图片 + 第三方通知 + 通讯录国家 + ID + 公开名称 + 最近一次上线 + %1$s @ %2$s + 家服务器 + 身份服务器 + 实验室 + 通过和你其它会话里的用户设置对比以下内容来确认: + 如果它们不匹配,你通讯的安全性可能会受到影响。 + 邀请 + 收藏夹 + 联系人 + 房间 + 按房间名称过滤 + 邀请 + 低优先级 + 对话 + 只显示 Matrix 联系人 + 没有结果 + 房间 + 选择一个房间目录 + 服务器名称 + %s 服务器上的所有房间 + 所有本地 %s 房间 + 跳到未读 + 主页显示 + 固定含错过通知的房间 + 置顶含有未读消息的房间 + 用户界面 + 语言 + 请选择语言 + 开机时自动启动 + 清空缓存的媒体文件 + 保留媒体文件 + 为所有消息显示时间戳 + 3天 + 1周 + 1个月 + 永远 + 主题 + 文字大小 + 微小 + + 标准 + + 更大 + 最大 + 巨大 + 浅色主题 + 深色主题 + 黑色主题 + 通知声音 + 使用 12 小时制显示时间戳 + 确定要从此房间中删除小部件吗? + 无法创建小部件。 + 发送请求失败。 + 权限等级必须是正整数。 + 你不在这个房间。 + 你没权限在当前房间执行此操作。 + 请求中缺失 room_id。 + 请求中缺失 user_id。 + 房间 %s 不可见。 + 添加 Matrix 应用 + 监听事件 + 通话 + 包含我显示名称的消息 + 包含我用户名的消息 + 你添加了一个新会话“%s”,它正在请求加密密钥。 + 你的未验证会话“%s”正在请求加密密钥。 + 开始验证 + 错误报告 + 拍摄照片 + 拍摄视频 + 使用原生相机 + 命令错误 + 不可识别的命令:%s + 关闭 + 已加密消息 + 响铃通知 + 静默通知 + 数据分析 + 响铃 + 正在加载…… + 你确定要发起语音通话吗? + 你确定要发起视频通话吗? + 封禁用户会把他们移出此房间并阻止他们再次加入。 + 全部消息 + 添加到主屏幕 + 内联网址预览 + 提及用户时震动 + 创建 + + %d 条新消息 + + 摇一摇快捷反馈问题 + + %d个成员状态变动 + + + %d 个成员 + + + %d条未读的已通知消息 + + 成员 + + %d 个房间 + + + %d 个活动的小部件 + + 主页 + 房间 + 已邀请 + 你已被 %2$s 从 %1$s 中移除 + 你已被 %2$s 从 %1$s 中封禁 + 理由:%1$s + 头像 + %1$s 条在 %2$s 中 + 停用账户 + 停用我的账户 + 发送数据分析数据 + ${app_name}收集匿名数据分析以允许我们改进应用。 + 停用账户 + 这将使你的账户永远不再可用。你将无法登录,也不能使用相同的用户 ID 重新注册。你的账户将退出所有已加入的房间,你在身份服务器上的账户信息也会被删除。<b>此操作是不可逆的。</b> +\n +\n停用你的账户<b>不会默认忘记你已发送的消息</b>。如果你希望我们忘记你发送的消息,请勾选下面的选择框。 +\n +\nMatrix 中的消息可见性类似于电子邮件。我们忘记你的消息意味着你发送的消息不会被发给新注册或未注册的用户,但是已收到你的消息的注册用户依旧可以看到这些消息的副本。 + 请在我停用账户的同时忘记我发送的所有消息(警告:这将导致未来的用户看到残缺的对话) + 停用账户 + 发送贴纸 + 发送贴纸 + 你目前没有启用任何贴纸包。 +\n +\n要添加一些吗? + 缺少一个必需参数。 + 要想继续使用家服务器 %1$s 你必须阅读并同意其服务条款。 + 现在阅读 + 下载 + 发送语音消息 + 对不起,没有可完成此操作的外部应用。 + 从你的其它会话上重新请求加密密钥。 + 请在其它可解密此消息的设备上启动 ${app_name},以便其将密钥发送至当前会话。 + 请输入你的密码。 + 如果可能的话,请使用英文撰写问题描述。 + 发送前预览媒体文件 + 显示动作 + 按照 ID 封禁用户 + 按照 ID 解禁用户 + 定义用户的权限等级 + 按照 ID 取消用户管理员权限 + 按照 ID 邀请用户进入当前房间 + 用给定地址加入房间 + 离开房间 + 设置房间话题 + 从此房间移除指定ID的用户 + 更改你显示的显示名称 + 打开/关闭 markdown + 修复 Matrix Apps 管理 + 此房间已被替换,不再处于活动状态。 + 对话在此继续 + 这个房间是另一个对话的延续 + 点击此处查看更早的消息 + + 已选择 %d 个 + + 系统警告 + 联系你的服务管理员 + 本服务器其中一项资源已超出限制,部分用户将无法登录 + 本服务器其中一项资源已超出限制。 + " 此家服务器已达到其每月活跃用户限制,因此<b>某些用户将无法登录</b>。" + 此家服务器已达到其每月活跃用户限制。 + 请 %s 以继续使用本服务。 + 请 %s 以增加此限制的额度。 + 接受 + 错误 + 请审阅并接受此家服务器的政策: + 通话 + 为来电使用 ${app_name} 的默认铃声 + 来电铃声 + 选择来电铃声: + 从聊天移除 + 通知故障排除 + 故障排除诊断 + 运行测试 + 正在测试……(%2$d 中的 %1$d) + 基本诊断结果正常。若你还是没有收到通知,请提交错误报告以协助我们调查此问题。 + 一个或多个测试没有通过,请尝试建议的修复方法。 + 一个或多个测试没有通过,请提交错误反馈以协助我们调查此问题。 + 系统设置。 + 已在系统设置中启用通知。 + 通知已在系统设置中禁用。 +\n请检查系统设置。 + 打开设置 + 账户设置。 + 你的账户已启用通知。 + 你的账户已禁用通知。 +\n请检查账户设置。 + 启用 + 会话设置。 + 已为此会话启用通知。 + 此会话未启用通知。 +\n请检查 ${app_name} 设置。 + 启用 + Play 服务检查 + Google Play 服务的 APK 文件可用且为最新版本。 + ${app_name} 使用 Google Play 服务来推送通知,但它似乎并未正确设置: +\n%1$s + 修复 Play 服务 + Firebase 令牌 + 成功获取FCM令牌: +\n%1$s + FCM令牌获取失败: +\n%1$s + 注册令牌 + FCM令牌已成功注册至家服务器。 + 未能将FCM令牌注册到家服务器: +\n %1$s + 启动系统相机而非自定义的相机屏幕。 + 开机时启动 + 启用开机时启动 + 检查后台限制 + 电池优化 + 当家服务器支持此功能时,在聊天中预览链接。 + 发送正在输入通知 + 让房间中的其他用户知道你正在输入。 + Markdown 格式化 + 在消息发出之前使用 Markdown 语法格式化消息。这允许你使用高级的文字格式,例如使用星号显示斜体文字。 + 显示已读回执 + 单击已读回执以获取详细列表。 + 显示加入与离开事件 + 邀请、移除与封禁不受影响。 + 显示账户变动事件 + 包括头像与显示名称的变动。 + 密码 + +%d + %1$s:%2$s + 收起 + 展开 + 抱歉,发生了一个错误 + Markdown 已禁用。 + 已启用 Markdown。 + 视频通话中…… + 服务将在设备重启后启动。 + 服务不会在设备重启后启动,在你打开 ${app_name} 一次之前你将不会收到消息通知。 + 已禁用对 ${app_name} 的后台限制。此测试应使用移动数据(非Wi-Fi)进行。 +\n%1$s + 已启用对 ${app_name} 的后台限制。 +\n${app_name} 在后台时的工作将被显著地限制,这可能会影响消息通知。 +\n%1$s + 关闭后台限制 + ${app_name} 未被电池优化影响。 + 如果设备在未充电的情况下关屏静置一段时间,其将进入低电耗模式(Doze)。这将阻止应用访问网络并延后其运行、同步与响铃。 + 忽略电池优化 + 请输入用于加密被导出密钥的口令词组。恢复此备份时,必须输入相同的口令词组才能导入密钥。 + 创建口令词组 + 口令词组不匹配 + 指令 %s 需要更多参数,或者有些参数不正确。 + 没有可用的 Google Play Services APK。消息通知可能不能正常工作。 + 密钥备份 + 使用密钥备份 + 如果你此时登出账户,你将会失去你的已加密消息 + 密钥备份进行中。如果你此时登出账户将无法再访问你的已加密消息。 + 安全密钥备份应该在你的所有会话中都处于活动状态,以避免失去对加密消息的访问权限。 + 我不想要我的已加密消息 + 正在备份密钥…… + 确定吗? + 备份 + 如果你在登出账户之前不备份密钥,你将失去你的已加密消息的访问权。 + 跳过 + 完成 + 你确定要登出账户吗? + 高级通知设置 + 事件的通知重要程度 + 自定义设置。 + 请注意一些消息类型已设置为静音(将会生成一条没有铃声的通知)。 + 有些通知已在你的自定义设置中被禁用。 + [%1$s] +\n此错误不受 ${app_name} 控制,根据 Google 的说法,此错误表示该设备在 FCM 中注册了太多应用。该错误仅在应用程序数量极多的情况下发生,因此不应影响普通用户。 + [%1$s] +\n此错误不受 ${app_name} 控制。它的发生可能有几个原因。也许你稍后重试就有效了,你也可以检查一下 Google Play 服务是否被系统设置限制了数据使用,或者你的设备时钟是否正确,或者可能发生在自定义的 ROM 中。 + [%1$s] +\n此错误不受 ${app_name} 控制。此设备上没有登录 Google 账户。请打开账户管理器并添加一个 Google 账户。 + 添加账户 + 设置响铃通知 + 设置电话通知 + 设置静音通知 + 选择LED颜色、震动、铃声…… + 加密密钥管理 + 恢复已加密消息 + 管理密钥备份 + 静音 + 请输入一个用户名。 + 请输入口令词组 + 口令词组太弱了 + 如果你想要 ${app_name} 生成一个恢复密钥,请删除口令词组。 + 永不丢失已加密消息 + 加密房间中的消息是端到端加密的,以确保安全。只有你和接收者拥有密钥读取这些消息。 +\n +\n安全地备份你的密钥以免丢失消息。 + 开始使用备份密钥 + (高级) + 手动导出密钥 + 使用口令词组保护你的备份。 + 我们将会在家服务器上为你的密钥保存一份加密拷贝。设置一个口令词组来保护你的备份的安全。 +\n +\n为了最大的安全性,此口令词组应当与你的账户密码不同。 + 设置口令词组 + 正在创建备份 + 或者用一个恢复密钥来保护你的备份,将其保存到另一个安全的地方。 + (高级)设置一个恢复密钥 + 成功! + 正在备份你的密钥。 + 你的恢复密钥是一张安全网——如果你忘记了口令词组,你可以利用它重获你的已加密消息的访问权。 +\n请将你的恢复密钥保存在一个非常安全的地方,比如密码管理器中(或保险箱里) + 将你的恢复密钥保存在一个非常安全的地方,比如密码管理器中(或保险箱里) + 完成 + 我已经制作了一份拷贝 + 保存恢复密钥 + 共享 + 保存为文件 + 请制作一份拷贝 + 与…共享恢复密钥 + 正在使用口令词组来生成恢复密钥,此过程可能会花费几秒钟。 + 恢复密钥 + 意外错误 + 你确定吗? + 如果你登出账户或者丢失此设备,你可能再也无法访问你的信息。 + 正在获取备份的版本 … + 使用恢复口令词组解锁你的已加密消息历史 + 使用你的恢复密钥 + 如果不知道你的恢复口令词组,你可以 %s。 + 使用恢复密钥解锁你的已加密历史消息 + 输入恢复密钥 + 丢失了恢复密钥?你可以在设置中新建一个。 + 无法使用此口令词组解密备份:请检查你输入的恢复口令词组是否正确。 + 正在恢复备份: + 正在计算恢复密钥… + 正在下载密钥… + 正在导入密钥… + 解锁历史 + 请输入恢复密钥 + 无法使用此恢复密钥解密备份:请检查你输入的恢复密钥是否正确。 + 备份已恢复 %s ! + + 恢复了一个包含 %d 个密钥的备份。 + + + %d个新密钥已被添加到此会话中。 + + 无法获取最新的恢复密钥版本 (%s) 。 + 从备份恢复 + 删除备份 + 已为此会话正确设置密钥备份。 + 密钥备份在此会话上未激活。 + 你的密钥未从此会话备份。 + 备份含有来自ID为%s的未知会话的一个签名。 + 备份具有来自此会话的有效签名。 + 备份具有来自已验证会话%s的有效签名。 + 备份具有来自未验证会话%s的有效签名 + 备份具有来自已验证会话%s的无效签名 + 备份具有来自未验证会话%s的无效签名 + 要在此会话中使用密钥备份,请立即使用口令词组或恢复密钥进行恢复。 + 正在删除备份… + 删除备份 + 要从此服务器中删除你备份的加密密钥吗?你将无法再使用恢复密钥来读取加密的历史消息。 + 永不丢失已加密消息 + 使用备份密钥 + 新安全消息密钥 + 管理密钥备份 + 正在备份密钥… + 所有密钥都已备份 + + 正在备份 %d 个密钥… + + 版本 + 算法 + 签名 + 忽略 + 以单点登录方式登录 + 按回车发送消息 + 软键盘的 Enter 按钮将发送消息而不是添加换行符 + 密码无效 + 媒体 + 默认压缩 + 选择 + 默认媒体来源 + 选择 + 播放快门声 + 标记为已读 + + %1$s:%2$d条消息 + + + %d 条通知 + + 新事件 + 房间 + 新消息 + 新邀请 + + ** 发送失败 - 请打开房间 + 抱歉,旧设备(Android 系统版本低于 6.0)不支持使用 Jitsi 创建电话会议 + 未知 IP + 一个新会话正在请求加密密钥。 +\n会话名称:%1$s +\n最近上线于:%2$s +\n若你未曾在另一个会话上登录,则忽略此请求。 + 一个未验证的会话正在请求加密密钥。 +\n会话名称:%1$s +\n最近上线于:%2$s +\n若你未曾在另一个会话上登录,则忽略此请求。 + 共享 + 密钥共享请求 + 忽略 + 替换 + 终止 + 正在检查备份状态 + 已验证! + 了解了 + 验证请求 + %s 想验证你的会话 + 未知错误 + 编辑 + 回复 + 重试 + 向你发送邀请 + 由 %s 邀请 + 对话 + 房间 + 回应 + 同意 + 添加回应 + 查看回应 + 反应 + 事件被用户删除 + 创建新房间 + 修改 + 请稍候…… + 无法预览此房间 + 房间 + 创建 + 名称 + Matrix SDK 版本 + 通用 + 偏好 + 安全与隐私 + 推送规则 + 尚未定义任何推送规则 + 没有已注册的推送通道 + 应用ID: + 推送密钥: + 应用显示名称: + 会话显示名称: + URL: + 格式: + 音频与视频 + 帮助和关于 + (已编辑) + + 撤销 + 断开连接 + 拒绝 + 这不是有效的 Matrix 服务器地址 + 无法在此 URL 找到家服务器,请检查 + 播放 + 忽略 + 复制 + 成功 + 通知 + ${app_name} 呼叫失败 + 无法建立实时连接。 +\n请让你的家服务器的管理员配置一个 TURN 服务器,以便呼叫能够可靠地工作。 + 选择声音设备 + 电话 + 扬声器 + 耳机 + 无线耳机 + 切换相机 + + + 关闭 HD + 打开 HD + SSL 错误:尚未验证对等端身份。 + SSL 错误。 + 取消邀请 + 降低你自己的级别? + 你正在降低你的级别,此操作无法撤销。如果你是房间中最后一个特权用户,你将无法恢复特权。 + 降级 + 忽略用户 + 忽略此用户将从你共享的房间移除他们的消息。 +\n +\n你随时可以在通用设置中反转此操作。 + 取消忽略用户 + 取消忽略此用户将重新显示来自他们的全部消息。 + 取消邀请 + 你确定想要取消邀请此用户吗? + 移除用户 + 移除的理由 + 用户将从此房间移除。 +\n +\n为防止他们再次加入,你应改为封禁他们。 + 封禁用户 + 封禁理由 + 取消封禁用户 + 取消封禁用户将允许他们再次加入房间。 + 后台同步模式 + 电池优化 + ${app_name} 将在后台以保留设备有限资源(电池)的方式同步。 +\n取决于你的设备资源状态,同步可能被操作系统推迟。 + 实时优化 + ${app_name} 将在后台定期准时同步(可配置)。 +\n这将影响网络和电池的使用,将显示一个永久通知表明 ${app_name} 正在监听事件。 + 无后台同步 + 应用在后台时你不会收到消息通知。 + 集成 + 使用集成管理器来管理机器人、桥接、小部件和贴纸包。 +\n集成管理器接收配置数据,并可以代表你修改小部件、发送房间邀请和设置权限等级。 + 安全备份 + 设置安全备份 + 重置安全备份 + 在此设备上设置 + 通过在你的服务器上备份加密密钥,防止失去对加密消息和数据的访问。 + 为你已有的备份生成新的安全密钥或设置新的安全短语。 + 这将替换你的当前密钥或短语。 + 发现 + 管理你的发现设置。 + 允许集成 + 集成管理器 + 集成已禁用 + 请在设置中启用“允许集成”。 + + %d 个封禁用户 + + 成功导出密钥 + %1$s:%2$s + %1$s:%2$s %3$s + 查看 + 活动小部件 + 小部件 + 加载小部件 + 此小部件由以下人员添加: + 使用它可能会设置 cookie 并与 %s 共享数据: + 使用它可能会与 %s 共享数据: + 加载小部件失败。 +\n%s + 重新加载小部件 + 在浏览器中打开 + 撤消我的访问权限 + 你的显示名称 + 你的头像 URL + 你的用户 ID + 你的主题 + 小部件 ID + 房间 ID + 这个小部件想要使用以下资源: + 允许 + 阻止全部 + 使用相机 + 使用麦克风 + 读取受 DRM 保护的媒体 + 若要继续请接受服务条款。 + 恢复密钥已保存。 + 你的家服务器上已存在备份 + 你似乎已在另一个会话中设置密钥备份。你想要将其替换为正在创建的吗? + 安全备份 + 保护加密消息及数据的访问权 + 设置安全备份 + 你未使用身份服务器 + 你似乎正在试图连接到另一个家服务器。你想要登出吗? + 你已经跟上了! + 你没有未读消息 + 你的私聊消息将显示在此处。点击右下角的 + 开始一些对话。 + 你的房间将显示在此处。点击右下角的 + 来找到现有的房间或者创建你自己的房间。 + 消息已移除 + 显示已移除消息 + 对已移除消息显示占位符 + 事件被房间管理员删除 + 格式错误事件,无法显示 + 无网络。请检查你的网络连接。 + 更改网络 + 私聊消息 + 公开 + 任何人都可以加入此房间 + 获取信任信息时发生错误 + 获取密钥备份数据时发生错误 + 从文件“%1$s”导入端到端密钥。 + 其它第三方通知 + 你已经在查看此房间! + 注册令牌 + 提出建议 + 请在下方写下你的建议。 + 请在此描述你的建议 + 谢谢,建议已成功发送 + 建议发送失败 (%s) + 在时间线上显示隐藏事件 + 私聊消息 + 正在等待…… + 正在加密缩略图… + 正在发送缩略图 (%1$s / %2$s) + 正在加密文件… + 正在发送文件 (%1$s / %2$s) + 文件%1$s 已被下载! + 消息编辑 + 未找到编辑 + 过滤对话…… + 找不到你要找的? + 创建新房间 + 发送新私聊消息 + 查看房间目录 + 名称或 ID (#example:matrix.org) + 启用在时间线中滑动回复 + 在主屏幕上添加未读通知选项卡。 + 链接已复制到剪贴板 + 正在创建房间… + 查看编辑历史 + 服务条款 + 可被其他人发现 + 使用机器人、桥接、小部件和贴纸包 + 身份服务器 + 断开身份服务器 + 配置身份服务器 + 更改身份服务器 + 你正在使用 %1$s 与你知道的现有联系人相互发现。 + 你当前未使用身份服务器。若要与你知道的现有联系人相互发现,请在下方配置。 + 可发现的电子邮件地址 + 发现选项将在你添加电子邮件地址后出现。 + 发现选项将在你添加电话号码后出现。 + 与你的身份服务器断开连接意味着你将不会被其他用户发现,并且你将无法通过电子邮件或电话邀请其他人。 + 可发现电话号码 + 我们向%s发送了一封电子邮件,请检查你的电子邮件并点击确认链接 + 我们向 %s 发送了一封电子邮件,请先检查你的电子邮件并点击确认链接 + 输入身份服务器 URL + 无法连接到身份服务器 + 请输入身份服务器 url + 身份服务器无服务条款 + 你选择的身份服务器无任何服务条款。仅在你信任服务所有者时继续 + 已向 %s 发送文字消息。请输入它包含的验证码。 + 验证码不正确。 + 你当前在身份服务器 %1$s 上共享电子邮件地址或电话号码。你需要重新连接到 %2$s 才能停止共享它们。 + 同意身份服务器 (%s) 服务条款使你可以通过电子邮件地址或电话号码被发现。 + 启用详细日志。 + 详细日志将通过在你发送愤怒摇动(RageShake)时提供更多日志来帮助开发人员。即使启用,应用程序也不会记录消息内容或任何其他私人数据。 + 接收你的家服务器条款和条件后请重试。 + 服务器似乎响应时间太长,这可能是由于连接不良或服务器错误引起的。请稍后再试。 + 发送附件 + 打开导航菜单 + 打开创建房间菜单 + 关闭创建房间菜单… + 创建新的私聊对话 + 创建新房间 + 关闭密钥备份横幅 + 跳到底部 + %1$s,%2$s 和 %3$s 已读 + %1$s 和 %2$s 已读 + %s 已读 + + %d 个用户已读 + + 文件 + 联系人 + 相机 + 相册 + 贴纸 + 无法处理共享数据 + 媒体 + 此房间中暂无媒体 + 文件 + %1$s 于 %2$s + 此房间中暂无文件 + 垃圾信息 + 不合适的内容 + 自定义报告…… + 报告此内容 + 报告此内容的理由 + 报告 + 忽略用户 + 内容已报告 + 此内容已报告。 +\n +\n如果你不希望再看到此用户的更多内容,你可以忽略他们以隐藏他们的信息。 + 报告为垃圾信息 + 此内容已报告为垃圾信息。 +\n +\n如果你不希望再看到此用户的更多内容,你可以忽略他们以隐藏他们的信息。 + 报告为不合适的内容 + 此内容已报告为不合适。 +\n +\n如果你不希望再看到此用户的更多内容,你可以忽略他们以隐藏他们的消息。 + 忽略用户 + 全部消息(嘈杂) + 全部消息 + 仅提到我的 + 静音 + 设置 + 添加到收藏 + 从收藏中移除 + 离开房间 + %1$s 未做更改 + 你未做更改 + 你未忽略任何用户 + 长按房间查看更多选项 + %1$s 将房间设为对任何知道链接的用户公开。 + 你将房间设为对任何知道链接的用户公开。 + %1$s 将房间设为仅限邀请。 + 你将房间设为仅限邀请。 + 未读消息 + 这是你的对话。它只属于你。 + 与人们私聊或群聊 + 通过加密保证对话私密 + 扩展 & 自定义你的体验 + 开始吧 + 选择服务器 + 就像电子邮件,账户有一个家,尽管你可以与任何人聊天 + 在最大的公共服务器上免费加入数百万用户 + 面向组织的高级托管 + 了解更多 + 其他 + 自定义 & 高级设置 + 继续 + 连接到 %1$s + 连接到 Element Matrix 服务 + 连接到自定义服务器 + 登录 %1$s + 注册 + 登录 + 使用单点登录继续 + Element Matrix 服务地址 + 地址 + 面向组织的高级托管 + 输入 Modular Element 或你想使用的服务器地址 + 输入你想使用的服务器的地址 + 载入页面时出错:%1$s (%2$d) + 应用无法登录到此家服务器。家服务器支持以下登录类型:%1$s。 +\n +\n你想要通过网页客户端登录吗? + 抱歉,此服务器不接受新账户。 + 应用无法在此服务器上创建账户。 +\n +\n你想要通过网页客户端注册吗? + 此电子邮件地址未关联到任何账户。 + 在 %1$s 上重置密码 + 验证邮件将发送到你的收件箱以确认设置你的新密码。 + 下一个 + 电子邮件 + 新密码 + 警告! + 更改你的密码将重置所有会话上的端到端加密密钥,从而使加密聊天记录无法读取。在重设密码之前,请设置“密钥备份”或从另一个会话中导出房间密钥。 + 继续 + 此电子邮件地址未链接到任何账户 + 检查你的收件箱 + 验证电子邮件已发送到 %1$s。 + 点击链接以确认你的新密码。跟随包含的链接验证后,请点击下方。 + 我已验证我的电子邮件地址 + 成功! + 你的密码已重置。 + 你已登出全部会话,不会再接收到推送通知。若要重新启用通知,请在每个设备上再次登录。 + 返回登录 + 警告 + 你的密码尚未更改。 +\n +\n是否中止密码更改过程? + 设置电子邮件地址 + 设置电子邮件地址以用于恢复你的账户。之后,你可以选择允许你认识的人通过此地址发现你。 + 电子邮件 + 电子邮件(可选) + 下一个 + 设置电话号码 + 设置电话号码,以选择允许你认识的人发现你。 + 请使用国际格式。 + 电话号码 + 电话号码(可选) + 下一个 + 确认电话号码 + 我们向 %1$s 发送了验证码。在下方输入它以验证你的身份。 + 输入验证码 + 重新发送 + 下一个 + 国际电话号码必须以“+”开头 + 电话号码似乎无效。请检查 + 在 %1$s 上注册 + 用户名或电子邮件 + 用户名 + 密码 + 下一个 + 该用户名已被使用 + 警告 + 你的账户尚未创建。是否中止注册过程? + 选择 matrix.org + 选择 Element Matrix Services + 选择自定义家服务器 + 请进行人机验证 + 接受条款以继续 + 请检查你的电子邮件 + 我们向 %1$s 发送了电子邮件。 +\n请点击其中包含的链接继续账户创建。 + 输入的验证码不正确。请检查。 + 过时的家服务器 + + 发送了太多请求。你可以在 %1$d 秒后重试… + + 使用 Matrix ID 登录 + 使用 Matrix ID 登录 + 如果你在家服务器上设置了账户,在下方使用你的 Matrix ID(例 @user:domain.com)和密码。 + Matrix ID + 如果你不知道你的密码,返回并重置。 + 这不是有效的用户标识符。预期格式:\'@user:homeserver.org\' + 无法找到有效的家服务器。请检查你的标识符 + 你已登出 + 这可能由于多种原因: +\n +\n• 你已在其它会话中更改了你的密码。 +\n +\n• 你已从其它会话删除了此会话。 +\n +\n• 你的服务器管理员出于安全原因已取消你的访问权限。 + 重新登录 + 你已登出 + 登录 + 你的家服务器 (%1$s) 管理员将你从你的账户 %2$s (%3$s) 登出。 + 登录以恢复仅存储在此设备上的加密密钥。 你需要使用它们在任何设备上阅读所有安全消息。 + 登录 + 密码 + 清除个人数据 + 警告:你的个人数据(包括加密密钥)仍存储在此设备上。 +\n +\n如果你不再使用此设备,或想登录另一个账户,请清除它。 + 清除全部数据 + 清除数据 + 是否清除当前存储在此设备上的全部数据? +\n再次登录以访问你的账户数据和消息。 + 除非你登录以恢复加密密钥,否则你将无法访问安全消息。 + 当前会话用于用户 %1$s 而你提供了用户 %2$s 的凭证。${app_name} 不支持此功能。 +\n请先清除数据,然后重新登录另一个账户。 + 你的 matrix.to 链接格式错误 + 描述太短 + 初始同步… + 高级设置 + 开发者模式 + 开发者模式激活隐藏的功能,也可能使应用不稳定。仅供开发者使用! + 愤怒摇动(Rageshake) + 检测阈值 + 摇动手机以测试检测阈值 + 检测到摇动! + 设置 + 当前会话 + 其它会话 + 仅显示第一个结果,请输入更多字符… + 快速失败(Fail-fast) + 发生意外错误时,${app_name} 可能更经常崩溃 + 在明文消息前添加 ¯\\_(ツ)_/¯ + 启用加密 + 启用后,无法禁用加密。 + 你的电子邮件域无权注册此服务器 + 未信任的登录 + 匹配 + 不匹配 + 不安全 + 以下其中一项可能会受到威胁: +\n +\n - 你的家服务器 +\n - 你验证的用户连接到的家服务器 +\n - 你或其他用户的网络连接 +\n - 你或其他用户的设备 + 视频。 + 图片。 + 音频 + 文件 + 贴纸 + 正在等待…… + %s已取消 + 你已取消 + %s 已接受 + 你已接受 + 验证已发送 + 验证请求 + 验证此会话 + 使用其他用户的设备扫描此码以安全地相互验证 + 扫描他们的码 + 无法扫描 + 如果你不在现场,请比较表情符号 + 通过比较表情符号验证 + 验证 %s + 已验证 %s + 正在等待%s…… + 此房间的消息未经端到端加密。 + 该房间的消息已端到端加密。 +\n +\n你的消息受加密保护,并且只有你和消息接收者拥有唯一解密密钥。 + 安全 + 了解更多 + 更多 + 管理员操作 + 房间设置 + 通知 + + %1$d 人 + + 上传 + 离开房间 + 正在离开房间…… + 管理员 + 协管员 + 自定义 + 邀请 + 用户 + %1$s里的管理员 + %1$s里的协管员 + %1$s里的默认 + %2$s里的自定义(%1$d) + ${app_name} 无法处理类型为 \'%1$s\' 的事件 + ${app_name} 在呈现 ID 为“%1$s”的事件内容时遇到问题 + 取消忽略 + 该会话无法与你的其它会话共享此验证。 +\n验证将保存在本地,并在此应用的未来版本中共享。 + 给给定的消息和彩虹一样上色后发送 + 和彩虹一样给给定的表情上色后发送 + 时间线 + 消息编辑器 + 启用端到端加密…… + 是否启用加密? + 房间加密一经启用,便无法禁用。在加密房间中,发送的消息无法被服务器看到,只能被房间的参与者看到。启用加密可能会使许多机器人和桥接无法正常运作。 + 启用加密 + 为保证安全,请核对一次性代码以验证 %s。 + 为保证安全,请当面验证,或者使用其它通讯方式验证。 + 比较独特表情,确保它们以相同顺序出现。 + 与其他用户设备上显示的代码比较。 + 与此用户的消息是端到端加密的,无法被第三方读取。 + 你的新会话已验证。它可以访问你的加密消息,其他用户会将其视为可信任。 + 交叉签名 + 已启用交叉签名 +\n设备上的私钥。 + 已启用交叉签名 +\n密钥可信任。 +\n私钥未知 + 已启用交叉签名。 +\n密钥未信任 + 未启用交叉签名 + 你的服务器管理员已默认禁用私有房间和私聊消息端到端加密。 + 可用会话 + 显示全部会话 + 管理会话 + 登出此会话 + 加密信息不可用 + 因为你已验证此会话,所以其在安全地收发消息上可受信任: + 验证此会话以将其标记为可信,并授予其访问加密消息的权限。如果你未登录此会话,则你的账户可能已被盗: + + %d 个活动会话 + + 验证此设备 + 使用现有会话来验证此会话,并授予其访问加密消息的权限。 + 验证 + 已验证 + 警告 + 无法获取会话 + 会话 + 可信任 + 未信任 + 可信任此会话用于安全地收发消息,因为%1$s(%2$s)已验证了它: + %1$s (%2$s) 使用新会话登录: + 在此用户信任此会话之前,发送到该会话和从该会话发送的消息均标有警告。或者,你可以手动进行验证。 + 初始化交叉签名 + 重置密钥 + QR码 + 快要完成了!%s 显示对勾了吗? + + + 到服务器的连接已丢失 + 飞行模式已打开 + 开发工具 + 账户数据 + 使用恢复口令词组或密钥 + 如果你无法访问已有会话 + 无法在存储中找到秘密 + 移除…… + 你想要发送此附件到 %1$s 吗? + + 发送原始尺寸图片 + + 确认移除 + 你确定要移除(删除)此事件吗?注意,如果删除房间名称或话题的更改,更改会被撤销。 + 附加理由 + 删除理由 + 事件被用户删除,理由:%1$s + ${app_name} Android + 密钥请求 + 解锁加密消息历史 + 刷新 + 新登录。是你吗? + 使用此会话验证新的会话,授权访问加密消息。 + 这不是我 + 你的账户可能已被盗用 + 如果你取消,你将无法在此设备上读取加密消息,其他用户不会信任它 + 如果你取消,你将无法在新设备上读取加密消息,其他用户不会信任它 + 如果你现在取消将不会验证 %1$s (%2$s)。在他们的用户个人档案中重新开始。 + 以下其中一项可能有风险: +\n +\n- 你的密码 +\n- 你的家服务器 +\n- 此设备或其它设备 +\n- 设备使用的网络连接 +\n +\n我们推荐你在设置中立即更换你的密码和恢复密钥。 + 已取消验证。 你可以重新开始验证。 + 验证已取消 + 恢复口令词组 + 消息密钥 + 输入你的 %s 以继续。 + 不要使用你的账户密码。 + 输入只有你知道的安全短语,用于保护服务器上的秘密。 + 这可能会花费数秒,请耐心等待。 + 设置恢复。 + 完成了! + 保持安全 + 完成 + 发布创建的身份密钥 + 从口令词组生成安全密钥 + 正在定义 SSSS 默认密钥 + 正在同步主密钥 + 正在同步用户密钥 + 正在同步自签名密钥 + 正在设置密钥备份 + 你的 %2$s 和 %1$s 已设置。 +\n +\n请安全地保管它。如果你丢失了全部活动会话你将需要使用它们解锁加密消息和安全信息。 + 将它打印出来并存放在安全的地方 + 将给定信息作为剧透发送 + 剧透 + 输入关键字以查找反应。 + 已读 + 跳至已读回执 + 事件被房间管理员删除,理由:%1$s + 密钥已是最新! + 保存到优盘或者备份盘 + 复制到你的个人云存储 + 如果你现在取消,那么当你失去登录权限时也会丢失加密的信息和数据。 +\n +\n你也可以通过设置菜单来建立保护备份以及管理你的密钥。 + 加密已开启 + 本房间的消息端到端加密。在成员用户资料中了解更多信息与验证成员。 + 加密未开启 + 不支持本房间使用的加密方式 + %s 创建并配置了房间。 + 你创建并配置了房间。 + 接近完成!另外的设备是否正显示对勾? + 接近完成!等候确认…… + 正在等候 %s… + 导入密钥失败 + 通知配置 + 一对一聊天的加密消息 + 群聊的加密消息 + 消息包含 @room + 当房间升级 + 故障诊断 + 以纯文本形式发送消息,而不将其解释为 markdown + 用户名和/或密码不正确。输入的密码以空格开头或结尾,请检查。 + 此账户已停用。 + 消息…… + 加密升级可用 + 验证你自己和其他人以保证你的聊天安全 + 输入你的 %s 以继续 + 使用文件 + 无效的恢复密钥 + 请输入恢复密钥 + 检查备份密钥 + 检查备份密钥 (%s) + 获取曲线密钥 + 从口令词组生成 SSSS 密钥 + 从口令词组生成 SSSS 密钥(%s) + 从恢复密钥生成 SSSS 密钥 + 正在在 SSSS 中保存密钥备份秘密 + 输入你的密钥备份口令词组以继续。 + 使用你的密钥备份恢复密钥 + 不知道你的密钥备份口令词组,你可以 %s。 + 密钥备份恢复密钥 + 阻止应用内屏幕截图 + 启用此设置会将 FLAG_SECURE 添加到所有活动项。重新启动应用程序以使更改生效。 + 无法保存媒体文件 + 设置新账户密码…… + 在你的其它设备上使用最新的 ${app_name}、${app_name} Web、${app_name} Desktop、${app_name} iOS、${app_name} for Android 或其他支持交叉签名的 Matrix 客户端 + ${app_name} Web +\n${app_name} Desktop + ${app_name} iOS +\n${app_name} Android + 或其它支持交叉签名的 Matrix 客户端 + 在你的其它设备上使用最新的 ${app_name}: + 强制丢弃加密房间中的当前出站群组会话 + 仅在加密房间中支持 + 使用你的 %1$s 或使用你的 %2$s 继续。 + 使用恢复密钥 + 选择你的恢复密钥,或手动输入或从剪贴板粘贴 + 访问安全存储失败 + 未加密 + 由未验证设备加密 + 验证访问你的账户的新登录:%1$s + 使用文本手动验证 + 验证登录 + 使用表情交互式验证 + 通过从你的其它会话验证此登录确认你的身份,授权它访问你的加密消息。 + 请选择用户名。 + 请选择密码。 + 仔细检查此链接 + 链接 %1$s 正在将你带到另一个站点:%2$s。 +\n +\n你确定想要继续吗? + 我们无法创建你的私聊消息。请检查你要邀请的用户并重试。 + 添加成员 + 邀请 + 正在邀请用户… + 邀请用户 + 邀请已发送到 %1$s + 邀请已发送到 %1$s 和 %2$s + + 邀请已发送到 %1$s 和 %2$d等 + + 我们无法邀请用户,请检查你想要邀请的用户并重试。 + 当前语言 + 其它可用语言 + 正在载入可用语言… + 打开 %s 条款 + 是否从身份服务器 %s 断开? + 身份服务器已过期。${app_name} 仅支持 API V2。 + 无法执行此操作。家服务器已过时。 + 请先配置身份服务器。 + 请先在设置中接受身份服务器的条款。 + 为了你的隐私,${app_name}仅支持发送经过哈希处理的用户电子邮件的和电话号码。 + 关联失败。 + 当前与此标识符没有关联。 + 你的家服务器(%1$s)建议使用 %2$s 作为你的身份服务器 + 使用 %1$s + 或者,你可以输入任何其它身份服务器网址 + 输入身份服务器 URL + 提交 + 设置角色 + 角色 + 打开聊天 + 静音麦克风 + 取消静音麦克风 + 停止相机 + 启动相机 + 安全备份 + 通过在你的服务器上备份加密密钥,防止失去对加密消息和数据的访问。 + 设置 + 使用安全密钥 + 生成安全密钥以存储在密码管理器或保险箱等安全位置。 + 使用安全短语 + 输入仅有你知道的秘密短语,生成备份用的密钥。 + 保存你的安全密钥 + 将你的安全密钥存储在安全的地方,例如密码管理器或保险箱。 + 设置安全短语 + 输入只有你知道的安全短语,用于保护你的服务器上的秘密。 + 安全短语 + 再次输入你的安全短语以确认。 + 房间名称 + 话题 + 你已成功更改房间设置 + 你无法访问此消息 + 正在等待此消息,可能会花费一些时间 + 由于端到端加密,你可能需要等待某人的消息到达,因为加密密钥未正确发送给你。 + 你无法访问此消息因为你已屏蔽此发送者 + 你无法访问此消息,因为你的会话不被发送者信任 + 你无法访问此消息因为发送者有意不发送密钥 + 正在等待加密历史 + Riot 现已成为 Element! + 我们很高兴地宣布我们已经更名了!你的应用程序是最新的,并且你已登录到你的账户。 + 明白了 + 了解更多 + 将恢复密钥保存到 + 正在获取你的联系人…… + 你的通讯录是空的 + 通讯录 + 撤销邀请 + 是否撤销对 %1$s 的邀请? + 被 %1$s 封禁 + 解封用户失败 + 推送通知已禁用 + 检查你的设置以启用推送通知 + 选择 PIN 以确保安全 + 确认 PIN + 验证 PIN 失败,请输入新的。 + 输入你的 PIN + 忘记 PIN? + 重置 PIN + 新 PIN + 为重置你的 PIN,你将需要重新登录并创建新的。 + 启用 PIN + 如果你想要重置你的 PIN,点按忘记 PIN 登出并重置。 + 防止意外通话 + 在开始通话之前要求确认 + 你没有权限在此房间发起会议通话 + 发起视频会议 + 发起音频会议 + 会议使用 Jitsi 安全和权限策略。 当前在会议室中的所有人都会在会议进行期间看到加入邀请。 + 你无法呼叫你自己 + 你无法与自己通话,请等待参与者接受邀请 + 添加小部件失败 + 移除小部件失败 + + 成功导入 %1$d/%2$d 个密钥。 + + 管理集成 + 没有活动的小部件 + 房间已创建,但由于以下原因一些邀请尚未发送: +\n +\n%s + + %1$s,%2$s 和其他 %3$d 人已读 + + + 错误代码,剩余 %d 次尝试 + + 警告!登出前最后一次尝试! + 错误次数过多,你已被登出 + 此电话号码已定义。 + 你的账户尚未添加电话号码 + 电子邮件地址 + 你的账户尚未添加电子邮件地址 + 电话号码 + 移除 %s? + 请确认你已点击我们向你发送的电子邮件中的链接。 + 电子邮件和电话号码 + 管理与你的 Matrix 账户链接的电子邮件地址和电话号码 + 代码 + 请使用国际格式(电话号码必须以“+”开头) + 验证此登录来确认你的身份,授权其访问加密消息。 + 无法打开你被封禁的房间。 + 无法找到此房间。请确认它存在。 + 你没有权限在此房间发起通话 + + %d 秒 + + 轮询 + 用%s回应 + 验证结果 + 是否删除类型 %1$s 的账户数据? +\n +\n小心使用,它可能导致意外行为。 + 链接格式不正确 + 每次打开 ${app_name} 时都需要 PIN 码。 + 未使用 ${app_name} 2 分钟后需要 PIN 码。 + 2 分钟后需要 PIN 码 + 仅在一个简单的通知中显示未读消息的数量。 + 显示详情,如房间名称和消息内容。 + 在通知中显示内容 + PIN 码是解锁 ${app_name} 的唯一方式。 + 启用设备特定的生物特征识别,如指纹和面部识别。 + 启用生物特征识别 + 配置保护 + 使用 PIN 和生物特征识别保护访问。 + 保护访问 + + 显示 %d 部设备,这些设备是你现在可以验证的 + + 你将重新启动,没有历史记录,消息,受信任的设备或受信任的用户 + 如果你重置一切 + 仅当没有其它设备可用来验证此设备时,才执行此操作。 + 全部重置 + 忘记或丢失了所有的恢复选项?重置一切 + 你已加入。 + %s 已加入。 + 此聊天的消息是端到端加密的。 + 离开 + 设置 + 此处的消息已端到端加密。 +\n +\n你的消息受加密保护,并且只有你和消息接收者拥有唯一解密密钥。 + 此处的消息未经端到端加密。 + 此家服务器正在运行旧版本。 请让你的家服务器管理员升级。 你可以继续,但某些功能可能无法正常工作。 + 你将此房间设为仅邀请。 + %1$s 仅发出此邀请。 + 在加密房间显示完整历史 + %1$s 和 %2$s + %1$s 条在 %2$s 和 %3$s 中 + + %d 个邀请 + + 通知已点击! + 请点击通知。如果你未看到通知,请检查系统设置。 + 通知显示 + 你正在查看通知!点我! + 接受推送失败。重装应用或可解决。 + 应用正在接受推送 + 应用正在等待推送 + 测试推送 + 过滤被封禁的用户 + 你没有权限发起通话 + 你没有权限发起会议通话 + 重置 + 允许访问你的联系人。 + 如需扫描QR码,你须允许相机访问权限。 + 没有更多结果 + 开始聊天 + 删除地址 \"%1$s\"? + 取消发布地址 \"%1$s\"? + 发布 + 手动发布新地址 + 其它发布的地址: + 这是主要地址 + 任何服务器上的任何人都可用发布的地址加入你的房间。一个地址必须先设置为本地地址才可发布。 + 发布的地址 + 查看和管理此房间的地址,以及它在房间目录中的可见性。 + 房间地址 + 房间访问权限 + 对谁可以阅读历史消息的变更只会应用于此房间未来的消息。已经存在的历史消息的可见性将不会改变。 + 发送密钥共享请求历史记录 + 取消发布 + 添加 + 设置交叉签名失败 + 发送落雪 ❄️ + 发送五彩纸屑 🎉 + 将下雪效果和给定消息一起发送 + 将给定的消息和五彩纸屑一起发送 + "话题: " + 添加一个话题 + %s让人们知道此房间是关于什么的。 + 这是你和%s的私聊消息历史的开始。 + 这是此对话的开始。 + 这是 %s 的开始。 + 导出审计 + 你没有权限在此房间启用加密。 + 私聊消息 + 正在创建房间… + 一些字符不被允许 + 请提供一个房间地址 + 此地址已被使用 + 若房间仅用于与你的家服务器上的内部团队协作,则你可以启用此选项。此选项之后无法更改。 + 阻止任何不属于%s的人加入此房间 + 隐藏高级 + 显示高级 + 清除历史记录 + 单点登录 + 通过 %s 登录 + 通过 %s 登录 + 以 %s 继续 + + 从低优先级移除 + 添加到低优先级 + %1$d / %2$d + 旋转和裁剪 + 添加图像自 + 授予许可 + 撤销我的许可 + 你已同意发送电子邮件地址和电话号码到身份服务器以从你的联系人发现其他用户。 + 发送电子邮件和电话号码 + 建议 + 已知用户 + QR码 + 通过QR码添加 + 房间设置 + 话题 + 房间话题(可选) + 房间名称 + 此房间无法预览。你想加入吗? + 目前无法访问此房间。 +\n请稍后重试,或询问房间管理员以确认你是否拥有访问权限。 + 无法获取当前房间目录可见性(%1$s)。 + 是否将此房间发布至 %1$s 的房间目录中? + 取消发布此地址 + 发布此地址 + 添加本地地址 + 此房间没有本地地址 + 为此房间设置地址以便用户通过你的家服务器(%1$s)找到此房间 + 本地地址 + 新的发布的地址(例如 #alias:server) + 尚无其它已发布地址。 + 还没有别的发布的地址,可在下方添加。 + 在消息框添加打开 emoji 键盘的按钮 + 显示 emoji 键盘 + 使用 /confetti 命令或发送包含 ❄️ 或 🎉 的消息 + 显示聊天特效 + 更改话题 + 升级房间 + 发送 m.room.server_acl 事件 + 更改权限 + 更改房间名称 + 更改历史记录可见性 + 启用房间加密 + 更改房间主要地址 + 更改房间头像 + 修改小部件 + 通知每个人 + 移除其他人发送的消息 + 封禁用户 + 移除用户 + 更改设置 + 邀请用户 + 发送消息 + 默认角色 + 你没有权限更新更改房间多个部分所需角色 + 选择更改房间各个部分所需的角色 + 权限 + 查看和更新更改房间各个部分所需的角色。 + 房间权限 + 此房间不公开。没有邀请,你将无法重新加入。 + 你保持通话 + %s 保持通话 + 保持 + 继续 + 未验证,缺少有效验证凭证 + 系统默认 + • 匹配 %s 的服务器现已被屏蔽。 + • 已封禁匹配 IP 地址的服务器。 + • 已允许匹配 IP 地址的服务器。 + • 匹配 %s 的服务器已被屏蔽。 + • 已允许匹配 %s 的服务器。 + 已勾选 + 已选中 + 可用通话(%1$s) + 需要重新验证 + 删除失败的消息 + 你确定要取消发送消息吗? + 消息发送失败 + 删除未发送的消息 + 你确定要删除此房间中所有未发送的消息吗? + 失败 + 状态事件已发送! + 事件已发送! + 事件格式错误 + 已发送 + 正在发送 + 事件内容 + 无内容 + 事件内容 + 类型 + 发送自定义状态事件 + 编辑内容 + 状态事件 + 发送状态事件 + 发送自定义事件 + 开发者工具 + 视频 + 验证失败 + 用户 + 回拨 + + %d 个条目 + + 这不是有效的 Matrix QR码 + 扫描QR码 + 添加人员 + 邀请朋友 + 服务器版本 + 服务器名称 + 切换 + 初始化同步: +\n正在下载数据… + 初始化同步: +\n正在等待服务器响应…… + 空房间(曾为 %s) + + %1$s,%2$s,%3$s 和 %4$d 位其他成员 + + %1$s,%2$s,%3$s 和 %4$s + %1$s,%2$s 和 %3$s + 设置头像 + 房间设置 + 房间版本 + 放弃修改 + 拨号键盘 + 转移 + 连接 + 删除头像 + 修改头像 + 图片 + 关闭 Emoji 选择器 + 打开 Emoji 选择器 + 可信信任等级 + 警告信任等级 + 默认信任等级 + 你修改了此房间的服务器访问控制列表。 + %s 修改了此房间的服务器访问控制列表。 + %s 为此房间设置了服务器访问控制列表。 + 你为此房间设置了服务器访问控制列表。 + 在 Matrix 上查找联系人 + 用户尚未同意条款。 + 共享此二维码,其他人扫描后即可添加你,并开始聊天。 + 我的二维码 + 共享我的二维码 + 消息类型缺失 + 检查房间状态 + 查看已读回执 + 关闭通知 + 无声通知 + 有声通知 + 有未发送的草稿 + 有些消息未被发送 + 从文件中导入密钥 + 发生错误,消息未能发送 + 状态键 + 有些房间可能被隐藏,因为其为私有房间,你需要得到邀请。 + 有些房间可能被隐藏,因为其为私有房间,你需要得到邀请。 +\n你没有权限添加房间。 + 此空间没有房间 + 请联系你的家服务器管理员以取得进一步资讯 + 看来你的家服务器尚未支持空间 + 想要使用实验功能? +\n你可以将现有的空间添加到其它空间中。 + 管理房间和空间 + 标记为不建议 + 标记为建议 + 建议 + 管理房间 + 正在寻找不在 %s 中的人? + %s 邀请了你 + 你被邀请 + 空间是把房间和人分组的新方式。 + 添加现有房间和空间 + 你是此空间唯一的管理员。离开就意味着没人能控制它。 + 除非你被重新邀请,否则你将无法重新加入。 + 你是这唯一的人。如果你离开,包括你在内的所有人都将无法加入此空间。 + 离开 + 添加房间 + 探索房间 + + 你认识的 %d 个人已加入 + + 此别名当前无法被访问。 +\n请稍后再试,或询问房间管理员你是否有权访问。 + 依然加入 + 加入空间 + 创建空间 + 暂且略过 + 加入我的空间 %1$s %2$s + 他们不会成为 %s 的一部分 + 刚到此房间 + 他们将可以探索 %s + 邀请至 %s + 共享链接 + 通过电子邮件进行邀请 + 此刻只有你。%s与他人一道会更好。 + 邀请至 %s + 邀请人们 + 邀请人们加入你的空间 + 描述 + 正在创建空间…… + 随机 + 一般性 + 让我们为他们每个人创建一个房间。 你也可以稍后添加更多内容,包括已经存在的内容。 + 你在做些什么? + 我们将会为此创建房间。你也可以在稍后增加更多。 + 你希望在 %s 中进行哪些讨论? + 为它取名以继续。 + 增加一些详细信息以帮助人们识别。你可以随时更改这些信息。 + 增加一些详细信息以帮助其脱颖而出。你可以随时更改这些详细信息。 + 创建空间 + 仅邀请,最适合你自己或团队 + 私有 + 对任何人开放,最适合社群 + 公开 + 供你和你的伙伴使用的私有空间 + 我和伙伴 + 用于整理你房间的私有空间 + 仅我 + 确保正确的人可以访问%s。 + 你与谁一同工作? + 要加入现有空间,你需要获得邀请。 + 你可以稍后更改 + 你想要创建哪种类型的空间? + 你的私有空间 + 你的公开空间 + 添加空间 + 离开给定id的房间(如果为null则为当前所处的房间) + 使用给定的id加入空间 + 创建空间 + 公开房间 + 未检查 + 打开小部件 + 屏幕截图 + ${app_name} 需要你输入凭据才能执行此操作。 + 呼叫转移时发生错误 + 先询问 + 查找电话号码时发生了错误 + 此通话已结束 + %1$s 拒绝了此通话 + 有未保存的更改。要放弃更改吗? + 房间尚未创建。取消创建房间? + 未扫描QR码! + 无效的QR码(无效的标识)! + 无法向你自己发送私聊消息! + 通过文字共享 + 更改你当前的 PIN + 更改 PIN + 🔐️ 在 ${app_name} 上加入我的行列 + 嗨,和我在 ${app_name} 上聊天吧:%s + 发送原始大小的媒体 + + 发送原始大小的视频 + + 限制未知。 + 你的家服务器能接受大小最大为 %s 的附件(文件、媒体等)。 + 服务器文件上传限制 + 此文件过大,无法上传。 + 搜索名称 + 正在压缩视频 %d%% + 正在压缩图片…… + 提供反馈 + 反馈发送失败(%s) + 感谢,你的反馈已成功送达 + 如果你有任何后续问题,可以联系我 + 你正在使用空间的测试版。你的反馈将有助于改善下一版本。我们将会记录你的平台和用户名以帮助我们尽我们所能多发挥你的反馈的作用。 + 反馈 + 空间反馈 + 离开当前会议并切换至另一个? + 抱歉,在尝试加入会议时发生了错误 + 所有在此空间中的人都可以找到并加入它。仅有此房间的管理员可以将其添加到空间中。 + 仅空间成员 + 任何人都能找到房间并加入 + 公开 + 仅有被邀请的人才能找到并加入 + 私有 + 未知的访问设置(%s) + 任何人都可以要求加入房间,成员可以接受或拒绝 + 允许访客加入 + 设置为默认值,并不再询问 + 总是询问 + 空间 + 显示房间目录中的所有房间,包括带有脏标的房间。 + 显示带有脏标的房间 + 房间目录 + 推荐的房间 + 新值 + 你更改了此房间的地址。 + %1$s 更改了此房间的地址。 + 你为此房间更改了主要和备用地址。 + %1$s 已为此房间更改了主要和备用地址。 + %1$s 更改了此房间的备用地址。 + 你已为此房间更改了备用地址。 + + 你已为此房间移除了备用地址 %1$s。 + + + %1$s 已为此房间移除了备用地址 %2$s。 + + + 你已为此房间添加了备用地址 %1$s。 + + + %1$s 已为此房间添加了备用地址 %2$s。 + + 消息已发送 + 🎉 所有服务器都被禁止参与!此房间已无法再使用。 + 无更改。 + • 已封禁匹配 IP 地址的服务器。 + • 现已允许匹配 IP 地址的服务器。 + • 已从允许列表中移除匹配 %s 的服务器。 + • 已允许匹配 %s 的服务器。 + • 已从封禁列表中移除匹配 %s 的服务器。 + 未命名的房间 + 私有空间 + 公开空间 + 陌生人 + 转移给 %1$s + 与 %1$s 商量 + 该服务器已经存在于列表中 + 找不到此服务器或它的房间列表 + 输入你想要探索的新服务器的名称。 + 添加一个新的服务器 + 你的服务器 + 抱歉,尝试加入 %s 时发生了一个错误 + 空间地址 + 查看和管理这个空间的地址。 + 空间地址 + 升级到推荐的房间版本 + 这个房间运行房间版本 %s,此家服务器已将其标记为不稳定。 + 你需要权限才能升级房间 + 自动更新空间父级 + 自动邀请用户 + 你将把此房间从 %1$s 升级到 %2$s。 + 升级房间是一项高级操作,通常建议在由于错误、缺少功能或安全漏洞造成房间不稳定时进行此操作。 +\n这通常只会影响此服务器如何处理该房间。 + 升级私人房间 + 升级公共房间 + 升级 + 请耐心等待,这可能需要一些时间。 + 加入替换房间 + 将房间升级到新版本 + 不稳定 + 稳定 + 默认版本 + 房间版本 👓 + 通过比较表情符号来验证 + 使用此设备扫描 + 使用其它设备扫码或切换并使用本设备扫码 + 家服务器API URL + 缺少权限 + 要执行此操作,请从系统设置中授予相机权限。 + 缺少执行此操作的某些权限,请从系统设置中授予权限。 + + %d 个未接视频电话 + + + %d 个未接音频电话 + + 请注意,升级将使房间焕然一新。 所有当前消息都将保留在此存档的房间中。 + 主空间中的任何人都可以找到并加入此房间 - 无需手动邀请所有人。 你可以随时在房间设置中更改此设置。 + %s 中的任何人将可以查找并加入此房间 - 无需手动邀请所有人。 你可以随时在房间设置中更改此设置。 + 语音消息 (%1$s) + 语音消息处于活动状态时无法回复或编辑 + 无法录制语音消息 + 无法播放此语音消息 + 点按你的录音以停止或收听 + 剩余 %1$d秒 + 按住录音,松开发送 + 删除录音 + 录制语音消息 + 暂停语音消息 + 播放语音消息 + 滑动取消 + 录制语音消息 + 需要升级 + 语音 + 你可能不知道的其它空间或房间 + 你知道的包含这个房间的空间 + 决定谁能找到并加入这个房间。 + 点按即可编辑空间 + 选择空间 + 决定哪些空间可以进入这个房间。 如果选择了一个空间,其成员将能够找到并加入房间名称。 + 可访问的空间 + 允许空间成员查找和访问。 + %s 空间的成员可找到、预览和加入。 + 私人(仅限邀请) + 要发送语音消息,请授予麦克风权限。 + 房间升级 + 机器人消息 + 房间邀请 + 加密的群组消息 + 群组消息 + 加密的私信 + 私信 + 我的用户名 + 我的显示名称 + 通知事项 + 其它 + 提及和关键词 + 默认通知 + 可用视频通话 + 可用语音通话 + 在 ${app_name} 中直接接收邀请的设置 %s。 + 将此电子邮件地址与你的账户链接 + 此空间的邀请已发送至与你的账户无关的 %s + 此房间的邀请已发送至与你的账户无关的 %s + 你所在的全部房间将显示在主页上。 + 在主页上显示所有房间 + 滑动结束通话 + %1$s 轻按返回 + 可用通话 (%1$s) · + + %1$d 个可用通话· + + 无应答 + 未接视频通话 + 未接语音通话 + 视频通话被拒绝 + 语音通话被拒绝 + 视频通话已结束 • %1$s + 语音通话已结束 • %1$s + 视频来电 + 语音来电 + 你拒绝了此通话 + 账户设置 + 你可以管理 %1$s 中的通知。 + 请注意,提及和关键字通知在移动端的加密房间中不可用。 + 通知事项 + 在移动端的加密房间里,你不会收到提及和关键字的通知。 + 关键词 + \@房间 + 关键词不能包含 \'%s\' + 关键词不能以 \'.\' 开头 + 添加新关键词 + 你的关键词 + + 仅提及和关键词 + 正结束通话… + 无应答 + 你呼叫的用户正忙。 + 用户忙 + 与 %s 音频通话 + 和 %s 视频通话 + 来电响铃中… + 空间 + 将一个空间添加到你管理的任何空间。 + 添加现有空间 + 添加现有房间 + 你确定要离开 %s 吗? + 发现 (%s) + 完成设置 + 通过电子邮件邀请、寻找联系人和更多… + 设置“发现”已毕。 + 你目前没有使用身份服务器。为了邀请队友并能让他们发现,在下方配置一个。 + 通过用户名或邮件邀请 + 确保只有合适的人能访问 %s 空间。稍后你可以邀请更多的人加入。 + 谁是你的队友? + 添加至给定的空间 + 创建空间中… + 显示一些有用的信息以帮助调试应用程序 + 在屏幕上显示调试信息 + 看起来不像是有效的邮箱地址 + 打开“发现”设置 + 按名称、ID或邮箱搜索 + 创建新空间 + 任何人均可找到此空间并加入 + 空间访问 + 谁可以访问? + 为 %s 启用电子邮件通知 + 要接收带有通知的电子邮件,请将电子邮件地址链接到你的 Matrix 账户 + 电子邮件通知 + 升级空间 + 更改空间名称 + 启用空间加密 + 更改空间主地址 + 更改空间头像 + 你没有权限更新更改该空间的各个部分所需的角色 + 选择更改该空间的各个部分所需的角色 + 查看和更新更改空间的各个部分所需的角色。 + 空间权限 + 解除禁令将允许被封禁的用户再次加入空间。 + 封禁用户会把他们移出此空间并阻止他们再次加入。 + 用户将从此空间移除。 +\n +\n为了防止他们再次加入,你应改为封禁他们。 + 停止录制 + 预置 ( ͡° ͜ʖ ͡°) 到纯文本消息 + 身份服务器未提供政策 + 隐藏身份服务器政策 + 显示身份服务器策略 + 显示用户信息 + 仅更改你在当前房间的头像 + 更改当前房间的头像 + 仅在当前房间更改你的显示昵称 + 设置房间名称 + 停止忽略用户,继续显示他们的消息 + 忽略用户,隐藏他们的消息 + 离开 + 离线 + 在线 + 选择家服务器 + 无法访问 URL %s 上的家服务器。请检查你的链接或手动选择一个家服务器。 + 侦听通知 + + 需要至少 %1$s 个选项 + + 问题不能为空 + 创建投票 + 添加选项 + 选项 %1$d + 创建选项 + 问题或话题 + 投票问题或话题 + 创建投票 + 投票 + 向%s发送电子邮件地址和电话号码 + 你的联系人是私密的。 要从你的联系人中发现用户,我们需要你的许可才能将联系信息发送到你的身份服务器。 + 已登出此会话! + 已离开此房间! + 你同意发送此信息吗? + 要发现现有的联系人,你需要将联系人信息(电子邮件地址和电话号码)发送到你的身份服务器。出乎隐私考量,我们会在发送前对你的数据进行散列处理。 + 不是现在 + 你确定要删除此投票吗?一旦移除,就无法恢复。 + 删除投票 + 投票已结束 + 投票 + 结束投票 + 这将使人们无法再投票,并将显示投票的最终结果。 + 结束此投票? + 结束投票 + + 基于 %1$d 票的最终结果 + + + 已投了 %1$d 票。投票以查看结果 + + + 基于 %1$d 票 + + + %1$d 票 + + 系统设置 + 版本 + 获取使用 ${app_name} 的帮助 + 帮助和支持 + 帮助 + 法律 + 此服务器不提供任何政策。 + 第三方库 + 你的身份服务器政策 + 我们记录任何账户数据或绘制任何账户数据的画像 + 你的家服务器政策 + ${app_name} 政策 + 你可以随时在设置中关闭它 + 我们与第三方共享信息 + 此处 + 通过共享匿名使用数据,帮助我们识别问题并改进 ${app_name}。为了理解人们如何使用多台设备,我们将生成一个随机标识符,由你的设备共享。 +\n +\n你可以阅读我们所有的条款 %s。 + 帮助改进 ${app_name} + 启用 + 你不能加入这个房间 + + 修改服务器 %d 的 ACLs + + 消息列帮助你的对话不离题且易于跟踪。 + 显示当前房间的所有消息列 + 所有消息列 + 过滤器 + 消息列 + 过滤房间中的消息列 + 复制消息列的链接 + 在房间中查看 + 房间通知 + 我们越来越接近发布消息列的公共 Beta 版。 +\n +\n在我们为此做准备时,我们需要进行一些更改:在此之前创建的消息列将显示为常规回复。 +\n +\n这将是一次性的过渡,因为消息列现在是 Matrix 规范的一部分。 + + %1$d 更多 + + 请注意:这是使用临时实现的实验室功能。这意味着你将无法删除你的位置历史记录,即使你停止与此房间共享你的实时位置,高级用户也将能够看到你的位置历史记录。 + 当前网关:%s + 网关 + 提供反馈 + 为你的团队发送消息。 + 消息列 beta + 消息列 + 为所有消息显示最新资料信息(头像和显示名称)。 + 显示名称 + 选择显示名称 + 覆盖显示名称颜色 + 检查你的电子邮件。 + 电子邮件 + 一切由你掌控。 + BETA + 共享你的实时位置 + 缩放到当前位置 + 地图上选定位置的固定标记 + 无投票 + 验证你的电子邮件 + + %d 条消息已移除 + + 启用位置共享 + 实时位置共享 + 找不到端点。 + 当前端点:%s + 端点 + 目前正在使用 %s。 + 方式 + + 找到 %d 个方式。 + + 除了后台同步,没有发现其它方法。 + 找不到除了 Google Play 服务以外的方式。 + 可用方式 + 通知方式 + 后台同步 + Google 服务 + 选择如何接收通知 + 屏幕共享进行中 + ${app_name} 屏幕共享 + 用户 + 通知整个房间 + 显示更少 + 共享位置 + 显示消息气泡 + 共享位置 + 你需要拥有正确的权限才能在此房间中共享实时位置。 + 你没有权限共享实时位置 + %1$s 前已更新 + 临时执行:地点在房间历史中持续存在 + 启用实时位置共享 + 位置共享正在进行中 + ${app_name} 实时位置 + 剩余 %1$s + 停止 + 实时共享直到 %1$s + 查看实时位置 + 实时位置已结束 + 正在加载实时位置…… + 启用实时位置 + 加载地图失败 + 打开,用 + ${app_name} 无法访问你的位置。请稍后再试。 + ${app_name} 无法访问你的位置 + 在房间中查看 + MSC3061:为过去的消息共享房间密钥 + 在共享历史的加密房间中邀请时,加密历史将可见。 + 8 小时 + 1 小时 + 15 分钟 + 共享此位置 + 共享此位置 + 共享实时位置 + 共享实时位置 + 共享我当前的位置 + 共享我当前的位置 + 地图 + 位置 + 共享位置 + 结果仅在你结束投票后展示 + 封闭式投票 + 投票者一投票就能看到结果 + 开放式投票 + 投票类型 + 编辑投票 + 结果将在投票结束时可见 + 跳过此步 + 随时前往设置以更新你的用户资料 + 是时候给名称加一张脸了 + 添加用户资料图片 + 重发电子邮件 + 没有收到电子邮件? + 跟随发送到%s的说明 + 重新发送验证码 + 代码已发送到%s + 确认你的电话号码 + 登出所有设备 + 重设密码 + 确认其为8个字符或更多。 + 选择新密码 + 新密码 + %s会给你发送验证链接 + 确认码 + 电话号码 + %s需要验证你的账户 + 输入你的电话号码 + %s需要验证你的账户 + 输入你的email + 请仔细阅读%s的条款和政策 + 取得联系 + 你的服务器地址是什么?这就像你所有数据的家 + 个性化用户资料 + 端到端加密,不需要电话号码。没有广告和数据挖掘。 + Threads是一项正在进行中的工作,包含了新的、令人兴奋的即将推出的功能,例如改进的通知。我们乐意听到你的反馈! + 创建投票 + 打开联系人 + 发送贴纸 + 上传文件 + 发送图片和视频 + 打开相机 + 服务器政策 + Element Matrix Services (EMS) 是一种强大且可靠的托管服务,可实现快速、安全和实时的通信。 了解如何在 <a href=\"${ftue_ems_url}\">element.io/ems</a> + 想架设自己的服务器? + 服务器URL + 选择你的服务器 + 还不确定?%s + 社群 + 团队 + 我们会帮你建立连接 + 你会与谁聊最多? + ${app_name}也非常适合工作场所。受到世界上最安全的组织信任。 + 选择保存你的对话的位置,给予你控制权和独立性。通过 Matrix 连接。 + 安全且独立的通信,为你提供和在家中面对面对话同样等级的隐私。 + 安全传送消息。 + 向家服务器注册端点token失败: +\n%1$s + 消息列有助于使你的对话保持话题并易于跟踪。%s 创建消息列将刷新应用程序。对于某些账户,这可能需要更长的时间。 + 重启应用以使更改生效。 + 启用 LaTeX 数学 + (%1$s) + %1$s(%2$s) + 无法播放%1$s + 暂停%1$s + 播放%1$s + %1$d分钟%2$d秒 + %1$s、%2$s、%3$s + 显示最新用户信息 + 注意:应用将重启 + 启用消息列消息 + 当无法解密的错误出现时,你的系统会自动发送日志 + 自动报告解密错误。 + 一些结果可能被隐藏,因为它们是私有的,你需要它们的邀请。 + 找不到结果 + 不离开 + 离开全部 + 此空间里的东西 + + 无法启用生物特征识别。 + 生物特征识别被禁用,因为最近添加了新的生物特征识别方法。 你可以在“设置”中再次启用它。 + 家服务器不接收仅有数字的用户名。 + 发送你的第一条消息邀请%s聊天 + 加密配置错误 + 此聊天中的消息会端到端加密。 + 还原加密 + 请联系管理员将加密还原到有效状态。 + 加密被错误地配置了。 + 共享了他们的实时位置 + 共享了他们的位置 + 无法打开此链接:社群已被空间取代 + 我已经有账户了 + 创建账户 + 保存并继续 + 看起来不错! + 走吧 + 你可以稍后更改这个 + 用户名/电子邮件/电话号码 + 你是人类吗? + 按照发送到%s的操作说明 + 密码重设 + 忘记密码 + 欢迎回来! + 编辑 + + 你的对话将进行的地方 + 必须有8个及以上的字符 + 其他人可以通过 %s 发现你 + 创建你的账户 + 恭喜! + 你的账户%s已创建 + 带我回家 + 连接服务器 + 想要加入已有的服务器? + 跳过此问题 + 家人和朋友 + 拥有你的对话。 + 位置 + Threads Beta反馈 + BETA + 重设通知方式 + 资料标签: + 你已经在查看这个消息列了! + 出发 + 在消息列中回复 + 备份具有来自该用户的有效签名。 + 命令“%s”可被识别但在消息列中不被支持。 + 使用系统默认值 + 手动选择 + 自动设置 + 选择字体大小 + 若启用,即使正在使用应用,你也会对其他用户显示为离线状态。 + 离线模式 + 在场 + 动画图片一出现就在时间线中播放 + Threads Beta + ${app_name} needs to perform a clear cache to be up to date, 原因如下: +\n%s +\n +\n注意,此操作会重启应用并可能需要一些时间。 + 自动播放动画图片 + 端点成功注册到家服务器。 + 端点注册 + 你的家服务器当前不支持消息列,因此此功能可能不可靠。某些消息列的消息可能无法可靠地使用。 %s 你仍然要启用消息列吗? + Threads接近Beta了 🎉 + 来自消息列 + 实用提示:长按消息并使用“%s”。 + 使用消息列来保持讨论的条理性 + 显示你参与的所有消息列 + 我的消息列 + 加密被错误地配置了,所以你无法发送消息。点击以打开设置。 + 加密被错误地配置了,所以你无法发送消息。请联系管理员将加密还原到有效的状态。 + %1$s、%2$s 与其他人 + %1$s与%2$s + 共享屏幕 + 停止共享屏幕 + 下一步 + 进一步了解 + 试试看 + 停用 + 查看消息列 + + 分钟 + 小时 + - 一些用户已被取消忽略 + 初始同步请求 + + %1$s 与其他 %2$d人 + + 正在更新你的数据…… + 自动允许 Element 通话小部件并授予相机/麦克风访问权限 + 启用 Element 通话权限快捷方式 + 实时位置 + 此QR码看起来格式不正确。请尝试使用其它方法进行验证。 + 你无法访问加密消息历史。重置你的安全消息备份和验证密钥以重新开始。 + 无法验证此设备 + 你的服务器地址是什么? + 你的对话发生的地方 + %1$s 和 %2$s + 电子邮件未验证,请检查你的收件箱 + 无法加载地图 +\n此家服务器可能没有设置显示地图。 + 打开设置 + 全部聊天 + 为获得最佳安全性,请验证你的会话,并从任何你不认识或不再使用的会话登出。 + 其它会话 + 会话 + 打开空间列表 + 创建新对话或房间 + + 收藏 + 未读 + 全部 + A—Z + 活动 + 排序方式 + 显示最近 + 显示过滤条件 + 布局偏好 + 探索房间 + 创建房间 + 开始聊天 + 抱歉,未发现此房间。 +\n请晚些重试。%s + 未验证 · 上次活动 %1$s + 已验证 · 上次活动 %1$s + 查看全部(%1$d) + 查看详情 + 验证会话 + 未验证的会话 + 已验证的会话 + 未知的设备类型 + 邀请 + 移动设备 + Web + 桌面 + 更改空间 + 尚无空间。 + 没有新的东西。 + 你的新请求和邀请会在这里。 + + 闲置 %1$d+ 天 (%2$s) + + 安全建议 + 按照这些建议改善你的账户安全。 + 未验证的会话 + 验证未验证的会话或从之登出。 + 闲置会话 + + 请考虑从不再使用的旧会话(%1$d天或更久)登出。 + + 欢迎来到 ${app_name}, +\n%s。 + 当你有一些未读消息时,这里会显示你的未读消息。 + 提供反馈 + 点击右上角查看反馈选项。 + 试用 + 空间是对房间和人进行分组的新方式。创建一个空间来开始吧。 + 启用新布局 + IP地址 + 验证你的会话以增强安全消息传递或从你不再识别或不再使用的会话中登出。 + 尚未准备好安全收发消息 + 准备好安全收发消息 + 已验证 + 全部会话 + 过滤器 + 上次活动 %1$s + 设备 + 会话 + 当前会话 + 验证你的会话以增强消息传输的安全性。 + 访问你的空间(右下角)比以前更快、更容易。 + 此会话已准备好安全地收发消息。 + 你当前的会话已准备好安全地收发消息。 + 仅在首条消息创建私聊消息 + 启用延迟的私聊消息 + 简化的 Element,带有可选的标签 + 无痕键盘 + 请求键盘不要根据你在对话中输入的内容更新任何个性化数据,例如输入历史记录和字典。 请注意,某些键盘可能不遵守此设置。 + ${app_name}需要权限来显示通知。通知可以显示消息、邀请等。 +\n +\n请在下个弹窗允许访问以便查看通知。 + 试用富文本编辑器(纯文本模式即将到来) + 启用富文本编辑器 + 折叠 %s 子空间 + 展开 %s 子空间 + 启用新的会话管理器 + 访问空间 + 欢迎使用新视图! + ⚠ 此房间里有未经验证的设备,它们将无法解密你发送的消息。 + 永远不要向这个房间里未经验证的会话发送加密的消息。 + %s +\n看起来有点空荡荡的。 + 能够在房间时间线中录制和发送语音广播。 + 启用语音广播 + 记录客户端名称、版本和网址,以便在会话管理器中更轻松地识别会话。 + 启用客户端信息记录 + 对所有会话有更好的可见性和控制。 + 你加入的私聊消息和房间中的其他用户可以查看你的会话的完整列表。 +\n +\n这让他们确信他们真的在与你交谈,但这也意味着他们可以看到你在此处输入的会话名称。 + 重命名会话 + 闲置会话是你一段时间未使用的会话,但它们会继续接收加密密钥。 +\n +\n删除闲置会话可以提高安全性和性能,并使你更容易识别新会话是否可疑。 + 闲置会话 + 你可以使用此设备通过QR码登录移动设备或网络设备。 有两种方法可以做到这一点: + 使用QR码登录 + 请注意,与你交流的人也可以看到会话名称。 + 自定义会话名称可以帮助你更轻松地识别你的设备。 + 重命名会话 + 操作系统 + 型号 + 浏览器 + 网址 + 版本 + 名称 + 应用 + 上次活动 + 会话名称 + 接收有关此会话的推送通知。 + 推送通知 + 应用程序、设备和活动信息。 + 会话详情 + 登出此会话 + 清除过滤器 + 未找到闲置会话。 + 未找到未验证的会话。 + 未找到已验证的会话。 + + 考虑登出你不再使用的旧会话(%1$d 天或更长时间)。 + + 闲置 + 未验证 + 为获得最佳安全性,请从你不认识或不再使用的任何会话中登出。 + 已验证 + 过滤器 + + 闲置 %1$d 天或更长时间 + + 未验证 + 未验证 · 你当前的会话 + 验证你当前的会话以显示此会话的验证状态。 + 未知的验证状态 + 开始语音广播 + 正在缓冲…… + 暂停语音广播 + 实时 + 知道了 + 应用下划线格式 + 应用删除线格式 + 应用斜体格式 + 应用粗体格式 + 请确保你知道此代码的来源。 通过链接设备,你将为某人提供对你账户的完全访问权限。 + 确认 + 再试一次 + 不匹配? + 登录 + 连接到设备 + 扫描QR码 + 登录移动设备? + 在此设备中显示QR码 + 选择“扫描QR码” + 从登录屏幕开始 + 选择“使用QR码登录” + 从登录屏幕开始 + 选择“显示QR码” + 转到设置 -> 安全和隐私 + 在你的其它设备上打开应用程序 + 家服务器不支持QR码登录。 + 登录已在另一台设备上取消。 + 该QR码无效。 + 另一台设备必须登录。 + 另一台设备已登录。 + 链接未在规定时间内完成。 + 设置安全消息传递时遇到安全问题。 以下其中一项可能会受到损害:你的家庭服务器; 你的互联网连接; 你的设备; + 请求失败。 + 该请求在另一台设备上被拒绝。 + 不支持与此设备链接。 + 连接不成功 + 检查你已登录的设备,应显示以下代码。 确认以下代码与该设备匹配: + 已建立安全连接 + 使用已退出登录的设备扫描下方QR码。 + 使用你已登录的设备扫描下方QR码: + 使用QR码登录 + 使用此设备上的相机扫描其它设备上显示的QR码: + 扫描QR码 + 3 + 2 + 1 + 为了简化你的 ${app_name},选项卡现在是可选的。 使用右上角的菜单管理它们。 + 无需报告。 + 适用于团队、朋友和组织的一体化安全聊天应用程序。 创建一个聊天或加入一个现有的房间来开始。 + 空间是一种对房间和人员进行分组的新方式。 使用右下角的按钮添加现有房间或创建新房间。 + 已验证会话 + 未验证会话是使用你的凭据登录但未经交叉验证的会话。 +\n +\n你应特别确定你识别这些会话,因为它们可能代表未经授权使用你的账户。 + 未验证会话 + 闲置 + 会话名称 + 验证或登出此会话以获得最佳安全性和可靠性。 + 播放或恢复语音广播 + 此设备无法保证此加密消息的真实性。 + 将 (╯°□°)╯︵ ┻━┻ 添加到纯文本消息中 + ${app_name} 需要显示通知的权限。 +\n请授予权限。 + 打开开发者工具屏幕 + 🔒 你已在安全设置中为所有房间启用了仅对已验证会话加密。 + 授予权限 + 停止语音广播录制 + 暂停语音广播录制 + 继续语音广播录制 + 扫描QR码 + 语音广播 + 已启用: + 会话ID: + 出了点差错。请检查你的网络连接并重试。 + 联系人 + 切换全屏模式 + 选择会话 + 文本格式 + 相机 + 位置 + 投票 + 语音广播 + 附件 + 贴纸 + 照片库 + 你没有在此房间内开始语音广播所需的权限。联系房间管理员升级你的权限。 + 其他人已经在录制语音广播。等待他们的语音广播结束以开始新的广播。 + 你已经在录制语音广播。请结束你当前的语音广播以开始新的语音广播。 + 无法开始新的语音广播 + 快进 30 秒 + 快退 30 秒 + 取消全选 + 全选 + + 已选择 %1$d + + 已创建投票。 + 已发送贴纸。 + 已发送视频。 + 已发送图片。 + 已发送语音消息。 + 已发送音频文件。 + 已发送文件。 + 已验证的会话是在输入你的口令词组或用另一个已验证的会话确认你的身份之后你使用此账户的任何地方。 +\n +\n这意味着你拥有解锁你的已加密消息和向其他用户证明你信任此会话所需的全部密钥。 + + 登出%1$d个会话 + + 登出 + 剩余%1$s + 正在编辑 + 回复给%s + 引用 + 显示IP地址 + 隐藏IP地址 + 回复给 + 启用直接分享 + 在系统分享菜单中显示最近聊天 + 复查以确保你的账户是安全的 + 你有未验证的会话 + 登出全部其他会话 + 这个会话不支持加密,因此不能被验证。 + 获取最新构建(注意:你可能在登录时遇到麻烦) + 实时广播 + Nightly构建 + 你结束了一个语音广播。 + %1$s结束了一个语音广播。 + 停止实时广播? + 无法播放此语音广播。 + 你无法启动语音消息因为你正在录制实时广播。请终止实时广播以开始录制语音消息 + 无法启动语音消息 + 结束了投票。 + 你的访问令牌提供对你账户的完全访问权限。勿与任何人分享它。 + 访问令牌 + 继续重设 + %1$s更改了其显示名称为%2$s + 账户 + 是的,停止 + 无法连接家服务器。若仍登出,此设备将不会从设备列表擦除,你或许想用另一个客户端移除它。 + 无论如何都要登出 + 你的家服务器还不支持列出消息列。 + 空间%1$s的头像 + 房间%1$s的头像 + 用户%1$s的用户资料图片 + 可接受的使用政策 + 正在等待用户加入${app_name} + 正从安全密钥或短语验证…… + 投票历史 + 应用已更新 + 验证你的身份以访问加密消息并向他人证明你的身份。 + 发送至和发送自此会话的消息带有警告标签,直至此用户信任此会话。 + 更新你的通知偏好时出错。请再试一次。 + 你的账户详细信息于%1$s单独管理。 + 加密版本 + 用另一设备验证 + 你一次仅能邀请一个电子邮件 + 开始语音广播 + 继续 + 已结束投票 + 投票 + 过去的投票 + 消息 + 加载更多投票 + 链接 + 创建链接 + 编辑链接 + 切换无序列表 + 房间/空间 + 进行中的投票 + 取消缩进 + 文本 + 已结束投票。 + 缩进 + 设置链接 + 显示投票 + 切换引用 + 切换有序列表 + \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values-zh-rTW/strings.xml b/library/ui-strings/src/main/res/values-zh-rTW/strings.xml index 2b0a6c2d5b..8c51b44395 100644 --- a/library/ui-strings/src/main/res/values-zh-rTW/strings.xml +++ b/library/ui-strings/src/main/res/values-zh-rTW/strings.xml @@ -1301,9 +1301,9 @@ 確認移除 您確定要刪除此事件嗎?注意,如果您刪除聊天室名稱或主題的變更事件,該變更將被取消。 包含理由 - 修改原因 + 刪除原因 使用者刪除事件,理由:%1$s - 聊天室管理員管理了事件,理由:%1$s + 聊天室管理員刪除了事件,理由:%1$s 金鑰已為最新! ${app_name} Android 金鑰請求 @@ -2889,4 +2889,13 @@ 可接受的使用政策 繼續重設 加密版本 + %1$s 變更了他們的顯示名稱為 %2$s + 使用者 %1$s 的個人資料照片 + 聊天室 %1$s 的大頭貼 + 聊天空間 %1$s 的大頭貼 + 最新更新改善了安全訊息傳遞。請重新驗證您的裝置。 + 在該使用者信任該工作階段之前,發送到該工作階段與從該工作階段傳送的訊息都帶有警告標籤。 + 應用程式已更新 + 無法連線至家伺服器。若您仍要登出,此裝置將不會從您的裝置清單中移除,您可能需要使用其他客戶端來移除。 + 仍要登出 \ No newline at end of file diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index f4a18ee304..abf972766c 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -1730,6 +1730,8 @@ "Public" "Anyone will be able to join this room" "The room has been created, but some invitations have not been sent for the following reason:\n\n%s" + Unable to find profiles for the Matrix IDs listed below. Would you like to start a chat anyway?\n\n%s + Start chat anyway "An error occurred getting trust info" "An error occurred getting keys backup data" @@ -2484,7 +2486,8 @@ Yes No - Connectivity to the server has been lost + ${app_name} is not available + \nat the moment. Airplane mode is on Dev Tools @@ -2746,6 +2749,8 @@ Invitations sent to %1$s and %2$d more We could not invite users. Please check the users you want to invite and try again. + Unable to find profiles for the Matrix IDs listed below. Would you like to invite them anyway?\n\n%s + Invite anyway Scan a QR code Share my code diff --git a/library/ui-strings/src/main/res/values/strings_tchap.xml b/library/ui-strings/src/main/res/values/strings_tchap.xml index ed352b1f41..10efd93c50 100644 --- a/library/ui-strings/src/main/res/values/strings_tchap.xml +++ b/library/ui-strings/src/main/res/values/strings_tchap.xml @@ -112,4 +112,7 @@ Failed to verify your new session. + + + View the status of services diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index 52cc24d13c..02d6705844 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -17,7 +17,7 @@ buildscript { } } dependencies { - classpath "io.realm:realm-gradle-plugin:10.15.1" + classpath "io.realm:realm-gradle-plugin:10.16.0" } } @@ -63,7 +63,7 @@ android { // that the app's state is completely cleared between tests. testInstrumentationRunnerArguments clearPackageData: 'true' - buildConfigField "String", "SDK_VERSION", "\"1.6.2\"" + buildConfigField "String", "SDK_VERSION", "\"1.6.5\"" buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\"" buildConfigField "String", "GIT_SDK_REVISION_UNIX_DATE", "\"${gitRevisionUnixDate()}\"" @@ -190,7 +190,7 @@ dependencies { // Database implementation 'com.github.Zhuinden:realm-monarchy:0.7.1' - kapt 'dk.ilios:realmfieldnameshelper:2.0.0' + kapt project(":library:external:realmfieldnameshelper") // Shared Preferences implementation libs.androidx.preferenceKtx @@ -217,7 +217,7 @@ dependencies { implementation libs.google.phonenumber - rustCryptoImplementation("org.matrix.rustcomponents:crypto-android:0.3.9") + rustCryptoImplementation("org.matrix.rustcomponents:crypto-android:0.3.10") // rustCryptoApi project(":library:rustCrypto") testImplementation libs.tests.junit diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt index bb5618b816..61bd1b42ea 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt @@ -64,9 +64,15 @@ class DeactivateAccountTest : InstrumentedTest { // Test the error assertTrue( + "Unexpected deactivated error $throwable", throwable is Failure.ServerError && - throwable.error.code == MatrixError.M_USER_DEACTIVATED && - throwable.error.message == "This account has been deactivated" + ( + (throwable.error.code == MatrixError.M_USER_DEACTIVATED && + throwable.error.message == "This account has been deactivated") || + // Workaround for a breaking change on synapse to fix CI + // https://github.com/matrix-org/synapse/issues/15747 + throwable.error.code == MatrixError.M_FORBIDDEN + ) ) // Try to create an account with the deactivate account user id, it will fail (M_USER_IN_USE) diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt index 091ea0b7ea..6bb500ae77 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt @@ -99,6 +99,23 @@ class CommonTestHelper internal constructor(context: Context, val cryptoConfig: } } } + + @OptIn(ExperimentalCoroutinesApi::class) + internal fun runLongCryptoTest(context: Context, cryptoConfig: MXCryptoConfig? = null, autoSignoutOnClose: Boolean = true, block: suspend CoroutineScope.(CryptoTestHelper, CommonTestHelper) -> Unit) { + val testHelper = CommonTestHelper(context, cryptoConfig) + val cryptoTestHelper = CryptoTestHelper(testHelper) + return runTest(dispatchTimeoutMs = TestConstants.timeOutMillis * 4) { + try { + withContext(Dispatchers.Default) { + block(cryptoTestHelper, testHelper) + } + } finally { + if (autoSignoutOnClose) { + testHelper.cleanUpOpenedSessions() + } + } + } + } } internal val matrix: TestMatrix diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/RoomShieldTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/RoomShieldTest.kt new file mode 100644 index 0000000000..8e2284d588 --- /dev/null +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/RoomShieldTest.kt @@ -0,0 +1,133 @@ +/* + * Copyright 2023 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.crypto + +import android.util.Log +import androidx.lifecycle.Observer +import androidx.test.filters.LargeTest +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.junit.FixMethodOrder +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.junit.runners.MethodSorters +import org.matrix.android.sdk.InstrumentedTest +import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel +import org.matrix.android.sdk.api.session.getRoom +import org.matrix.android.sdk.api.session.room.model.RoomSummary +import org.matrix.android.sdk.api.util.Optional +import org.matrix.android.sdk.common.CommonTestHelper +import org.matrix.android.sdk.common.SessionTestParams +import org.matrix.android.sdk.common.TestConstants +import java.util.concurrent.CountDownLatch +import java.util.concurrent.TimeUnit + +@RunWith(JUnit4::class) +@FixMethodOrder(MethodSorters.JVM) +@LargeTest +class RoomShieldTest : InstrumentedTest { + + @Test + fun testShieldNoVerification() = CommonTestHelper.runCryptoTest(context()) { cryptoTestHelper, _ -> + val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom() + + val roomId = testData.roomId + + cryptoTestHelper.initializeCrossSigning(testData.firstSession) + cryptoTestHelper.initializeCrossSigning(testData.secondSession!!) + + // Test are flaky unless I use liveData observer on main thread + // Just calling getRoomSummary() with retryWithBackOff keeps an outdated version of the value + testData.firstSession.assertRoomShieldIs(roomId, RoomEncryptionTrustLevel.Default) + testData.secondSession!!.assertRoomShieldIs(roomId, RoomEncryptionTrustLevel.Default) + } + + @Test + fun testShieldInOneOne() = CommonTestHelper.runLongCryptoTest(context()) { cryptoTestHelper, testHelper -> + val testData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom() + + val roomId = testData.roomId + + Log.v("#E2E TEST", "Initialize cross signing...") + cryptoTestHelper.initializeCrossSigning(testData.firstSession) + cryptoTestHelper.initializeCrossSigning(testData.secondSession!!) + Log.v("#E2E TEST", "... Initialized.") + + // let alive and bob verify + Log.v("#E2E TEST", "Alice and Bob verify each others...") + cryptoTestHelper.verifySASCrossSign(testData.firstSession, testData.secondSession!!, testData.roomId) + + // Add a new session for bob + // This session will be unverified for now + + Log.v("#E2E TEST", "Log in a new bob device...") + val bobSecondSession = testHelper.logIntoAccount(testData.secondSession!!.myUserId, SessionTestParams(true)) + + Log.v("#E2E TEST", "Bob session logged in ${bobSecondSession.myUserId.take(6)}") + + Log.v("#E2E TEST", "Assert room shields...") + testData.firstSession.assertRoomShieldIs(roomId, RoomEncryptionTrustLevel.Warning) + // in 1:1 we ignore our own status + testData.secondSession!!.assertRoomShieldIs(roomId, RoomEncryptionTrustLevel.Trusted) + + // Adding another user should make bob consider his devices now and see same shield as alice + Log.v("#E2E TEST", "Create Sam account") + val samSession = testHelper.createAccount(TestConstants.USER_SAM, SessionTestParams(withInitialSync = true)) + + // Let alice invite sam + Log.v("#E2E TEST", "Let alice invite sam") + testData.firstSession.getRoom(roomId)!!.membershipService().invite(samSession.myUserId) + testHelper.waitForAndAcceptInviteInRoom(samSession, roomId) + + Log.v("#E2E TEST", "Assert room shields...") + testData.firstSession.assertRoomShieldIs(roomId, RoomEncryptionTrustLevel.Warning) + testData.secondSession!!.assertRoomShieldIs(roomId, RoomEncryptionTrustLevel.Warning) + + // Now let's bob verify his session + + Log.v("#E2E TEST", "Bob verifies his new session") + cryptoTestHelper.verifyNewSession(testData.secondSession!!, bobSecondSession) + + testData.firstSession.assertRoomShieldIs(roomId, RoomEncryptionTrustLevel.Trusted) + testData.secondSession!!.assertRoomShieldIs(roomId, RoomEncryptionTrustLevel.Trusted) + } + + @OptIn(DelicateCoroutinesApi::class) + private suspend fun Session.assertRoomShieldIs(roomId: String, state: RoomEncryptionTrustLevel?) { + val lock = CountDownLatch(1) + val roomLiveData = withContext(Dispatchers.Main) { + roomService().getRoomSummaryLive(roomId) + } + val observer = object : Observer> { + override fun onChanged(value: Optional) { + Log.v("#E2E TEST ${this@assertRoomShieldIs.myUserId.take(6)}", "Shield Update ${value.getOrNull()?.roomEncryptionTrustLevel}") + if (value.getOrNull()?.roomEncryptionTrustLevel == state) { + lock.countDown() + roomLiveData.removeObserver(this) + } + } + } + GlobalScope.launch(Dispatchers.Main) { roomLiveData.observeForever(observer) } + + lock.await(40_000, TimeUnit.MILLISECONDS) + } +} diff --git a/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt b/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt index 3090bb805e..e020946484 100644 --- a/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt +++ b/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt @@ -49,7 +49,6 @@ import org.matrix.android.sdk.internal.di.SessionId import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.di.WorkManagerProvider import org.matrix.android.sdk.internal.session.SessionScope -import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.util.JsonCanonicalizer import org.matrix.android.sdk.internal.util.logLimit import org.matrix.android.sdk.internal.worker.WorkerParamsFactory @@ -66,7 +65,6 @@ internal class DefaultCrossSigningService @Inject constructor( private val deviceListManager: DeviceListManager, private val initializeCrossSigningTask: InitializeCrossSigningTask, private val uploadSignaturesTask: UploadSignaturesTask, - private val taskExecutor: TaskExecutor, private val coroutineDispatchers: MatrixCoroutineDispatchers, private val cryptoCoroutineScope: CoroutineScope, private val workManagerProvider: WorkManagerProvider, @@ -612,9 +610,7 @@ internal class DefaultCrossSigningService @Inject constructor( withContext(coroutineDispatchers.crypto) { // This device should be yours val device = cryptoStore.getUserDevice(myUserId, deviceId) - if (device == null) { - throw IllegalArgumentException("This device [$deviceId] is not known, or not yours") - } + ?: throw IllegalArgumentException("This device [$deviceId] is not known, or not yours") val myKeys = getUserCrossSigningKeys(myUserId) ?: throw Throwable("CrossSigning is not setup for this account") diff --git a/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt b/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt index ce6e046de5..80f37a6c57 100644 --- a/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt +++ b/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorker.kt @@ -31,7 +31,7 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.isCrossSignedVerif import org.matrix.android.sdk.api.session.crypto.crosssigning.isVerified import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel import org.matrix.android.sdk.internal.SessionManager -import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore +import org.matrix.android.sdk.internal.crypto.CryptoSessionInfoProvider import org.matrix.android.sdk.internal.crypto.store.db.mapper.CrossSigningKeysMapper import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntity import org.matrix.android.sdk.internal.crypto.store.db.model.CrossSigningInfoEntityFields @@ -40,10 +40,7 @@ import org.matrix.android.sdk.internal.crypto.store.db.model.TrustLevelEntity import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntity import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields import org.matrix.android.sdk.internal.database.awaitTransaction -import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntity -import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFields import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity -import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.di.CryptoDatabase import org.matrix.android.sdk.internal.di.SessionDatabase @@ -83,35 +80,54 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses @Inject lateinit var myUserId: String @Inject lateinit var crossSigningKeysMapper: CrossSigningKeysMapper @Inject lateinit var updateTrustWorkerDataRepository: UpdateTrustWorkerDataRepository + @Inject lateinit var cryptoSessionInfoProvider: CryptoSessionInfoProvider // @Inject lateinit var roomSummaryUpdater: RoomSummaryUpdater - @Inject lateinit var cryptoStore: IMXCryptoStore +// @Inject lateinit var cryptoStore: IMXCryptoStore override fun injectWith(injector: SessionComponent) { injector.inject(this) } override suspend fun doSafeWork(params: Params): Result { - val userList = params.filename + val sId = myUserId.take(5) + Timber.v("## CrossSigning - UpdateTrustWorker started..") + val workerParams = params.filename ?.let { updateTrustWorkerDataRepository.getParam(it) } - ?.userIds - ?: params.updatedUserIds.orEmpty() + ?: return Result.success().also { + Timber.w("## CrossSigning - UpdateTrustWorker failed to get params") + cleanup(params) + } + + Timber.v("## CrossSigning [$sId]- UpdateTrustWorker userIds:${workerParams.userIds.logLimit()}, roomIds:${workerParams.roomIds.orEmpty().logLimit()}") + val userList = workerParams.userIds // List should not be empty, but let's avoid go further in case of empty list if (userList.isNotEmpty()) { // Unfortunately we don't have much info on what did exactly changed (is it the cross signing keys of that user, // or a new device?) So we check all again :/ - Timber.v("## CrossSigning - Updating trust for users: ${userList.logLimit()}") + Timber.v("## CrossSigning [$sId]- Updating trust for users: ${userList.logLimit()}") updateTrust(userList) } + val roomsToCheck = workerParams.roomIds ?: cryptoSessionInfoProvider.getRoomsWhereUsersAreParticipating(userList) + Timber.v("## CrossSigning [$sId]- UpdateTrustWorker roomShield to check:${roomsToCheck.logLimit()}") + var myCrossSigningInfo: MXCrossSigningInfo? + Realm.getInstance(cryptoRealmConfiguration).use { realm -> + myCrossSigningInfo = getCrossSigningInfo(realm, myUserId) + } + // So Cross Signing keys trust is updated, device trust is updated + // We can now update room shields? in the session DB? + updateRoomShieldInSummaries(roomsToCheck, myCrossSigningInfo) + cleanup(params) return Result.success() } private suspend fun updateTrust(userListParam: List) { + val sId = myUserId.take(5) var userList = userListParam - var myCrossSigningInfo: MXCrossSigningInfo? = null + var myCrossSigningInfo: MXCrossSigningInfo? // First we check that the users MSK are trusted by mine // After that we check the trust chain for each devices of each users @@ -123,7 +139,7 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses var myTrustResult: UserTrustResult? = null if (userList.contains(myUserId)) { - Timber.d("## CrossSigning - Clear all trust as a change on my user was detected") + Timber.d("## CrossSigning [$sId]- Clear all trust as a change on my user was detected") // i am in the list.. but i don't know exactly the delta of change :/ // If it's my cross signing keys we should refresh all trust // do it anyway ? @@ -153,7 +169,7 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses myUserId -> myTrustResult else -> { crossSigningService.checkOtherMSKTrusted(myCrossSigningInfo, entry.value).also { - Timber.v("## CrossSigning - user:${entry.key} result:$it") + Timber.v("## CrossSigning [$sId]- user:${entry.key} result:$it") } } } @@ -163,12 +179,12 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses // i have all the new trusts, update DB trusts.forEach { val verified = it.value?.isVerified() == true - Timber.v("[$myUserId] ## CrossSigning - Updating user trust: ${it.key} to $verified") + Timber.v("[$myUserId] ## CrossSigning [$sId]- Updating user trust: ${it.key} to $verified") updateCrossSigningKeysTrust(cryptoRealm, it.key, verified) } // Ok so now we have to check device trust for all these users.. - Timber.v("## CrossSigning - Updating devices cross trust users: ${trusts.keys.logLimit()}") + Timber.v("## CrossSigning [$sId]- Updating devices cross trust users: ${trusts.keys.logLimit()}") trusts.keys.forEach { userId -> val devicesEntities = cryptoRealm.where() .equalTo(UserEntityFields.USER_ID, userId) @@ -184,9 +200,9 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses // Update trust if needed devicesEntities?.forEach { device -> val crossSignedVerified = trustMap?.get(device)?.isCrossSignedVerified() - Timber.v("## CrossSigning - Trust for ${device.userId}|${device.deviceId} : cross verified: ${trustMap?.get(device)}") + Timber.v("## CrossSigning [$sId]- Trust for ${device.userId}|${device.deviceId} : cross verified: ${trustMap?.get(device)}") if (device.trustLevelEntity?.crossSignedVerified != crossSignedVerified) { - Timber.d("## CrossSigning - Trust change detected for ${device.userId}|${device.deviceId} : cross verified: $crossSignedVerified") + Timber.d("## CrossSigning [$sId]- Trust change detected for ${device.userId}|${device.deviceId} : cross verified: $crossSignedVerified") // need to save val trustEntity = device.trustLevelEntity if (trustEntity == null) { @@ -197,50 +213,46 @@ internal class UpdateTrustWorker(context: Context, params: WorkerParameters, ses } else { trustEntity.crossSignedVerified = crossSignedVerified } + } else { + Timber.v("## CrossSigning [$sId]- Trust unchanged for ${device.userId}|${device.deviceId} : cross verified: $crossSignedVerified") } } } } - - // So Cross Signing keys trust is updated, device trust is updated - // We can now update room shields? in the session DB? - updateTrustStep2(userList, myCrossSigningInfo) } - private suspend fun updateTrustStep2(userList: List, myCrossSigningInfo: MXCrossSigningInfo?) { - Timber.d("## CrossSigning - Updating shields for impacted rooms...") + private suspend fun updateRoomShieldInSummaries(roomList: List, myCrossSigningInfo: MXCrossSigningInfo?) { + val sId = myUserId.take(5) + Timber.d("## CrossSigning [$sId]- Updating shields for impacted rooms... ${roomList.logLimit()}") awaitTransaction(sessionRealmConfiguration) { sessionRealm -> Timber.d("## CrossSigning - Updating shields for impacted rooms - in transaction") Realm.getInstance(cryptoRealmConfiguration).use { cryptoRealm -> - sessionRealm.where(RoomMemberSummaryEntity::class.java) - .`in`(RoomMemberSummaryEntityFields.USER_ID, userList.toTypedArray()) - .distinct(RoomMemberSummaryEntityFields.ROOM_ID) - .findAll() - .map { it.roomId } - .also { Timber.d("## CrossSigning - ... impacted rooms ${it.logLimit()}") } - .forEach { roomId -> - RoomSummaryEntity.where(sessionRealm, roomId) - .equalTo(RoomSummaryEntityFields.IS_ENCRYPTED, true) - .findFirst() - ?.let { roomSummary -> - Timber.v("## CrossSigning - Check shield state for room $roomId") - val allActiveRoomMembers = RoomMemberHelper(sessionRealm, roomId).getActiveRoomMemberIds() - try { - val updatedTrust = computeRoomShield( - myCrossSigningInfo, - cryptoRealm, - allActiveRoomMembers, - roomSummary - ) - if (roomSummary.roomEncryptionTrustLevel != updatedTrust) { - Timber.d("## CrossSigning - Shield change detected for $roomId -> $updatedTrust") - roomSummary.roomEncryptionTrustLevel = updatedTrust - } - } catch (failure: Throwable) { - Timber.e(failure) - } + roomList.forEach { roomId -> + Timber.v("## CrossSigning [$sId]- Checking room $roomId") + RoomSummaryEntity.where(sessionRealm, roomId) +// .equalTo(RoomSummaryEntityFields.IS_ENCRYPTED, true) + .findFirst() + ?.let { roomSummary -> + Timber.v("## CrossSigning [$sId]- Check shield state for room $roomId") + val allActiveRoomMembers = RoomMemberHelper(sessionRealm, roomId).getActiveRoomMemberIds() + try { + val updatedTrust = computeRoomShield( + myCrossSigningInfo, + cryptoRealm, + allActiveRoomMembers, + roomSummary + ) + if (roomSummary.roomEncryptionTrustLevel != updatedTrust) { + Timber.d("## CrossSigning [$sId]- Shield change detected for $roomId -> $updatedTrust") + roomSummary.roomEncryptionTrustLevel = updatedTrust + } else { + Timber.v("## CrossSigning [$sId]- Shield unchanged for $roomId -> $updatedTrust") } - } + } catch (failure: Throwable) { + Timber.e(failure) + } + } + } } } Timber.d("## CrossSigning - Updating shields for impacted rooms - END") diff --git a/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/session/sync/handler/ShieldSummaryUpdater.kt b/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/session/sync/handler/ShieldSummaryUpdater.kt new file mode 100644 index 0000000000..bcc078b550 --- /dev/null +++ b/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/session/sync/handler/ShieldSummaryUpdater.kt @@ -0,0 +1,56 @@ +/* + * Copyright 2023 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.sync.handler + +import androidx.work.BackoffPolicy +import androidx.work.ExistingWorkPolicy +import org.matrix.android.sdk.internal.crypto.crosssigning.UpdateTrustWorker +import org.matrix.android.sdk.internal.crypto.crosssigning.UpdateTrustWorkerDataRepository +import org.matrix.android.sdk.internal.di.SessionId +import org.matrix.android.sdk.internal.di.WorkManagerProvider +import org.matrix.android.sdk.internal.session.SessionScope +import org.matrix.android.sdk.internal.util.logLimit +import org.matrix.android.sdk.internal.worker.WorkerParamsFactory +import timber.log.Timber +import java.util.concurrent.TimeUnit +import javax.inject.Inject + +@SessionScope +internal class ShieldSummaryUpdater @Inject constructor( + @SessionId private val sessionId: String, + private val workManagerProvider: WorkManagerProvider, + private val updateTrustWorkerDataRepository: UpdateTrustWorkerDataRepository, +) { + + fun refreshShieldsForRoomIds(roomIds: Set) { + Timber.d("## CrossSigning - checkAffectedRoomShields for roomIds: ${roomIds.logLimit()}") + val workerParams = UpdateTrustWorker.Params( + sessionId = sessionId, + filename = updateTrustWorkerDataRepository.createParam(emptyList(), roomIds = roomIds.toList()) + ) + val workerData = WorkerParamsFactory.toData(workerParams) + + val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder() + .setInputData(workerData) + .setBackoffCriteria(BackoffPolicy.LINEAR, WorkManagerProvider.BACKOFF_DELAY_MILLIS, TimeUnit.MILLISECONDS) + .build() + + workManagerProvider.workManager + .beginUniqueWork("TRUST_UPDATE_QUEUE", ExistingWorkPolicy.APPEND_OR_REPLACE, workRequest) + .enqueue() + } +} diff --git a/matrix-sdk-android/src/main/java/fr/gouv/tchap/android/sdk/internal/auth/AccountValidityAPI.kt b/matrix-sdk-android/src/main/java/fr/gouv/tchap/android/sdk/internal/auth/AccountValidityAPI.kt index eb71c58055..25f7c76e49 100644 --- a/matrix-sdk-android/src/main/java/fr/gouv/tchap/android/sdk/internal/auth/AccountValidityAPI.kt +++ b/matrix-sdk-android/src/main/java/fr/gouv/tchap/android/sdk/internal/auth/AccountValidityAPI.kt @@ -15,7 +15,6 @@ */ package fr.gouv.tchap.android.sdk.internal.auth -import org.matrix.android.sdk.internal.network.NetworkConstants import retrofit2.http.GET import retrofit2.http.POST import retrofit2.http.Query @@ -24,12 +23,12 @@ interface AccountValidityAPI { /** * Trigger sending a renewal email to the user that made the request. */ - @POST(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "account_validity/send_mail") + @POST("_synapse/client/email_account_validity/send_mail") suspend fun requestRenewalEmail() /** * Submit a token to renew the account validity. */ - @GET(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "account_validity/renew") + @GET("_synapse/client/email_account_validity/renew") suspend fun renewAccountValidity(@Query("token") token: String?) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt index 4968df775a..78672adb00 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilities.kt @@ -77,9 +77,9 @@ data class HomeServerCapabilities( val canRemotelyTogglePushNotificationsOfDevices: Boolean = false, /** - * True if the home server supports event redaction with relations. + * True if the home server supports redaction of related events. */ - var canRedactEventWithRelations: Boolean = false, + var canRedactRelatedEvents: Boolean = false, /** * External account management url for use with MSC3824 delegated OIDC, provided in Wellknown. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Action.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Action.kt index 6122aae972..bbf65288cc 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Action.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/Action.kt @@ -20,7 +20,6 @@ import timber.log.Timber sealed class Action { object Notify : Action() - object DoNotNotify : Action() data class Sound(val sound: String = ACTION_OBJECT_VALUE_VALUE_DEFAULT) : Action() data class Highlight(val highlight: Boolean) : Action() @@ -72,7 +71,6 @@ fun List.toJson(): List { return map { action -> when (action) { is Action.Notify -> Action.ACTION_NOTIFY - is Action.DoNotNotify -> Action.ACTION_DONT_NOTIFY is Action.Sound -> { mapOf( Action.ACTION_OBJECT_SET_TWEAK_KEY to Action.ACTION_OBJECT_SET_TWEAK_VALUE_SOUND, @@ -95,7 +93,7 @@ fun PushRule.getActions(): List { actions.forEach { actionStrOrObj -> when (actionStrOrObj) { Action.ACTION_NOTIFY -> Action.Notify - Action.ACTION_DONT_NOTIFY -> Action.DoNotNotify + Action.ACTION_DONT_NOTIFY -> return@forEach is Map<*, *> -> { when (actionStrOrObj[Action.ACTION_OBJECT_SET_TWEAK_KEY]) { Action.ACTION_OBJECT_SET_TWEAK_VALUE_SOUND -> { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/PushRule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/PushRule.kt index a11ffc0a98..31dbd8dd2e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/PushRule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/PushRule.kt @@ -121,8 +121,6 @@ data class PushRule( if (notify) { mutableActions.add(Action.ACTION_NOTIFY) - } else { - mutableActions.add(Action.ACTION_DONT_NOTIFY) } return copy(actions = mutableActions) @@ -140,5 +138,5 @@ data class PushRule( * * @return true if the rule should not play sound */ - fun shouldNotNotify() = actions.contains(Action.ACTION_DONT_NOTIFY) + fun shouldNotNotify() = actions.isEmpty() || actions.contains(Action.ACTION_DONT_NOTIFY) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt index 07036f4b65..9eb0fa4097 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt @@ -158,10 +158,10 @@ interface SendService { * Redact (delete) the given event. * @param event the event to redact * @param reason optional reason string - * @param withRelations the list of relation types to redact with this event + * @param withRelTypes the list of relation types to redact with this event * @param additionalContent additional content to put in the event content */ - fun redactEvent(event: Event, reason: String?, withRelations: List? = null, additionalContent: Content? = null): Cancelable + fun redactEvent(event: Event, reason: String?, withRelTypes: List? = null, additionalContent: Content? = null): Cancelable /** * Schedule this message to be resent. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt index 3fe5541b68..83186344bb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/version/Versions.kt @@ -59,8 +59,7 @@ private const val FEATURE_QR_CODE_LOGIN = "org.matrix.msc3882" private const val FEATURE_THREADS_MSC3771 = "org.matrix.msc3771" private const val FEATURE_THREADS_MSC3773 = "org.matrix.msc3773" private const val FEATURE_REMOTE_TOGGLE_PUSH_NOTIFICATIONS_MSC3881 = "org.matrix.msc3881" -private const val FEATURE_EVENT_REDACTION_WITH_RELATIONS = "org.matrix.msc3912" -private const val FEATURE_EVENT_REDACTION_WITH_RELATIONS_STABLE = "org.matrix.msc3912.stable" +private const val FEATURE_REDACTION_OF_RELATED_EVENT = "org.matrix.msc3912" /** * Return true if the SDK supports this homeserver version. @@ -162,9 +161,8 @@ internal fun Versions.doesServerSupportRemoteToggleOfPushNotifications(): Boolea /** * Indicate if the server supports MSC3912: https://github.com/matrix-org/matrix-spec-proposals/pull/3912. * - * @return true if event redaction with relations is supported + * @return true if redaction of related events is supported */ -internal fun Versions.doesServerSupportRedactEventWithRelations(): Boolean { - return unstableFeatures?.get(FEATURE_EVENT_REDACTION_WITH_RELATIONS).orFalse() || - unstableFeatures?.get(FEATURE_EVENT_REDACTION_WITH_RELATIONS_STABLE).orFalse() +internal fun Versions.doesServerSupportRedactionOfRelatedEvents(): Boolean { + return unstableFeatures?.get(FEATURE_REDACTION_OF_RELATED_EVENT).orFalse() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoSessionInfoProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoSessionInfoProvider.kt index e26ca2f86a..086d741acc 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoSessionInfoProvider.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/CryptoSessionInfoProvider.kt @@ -19,19 +19,19 @@ package org.matrix.android.sdk.internal.crypto import com.zhuinden.monarchy.Monarchy import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel import org.matrix.android.sdk.api.session.events.model.EventType +import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.internal.database.mapper.EventMapper import org.matrix.android.sdk.internal.database.model.EventEntity import org.matrix.android.sdk.internal.database.model.EventEntityFields -import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntity -import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFields import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity +import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.database.query.whereType import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.di.UserId +import org.matrix.android.sdk.internal.query.process import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper import org.matrix.android.sdk.internal.util.fetchCopied -import org.matrix.android.sdk.internal.util.logLimit import timber.log.Timber import javax.inject.Inject @@ -89,14 +89,30 @@ internal class CryptoSessionInfoProvider @Inject constructor( } fun getRoomsWhereUsersAreParticipating(userList: List): List { + if (userList.contains(myUserId)) { + // just take all + val roomIds: List? = null + monarchy.doWithRealm { sessionRealm -> + RoomSummaryEntity.where(sessionRealm) + .process(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.activeMemberships()) + .findAll() + .map { it.roomId } + } + return roomIds.orEmpty() + } var roomIds: List? = null monarchy.doWithRealm { sessionRealm -> - roomIds = sessionRealm.where(RoomMemberSummaryEntity::class.java) - .`in`(RoomMemberSummaryEntityFields.USER_ID, userList.toTypedArray()) - .distinct(RoomMemberSummaryEntityFields.ROOM_ID) + roomIds = RoomSummaryEntity.where(sessionRealm) + .process(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.activeMemberships()) .findAll() + .filter { it.otherMemberIds.any { it in userList } } .map { it.roomId } - .also { Timber.d("## CrossSigning - ... impacted rooms ${it.logLimit()}") } +// roomIds = sessionRealm.where(RoomMemberSummaryEntity::class.java) +// .`in`(RoomMemberSummaryEntityFields.USER_ID, userList.toTypedArray()) +// .distinct(RoomMemberSummaryEntityFields.ROOM_ID) +// .findAll() +// .map { it.roomId } +// .also { Timber.d("## CrossSigning - ... impacted rooms ${it.logLimit()}") } } return roomIds.orEmpty() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorkerDataRepository.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorkerDataRepository.kt index 0878a9f765..d9207d05be 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorkerDataRepository.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/UpdateTrustWorkerDataRepository.kt @@ -28,7 +28,10 @@ import javax.inject.Inject @JsonClass(generateAdapter = true) internal data class UpdateTrustWorkerData( @Json(name = "userIds") - val userIds: List + val userIds: List, + // When we just need to refresh the room shield (no change on user keys, but a membership change) + @Json(name = "roomIds") + val roomIds: List? = null ) internal class UpdateTrustWorkerDataRepository @Inject constructor( @@ -38,12 +41,12 @@ internal class UpdateTrustWorkerDataRepository @Inject constructor( private val jsonAdapter = MoshiProvider.providesMoshi().adapter(UpdateTrustWorkerData::class.java) // Return the path of the created file - fun createParam(userIds: List): String { + fun createParam(userIds: List, roomIds: List? = null): String { val filename = "${UUID.randomUUID()}.json" workingDirectory.mkdirs() val file = File(workingDirectory, filename) - UpdateTrustWorkerData(userIds = userIds) + UpdateTrustWorkerData(userIds = userIds, roomIds = roomIds) .let { jsonAdapter.toJson(it) } .let { file.writeText(it) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/RedactEventTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/RedactEventTask.kt index b060748a61..01d59a8c80 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/RedactEventTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/RedactEventTask.kt @@ -30,7 +30,7 @@ internal interface RedactEventTask : Task { val roomId: String, val eventId: String, val reason: String?, - val withRelations: List?, + val withRelTypes: List?, ) } @@ -41,9 +41,9 @@ internal class DefaultRedactEventTask @Inject constructor( ) : RedactEventTask { override suspend fun execute(params: RedactEventTask.Params): String { - val withRelations = if (homeServerCapabilitiesDataSource.getHomeServerCapabilities()?.canRedactEventWithRelations.orFalse() && - !params.withRelations.isNullOrEmpty()) { - params.withRelations + val withRelTypes = if (homeServerCapabilitiesDataSource.getHomeServerCapabilities()?.canRedactRelatedEvents.orFalse() && + !params.withRelTypes.isNullOrEmpty()) { + params.withRelTypes } else { null } @@ -55,7 +55,7 @@ internal class DefaultRedactEventTask @Inject constructor( eventId = params.eventId, body = EventRedactBody( reason = params.reason, - withRelations = withRelations, + unstableWithRelTypes = withRelTypes, ) ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt index 1c7a0591a1..b566cf7cb6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/HomeServerCapabilitiesMapper.kt @@ -47,7 +47,7 @@ internal object HomeServerCapabilitiesMapper { canLoginWithQrCode = entity.canLoginWithQrCode, canUseThreadReadReceiptsAndNotifications = entity.canUseThreadReadReceiptsAndNotifications, canRemotelyTogglePushNotificationsOfDevices = entity.canRemotelyTogglePushNotificationsOfDevices, - canRedactEventWithRelations = entity.canRedactEventWithRelations, + canRedactRelatedEvents = entity.canRedactEventWithRelations, externalAccountManagementUrl = entity.externalAccountManagementUrl, ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt index a368325793..71f6ebd6e3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/GetHomeServerCapabilitiesTask.kt @@ -25,7 +25,7 @@ import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities import org.matrix.android.sdk.internal.auth.version.Versions import org.matrix.android.sdk.internal.auth.version.doesServerSupportLogoutDevices import org.matrix.android.sdk.internal.auth.version.doesServerSupportQrCodeLogin -import org.matrix.android.sdk.internal.auth.version.doesServerSupportRedactEventWithRelations +import org.matrix.android.sdk.internal.auth.version.doesServerSupportRedactionOfRelatedEvents import org.matrix.android.sdk.internal.auth.version.doesServerSupportRemoteToggleOfPushNotifications import org.matrix.android.sdk.internal.auth.version.doesServerSupportThreadUnreadNotifications import org.matrix.android.sdk.internal.auth.version.doesServerSupportThreads @@ -154,7 +154,7 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor( homeServerCapabilitiesEntity.canRemotelyTogglePushNotificationsOfDevices = getVersionResult.doesServerSupportRemoteToggleOfPushNotifications() homeServerCapabilitiesEntity.canRedactEventWithRelations = - getVersionResult.doesServerSupportRedactEventWithRelations() + getVersionResult.doesServerSupportRedactionOfRelatedEvents() } if (getWellknownResult != null && getWellknownResult is WellknownResult.Prompt) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt index ca348b5f4c..5bef61cae1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt @@ -60,12 +60,8 @@ internal class CreateRoomBodyBuilder @Inject constructor( // This can throw an exception if identity server is not configured ensureIdentityTokenTask.execute(Unit) - var identityServerUrlWithoutProtocol = identityStore.getIdentityServerUrlWithoutProtocol() + val identityServerUrlWithoutProtocol = identityStore.getIdentityServerUrlWithoutProtocol() ?: throw IdentityServiceError.NoIdentityServerConfigured - // Tchap : remove last char if it is a '/' else server will respond with a 500 error. - if (identityServerUrlWithoutProtocol.endsWith(char = '/')) { - identityServerUrlWithoutProtocol = identityServerUrlWithoutProtocol.dropLast(1) - } val identityServerAccessToken = accessTokenProvider.getToken() ?: throw IdentityServiceError.NoIdentityServerConfigured invites.map { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/RoomPushRuleMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/RoomPushRuleMapper.kt index 42b069f8fa..8707c24383 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/RoomPushRuleMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/RoomPushRuleMapper.kt @@ -63,7 +63,7 @@ internal fun RoomNotificationState.toRoomPushRule(roomId: String): RoomPushRule? pattern = roomId ) val rule = PushRule( - actions = listOf(Action.DoNotNotify).toJson(), + actions = emptyList().toJson(), enabled = true, ruleId = roomId, conditions = listOf(condition) @@ -81,7 +81,7 @@ internal fun RoomNotificationState.toRoomPushRule(roomId: String): RoomPushRule? internal fun RoomPushRule.toRoomNotificationState(): RoomNotificationState { return if (rule.enabled) { val actions = rule.getActions() - if (actions.contains(Action.DoNotNotify)) { + if (actions.isEmpty()) { if (kind == RuleSetKey.OVERRIDE) { RoomNotificationState.MUTE } else { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt index 7176e36e0c..04749103c1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt @@ -140,11 +140,11 @@ internal class DefaultSendService @AssistedInject constructor( .let { sendEvent(it) } } - override fun redactEvent(event: Event, reason: String?, withRelations: List?, additionalContent: Content?): Cancelable { + override fun redactEvent(event: Event, reason: String?, withRelTypes: List?, additionalContent: Content?): Cancelable { // TODO manage media/attachements? - val redactionEcho = localEchoEventFactory.createRedactEvent(roomId, event.eventId!!, reason, withRelations, additionalContent) + val redactionEcho = localEchoEventFactory.createRedactEvent(roomId, event.eventId!!, reason, withRelTypes, additionalContent) .also { createLocalEcho(it) } - return eventSenderProcessor.postRedaction(redactionEcho, reason, withRelations) + return eventSenderProcessor.postRedaction(redactionEcho, reason, withRelTypes) } override fun resendTextMessage(localEcho: TimelineEvent): Cancelable { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt index c2bdec3596..9510f50420 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt @@ -812,12 +812,12 @@ internal class LocalEchoEventFactory @Inject constructor( } } */ - fun createRedactEvent(roomId: String, eventId: String, reason: String?, withRelations: List? = null, additionalContent: Content? = null): Event { + fun createRedactEvent(roomId: String, eventId: String, reason: String?, withRelTypes: List? = null, additionalContent: Content? = null): Event { val localId = LocalEcho.createLocalEchoId() - val content = if (reason != null || withRelations != null) { + val content = if (reason != null || withRelTypes != null) { EventRedactBody( reason = reason, - withRelations = withRelations, + unstableWithRelTypes = withRelTypes, ).toContent().plus(additionalContent.orEmpty()) } else { additionalContent diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/RedactEventWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/RedactEventWorker.kt index 576f31c64c..270d3a228e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/RedactEventWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/RedactEventWorker.kt @@ -43,7 +43,7 @@ internal class RedactEventWorker(context: Context, params: WorkerParameters, ses val roomId: String, val eventId: String, val reason: String?, - val withRelations: List? = null, + val withRelTypes: List? = null, override val lastFailureMessage: String? = null ) : SessionWorkerParams @@ -63,7 +63,7 @@ internal class RedactEventWorker(context: Context, params: WorkerParameters, ses roomId = params.roomId, eventId = params.eventId, reason = params.reason, - withRelations = params.withRelations, + withRelTypes = params.withRelTypes, ) ) }.fold( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/model/EventRedactBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/model/EventRedactBody.kt index cf2bc0dc4f..2ed5c9f363 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/model/EventRedactBody.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/model/EventRedactBody.kt @@ -25,5 +25,10 @@ internal data class EventRedactBody( val reason: String? = null, @Json(name = "org.matrix.msc3912.with_relations") - val withRelations: List? = null, -) + val unstableWithRelTypes: List? = null, + + @Json(name = "with_rel_types") + val withRelTypes: List? = null, +) { + fun getBestWithRelTypes() = withRelTypes ?: unstableWithRelTypes +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessor.kt index b285e90c9a..90d78a51e0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessor.kt @@ -26,9 +26,9 @@ internal interface EventSenderProcessor : SessionLifecycleObserver { fun postEvent(event: Event, encrypt: Boolean): Cancelable - fun postRedaction(redactionLocalEcho: Event, reason: String?, withRelations: List? = null): Cancelable + fun postRedaction(redactionLocalEcho: Event, reason: String?, withRelTypes: List? = null): Cancelable - fun postRedaction(redactionLocalEchoId: String, eventToRedactId: String, roomId: String, reason: String?, withRelations: List? = null): Cancelable + fun postRedaction(redactionLocalEchoId: String, eventToRedactId: String, roomId: String, reason: String?, withRelTypes: List? = null): Cancelable fun postTask(task: QueuedTask): Cancelable diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorCoroutine.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorCoroutine.kt index 9ce29c3c08..a4e3773eb9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorCoroutine.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorCoroutine.kt @@ -101,8 +101,8 @@ internal class EventSenderProcessorCoroutine @Inject constructor( return postTask(task) } - override fun postRedaction(redactionLocalEcho: Event, reason: String?, withRelations: List?): Cancelable { - return postRedaction(redactionLocalEcho.eventId!!, redactionLocalEcho.redacts!!, redactionLocalEcho.roomId!!, reason, withRelations) + override fun postRedaction(redactionLocalEcho: Event, reason: String?, withRelTypes: List?): Cancelable { + return postRedaction(redactionLocalEcho.eventId!!, redactionLocalEcho.redacts!!, redactionLocalEcho.roomId!!, reason, withRelTypes) } override fun postRedaction( @@ -110,9 +110,9 @@ internal class EventSenderProcessorCoroutine @Inject constructor( eventToRedactId: String, roomId: String, reason: String?, - withRelations: List? + withRelTypes: List? ): Cancelable { - val task = queuedTaskFactory.createRedactTask(redactionLocalEchoId, eventToRedactId, roomId, reason, withRelations) + val task = queuedTaskFactory.createRedactTask(redactionLocalEchoId, eventToRedactId, roomId, reason, withRelTypes) return postTask(task) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/QueueMemento.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/QueueMemento.kt index a900e4ae5d..85238ae944 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/QueueMemento.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/QueueMemento.kt @@ -118,7 +118,7 @@ internal class QueueMemento @Inject constructor( eventId = it.redacts, roomId = it.roomId, reason = body?.reason, - withRelations = body?.withRelations, + withRelTypes = body?.getBestWithRelTypes(), ) ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/QueuedTaskFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/QueuedTaskFactory.kt index 46df7e29f3..e79808ee3f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/QueuedTaskFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/QueuedTaskFactory.kt @@ -43,13 +43,13 @@ internal class QueuedTaskFactory @Inject constructor( ) } - fun createRedactTask(redactionLocalEcho: String, eventId: String, roomId: String, reason: String?, withRelations: List? = null): QueuedTask { + fun createRedactTask(redactionLocalEcho: String, eventId: String, roomId: String, reason: String?, withRelTypes: List? = null): QueuedTask { return RedactQueuedTask( redactionLocalEchoId = redactionLocalEcho, toRedactEventId = eventId, roomId = roomId, reason = reason, - withRelations = withRelations, + withRelTypes = withRelTypes, redactEventTask = redactEventTask, localEchoRepository = localEchoRepository, cancelSendTracker = cancelSendTracker diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/RedactQueuedTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/RedactQueuedTask.kt index f484c24aae..b51a04f863 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/RedactQueuedTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/RedactQueuedTask.kt @@ -26,14 +26,14 @@ internal class RedactQueuedTask( val redactionLocalEchoId: String, private val roomId: String, private val reason: String?, - private val withRelations: List?, + private val withRelTypes: List?, private val redactEventTask: RedactEventTask, private val localEchoRepository: LocalEchoRepository, private val cancelSendTracker: CancelSendTracker ) : QueuedTask(queueIdentifier = roomId, taskIdentifier = redactionLocalEchoId) { override suspend fun doExecute() { - redactEventTask.execute(RedactEventTask.Params(redactionLocalEchoId, roomId, toRedactEventId, reason, withRelations)) + redactEventTask.execute(RedactEventTask.Params(redactionLocalEchoId, roomId, toRedactEventId, reason, withRelTypes)) } override fun onTaskFailed() { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt index 930a869b4a..5dd0d3e2fd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryUpdater.kt @@ -172,6 +172,9 @@ internal class RoomSummaryUpdater @Inject constructor( val roomAliases = ContentMapper.map(lastAliasesEvent?.content).toModel()?.aliases .orEmpty() roomSummaryEntity.updateAliases(roomAliases) + + val wasEncrypted = roomSummaryEntity.isEncrypted + roomSummaryEntity.isEncrypted = encryptionEvent != null roomSummaryEntity.e2eAlgorithm = ContentMapper.map(encryptionEvent?.content) @@ -201,17 +204,13 @@ internal class RoomSummaryUpdater @Inject constructor( // better to use what we know roomSummaryEntity.joinedMembersCount = otherRoomMembers.size + 1 } - if (roomSummaryEntity.isEncrypted && otherRoomMembers.isNotEmpty()) { - if (aggregator == null) { - // Do it now - // mmm maybe we could only refresh shield instead of checking trust also? - // XXX why doing this here? we don't show shield anymore and it will be refreshed - // by the sdk - // crossSigningService.checkTrustAndAffectedRoomShields(otherRoomMembers) - } else { - // Schedule it - aggregator.userIdsForCheckingTrustAndAffectedRoomShields.addAll(otherRoomMembers) - } + } + + if (roomSummaryEntity.isEncrypted) { + if (!wasEncrypted || updateMembers || roomSummaryEntity.roomEncryptionTrustLevel == null) { + // trigger a shield update + // if users add devices/keys or signatures the device list manager will trigger a refresh + aggregator?.roomsWithMembershipChangesForShieldUpdate?.add(roomId) } } } @@ -414,7 +413,7 @@ internal class RoomSummaryUpdater @Inject constructor( val relatedSpaces = lookupMap.keys .filter { it.roomType == RoomType.SPACE } .filter { - dmRoom.otherMemberIds.toList().intersect(it.otherMemberIds.toList()).isNotEmpty() + dmRoom.otherMemberIds.toList().intersect(it.otherMemberIds.toSet()).isNotEmpty() } .map { it.roomId } .distinct() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregator.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregator.kt index af05e08da3..4532a8d418 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregator.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregator.kt @@ -29,7 +29,8 @@ internal class SyncResponsePostTreatmentAggregator { val userIdsToFetch = mutableSetOf() // Set of users to call `crossSigningService.checkTrustAndAffectedRoomShields` once per sync - val userIdsForCheckingTrustAndAffectedRoomShields = mutableSetOf() + + val roomsWithMembershipChangesForShieldUpdate = mutableSetOf() // For the crypto store val cryptoStoreAggregator = CryptoStoreAggregator() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/SyncResponsePostTreatmentAggregatorHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/SyncResponsePostTreatmentAggregatorHandler.kt index 948a0a2501..3c205d5013 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/SyncResponsePostTreatmentAggregatorHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/SyncResponsePostTreatmentAggregatorHandler.kt @@ -19,7 +19,7 @@ package org.matrix.android.sdk.internal.session.sync.handler import androidx.work.BackoffPolicy import androidx.work.ExistingWorkPolicy import org.matrix.android.sdk.api.MatrixPatterns -import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningService +import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.internal.crypto.crosssigning.UpdateTrustWorker import org.matrix.android.sdk.internal.crypto.crosssigning.UpdateTrustWorkerDataRepository import org.matrix.android.sdk.internal.di.SessionId @@ -39,16 +39,16 @@ internal class SyncResponsePostTreatmentAggregatorHandler @Inject constructor( private val directChatsHelper: DirectChatsHelper, private val ephemeralTemporaryStore: RoomSyncEphemeralTemporaryStore, private val updateUserAccountDataTask: UpdateUserAccountDataTask, - private val crossSigningService: CrossSigningService, private val updateTrustWorkerDataRepository: UpdateTrustWorkerDataRepository, private val workManagerProvider: WorkManagerProvider, + private val roomShieldSummaryUpdater: ShieldSummaryUpdater, @SessionId private val sessionId: String, ) { suspend fun handle(aggregator: SyncResponsePostTreatmentAggregator) { cleanupEphemeralFiles(aggregator.ephemeralFilesToDelete) updateDirectUserIds(aggregator.directChatsToCheck) fetchAndUpdateUsers(aggregator.userIdsToFetch) - handleUserIdsForCheckingTrustAndAffectedRoomShields(aggregator.userIdsForCheckingTrustAndAffectedRoomShields) + handleRefreshRoomShieldsForRooms(aggregator.roomsWithMembershipChangesForShieldUpdate) } private fun cleanupEphemeralFiles(ephemeralFilesToDelete: List) { @@ -82,7 +82,9 @@ internal class SyncResponsePostTreatmentAggregatorHandler @Inject constructor( } } if (hasUpdate) { - updateUserAccountDataTask.execute(UpdateUserAccountDataTask.DirectChatParams(directMessages = directChats)) + tryOrNull("Unable to update user account data") { + updateUserAccountDataTask.execute(UpdateUserAccountDataTask.DirectChatParams(directMessages = directChats)) + } } } @@ -105,8 +107,8 @@ internal class SyncResponsePostTreatmentAggregatorHandler @Inject constructor( .enqueue() } - private suspend fun handleUserIdsForCheckingTrustAndAffectedRoomShields(userIdsWithDeviceUpdate: Collection) { - if (userIdsWithDeviceUpdate.isEmpty()) return - crossSigningService.checkTrustAndAffectedRoomShields(userIdsWithDeviceUpdate.toList()) + private fun handleRefreshRoomShieldsForRooms(roomIds: Set) { + if (roomIds.isEmpty()) return + roomShieldSummaryUpdater.refreshShieldsForRoomIds(roomIds) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UserAccountDataSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UserAccountDataSyncHandler.kt index 92ebb41ad9..bc49682565 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UserAccountDataSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/UserAccountDataSyncHandler.kt @@ -20,6 +20,7 @@ import com.zhuinden.monarchy.Monarchy import io.realm.Realm import io.realm.RealmList import io.realm.kotlin.where +import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.failure.GlobalError import org.matrix.android.sdk.api.failure.InitialSyncRequestReason import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent @@ -122,7 +123,7 @@ internal class UserAccountDataSyncHandler @Inject constructor( val updateUserAccountParams = UpdateUserAccountDataTask.DirectChatParams( directMessages = directChats ) - updateUserAccountDataTask.execute(updateUserAccountParams) + tryOrNull("Unable to update user account data") { updateUserAccountDataTask.execute(updateUserAccountParams) } } } diff --git a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/Device.kt b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/Device.kt index 7f2b1232fe..4cb329175b 100644 --- a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/Device.kt +++ b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/Device.kt @@ -187,8 +187,7 @@ internal class Device @AssistedInject constructor( locallyVerified = innerDevice.locallyTrusted ), isBlocked = innerDevice.isBlocked, - // TODO - firstTimeSeenLocalTs = null + firstTimeSeenLocalTs = innerDevice.firstTimeSeenTs.toLong() ) } } diff --git a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/network/OutgoingRequestsProcessor.kt b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/network/OutgoingRequestsProcessor.kt index 77fd9b3ea3..9e0301f487 100644 --- a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/network/OutgoingRequestsProcessor.kt +++ b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/network/OutgoingRequestsProcessor.kt @@ -27,10 +27,10 @@ import org.matrix.android.sdk.api.MatrixConfiguration import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.session.events.model.Event -import org.matrix.android.sdk.internal.crypto.ComputeShieldForGroupUseCase import org.matrix.android.sdk.internal.crypto.CryptoSessionInfoProvider import org.matrix.android.sdk.internal.crypto.OlmMachine import org.matrix.android.sdk.internal.session.SessionScope +import org.matrix.android.sdk.internal.session.sync.handler.ShieldSummaryUpdater import org.matrix.rustcomponents.sdk.crypto.Request import org.matrix.rustcomponents.sdk.crypto.RequestType import timber.log.Timber @@ -43,7 +43,7 @@ internal class OutgoingRequestsProcessor @Inject constructor( private val requestSender: RequestSender, private val coroutineScope: CoroutineScope, private val cryptoSessionInfoProvider: CryptoSessionInfoProvider, - private val computeShieldForGroup: ComputeShieldForGroupUseCase, + private val shieldSummaryUpdater: ShieldSummaryUpdater, private val matrixConfiguration: MatrixConfiguration, private val coroutineDispatchers: MatrixCoroutineDispatchers, ) { @@ -137,7 +137,7 @@ internal class OutgoingRequestsProcessor @Inject constructor( return try { val response = requestSender.queryKeys(request) olmMachine.markRequestAsSent(request.requestId, RequestType.KEYS_QUERY, response) - coroutineScope.updateShields(olmMachine, request.users) + shieldSummaryUpdater.refreshShieldsForRoomsWithMembers(request.users) coroutineScope.markMessageVerificationStatesAsDirty(request.users) true } catch (throwable: Throwable) { @@ -146,18 +146,6 @@ internal class OutgoingRequestsProcessor @Inject constructor( } } - private fun CoroutineScope.updateShields(olmMachine: OlmMachine, userIds: List) = launch(coroutineDispatchers.computation) { - cryptoSessionInfoProvider.getRoomsWhereUsersAreParticipating(userIds).forEach { roomId -> - if (cryptoSessionInfoProvider.isRoomEncrypted(roomId)) { - val userGroup = cryptoSessionInfoProvider.getUserListForShieldComputation(roomId) - val shield = computeShieldForGroup(olmMachine, userGroup) - cryptoSessionInfoProvider.updateShieldForRoom(roomId, shield) - } else { - cryptoSessionInfoProvider.updateShieldForRoom(roomId, null) - } - } - } - private fun CoroutineScope.markMessageVerificationStatesAsDirty(userIds: List) = launch(coroutineDispatchers.computation) { cryptoSessionInfoProvider.markMessageVerificationStateAsDirty(userIds) } diff --git a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/session/sync/handler/ShieldSummaryUpdater.kt b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/session/sync/handler/ShieldSummaryUpdater.kt new file mode 100644 index 0000000000..9f77d7003e --- /dev/null +++ b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/session/sync/handler/ShieldSummaryUpdater.kt @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.sync.handler + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers +import org.matrix.android.sdk.internal.crypto.ComputeShieldForGroupUseCase +import org.matrix.android.sdk.internal.crypto.CryptoSessionInfoProvider +import org.matrix.android.sdk.internal.crypto.OlmMachine +import org.matrix.android.sdk.internal.session.SessionScope +import javax.inject.Inject + +@SessionScope +internal class ShieldSummaryUpdater @Inject constructor( + private val olmMachine: dagger.Lazy, + private val coroutineScope: CoroutineScope, + private val coroutineDispatchers: MatrixCoroutineDispatchers, + private val cryptoSessionInfoProvider: CryptoSessionInfoProvider, + private val computeShieldForGroup: ComputeShieldForGroupUseCase, +) { + + fun refreshShieldsForRoomsWithMembers(userIds: List) { + coroutineScope.launch(coroutineDispatchers.computation) { + cryptoSessionInfoProvider.getRoomsWhereUsersAreParticipating(userIds).forEach { roomId -> + if (cryptoSessionInfoProvider.isRoomEncrypted(roomId)) { + val userGroup = cryptoSessionInfoProvider.getUserListForShieldComputation(roomId) + val shield = computeShieldForGroup(olmMachine.get(), userGroup) + cryptoSessionInfoProvider.updateShieldForRoom(roomId, shield) + } else { + cryptoSessionInfoProvider.updateShieldForRoom(roomId, null) + } + } + } + } + + fun refreshShieldsForRoomIds(roomIds: Set) { + coroutineScope.launch(coroutineDispatchers.computation) { + roomIds.forEach { roomId -> + val userGroup = cryptoSessionInfoProvider.getUserListForShieldComputation(roomId) + val shield = computeShieldForGroup(olmMachine.get(), userGroup) + cryptoSessionInfoProvider.updateShieldForRoom(roomId, shield) + } + } + } +} diff --git a/settings.gradle b/settings.gradle index ea20f12175..a0b9ce65ed 100644 --- a/settings.gradle +++ b/settings.gradle @@ -11,6 +11,12 @@ include ':library:multipicker' include ':library:external:jsonviewer' include ':library:external:diff-match-patch' include ':library:external:dialpad' +include ':library:external:textdrawable' +include ':library:external:autocomplete' +include ':library:external:realmfieldnameshelper' +include ':library:external:span' +include ':library:external:barcodescanner:core' +include ':library:external:barcodescanner:zxing' include ':library:rustCrypto' include ':matrix-sdk-android' diff --git a/towncrier.toml b/towncrier.toml index 2eb899d0d6..d93c1af179 100644 --- a/towncrier.toml +++ b/towncrier.toml @@ -1,5 +1,5 @@ [tool.towncrier] - version = "2.9.2" + version = "2.9.3" directory = "changelog.d" filename = "TCHAP_CHANGES.md" name = "Changes in Tchap" diff --git a/vector-app/build.gradle b/vector-app/build.gradle index b3565fd7fa..c43cc99f2e 100644 --- a/vector-app/build.gradle +++ b/vector-app/build.gradle @@ -37,7 +37,7 @@ ext.versionMinor = 9 // Note: even values are reserved for regular release, odd values for hotfix release. // When creating a hotfix, you should decrease the value, since the current value // is the value for the next regular release. -ext.versionPatch = 2 +ext.versionPatch = 3 static def getGitTimestamp() { def cmd = 'git show -s --format=%ct' @@ -497,6 +497,7 @@ dependencies { implementation project(':vector') implementation project(':vector-config') implementation project(':library:core-utils') + debugImplementation project(':library:external:span') debugImplementation project(':library:ui-styles') implementation libs.dagger.hilt implementation 'androidx.multidex:multidex:2.0.1' diff --git a/vector/build.gradle b/vector/build.gradle index 5bfaf466e6..b6ea44ff7c 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -144,6 +144,8 @@ dependencies { implementation project(":matrix-sdk-android-flow") implementation project(":library:external:jsonviewer") implementation project(":library:external:diff-match-patch") + implementation project(":library:external:textdrawable") + implementation project(":library:external:autocomplete") implementation project(":library:ui-strings") implementation project(":library:ui-styles") implementation project(":library:core-utils") @@ -212,11 +214,8 @@ dependencies { api libs.androidx.preferenceKtx // UI - implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1' implementation libs.google.material - api('me.gujun.android:span:1.7') { - exclude group: 'com.android.support', module: 'support-annotations' - } + implementation project(":library:external:span") implementation libs.markwon.core implementation libs.markwon.extLatex implementation libs.markwon.imageGlide @@ -238,8 +237,6 @@ dependencies { // Alerter implementation 'com.github.tapadoo:alerter:7.2.4' - implementation 'com.otaliastudios:autocomplete:1.1.0' - // Shake detection implementation 'com.squareup:seismic:1.0.3' @@ -298,11 +295,7 @@ dependencies { // Stick to 3.3.3 because of https://github.com/zxing/zxing/issues/1170 implementation 'com.google.zxing:core:3.3.3' - // Excludes the legacy support library annotation usages - // https://github.com/dm77/barcodescanner/blob/d036996c8a6f36a68843ffe539c834c28944b2d5/core/src/main/java/me/dm7/barcodescanner/core/CameraWrapper.java#L4 - implementation ('me.dm7.barcodescanner:zxing:1.9.13') { - exclude group: 'com.android.support', module: 'support-v4' - } + implementation project(":library:external:barcodescanner:zxing") // Emoji Keyboard api libs.vanniktech.emojiMaterial @@ -331,6 +324,7 @@ dependencies { testImplementation libs.tests.kluent testImplementation libs.mockk.mockk testImplementation libs.androidx.coreTesting + testImplementation libs.tests.robolectric // Plant Timber tree for test testImplementation libs.tests.timberJunitRule testImplementation libs.airbnb.mavericksTesting diff --git a/vector/src/main/java/im/vector/app/core/di/ConfigurationModule.kt b/vector/src/main/java/im/vector/app/core/di/ConfigurationModule.kt index 7a1f7f2292..7c8dea3b7d 100644 --- a/vector/src/main/java/im/vector/app/core/di/ConfigurationModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/ConfigurationModule.kt @@ -77,8 +77,8 @@ object ConfigurationModule { fun providesCryptoConfig() = CryptoConfig( fallbackKeySharingStrategy = when (Config.KEY_SHARING_STRATEGY) { KeySharingStrategy.WhenSendingEvent -> OutboundSessionKeySharingStrategy.WhenSendingEvent - KeySharingStrategy.WhenEnteringRoom -> OutboundSessionKeySharingStrategy.WhenSendingEvent - KeySharingStrategy.WhenTyping -> OutboundSessionKeySharingStrategy.WhenSendingEvent + KeySharingStrategy.WhenEnteringRoom -> OutboundSessionKeySharingStrategy.WhenEnteringRoom + KeySharingStrategy.WhenTyping -> OutboundSessionKeySharingStrategy.WhenTyping } ) diff --git a/vector/src/main/java/im/vector/app/core/resources/AppNameProvider.kt b/vector/src/main/java/im/vector/app/core/resources/AppNameProvider.kt index a25862f3a8..2686e489bf 100644 --- a/vector/src/main/java/im/vector/app/core/resources/AppNameProvider.kt +++ b/vector/src/main/java/im/vector/app/core/resources/AppNameProvider.kt @@ -40,7 +40,7 @@ class DefaultAppNameProvider @Inject constructor(private val context: Context) : appName } catch (e: Exception) { Timber.e(e, "## AppNameProvider() : failed") - "ElementAndroid" + "TchapAndroid" } } } diff --git a/vector/src/main/java/im/vector/app/features/autocomplete/RecyclerViewPresenter.kt b/vector/src/main/java/im/vector/app/features/autocomplete/RecyclerViewPresenter.kt index 7625eb6216..cd7ecb8a00 100644 --- a/vector/src/main/java/im/vector/app/features/autocomplete/RecyclerViewPresenter.kt +++ b/vector/src/main/java/im/vector/app/features/autocomplete/RecyclerViewPresenter.kt @@ -23,7 +23,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.otaliastudios.autocomplete.AutocompletePresenter -abstract class RecyclerViewPresenter(context: Context?) : AutocompletePresenter(context) { +abstract class RecyclerViewPresenter(context: Context) : AutocompletePresenter(context) { private var recyclerView: RecyclerView? = null private var clicks: ClickProvider? = null diff --git a/vector/src/main/java/im/vector/app/features/autocomplete/command/CommandAutocompletePolicy.kt b/vector/src/main/java/im/vector/app/features/autocomplete/command/CommandAutocompletePolicy.kt index 08f61be0f8..9097d2be43 100644 --- a/vector/src/main/java/im/vector/app/features/autocomplete/command/CommandAutocompletePolicy.kt +++ b/vector/src/main/java/im/vector/app/features/autocomplete/command/CommandAutocompletePolicy.kt @@ -32,16 +32,15 @@ class CommandAutocompletePolicy @Inject constructor() : AutocompletePolicy { return "" } - override fun onDismiss(text: Spannable?) { + override fun onDismiss(text: Spannable) { } // Only if text which starts with '/' and without space - override fun shouldShowPopup(text: Spannable?, cursorPos: Int): Boolean { - return enabled && text?.startsWith("/") == true && - !text.contains(" ") + override fun shouldShowPopup(text: Spannable, cursorPos: Int): Boolean { + return enabled && text.startsWith("/") && !text.contains(" ") } - override fun shouldDismissPopup(text: Spannable?, cursorPos: Int): Boolean { + override fun shouldDismissPopup(text: Spannable, cursorPos: Int): Boolean { return !shouldShowPopup(text, cursorPos) } } diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt index c9cd297dcc..23cf34ac55 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt @@ -44,6 +44,7 @@ import im.vector.app.features.qrcode.QrCodeScannerEvents import im.vector.app.features.qrcode.QrCodeScannerFragment import im.vector.app.features.qrcode.QrCodeScannerViewModel import im.vector.app.features.qrcode.QrScannerArgs +import im.vector.app.features.userdirectory.PendingSelection import im.vector.app.features.userdirectory.UserListFragment import im.vector.app.features.userdirectory.UserListFragmentArgs import im.vector.app.features.userdirectory.UserListSharedAction @@ -187,7 +188,19 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() { } private fun handleOnMenuItemSubmitClick(action: UserListSharedAction.OnMenuItemSubmitClick) { - viewModel.handle(CreateDirectRoomAction.PrepareRoomWithSelectedUsers(action.selections)) + val unknownUsers = action.selections.filter { it is PendingSelection.UserPendingSelection && it.isUnknownUser } + if (unknownUsers.isEmpty()) { + viewModel.handle(CreateDirectRoomAction.PrepareRoomWithSelectedUsers(action.selections)) + } else { + MaterialAlertDialogBuilder(this) + .setTitle(R.string.dialog_title_confirmation) + .setMessage(getString(R.string.create_room_unknown_users_dialog_content, unknownUsers.joinToString("\n • ", " • ") { it.getMxId() })) + .setPositiveButton(R.string.create_room_unknown_users_dialog_submit) { _, _ -> + viewModel.handle(CreateDirectRoomAction.PrepareRoomWithSelectedUsers(action.selections)) + } + .setNegativeButton(R.string.action_cancel, null) + .show() + } } // Tchap: Not used in Tchap diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapActions.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapActions.kt index 395b4d0475..fd61bdd5dd 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapActions.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapActions.kt @@ -20,6 +20,7 @@ import im.vector.app.core.platform.VectorViewModelAction import java.io.OutputStream sealed class BootstrapActions : VectorViewModelAction { + object Retry : BootstrapActions() // Navigation diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapBottomSheet.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapBottomSheet.kt index be02737ef8..586f60beaf 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapBottomSheet.kt @@ -212,6 +212,11 @@ class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment { + views.bootstrapIcon.isVisible = true + views.bootstrapTitleText.text = getString(R.string.bottom_sheet_setup_secure_backup_title) + showFragment(BootstrapErrorFragment::class) + } } super.invalidate() } diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapErrorFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapErrorFragment.kt new file mode 100644 index 0000000000..26b29d449a --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapErrorFragment.kt @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.crypto.recover + +import android.view.LayoutInflater +import android.view.ViewGroup +import com.airbnb.mvrx.parentFragmentViewModel +import com.airbnb.mvrx.withState +import dagger.hilt.android.AndroidEntryPoint +import im.vector.app.R +import im.vector.app.core.epoxy.onClick +import im.vector.app.core.extensions.setTextOrHide +import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.FragmentBootstrapErrorBinding + +@AndroidEntryPoint +class BootstrapErrorFragment : + VectorBaseFragment() { + + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapErrorBinding { + return FragmentBootstrapErrorBinding.inflate(inflater, container, false) + } + + val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel() + + override fun invalidate() = withState(sharedViewModel) { state -> + when (state.step) { + is BootstrapStep.Error -> { + views.bootstrapDescriptionText.setTextOrHide(errorFormatter.toHumanReadable(state.step.error)) + } + else -> { + // Should not happen, show a generic error + views.bootstrapDescriptionText.setTextOrHide(getString(R.string.unknown_error)) + } + } + views.bootstrapRetryButton.onClick { + sharedViewModel.handle(BootstrapActions.Retry) + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt index b3d83b948b..c9c2c5ce9a 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt @@ -54,6 +54,7 @@ import org.matrix.android.sdk.api.session.crypto.keysbackup.extractCurveKeyFromR import org.matrix.android.sdk.api.session.crypto.keysbackup.toKeysVersionResult import org.matrix.android.sdk.api.session.securestorage.RawBytesKeySpec import org.matrix.android.sdk.api.session.uia.DefaultBaseAuth +import timber.log.Timber import java.io.OutputStream import kotlin.coroutines.Continuation import kotlin.coroutines.resumeWithException @@ -118,37 +119,48 @@ class BootstrapSharedViewModel @AssistedInject constructor( } } SetupMode.NORMAL -> { - // need to check if user have an existing keybackup - setState { - copy(step = BootstrapStep.CheckingMigration) - } + checkMigration() + } + } + } + + private fun checkMigration() { + // need to check if user have an existing keybackup + setState { + copy(step = BootstrapStep.CheckingMigration) + } - // We need to check if there is an existing backup - viewModelScope.launch(Dispatchers.IO) { - val version = tryOrNull { session.cryptoService().keysBackupService().getCurrentVersion() }?.toKeysVersionResult() - if (version == null) { - // we just resume plain bootstrap - doesKeyBackupExist = false + // We need to check if there is an existing backup + viewModelScope.launch(Dispatchers.IO) { + try { + val version = tryOrNull { session.cryptoService().keysBackupService().getCurrentVersion() }?.toKeysVersionResult() + if (version == null) { + // we just resume plain bootstrap + doesKeyBackupExist = false + setState { + copy(step = BootstrapStep.FirstForm(keyBackUpExist = doesKeyBackupExist, methods = this.secureBackupMethod)) + } + } else { + // we need to get existing backup passphrase/key and convert to SSSS + val keyVersion = tryOrNull { + session.cryptoService().keysBackupService().getVersion(version.version) + } + if (keyVersion == null) { + // strange case... just finish? + _viewEvents.post(BootstrapViewEvents.Dismiss(false)) + } else { + doesKeyBackupExist = true + isBackupCreatedFromPassphrase = keyVersion.getAuthDataAsMegolmBackupAuthData()?.privateKeySalt != null setState { copy(step = BootstrapStep.FirstForm(keyBackUpExist = doesKeyBackupExist, methods = this.secureBackupMethod)) } - } else { - // we need to get existing backup passphrase/key and convert to SSSS - val keyVersion = tryOrNull { - session.cryptoService().keysBackupService().getVersion(version.version) - } - if (keyVersion == null) { - // strange case... just finish? - _viewEvents.post(BootstrapViewEvents.Dismiss(false)) - } else { - doesKeyBackupExist = true - isBackupCreatedFromPassphrase = keyVersion.getAuthDataAsMegolmBackupAuthData()?.privateKeySalt != null - setState { - copy(step = BootstrapStep.FirstForm(keyBackUpExist = doesKeyBackupExist, methods = this.secureBackupMethod)) - } - } } } + } catch (failure: Throwable) { + Timber.e(failure, "Error while checking key backup") + setState { + copy(step = BootstrapStep.Error(failure)) + } } } } @@ -268,6 +280,9 @@ class BootstrapSharedViewModel @AssistedInject constructor( copy(step = BootstrapStep.AccountReAuth(stringProvider.getString(R.string.authentication_error))) } } + BootstrapActions.Retry -> { + checkMigration() + } } } @@ -568,6 +583,12 @@ class BootstrapSharedViewModel @AssistedInject constructor( ) } } + is BootstrapStep.Error -> { + // do we let you cancel from here? + if (state.canLeave) { + _viewEvents.post(BootstrapViewEvents.SkipBootstrap(state.passphrase != null)) + } + } } } diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapStep.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapStep.kt index 3975f0e9a2..b807acc0ba 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapStep.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapStep.kt @@ -105,6 +105,8 @@ sealed class BootstrapStep { object Initializing : BootstrapStep() data class SaveRecoveryKey(val isSaved: Boolean) : BootstrapStep() object DoneSuccess : BootstrapStep() + + data class Error(val error: Throwable) : BootstrapStep() } fun BootstrapStep.GetBackupSecretForMigration.useKey(): Boolean { diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/self/SelfVerificationBottomSheet.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/self/SelfVerificationBottomSheet.kt index 5005ccd12b..e63c149a26 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/self/SelfVerificationBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/self/SelfVerificationBottomSheet.kt @@ -156,7 +156,7 @@ class SelfVerificationBottomSheet : VectorBaseBottomSheetDialogFragment { - dismiss() + dismiss() } is VerificationBottomSheetViewEvents.ConfirmCancel -> { // TODO? applies to self? @@ -229,6 +229,9 @@ class SelfVerificationBottomSheet : VectorBaseBottomSheetDialogFragment state.unknownSessions.invoke()?.let { unknownDevices -> + val uid = PopupAlertManager.REVIEW_LOGIN_UID if (unknownDevices.firstOrNull()?.currentSessionTrust == true) { - val uid = PopupAlertManager.REVIEW_LOGIN_UID alertManager.cancelAlert(uid) val olderUnverified = unknownDevices.filter { !it.isNew } val newest = unknownDevices.firstOrNull { it.isNew }?.deviceInfo @@ -176,6 +178,9 @@ class NewHomeDetailFragment : // In this case we prompt to go to settings to review logins promptToReviewChanges(uid, state, olderUnverified.map { it.deviceInfo }) } + } else { + // cancel as there are not anymore untrusted devices + alertManager.cancelAlert(uid) } } } @@ -298,7 +303,14 @@ class NewHomeDetailFragment : uid = uid, title = getString(R.string.review_unverified_sessions_title), description = getString(R.string.review_unverified_sessions_description), - iconId = R.drawable.ic_shield_warning + iconId = R.drawable.ic_shield_warning, + shouldBeDisplayedIn = { activity -> + // do not show when there is an ongoing verification flow + if (activity is VectorBaseActivity<*>) { + activity.supportFragmentManager.findFragmentByTag(SelfVerificationBottomSheet.TAG) == null && + activity !is QrCodeScannerActivity + } else true + } ).apply { viewBinder = VerificationVectorAlert.ViewBinder(user, avatarRenderer) colorInt = colorProvider.getColorFromAttribute(R.attr.colorPrimary) @@ -371,9 +383,9 @@ class NewHomeDetailFragment : }) } - /* ========================================================================================== - * KeysBackupBanner Listener - * ========================================================================================== */ +/* ========================================================================================== + * KeysBackupBanner Listener + * ========================================================================================== */ override fun onCloseClicked() { serverBackupStatusViewModel.handle(ServerBackupStatusAction.OnBannerClosed) diff --git a/vector/src/main/java/im/vector/app/features/home/ShortcutsHandler.kt b/vector/src/main/java/im/vector/app/features/home/ShortcutsHandler.kt index 3a72907467..89213b4a81 100644 --- a/vector/src/main/java/im/vector/app/features/home/ShortcutsHandler.kt +++ b/vector/src/main/java/im/vector/app/features/home/ShortcutsHandler.kt @@ -139,19 +139,20 @@ class ShortcutsHandler @Inject constructor( } private fun createShortcuts(rooms: List) { - if (hasPinCode.get()) { - // No shortcut in this case (privacy) - ShortcutManagerCompat.removeAllDynamicShortcuts(context) - } else { - val shortcuts = rooms - .take(maxShortcutCountPerActivity) - .mapIndexed { index, room -> - shortcutCreator.create(room, index) - } + // Tchap: remove all shortcuts before add others to avoid exceeding max shortcuts count per activity. + ShortcutManagerCompat.removeAllDynamicShortcuts(context) - shortcuts.forEach { shortcut -> - ShortcutManagerCompat.pushDynamicShortcut(context, shortcut) - } + // No shortcut in this case (privacy) + if (hasPinCode.get()) return + + val shortcuts = rooms + .take(maxShortcutCountPerActivity) + .mapIndexed { index, room -> + shortcutCreator.create(room, index) + } + + shortcuts.forEach { shortcut -> + ShortcutManagerCompat.pushDynamicShortcut(context, shortcut) } } diff --git a/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt index b65f03da57..5701366a28 100644 --- a/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt @@ -39,7 +39,6 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.sample import kotlinx.coroutines.launch -import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo @@ -116,8 +115,14 @@ class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor( session.sessionParams.deviceId != it.deviceId } .filter { info -> - // filter out verified sessions or those which do not support encryption (i.e. without crypto info) - cryptoList.firstOrNull { info.deviceId == it.deviceId }?.isVerified?.not().orFalse() + val matchingDeviceWithKeys = cryptoList.firstOrNull { it.deviceId == info.deviceId } + if (matchingDeviceWithKeys == null) { + // filter out verified sessions or those which do not support encryption (i.e. without crypto info) + false + } else { + // Only report unverified + !matchingDeviceWithKeys.isVerified + } } // filter out ignored devices .filter { shouldShowUnverifiedSessionsAlertUseCase.execute(it.deviceId) } @@ -136,7 +141,7 @@ class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor( } .distinctUntilChanged() .execute { async -> - Timber.v("## Detector trigger passed distinct") + Timber.v("## Detector trigger passed distinct ${async.invoke()}") copy( myMatrixItem = session.getUserOrDefault(session.myUserId).toMatrixItem(), unknownSessions = async diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/AutoCompleter.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/AutoCompleter.kt index 51e1fb06f2..568f4cf9e7 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/AutoCompleter.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/AutoCompleter.kt @@ -40,23 +40,31 @@ import im.vector.app.features.displayname.getBestName import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.html.PillImageSpan import im.vector.app.features.themes.ThemeUtils +import io.element.android.wysiwyg.EditorEditText +import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.permalinks.PermalinkService import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.api.util.toEveryoneInRoomMatrixItem import org.matrix.android.sdk.api.util.toMatrixItem import org.matrix.android.sdk.api.util.toRoomAliasMatrixItem +import timber.log.Timber class AutoCompleter @AssistedInject constructor( @Assisted val roomId: String, @Assisted val isInThreadTimeline: Boolean, + private val session: Session, private val avatarRenderer: AvatarRenderer, private val commandAutocompletePolicy: CommandAutocompletePolicy, autocompleteCommandPresenterFactory: AutocompleteCommandPresenter.Factory, private val autocompleteMemberPresenterFactory: AutocompleteMemberPresenter.Factory, private val autocompleteRoomPresenter: AutocompleteRoomPresenter, - private val autocompleteEmojiPresenter: AutocompleteEmojiPresenter + private val autocompleteEmojiPresenter: AutocompleteEmojiPresenter, ) { + private val permalinkService: PermalinkService + get() = session.permalinkService() + private lateinit var autocompleteMemberPresenter: AutocompleteMemberPresenter @AssistedFactory @@ -79,6 +87,7 @@ class AutoCompleter @AssistedInject constructor( } private lateinit var glideRequests: GlideRequests + private val autocompletes: MutableSet> = hashSetOf() fun setup(editText: EditText) { this.editText = editText @@ -90,26 +99,41 @@ class AutoCompleter @AssistedInject constructor( setupRooms(backgroundDrawable, editText) } + fun setEnabled(isEnabled: Boolean) = + autocompletes.forEach { + if (!isEnabled) { it.dismissPopup() } + it.setEnabled(isEnabled) + } + fun clear() { this.editText = null autocompleteEmojiPresenter.clear() autocompleteRoomPresenter.clear() autocompleteCommandPresenter.clear() autocompleteMemberPresenter.clear() + autocompletes.forEach { + it.setEnabled(false) + it.dismissPopup() + } + autocompletes.clear() } private fun setupCommands(backgroundDrawable: Drawable, editText: EditText) { - Autocomplete.on(editText) + autocompletes += Autocomplete.on(editText) .with(commandAutocompletePolicy) .with(autocompleteCommandPresenter) .with(ELEVATION_DP) .with(backgroundDrawable) .with(object : AutocompleteCallback { override fun onPopupItemClicked(editable: Editable, item: Command): Boolean { - editable.clear() - editable - .append(item.command) - .append(" ") + if (editText is EditorEditText) { + editText.replaceTextSuggestion(item.command) + } else { + editable.clear() + editable + .append(item.command) + .append(" ") + } return true } @@ -121,24 +145,22 @@ class AutoCompleter @AssistedInject constructor( private fun setupMembers(backgroundDrawable: ColorDrawable, editText: EditText) { autocompleteMemberPresenter = autocompleteMemberPresenterFactory.create(roomId) - Autocomplete.on(editText) + autocompletes += Autocomplete.on(editText) .with(CharPolicy(TRIGGER_AUTO_COMPLETE_MEMBERS, true)) .with(autocompleteMemberPresenter) .with(ELEVATION_DP) .with(backgroundDrawable) .with(object : AutocompleteCallback { override fun onPopupItemClicked(editable: Editable, item: AutocompleteMemberItem): Boolean { - return when (item) { - is AutocompleteMemberItem.Header -> false // do nothing header is not clickable - is AutocompleteMemberItem.RoomMember -> { - insertMatrixItem(editText, editable, TRIGGER_AUTO_COMPLETE_MEMBERS, item.roomMemberSummary.toMatrixItem()) - true - } - is AutocompleteMemberItem.Everyone -> { - insertMatrixItem(editText, editable, TRIGGER_AUTO_COMPLETE_MEMBERS, item.roomSummary.toEveryoneInRoomMatrixItem()) - true - } - } + val matrixItem = when (item) { + is AutocompleteMemberItem.Header -> null // do nothing header is not clickable + is AutocompleteMemberItem.RoomMember -> item.roomMemberSummary.toMatrixItem() + is AutocompleteMemberItem.Everyone -> item.roomSummary.toEveryoneInRoomMatrixItem() + } ?: return false + + insertMatrixItem(editText, editable, TRIGGER_AUTO_COMPLETE_MEMBERS, matrixItem) + + return true } override fun onPopupVisibilityChanged(shown: Boolean) { @@ -148,7 +170,7 @@ class AutoCompleter @AssistedInject constructor( } private fun setupRooms(backgroundDrawable: ColorDrawable, editText: EditText) { - Autocomplete.on(editText) + autocompletes += Autocomplete.on(editText) .with(CharPolicy(TRIGGER_AUTO_COMPLETE_ROOMS, true)) .with(autocompleteRoomPresenter) .with(ELEVATION_DP) @@ -166,7 +188,10 @@ class AutoCompleter @AssistedInject constructor( } private fun setupEmojis(backgroundDrawable: Drawable, editText: EditText) { - Autocomplete.on(editText) + // Rich text editor is not yet supported + if (editText is EditorEditText) return + + autocompletes += Autocomplete.on(editText) .with(CharPolicy(TRIGGER_AUTO_COMPLETE_EMOJIS, false)) .with(autocompleteEmojiPresenter) .with(ELEVATION_DP) @@ -197,7 +222,41 @@ class AutoCompleter @AssistedInject constructor( .build() } - private fun insertMatrixItem(editText: EditText, editable: Editable, firstChar: Char, matrixItem: MatrixItem) { + private fun insertMatrixItem(editText: EditText, editable: Editable, firstChar: Char, matrixItem: MatrixItem) = + if (editText is EditorEditText) { + insertMatrixItemIntoRichTextEditor(editText, matrixItem) + } else { + insertMatrixItemIntoEditable(editText, editable, firstChar, matrixItem) + } + + private fun insertMatrixItemIntoRichTextEditor(editorEditText: EditorEditText, matrixItem: MatrixItem) { + if (matrixItem is MatrixItem.EveryoneInRoomItem) { + editorEditText.replaceTextSuggestion(matrixItem.displayName) + return + } + + val permalink = permalinkService.createPermalink(matrixItem.id) + + if (permalink == null) { + Timber.e(NullPointerException("Cannot autocomplete as permalink is null")) + return + } + + val linkText = when (matrixItem) { + is MatrixItem.RoomAliasItem, + is MatrixItem.RoomItem, + is MatrixItem.SpaceItem -> + matrixItem.id + is MatrixItem.EveryoneInRoomItem, + is MatrixItem.UserItem, + is MatrixItem.EventItem -> + matrixItem.getBestName() + } + + editorEditText.setLinkSuggestion(url = permalink, text = linkText) + } + + private fun insertMatrixItemIntoEditable(editText: EditText, editable: Editable, firstChar: Char, matrixItem: MatrixItem) { // Detect last firstChar and remove it var startIndex = editable.lastIndexOf(firstChar) if (startIndex == -1) { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt index db20d55a13..0af3c953e1 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt @@ -767,6 +767,9 @@ class TimelineViewModel @AssistedInject constructor( return room?.membershipService()?.getRoomMember(userId) } + fun getRoom(roomId: String): RoomSummary? = + session.roomService().getRoomSummary(roomId) + private fun handleComposerFocusChange(action: RoomDetailAction.ComposerFocusChange) { if (room == null) return // Ensure outbound session keys diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerFragment.kt index 8e8bc2e6cd..4c026f3135 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerFragment.kt @@ -84,6 +84,7 @@ import im.vector.app.features.home.room.detail.TimelineViewModel import im.vector.app.features.home.room.detail.composer.link.SetLinkFragment import im.vector.app.features.home.room.detail.composer.link.SetLinkSharedAction import im.vector.app.features.home.room.detail.composer.link.SetLinkSharedActionViewModel +import im.vector.app.features.home.room.detail.composer.mentions.PillDisplayHandler import im.vector.app.features.home.room.detail.composer.voice.VoiceMessageRecorderView import im.vector.app.features.home.room.detail.timeline.action.MessageSharedActionViewModel import im.vector.app.features.home.room.detail.upgrade.MigrateRoomBottomSheet @@ -101,6 +102,7 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.content.ContentAttachmentData +import org.matrix.android.sdk.api.session.permalinks.PermalinkService import org.matrix.android.sdk.api.util.MatrixItem import reactivecircus.flowbinding.android.view.focusChanges import reactivecircus.flowbinding.android.widget.textChanges @@ -123,11 +125,12 @@ class MessageComposerFragment : VectorBaseFragment(), A @Inject lateinit var session: Session @Inject lateinit var errorTracker: ErrorTracker + private val permalinkService: PermalinkService + get() = session.permalinkService() + private val roomId: String get() = withState(timelineViewModel) { it.roomId } - private val autoCompleter: AutoCompleter by lazy { - autoCompleterFactory.create(roomId, isThreadTimeLine()) - } + private val autoCompleters: MutableMap = hashMapOf() private val emojiPopup: EmojiPopup by lifecycleAwareLazy { createEmojiPopup() @@ -263,9 +266,8 @@ class MessageComposerFragment : VectorBaseFragment(), A override fun onDestroyView() { super.onDestroyView() - if (!vectorPreferences.isRichTextEditorEnabled()) { - autoCompleter.clear() - } + autoCompleters.values.forEach(AutoCompleter::clear) + autoCompleters.clear() messageComposerViewModel.endAllVoiceActions() } @@ -280,7 +282,12 @@ class MessageComposerFragment : VectorBaseFragment(), A } else { // Tchap: set visibility to gone if there is no voice recorder button composer.sendButton.isGone = !messageComposerState.isSendButtonVisible - (composer as? RichTextComposerLayout)?.isTextFormattingEnabled = attachmentState.isTextFormattingEnabled + (composer as? RichTextComposerLayout)?.also { + val isTextFormattingEnabled = attachmentState.isTextFormattingEnabled + it.isTextFormattingEnabled = isTextFormattingEnabled + autoCompleters[it.richTextEditText]?.setEnabled(isTextFormattingEnabled) + autoCompleters[it.plainTextEditText]?.setEnabled(!isTextFormattingEnabled) + } } } @@ -322,8 +329,11 @@ class MessageComposerFragment : VectorBaseFragment(), A val composerEditText = composer.editText composerEditText.setHint(R.string.room_message_placeholder) - if (!vectorPreferences.isRichTextEditorEnabled()) { - autoCompleter.setup(composerEditText) + (composer as? RichTextComposerLayout)?.let { + initAutoCompleter(it.richTextEditText) + initAutoCompleter(it.plainTextEditText) + } ?: run { + initAutoCompleter(composer.editText) } observerUserTyping() @@ -418,6 +428,21 @@ class MessageComposerFragment : VectorBaseFragment(), A SetLinkFragment.show(isTextSupported, initialLink, childFragmentManager) } } + (composer as? RichTextComposerLayout)?.pillDisplayHandler = PillDisplayHandler( + roomId = roomId, + getRoom = timelineViewModel::getRoom, + getMember = timelineViewModel::getMember, + ) { matrixItem: MatrixItem -> + PillImageSpan(glideRequests, avatarRenderer, requireContext(), matrixItem) + } + } + + private fun initAutoCompleter(editText: EditText) { + if (autoCompleters.containsKey(editText)) return + + autoCompleters[editText] = + autoCompleterFactory.create(roomId, isThreadTimeLine()) + .also { it.setup(editText) } } private fun sendTextMessage(text: CharSequence, formattedText: String? = null) { @@ -449,12 +474,12 @@ class MessageComposerFragment : VectorBaseFragment(), A } private fun renderRegularMode(content: CharSequence) { - autoCompleter.exitSpecialMode() + autoCompleters.values.forEach(AutoCompleter::exitSpecialMode) composer.renderComposerMode(MessageComposerMode.Normal(content)) } private fun renderSpecialMode(mode: MessageComposerMode.Special) { - autoCompleter.enterSpecialMode() + autoCompleters.values.forEach(AutoCompleter::enterSpecialMode) composer.renderComposerMode(mode) } @@ -785,30 +810,37 @@ class MessageComposerFragment : VectorBaseFragment(), A } else { val roomMember = timelineViewModel.getMember(userId) val displayName = sanitizeDisplayName(roomMember?.displayName ?: userId) - val pill = buildSpannedString { - append(displayName) - setSpan( - PillImageSpan( - glideRequests, - avatarRenderer, - requireContext(), - MatrixItem.UserItem(userId, displayName, roomMember?.avatarUrl) - ) - .also { it.bind(composer.editText) }, - 0, - displayName.length, - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE - ) - append(if (startToCompose) ": " else " ") - } - if (startToCompose) { - if (displayName.startsWith("/")) { + if ((composer as? RichTextComposerLayout)?.isTextFormattingEnabled == true) { + // Rich text editor is enabled so we need to use its APIs + permalinkService.createPermalink(userId)?.let { url -> + (composer as RichTextComposerLayout).insertMention(url, displayName) + composer.editText.append(" ") + } + } else { + val pill = buildSpannedString { + append(displayName) + setSpan( + PillImageSpan( + glideRequests, + avatarRenderer, + requireContext(), + MatrixItem.UserItem(userId, displayName, roomMember?.avatarUrl), + ) + .also { it.bind(composer.editText) }, + 0, + displayName.length, + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE + ) + append(if (startToCompose) ": " else " ") + } + if (startToCompose && displayName.startsWith("/")) { // Ensure displayName will not be interpreted as a Slash command composer.editText.append("\\") } - composer.editText.append(pill) - } else { - composer.editText.text?.insert(composer.editText.selectionStart, pill) + // Always use EditText.getText().insert for adding pills as TextView.append doesn't appear + // to upgrade to BufferType.Spannable as hinted at in the docs: + // https://developer.android.com/reference/android/widget/TextView#append(java.lang.CharSequence) + composer.editText.text.insert(composer.editText.selectionStart, pill) } } focusComposerAndShowKeyboard() diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/RichTextComposerLayout.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/RichTextComposerLayout.kt index 49e8f0cdc6..48163a43bf 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/RichTextComposerLayout.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/RichTextComposerLayout.kt @@ -49,7 +49,11 @@ import im.vector.app.core.utils.DimensionConverter import im.vector.app.databinding.ComposerRichTextLayoutBinding import im.vector.app.databinding.ViewRichTextMenuButtonBinding import im.vector.app.features.home.room.detail.composer.images.UriContentListener +import im.vector.app.features.home.room.detail.composer.mentions.PillDisplayHandler import io.element.android.wysiwyg.EditorEditText +import io.element.android.wysiwyg.display.KeywordDisplayHandler +import io.element.android.wysiwyg.display.LinkDisplayHandler +import io.element.android.wysiwyg.display.TextDisplay import io.element.android.wysiwyg.utils.RustErrorCollector import io.element.android.wysiwyg.view.models.InlineFormat import io.element.android.wysiwyg.view.models.LinkAction @@ -88,7 +92,7 @@ internal class RichTextComposerLayout @JvmOverloads constructor( override val text: Editable? get() = editText.text override val formattedText: String? - get() = (editText as? EditorEditText)?.getHtmlOutput() + get() = (editText as? EditorEditText)?.getContentAsMessageHtml() override val editText: EditText get() = if (isTextFormattingEnabled) { views.richTextComposerEditText @@ -102,6 +106,13 @@ internal class RichTextComposerLayout @JvmOverloads constructor( override val attachmentButton: ImageButton get() = views.attachmentButton + val richTextEditText: EditText get() = + views.richTextComposerEditText + val plainTextEditText: EditText get() = + views.plainTextComposerEditText + + var pillDisplayHandler: PillDisplayHandler? = null + // Border of the EditText private val borderShapeDrawable: MaterialShapeDrawable by lazy { MaterialShapeDrawable().apply { @@ -227,6 +238,16 @@ internal class RichTextComposerLayout @JvmOverloads constructor( views.composerEditTextOuterBorder.background = borderShapeDrawable setupRichTextMenu() + views.richTextComposerEditText.linkDisplayHandler = LinkDisplayHandler { text, url -> + pillDisplayHandler?.resolveLinkDisplay(text, url) ?: TextDisplay.Plain + } + views.richTextComposerEditText.keywordDisplayHandler = object : KeywordDisplayHandler { + override val keywords: List + get() = pillDisplayHandler?.keywords.orEmpty() + + override fun resolveKeywordDisplay(text: String): TextDisplay = + pillDisplayHandler?.resolveKeywordDisplay(text) ?: TextDisplay.Plain + } updateTextFieldBorder(isFullScreen) } @@ -284,6 +305,10 @@ internal class RichTextComposerLayout @JvmOverloads constructor( fun removeLink() = views.richTextComposerEditText.removeLink() + // Update the API to insertMention when available + fun insertMention(url: String, displayText: String) = + views.richTextComposerEditText.insertLink(url, displayText) + @SuppressLint("ClickableViewAccessibility") private fun disallowParentInterceptTouchEvent(view: View) { view.setOnTouchListener { v, event -> diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/mentions/PillDisplayHandler.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/mentions/PillDisplayHandler.kt new file mode 100644 index 0000000000..c2b71ea15b --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/mentions/PillDisplayHandler.kt @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.home.room.detail.composer.mentions + +import android.text.style.ReplacementSpan +import io.element.android.wysiwyg.display.KeywordDisplayHandler +import io.element.android.wysiwyg.display.LinkDisplayHandler +import io.element.android.wysiwyg.display.TextDisplay +import org.matrix.android.sdk.api.session.permalinks.PermalinkData +import org.matrix.android.sdk.api.session.permalinks.PermalinkParser +import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary +import org.matrix.android.sdk.api.session.room.model.RoomSummary +import org.matrix.android.sdk.api.util.MatrixItem +import org.matrix.android.sdk.api.util.toEveryoneInRoomMatrixItem +import org.matrix.android.sdk.api.util.toMatrixItem +import org.matrix.android.sdk.api.util.toRoomAliasMatrixItem + +/** + * A rich text editor [LinkDisplayHandler] and [KeywordDisplayHandler] + * that helps with replacing user and room links with pills. + */ +internal class PillDisplayHandler( + private val roomId: String, + private val getRoom: (roomId: String) -> RoomSummary?, + private val getMember: (userId: String) -> RoomMemberSummary?, + private val replacementSpanFactory: (matrixItem: MatrixItem) -> ReplacementSpan, +) : LinkDisplayHandler, KeywordDisplayHandler { + override fun resolveLinkDisplay(text: String, url: String): TextDisplay { + val matrixItem = when (val permalink = PermalinkParser.parse(url)) { + is PermalinkData.UserLink -> { + val userId = permalink.userId + when (val roomMember = getMember(userId)) { + null -> MatrixItem.UserItem(userId, userId, null) + else -> roomMember.toMatrixItem() + } + } + is PermalinkData.RoomLink -> { + val roomId = permalink.roomIdOrAlias + val room = getRoom(roomId) + when { + room == null -> MatrixItem.RoomItem(roomId, roomId, null) + text == MatrixItem.NOTIFY_EVERYONE -> room.toEveryoneInRoomMatrixItem() + permalink.isRoomAlias -> room.toRoomAliasMatrixItem() + else -> room.toMatrixItem() + } + } + else -> + return TextDisplay.Plain + } + val replacement = replacementSpanFactory.invoke(matrixItem) + return TextDisplay.Custom(customSpan = replacement) + } + + override val keywords: List + get() = listOf(MatrixItem.NOTIFY_EVERYONE) + + override fun resolveKeywordDisplay(text: String): TextDisplay = + when (text) { + MatrixItem.NOTIFY_EVERYONE -> { + val matrixItem = getRoom(roomId)?.toEveryoneInRoomMatrixItem() + ?: MatrixItem.EveryoneInRoomItem(roomId) + TextDisplay.Custom(replacementSpanFactory.invoke(matrixItem)) + } + else -> TextDisplay.Plain + } +} diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt index 8b928cc997..f78d613d4d 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt @@ -288,7 +288,10 @@ class MessageItemFactory @Inject constructor( } else { null } - val pollContent = pollStartEvent?.root?.getClearContent()?.toModel() + + val editedContent = pollStartEvent?.annotations?.editSummary?.latestEdit?.getClearContent()?.toModel()?.newContent + val latestContent = editedContent ?: pollStartEvent?.root?.getClearContent() + val pollContent = latestContent?.toModel() return if (pollContent == null) { val title = stringProvider.getString(R.string.message_reply_to_ended_poll_preview).toEpoxyCharSequence() diff --git a/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt b/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt index 7f514d2ad2..c000efaef2 100644 --- a/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt +++ b/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt @@ -37,6 +37,7 @@ import im.vector.app.core.utils.onPermissionDeniedSnackbar import im.vector.app.core.utils.registerForPermissionsResult import im.vector.app.core.utils.toast import im.vector.app.features.contactsbook.ContactsBookFragment +import im.vector.app.features.userdirectory.PendingSelection import im.vector.app.features.userdirectory.UserListFragment import im.vector.app.features.userdirectory.UserListFragmentArgs import im.vector.app.features.userdirectory.UserListSharedAction @@ -94,7 +95,19 @@ class InviteUsersToRoomActivity : SimpleFragmentActivity() { } private fun handleOnMenuItemSubmitClick(action: UserListSharedAction.OnMenuItemSubmitClick) { - viewModel.handle(InviteUsersToRoomAction.InviteSelectedUsers(action.selections)) + val unknownUsers = action.selections.filter { it is PendingSelection.UserPendingSelection && it.isUnknownUser } + if (unknownUsers.isEmpty()) { + viewModel.handle(InviteUsersToRoomAction.InviteSelectedUsers(action.selections)) + } else { + MaterialAlertDialogBuilder(this) + .setTitle(R.string.dialog_title_confirmation) + .setMessage(getString(R.string.invite_unknown_users_dialog_content, unknownUsers.joinToString("\n • ", " • ") { it.getMxId() })) + .setPositiveButton(R.string.invite_unknown_users_dialog_submit) { _, _ -> + viewModel.handle(InviteUsersToRoomAction.InviteSelectedUsers(action.selections)) + } + .setNegativeButton(R.string.action_cancel, null) + .show() + } } private fun openPhoneBook() { diff --git a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt index b0b548a30c..07c07738db 100644 --- a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt +++ b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt @@ -249,8 +249,8 @@ class DefaultNavigator @Inject constructor( } if (context is AppCompatActivity) { - SelfVerificationBottomSheet.forTransaction(tx.transactionId) - .show(context.supportFragmentManager, "VERIF") + SelfVerificationBottomSheet.forTransaction(tx.transactionId) + .show(context.supportFragmentManager, "VERIF") } } } @@ -265,7 +265,7 @@ class DefaultNavigator @Inject constructor( ) if (context is AppCompatActivity) { context.supportFragmentManager.commitTransaction(allowStateLoss = true) { - add(SelfVerificationBottomSheet.forTransaction(request.transactionId), "VERIF") + add(SelfVerificationBottomSheet.forTransaction(request.transactionId), SelfVerificationBottomSheet.TAG) } } } @@ -273,25 +273,10 @@ class DefaultNavigator @Inject constructor( override fun requestSelfSessionVerification(context: Context) { coroutineScope.launch { - // TODO - // val session = sessionHolder.getSafeActiveSession() ?: return@launch -// val otherSessions = session.cryptoService() -// .getCryptoDeviceInfoList(session.myUserId) -// .filter { it.deviceId != session.sessionParams.deviceId } -// .map { it.deviceId } if (context is AppCompatActivity) { context.supportFragmentManager.commitTransaction(allowStateLoss = true) { - add(SelfVerificationBottomSheet.verifyOwnUntrustedDevice(), "VERIF") + add(SelfVerificationBottomSheet.verifyOwnUntrustedDevice(), SelfVerificationBottomSheet.TAG) } -// if (otherSessions.isNotEmpty()) { -// val pr = session.cryptoService().verificationService().requestSelfKeyVerification( -// supportedVerificationMethodsProvider.provide()) -// VerificationBottomSheet.forSelfVerification(session, pr.transactionId) -// .show(context.supportFragmentManager, VerificationBottomSheet.WAITING_SELF_VERIF_TAG) -// } else { -// VerificationBottomSheet.forSelfVerification(session) -// .show(context.supportFragmentManager, VerificationBottomSheet.WAITING_SELF_VERIF_TAG) -// } } } } @@ -300,7 +285,7 @@ class DefaultNavigator @Inject constructor( // val session = sessionHolder.getSafeActiveSession() ?: return coroutineScope.launch(Dispatchers.Main) { SelfVerificationBottomSheet.forTransaction(transactionId) - .show(fragmentActivity.supportFragmentManager, "SELF_VERIF_TAG") + .show(fragmentActivity.supportFragmentManager, SelfVerificationBottomSheet.TAG) } } diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationAction.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationAction.kt index 19c7fcea7d..ffa833b7ce 100644 --- a/vector/src/main/java/im/vector/app/features/notifications/NotificationAction.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationAction.kt @@ -30,7 +30,6 @@ fun List.toNotificationAction(): NotificationAction { forEach { action -> when (action) { is Action.Notify -> shouldNotify = true - is Action.DoNotNotify -> shouldNotify = false is Action.Highlight -> highlight = action.highlight is Action.Sound -> sound = action.sound } diff --git a/vector/src/main/java/im/vector/app/features/popup/PopupAlertManager.kt b/vector/src/main/java/im/vector/app/features/popup/PopupAlertManager.kt index 02275c933e..c59b2c7216 100644 --- a/vector/src/main/java/im/vector/app/features/popup/PopupAlertManager.kt +++ b/vector/src/main/java/im/vector/app/features/popup/PopupAlertManager.kt @@ -164,7 +164,7 @@ class PopupAlertManager @Inject constructor( next = alertQueue.maxByOrNull { it.priority } // If next alert with highest priority is higher than the current one, we should display it // and add the current one to queue again. - if (next != null && next.priority > currentAlerter?.priority ?: Int.MIN_VALUE) { + if (next != null && next.priority > (currentAlerter?.priority ?: Int.MIN_VALUE)) { alertQueue.remove(next) currentAlerter?.also { alertQueue.add(0, it) diff --git a/vector/src/main/java/im/vector/app/features/rageshake/VectorUncaughtExceptionHandler.kt b/vector/src/main/java/im/vector/app/features/rageshake/VectorUncaughtExceptionHandler.kt index d3174631e8..6d6ecd9edc 100644 --- a/vector/src/main/java/im/vector/app/features/rageshake/VectorUncaughtExceptionHandler.kt +++ b/vector/src/main/java/im/vector/app/features/rageshake/VectorUncaughtExceptionHandler.kt @@ -20,6 +20,7 @@ import android.content.SharedPreferences import android.os.Build import androidx.core.content.edit import im.vector.app.core.di.DefaultPreferences +import im.vector.app.core.resources.AppNameProvider import im.vector.app.core.resources.VersionCodeProvider import im.vector.app.features.version.VersionProvider import org.matrix.android.sdk.api.Matrix @@ -36,6 +37,7 @@ class VectorUncaughtExceptionHandler @Inject constructor( private val bugReporter: BugReporter, private val versionProvider: VersionProvider, private val versionCodeProvider: VersionCodeProvider, + private val appNameProvider: AppNameProvider, ) : Thread.UncaughtExceptionHandler { // key to save the crash status @@ -67,12 +69,12 @@ class VectorUncaughtExceptionHandler @Inject constructor( putBoolean(PREFS_CRASH_KEY, true) } val b = StringBuilder() - val appName = "Element" // TODO Matrix.getApplicationName() + val appName = appNameProvider.getAppName() - b.append(appName + " Build : " + versionCodeProvider.getVersionCode() + "\n") + b.append("$appName Build : ${versionCodeProvider.getVersionCode()}\n") b.append("$appName Version : ${versionProvider.getVersion(longFormat = true)}\n") b.append("SDK Version : ${Matrix.getSdkVersion()}\n") - b.append("Phone : " + Build.MODEL.trim() + " (" + Build.VERSION.INCREMENTAL + " " + Build.VERSION.RELEASE + " " + Build.VERSION.CODENAME + ")\n") + b.append("Phone : ${Build.MODEL.trim()} (${Build.VERSION.INCREMENTAL} ${Build.VERSION.RELEASE} ${Build.VERSION.CODENAME})\n") b.append("Memory statuses \n") diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt index 298a46c606..e98e6cb42c 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt @@ -78,6 +78,7 @@ import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerC import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService import org.matrix.android.sdk.flow.flow import org.matrix.android.sdk.flow.unwrap +import timber.log.Timber import java.io.File import java.net.URL import java.util.UUID @@ -309,7 +310,17 @@ class VectorSettingsGeneralFragment : // Disable it while updating the state, will be re-enabled by the account data listener. it.isEnabled = false lifecycleScope.launch { - session.integrationManagerService().setIntegrationEnabled(newValue as Boolean) + try { + session.integrationManagerService().setIntegrationEnabled(newValue as Boolean) + } catch (failure: Throwable) { + Timber.e(failure, "Failed to update integration manager state") + activity?.let { activity -> + Toast.makeText(activity, errorFormatter.toHumanReadable(failure), Toast.LENGTH_SHORT).show() + } + // Restore the previous state + it.isChecked = !it.isChecked + it.isEnabled = true + } } true } diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/StandardActions.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/StandardActions.kt index b19b5bcdd6..46aaa38ae5 100644 --- a/vector/src/main/java/im/vector/app/features/settings/notifications/StandardActions.kt +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/StandardActions.kt @@ -26,6 +26,6 @@ sealed class StandardActions( object NotifyRingSound : StandardActions(actions = listOf(Action.Notify, Action.Sound(sound = Action.ACTION_OBJECT_VALUE_VALUE_RING))) object Highlight : StandardActions(actions = listOf(Action.Notify, Action.Highlight(highlight = true))) object HighlightDefaultSound : StandardActions(actions = listOf(Action.Notify, Action.Highlight(highlight = true), Action.Sound())) - object DontNotify : StandardActions(actions = listOf(Action.DoNotNotify)) + object DontNotify : StandardActions(actions = emptyList()) object Disabled : StandardActions(actions = null) } diff --git a/vector/src/main/java/im/vector/app/features/sync/widget/SyncStateView.kt b/vector/src/main/java/im/vector/app/features/sync/widget/SyncStateView.kt index a40b70b8a6..f613036af2 100755 --- a/vector/src/main/java/im/vector/app/features/sync/widget/SyncStateView.kt +++ b/vector/src/main/java/im/vector/app/features/sync/widget/SyncStateView.kt @@ -18,11 +18,18 @@ package im.vector.app.features.sync.widget import android.annotation.SuppressLint import android.content.Context +import android.graphics.Typeface +import android.text.Spannable +import android.text.SpannableString +import android.text.style.StyleSpan +import android.text.style.UnderlineSpan import android.util.AttributeSet import android.widget.LinearLayout import androidx.core.view.isVisible import im.vector.app.R +import im.vector.app.core.epoxy.onClick import im.vector.app.core.utils.isAirplaneModeOn +import im.vector.app.core.utils.openUrlInExternalBrowser import im.vector.app.databinding.ViewSyncStateBinding import org.matrix.android.sdk.api.session.sync.SyncRequestState import org.matrix.android.sdk.api.session.sync.SyncState @@ -56,6 +63,15 @@ class SyncStateView @JvmOverloads constructor(context: Context, attrs: Attribute if (newState == SyncState.NoNetwork) { val isAirplaneModeOn = context.isAirplaneModeOn() + // Tchap: Add service status URL + val statusLink = context.getString(R.string.tchap_no_connection_service_status) + val spannable = SpannableString("${context.getString(R.string.no_connectivity_to_the_server_indicator)} $statusLink") + spannable.setSpan(StyleSpan(Typeface.BOLD), spannable.length - statusLink.length, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) + spannable.setSpan(UnderlineSpan(), spannable.length - statusLink.length, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) + views.syncStateNoNetwork.text = spannable + views.syncStateNoNetwork.onClick { + openUrlInExternalBrowser(context, TCHAP_SERVICE_STATUS_URL) + } views.syncStateNoNetwork.isVisible = isAirplaneModeOn.not() views.syncStateNoNetworkAirplane.isVisible = isAirplaneModeOn } else { @@ -87,4 +103,8 @@ class SyncStateView @JvmOverloads constructor(context: Context, attrs: Attribute else -> "?" } } + + companion object { + private const val TCHAP_SERVICE_STATUS_URL = "https://status.tchap.numerique.gouv.fr/" + } } diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/PendingSelection.kt b/vector/src/main/java/im/vector/app/features/userdirectory/PendingSelection.kt index 643aa30995..7838b76452 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/PendingSelection.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/PendingSelection.kt @@ -22,7 +22,7 @@ import org.matrix.android.sdk.api.session.user.model.User import org.matrix.android.sdk.api.util.toMatrixItem sealed class PendingSelection { - data class UserPendingSelection(val user: User) : PendingSelection() + data class UserPendingSelection(val user: User, var isUnknownUser: Boolean = false) : PendingSelection() data class ThreePidPendingSelection(val threePid: ThreePid) : PendingSelection() fun getBestName(): String { diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt index 1fa817d8af..971250dbfd 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt @@ -266,6 +266,7 @@ class UserListViewModel @AssistedInject constructor( .sortedBy { it.toMatrixItem().firstLetterOfDisplayName() } val userProfile = if (MatrixPatterns.isUserId(search)) { val user = tryOrNull { session.profileService().getProfileAsUser(search) } + setState { copy(unknownUserId = search.takeIf { user == null }) } User( userId = search, displayName = user?.displayName, @@ -290,6 +291,9 @@ class UserListViewModel @AssistedInject constructor( (action.pendingSelection is PendingSelection.UserPendingSelection && state.pendingSelections.last() is PendingSelection.UserPendingSelection) if (canSelectUser) { + if (action.pendingSelection is PendingSelection.UserPendingSelection) { + action.pendingSelection.isUnknownUser = action.pendingSelection.getMxId() == state.unknownUserId + } val selections = state.pendingSelections.toggle(action.pendingSelection, singleElement = state.singleSelection) setState { copy(pendingSelections = selections) } } diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewState.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewState.kt index ec932a2a57..27fa11bf54 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewState.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewState.kt @@ -30,6 +30,7 @@ data class UserListViewState( val matchingEmail: Async = Uninitialized, val filteredMappedContacts: List = emptyList(), val pendingSelections: Set = emptySet(), + val unknownUserId: String? = null, val searchTerm: String = "", val singleSelection: Boolean, val single3pidSelection: Boolean, diff --git a/vector/src/main/res/layout/fragment_bootstrap_error.xml b/vector/src/main/res/layout/fragment_bootstrap_error.xml new file mode 100644 index 0000000000..02c944fed2 --- /dev/null +++ b/vector/src/main/res/layout/fragment_bootstrap_error.xml @@ -0,0 +1,33 @@ + + + + + +