From 52e26e34d575918a25532c069db9ac5087b6842a Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 8 Sep 2023 21:48:39 +1000 Subject: [PATCH 1/8] DavDocumentsProvider: Log a warning for responses of type OTHER. (#400) If a WebDAV server is misconfigured (for example, behind an HTTP proxy that strips a URL prefix and doesn't correctly forward this to the WebDAV server) then PROPFIND can return resources whose URLs don't match the request URL. These are resolved by dav4jvm as HrefRelation.OTHER. Currently this situation produces no output at all in DAVx5 (logs or app) and the WebDAV share appears accessible but empty. It is possible to create files in the share, but not to see them again afterwards! Of course a misconfigured server isn't the WebDAV client's responsibility to resolve, but adding a warning in the log provides an extra clue for anyone trying to debug it. --- .../java/at/bitfire/davdroid/webdav/DavDocumentsProvider.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/at/bitfire/davdroid/webdav/DavDocumentsProvider.kt b/app/src/main/java/at/bitfire/davdroid/webdav/DavDocumentsProvider.kt index 2a2fb1e4f..ef07cd5d0 100644 --- a/app/src/main/java/at/bitfire/davdroid/webdav/DavDocumentsProvider.kt +++ b/app/src/main/java/at/bitfire/davdroid/webdav/DavDocumentsProvider.kt @@ -611,9 +611,11 @@ class DavDocumentsProvider: DocumentsProvider() { parent Response.HrefRelation.MEMBER -> // it's about a member WebDavDocument(mountId = parent.mountId, parentId = parent.id, name = response.hrefName()) - else -> - // we didn't request this; ignore it + else -> { + // we didn't request this; log a warning and ignore it + Logger.log.warning("Ignoring unexpected $response $relation in $parentUrl") return@propfind + } } response[ResourceType::class.java]?.types?.let { types -> -- GitLab From 464ba7d76e41dfe430444edf03a3ce66e810e9be Mon Sep 17 00:00:00 2001 From: Sunik Kupfer Date: Mon, 11 Sep 2023 11:40:51 +0200 Subject: [PATCH 2/8] Tests for ConnectionUtils (bitfireAT/davx5#372) * Add tests for internetAvailable() * Add tests for wifiAvailable() * Add TODO for test case * Add tests for internetAvailable() covering multiple network connections * Minor KDoc --------- Co-authored-by: Ricki Hirner --- .../davdroid/network/ConnectionUtilsTest.kt | 149 ++++++++++++++++++ .../davdroid/network/ConnectionUtils.kt | 12 +- .../davdroid/syncadapter/SyncWorker.kt | 7 +- 3 files changed, 158 insertions(+), 10 deletions(-) create mode 100644 app/src/androidTest/java/at/bitfire/davdroid/network/ConnectionUtilsTest.kt diff --git a/app/src/androidTest/java/at/bitfire/davdroid/network/ConnectionUtilsTest.kt b/app/src/androidTest/java/at/bitfire/davdroid/network/ConnectionUtilsTest.kt new file mode 100644 index 000000000..e13118214 --- /dev/null +++ b/app/src/androidTest/java/at/bitfire/davdroid/network/ConnectionUtilsTest.kt @@ -0,0 +1,149 @@ +/* + * Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details. + */ + +package at.bitfire.davdroid.network + +import android.net.ConnectivityManager +import android.net.Network +import android.net.NetworkCapabilities +import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET +import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN +import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED +import android.net.NetworkCapabilities.TRANSPORT_WIFI +import dagger.hilt.android.testing.HiltAndroidTest +import io.mockk.every +import io.mockk.mockk +import junit.framework.TestCase.assertFalse +import junit.framework.TestCase.assertTrue +import org.junit.Before +import org.junit.Test + +@HiltAndroidTest +class ConnectionUtilsTest { + + private val connectivityManager = mockk() + private val network1 = mockk() + private val network2 = mockk() + private val capabilities = mockk() + + @Before + fun setUp() { + every { connectivityManager.allNetworks } returns arrayOf(network1, network2) + every { connectivityManager.getNetworkInfo(network1) } returns mockk() + every { connectivityManager.getNetworkInfo(network2) } returns mockk() + every { connectivityManager.getNetworkCapabilities(network1) } returns capabilities + every { connectivityManager.getNetworkCapabilities(network2) } returns capabilities + } + + @Test + fun testWifiAvailable_capabilitiesNull() { + every { connectivityManager.getNetworkCapabilities(network1) } returns null + every { connectivityManager.getNetworkCapabilities(network2) } returns null + assertFalse(ConnectionUtils.wifiAvailable(connectivityManager)) + } + + @Test + fun testWifiAvailable() { + every { capabilities.hasTransport(TRANSPORT_WIFI) } returns false + every { capabilities.hasCapability(NET_CAPABILITY_VALIDATED) } returns false + assertFalse(ConnectionUtils.wifiAvailable(connectivityManager)) + } + + @Test + fun testWifiAvailable_wifi() { + every { capabilities.hasTransport(TRANSPORT_WIFI) } returns true + every { capabilities.hasCapability(NET_CAPABILITY_VALIDATED) } returns false + assertFalse(ConnectionUtils.wifiAvailable(connectivityManager)) + } + + @Test + fun testWifiAvailable_validated() { + every { capabilities.hasTransport(TRANSPORT_WIFI) } returns false + every { capabilities.hasCapability(NET_CAPABILITY_VALIDATED) } returns true + assertFalse(ConnectionUtils.wifiAvailable(connectivityManager)) + } + + @Test + fun testWifiAvailable_wifiValidated() { + every { capabilities.hasTransport(TRANSPORT_WIFI) } returns true + every { capabilities.hasCapability(NET_CAPABILITY_VALIDATED) } returns true + assertTrue(ConnectionUtils.wifiAvailable(connectivityManager)) + } + + + @Test + fun testInternetAvailable_capabilitiesNull() { + every { connectivityManager.getNetworkCapabilities(network1) } returns null + every { connectivityManager.getNetworkCapabilities(network2) } returns null + assertFalse(ConnectionUtils.internetAvailable(connectivityManager, false)) + } + + @Test + fun testInternetAvailable_Internet() { + every { capabilities.hasCapability(NET_CAPABILITY_INTERNET) } returns true + every { capabilities.hasCapability(NET_CAPABILITY_VALIDATED) } returns false + assertFalse(ConnectionUtils.internetAvailable(connectivityManager, false)) + } + + @Test + fun testInternetAvailable_Validated() { + every { capabilities.hasCapability(NET_CAPABILITY_INTERNET) } returns false + every { capabilities.hasCapability(NET_CAPABILITY_VALIDATED) } returns true + assertFalse(ConnectionUtils.internetAvailable(connectivityManager, false)) + } + + @Test + fun testInternetAvailable_InternetValidated() { + every { capabilities.hasCapability(NET_CAPABILITY_INTERNET) } returns true + every { capabilities.hasCapability(NET_CAPABILITY_VALIDATED) } returns true + assertTrue(ConnectionUtils.internetAvailable(connectivityManager, false)) + } + + @Test + fun testInternetAvailable_ignoreVpns() { + every { capabilities.hasCapability(NET_CAPABILITY_INTERNET) } returns true + every { capabilities.hasCapability(NET_CAPABILITY_VALIDATED) } returns true + every { capabilities.hasCapability(NET_CAPABILITY_NOT_VPN) } returns false + assertFalse(ConnectionUtils.internetAvailable(connectivityManager, true)) + } + + @Test + fun testInternetAvailable_ignoreVpns_Notvpn() { + every { capabilities.hasCapability(NET_CAPABILITY_INTERNET) } returns true + every { capabilities.hasCapability(NET_CAPABILITY_VALIDATED) } returns true + every { capabilities.hasCapability(NET_CAPABILITY_NOT_VPN) } returns true + assertTrue(ConnectionUtils.internetAvailable(connectivityManager, true)) + } + + @Test + fun testInternetAvailable_twoConnectionsFirstOneWithoutInternet() { + // The real case that failed in davx5-ose#395 is that the connection list contains (in this order) + // 1. a mobile network without INTERNET, but with VALIDATED + // 2. a WiFi network with INTERNET and VALIDATED + + // The "return false" of hasINTERNET will trigger at the first connection, the + // "andThen true" will trigger for the second connection + every { capabilities.hasCapability(NET_CAPABILITY_INTERNET) } returns false andThen true + every { capabilities.hasCapability(NET_CAPABILITY_VALIDATED) } returns true + + // There is an internet connection if any(!) connection has both INTERNET and VALIDATED. + assertTrue(ConnectionUtils.internetAvailable(connectivityManager, false)) + } + + @Test + fun testInternetAvailable_twoConnectionsFirstOneWithoutValidated() { + every { capabilities.hasCapability(NET_CAPABILITY_INTERNET) } returns true + every { capabilities.hasCapability(NET_CAPABILITY_VALIDATED) } returns false andThen true + assertTrue(ConnectionUtils.internetAvailable(connectivityManager, false)) + } + + @Test + fun testInternetAvailable_twoConnectionsFirstOneWithoutNotvpn() { + every { capabilities.hasCapability(NET_CAPABILITY_INTERNET) } returns true + every { capabilities.hasCapability(NET_CAPABILITY_VALIDATED) } returns true + every { capabilities.hasCapability(NET_CAPABILITY_NOT_VPN) } returns false andThen true + assertTrue(ConnectionUtils.internetAvailable(connectivityManager, true)) + } + +} \ No newline at end of file diff --git a/app/src/main/java/at/bitfire/davdroid/network/ConnectionUtils.kt b/app/src/main/java/at/bitfire/davdroid/network/ConnectionUtils.kt index f54ff2d47..36162a604 100644 --- a/app/src/main/java/at/bitfire/davdroid/network/ConnectionUtils.kt +++ b/app/src/main/java/at/bitfire/davdroid/network/ConnectionUtils.kt @@ -4,21 +4,18 @@ package at.bitfire.davdroid.network -import android.content.Context import android.net.ConnectivityManager import android.net.NetworkCapabilities import androidx.annotation.RequiresApi -import androidx.core.content.getSystemService import at.bitfire.davdroid.log.Logger import java.util.logging.Level object ConnectionUtils { /** - * Checks whether we are connected to working WiFi + * Checks whether we are connected to validated WiFi */ - internal fun wifiAvailable(context: Context): Boolean { - val connectivityManager = context.getSystemService()!! + internal fun wifiAvailable(connectivityManager: ConnectivityManager): Boolean { connectivityManager.allNetworks.forEach { network -> connectivityManager.getNetworkCapabilities(network)?.let { capabilities -> if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) && @@ -33,7 +30,7 @@ object ConnectionUtils { * Checks whether we are connected to the Internet. * * On API 26+ devices, if a VPN is used, WorkManager might start the SyncWorker without an - * internet connection (because NET_CAPABILITY_VALIDATED is always set for VPN connections). + * Internet connection (because [NetworkCapabilities.NET_CAPABILITY_VALIDATED] is always set for VPN connections). * To prevent the start without internet access, we don't check for VPN connections by default * (by using [NetworkCapabilities.NET_CAPABILITY_NOT_VPN]). * @@ -44,8 +41,7 @@ object ConnectionUtils { * @return whether we are connected to the Internet */ @RequiresApi(23) - internal fun internetAvailable(context: Context, ignoreVpns: Boolean): Boolean { - val connectivityManager = context.getSystemService()!! + internal fun internetAvailable(connectivityManager: ConnectivityManager, ignoreVpns: Boolean): Boolean { return connectivityManager.allNetworks.any { network -> val capabilities = connectivityManager.getNetworkCapabilities(network) Logger.log.log(Level.FINE, "Looking for validated Internet over this connection.", diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncWorker.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncWorker.kt index 9ca95ec5c..e8788c2da 100644 --- a/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncWorker.kt +++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncWorker.kt @@ -10,6 +10,7 @@ import android.content.ContentResolver import android.content.Context import android.content.Intent import android.content.SyncResult +import android.net.ConnectivityManager import android.net.wifi.WifiManager import android.os.Build import android.provider.CalendarContract @@ -254,7 +255,8 @@ class SyncWorker @AssistedInject constructor( return true // yes, continue // WiFi required, is it available? - if (!wifiAvailable(context)) { + val connectivityManager = context.getSystemService()!! + if (!wifiAvailable(connectivityManager)) { Logger.log.info("Not on connected WiFi, stopping") return false } @@ -282,7 +284,8 @@ class SyncWorker @AssistedInject constructor( // Check internet connection val ignoreVpns = AccountSettings(applicationContext, account).getIgnoreVpns() - if (Build.VERSION.SDK_INT >= 23 && !internetAvailable(applicationContext, ignoreVpns)) { + val connectivityManager = applicationContext.getSystemService()!! + if (Build.VERSION.SDK_INT >= 23 && !internetAvailable(connectivityManager, ignoreVpns)) { Logger.log.info("WorkManager started SyncWorker without Internet connection. Aborting.") return Result.failure() } -- GitLab From bc7a320916db7d42cac152c5717383850bd7bfd8 Mon Sep 17 00:00:00 2001 From: Ricki Hirner Date: Tue, 12 Sep 2023 13:03:15 +0200 Subject: [PATCH 3/8] Don't start multiple tests for PRs --- .github/workflows/test-dev.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-dev.yml b/.github/workflows/test-dev.yml index f7d635ecb..7aa25df8f 100644 --- a/.github/workflows/test-dev.yml +++ b/.github/workflows/test-dev.yml @@ -1,5 +1,5 @@ name: Development tests -on: [push, pull_request] +on: push concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true -- GitLab From 651ab9c53c2abe96353994238c5611bb381dc065 Mon Sep 17 00:00:00 2001 From: Arnau Mora Date: Tue, 12 Sep 2023 13:03:46 +0200 Subject: [PATCH 4/8] Fixed empty translators.json (#401) * Update translators.json * Added JSON parsing try-catch Signed-off-by: Arnau Mora * Log complete exception --------- Signed-off-by: Arnau Mora Co-authored-by: Ricki Hirner --- app/src/main/assets/translators.json | 1 + .../at/bitfire/davdroid/ui/AboutActivity.kt | 41 +++++++++++-------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/app/src/main/assets/translators.json b/app/src/main/assets/translators.json index e69de29bb..c092d915c 100644 --- a/app/src/main/assets/translators.json +++ b/app/src/main/assets/translators.json @@ -0,0 +1 @@ +{"ar_SA":["abdunnasir"],"bg":["dpa_transifex"],"ca":["Kintu","jordibrus","zagur"],"cs":["pavelb","tomas.odehnal"],"da":["Tntdruid_","knutztar","mjjzf","twikedk"],"de":["Atalanttore","TheName","Wyrrrd","YvanM","amandablue","anestiskaci","corppneq","crit12","hammaschlach","maxkl","nicolas_git","owncube"],"el":["KristinaQejvanaj","anestiskaci","diamond_gr"],"es":["Ark74","Elhea","GranPC","aluaces","jcvielma","plaguna","polkhas","xphnx"],"eu":["Osoitz","Thadah","cockeredradiation"],"fa":["Numb","ahangarha","amiraliakbari","joojoojoo","maryambehzi","mtashackori","taranehsaei"],"fr":["AlainR","Amadeen","Floflr","Llorc","LoiX07","Novick","Poussinou","Thecross","YvanM","alkino2","boutil","callmemagnus","chfo","chrcha","grenatrad","jokx","mathieugfortin","paullbn","vincen","ÉricB."],"fr_FR":["Llorc","Poussinou","chrcha"],"gl":["aluaces","pikamoku"],"hu":["Roshek","jtg"],"it":["Damtux","FranzMari","ed0","malaerba","noccio","nwandy","rickyroo","technezio"],"it_IT":["malaerba"],"ja":["Naofumi","yanorei32"],"nb_NO":["elonus"],"nl":["XtremeNova","davtemp","dehart","erikhubers","frankyboy1963","toonvangerwen"],"pl":["TORminator","TheName","Valdnet","gsz","mg6","oskarjakiela"],"pt":["amalvarenga","wanderlei.huttel"],"pt_BR":["wanderlei.huttel"],"ru":["aigoshin","anm","astalavister","nick.savin","vaddd"],"sk_SK":["brango67","tiborepcek"],"sl_SI":["MrLaaky","uroszor"],"sr":["daimonion"],"sv":["Mikaelb","campbelldavid"],"szl":["chlodny"],"tr_TR":["ooguz","pultars"],"uk":["androsua","olexn","twixi007"],"uk_UA":["astalavister"],"zh_CN":["anolir","jxj2zzz79pfp9bpo","linuxbckp","mofitt2016","oksjd","phy","spice2wolf"],"zh_TW":["linuxbckp","mofitt2016","phy","waiabsfabuloushk"]} diff --git a/app/src/main/java/at/bitfire/davdroid/ui/AboutActivity.kt b/app/src/main/java/at/bitfire/davdroid/ui/AboutActivity.kt index 296150001..a2079164a 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/AboutActivity.kt +++ b/app/src/main/java/at/bitfire/davdroid/ui/AboutActivity.kt @@ -35,6 +35,7 @@ import at.bitfire.davdroid.databinding.AboutBinding import at.bitfire.davdroid.databinding.AboutLanguagesBinding import at.bitfire.davdroid.databinding.AboutTranslationBinding import at.bitfire.davdroid.databinding.ActivityAboutBinding +import at.bitfire.davdroid.log.Logger import com.google.accompanist.themeadapter.material.MdcTheme import com.mikepenz.aboutlibraries.ui.compose.LibrariesContainer import dagger.BindsOptionalOf @@ -45,10 +46,12 @@ import dagger.hilt.android.components.ActivityComponent import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.apache.commons.io.IOUtils +import org.json.JSONException import org.json.JSONObject import java.text.Collator import java.text.SimpleDateFormat import java.util.* +import java.util.logging.Level import javax.inject.Inject import javax.inject.Qualifier @@ -280,27 +283,31 @@ class AboutActivity: AppCompatActivity() { val translations = object: MediatorLiveData>() { init { addSource(plainText) { rawJson -> - // parse JSON - val jsonTranslations = JSONObject(rawJson) - val result = LinkedList() - for (langCode in jsonTranslations.keys()) { - val jsonTranslators = jsonTranslations.getJSONArray(langCode) - val translators = Array(jsonTranslators.length()) { - idx -> jsonTranslators.getString(idx) + try { + // parse JSON + val jsonTranslations = JSONObject(rawJson) + val result = LinkedList() + for (langCode in jsonTranslations.keys()) { + val jsonTranslators = jsonTranslations.getJSONArray(langCode) + val translators = Array(jsonTranslators.length()) { + idx -> jsonTranslators.getString(idx) + } + + val langTag = langCode.replace('_', '-') + val language = Locale.forLanguageTag(langTag).displayName + result += Translation(language, translators) } - val langTag = langCode.replace('_', '-') - val language = Locale.forLanguageTag(langTag).displayName - result += Translation(language, translators) - } + // sort translations by localized language name + val collator = Collator.getInstance() + result.sortWith { o1, o2 -> + collator.compare(o1.language, o2.language) + } - // sort translations by localized language name - val collator = Collator.getInstance() - result.sortWith { o1, o2 -> - collator.compare(o1.language, o2.language) + postValue(result) + } catch (e: JSONException) { + Logger.log.log(Level.SEVERE, "Could not parse translators JSON", e) } - - postValue(result) } } } -- GitLab From ead6293be65aa52ef005fbfabf22acaa6aa4c6eb Mon Sep 17 00:00:00 2001 From: Arnau Mora Date: Thu, 21 Sep 2023 18:43:15 +0200 Subject: [PATCH 5/8] cert4android: certificates are not saved across app restarts; other bug fixes (bitfireAT/davx5#392) * Updated cert4android dependency --------- Signed-off-by: Arnau Mora Co-authored-by: Ricki Hirner --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ac2c34bab..cb0b0ce62 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ buildscript { commonsLang: '3.8.1', commonsText: '1.3', // own libraries - cert4android: 'd6fd798', + cert4android: '32104f5', dav4jvm: 'da94a8b', ical4android: 'b682476', vcard4android: 'b376d2e' -- GitLab From b8e4ba62f5451d8d8d027862550899f2afac7d54 Mon Sep 17 00:00:00 2001 From: Ricki Hirner Date: Thu, 21 Sep 2023 18:48:21 +0200 Subject: [PATCH 6/8] Update dependencies, bump version to 4.3.7-rc.1 --- app/build.gradle | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 2b22a0d46..893491266 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -18,8 +18,8 @@ android { defaultConfig { applicationId "at.bitfire.davdroid" - versionCode 403060100 - versionName '4.3.6.1' + versionCode 403070000 + versionName '4.3.7-rc.1' buildConfigField "long", "buildTime", System.currentTimeMillis() + "L" @@ -136,13 +136,13 @@ dependencies { implementation 'androidx.cardview:cardview:1.0.0' implementation 'androidx.concurrent:concurrent-futures-ktx:1.1.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - implementation 'androidx.core:core-ktx:1.10.1' + implementation 'androidx.core:core-ktx:1.12.0' implementation 'androidx.fragment:fragment-ktx:1.6.1' implementation 'androidx.hilt:hilt-work:1.0.0' kapt 'androidx.hilt:hilt-compiler:1.0.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' - implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1' - implementation 'androidx.paging:paging-runtime-ktx:3.2.0' + implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2' + implementation 'androidx.paging:paging-runtime-ktx:3.2.1' implementation 'androidx.preference:preference-ktx:1.2.1' implementation 'androidx.security:security-crypto:1.1.0-alpha06' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' -- GitLab From 7be6e0636b5c32e488659adc25c1ce0d4e144a5f Mon Sep 17 00:00:00 2001 From: Ricki Hirner Date: Fri, 22 Sep 2023 15:50:32 +0200 Subject: [PATCH 7/8] Bump version to 4.3.7 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 893491266..eca71949d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -18,8 +18,8 @@ android { defaultConfig { applicationId "at.bitfire.davdroid" - versionCode 403070000 - versionName '4.3.7-rc.1' + versionCode 403070001 + versionName '4.3.7' buildConfigField "long", "buildTime", System.currentTimeMillis() + "L" -- GitLab From 4faecc653f3b505ca6edab63f04a151f5c37e7d6 Mon Sep 17 00:00:00 2001 From: Ricki Hirner Date: Fri, 22 Sep 2023 15:57:01 +0200 Subject: [PATCH 8/8] Fetch translations from Transifex --- app/src/main/assets/translators.json | 2 +- app/src/main/res/values-bg/strings.xml | 2 + app/src/main/res/values-ca/strings.xml | 3 + app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-eu/strings.xml | 3 + app/src/main/res/values-gl/strings.xml | 3 + app/src/main/res/values-ja/strings.xml | 2 +- app/src/main/res/values-pl/strings.xml | 4 + app/src/main/res/values-ro/strings.xml | 443 ++++++++++++++++++ app/src/main/res/values-ru/strings.xml | 3 + app/src/main/res/values-zh/strings.xml | 3 + .../metadata/android/ro/short_description.txt | 1 + 12 files changed, 468 insertions(+), 2 deletions(-) create mode 100644 app/src/main/res/values-ro/strings.xml create mode 100644 fastlane/metadata/android/ro/short_description.txt diff --git a/app/src/main/assets/translators.json b/app/src/main/assets/translators.json index c092d915c..eb66b1fa1 100644 --- a/app/src/main/assets/translators.json +++ b/app/src/main/assets/translators.json @@ -1 +1 @@ -{"ar_SA":["abdunnasir"],"bg":["dpa_transifex"],"ca":["Kintu","jordibrus","zagur"],"cs":["pavelb","tomas.odehnal"],"da":["Tntdruid_","knutztar","mjjzf","twikedk"],"de":["Atalanttore","TheName","Wyrrrd","YvanM","amandablue","anestiskaci","corppneq","crit12","hammaschlach","maxkl","nicolas_git","owncube"],"el":["KristinaQejvanaj","anestiskaci","diamond_gr"],"es":["Ark74","Elhea","GranPC","aluaces","jcvielma","plaguna","polkhas","xphnx"],"eu":["Osoitz","Thadah","cockeredradiation"],"fa":["Numb","ahangarha","amiraliakbari","joojoojoo","maryambehzi","mtashackori","taranehsaei"],"fr":["AlainR","Amadeen","Floflr","Llorc","LoiX07","Novick","Poussinou","Thecross","YvanM","alkino2","boutil","callmemagnus","chfo","chrcha","grenatrad","jokx","mathieugfortin","paullbn","vincen","ÉricB."],"fr_FR":["Llorc","Poussinou","chrcha"],"gl":["aluaces","pikamoku"],"hu":["Roshek","jtg"],"it":["Damtux","FranzMari","ed0","malaerba","noccio","nwandy","rickyroo","technezio"],"it_IT":["malaerba"],"ja":["Naofumi","yanorei32"],"nb_NO":["elonus"],"nl":["XtremeNova","davtemp","dehart","erikhubers","frankyboy1963","toonvangerwen"],"pl":["TORminator","TheName","Valdnet","gsz","mg6","oskarjakiela"],"pt":["amalvarenga","wanderlei.huttel"],"pt_BR":["wanderlei.huttel"],"ru":["aigoshin","anm","astalavister","nick.savin","vaddd"],"sk_SK":["brango67","tiborepcek"],"sl_SI":["MrLaaky","uroszor"],"sr":["daimonion"],"sv":["Mikaelb","campbelldavid"],"szl":["chlodny"],"tr_TR":["ooguz","pultars"],"uk":["androsua","olexn","twixi007"],"uk_UA":["astalavister"],"zh_CN":["anolir","jxj2zzz79pfp9bpo","linuxbckp","mofitt2016","oksjd","phy","spice2wolf"],"zh_TW":["linuxbckp","mofitt2016","phy","waiabsfabuloushk"]} +{"ar_SA":["abdunnasir"],"bg":["dpa_transifex"],"ca":["Kintu","jordibrus","zagur"],"cs":["pavelb","tomas.odehnal"],"da":["Tntdruid_","knutztar","mjjzf","twikedk"],"de":["Atalanttore","TheName","Wyrrrd","YvanM","amandablue","anestiskaci","corppneq","crit12","hammaschlach","maxkl","nicolas_git","owncube"],"el":["KristinaQejvanaj","anestiskaci","diamond_gr"],"es":["Ark74","Elhea","GranPC","aluaces","jcvielma","plaguna","polkhas","xphnx"],"eu":["Osoitz","Thadah","cockeredradiation"],"fa":["Numb","ahangarha","amiraliakbari","joojoojoo","maryambehzi","mtashackori","taranehsaei"],"fr":["AlainR","Amadeen","Floflr","Llorc","LoiX07","Novick","Poussinou","Thecross","YvanM","alkino2","boutil","callmemagnus","chfo","chrcha","grenatrad","jokx","mathieugfortin","paullbn","vincen","ÉricB."],"fr_FR":["Llorc","Poussinou","chrcha"],"gl":["aluaces","pikamoku"],"hu":["Roshek","jtg"],"it":["Damtux","FranzMari","ed0","malaerba","noccio","nwandy","rickyroo","technezio"],"it_IT":["malaerba"],"ja":["Naofumi","yanorei32"],"nb_NO":["elonus"],"nl":["XtremeNova","davtemp","dehart","erikhubers","frankyboy1963","toonvangerwen"],"pl":["TORminator","TheName","Valdnet","gsz","mg6","oskarjakiela"],"pt":["amalvarenga","wanderlei.huttel"],"pt_BR":["wanderlei.huttel"],"ru":["aigoshin","anm","astalavister","nick.savin","vaddd"],"sk_SK":["brango67","tiborepcek"],"sl_SI":["MrLaaky","uroszor"],"sr":["daimonion"],"sv":["Mikaelb","campbelldavid"],"szl":["chlodny"],"tr_TR":["ooguz","pultars"],"uk":["androsua","olexn","twixi007"],"uk_UA":["astalavister"],"zh_CN":["anolir","jxj2zzz79pfp9bpo","linuxbckp","mofitt2016","oksjd","phy","spice2wolf"],"zh_TW":["linuxbckp","mofitt2016","phy","waiabsfabuloushk"]} diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml index fa8e029b7..34bd30c32 100644 --- a/app/src/main/res/values-bg/strings.xml +++ b/app/src/main/res/values-bg/strings.xml @@ -264,6 +264,8 @@ Профил в Гугъл Вход с Гугъл Идентификатор на клиент (по желание) + Политика за поверителност.]]> + Политиката за потребителски данни на услугите на Google API, включително на Изискванията за ограничена употреба.]]> Не може да бъде получен код за упълномощаване Откриване на настройки Изчакайте, запитване на сървъра… diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index b0f5c4813..249cb758a 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -299,6 +299,9 @@ Noms (SSID) separats per comes de les xarxes Wi-Fi permeses (deixeu-ho en blanc per a totes) La restricció per SSID de la Wi-Fi requereix una configuració addicional Gestió + Connexió VPN + Requerir connexió sense VPN (recomanat) + Les VPN compten com a connexió a Internet Autentificació Re-Autenticar Tornar a realitzar l\'inici de sessió amb OAuth diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 25333c71a..44f5b206d 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -299,6 +299,7 @@ Erlaubte WLAN-Namen (SSIDs, mit Komma getrennt, leer lassen für alle) WLAN-SSID-Einschränkung benötigt weitere Einstellungen Verwalten + VPN zählt als Internetverbindung Anmeldeinformationen Wieder anmelden Erneut mit OAuth anmelden diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index 28a69a4ef..bfd1b63ae 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -299,6 +299,9 @@ Komaz banatutako izenak (SSIDak) baimendutako WiFi sareentzako (utzi hutsik denentzako) WiFi SSID murriztapenak ezarpen gehiago behar ditu Kudeatu + VPN konexioa + VPN ez den konexioa behar da (gomendatua) + VPN Interneteko konexio gisa balio du Autentifikazioa Berriro autentifikatu Egin OAuth saioa berriro diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 93a31b5ce..f038d4e9c 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -299,6 +299,9 @@ Nome das rede WiFi permitidas (SSIDs) separados por vírgulas (en branco para todas) A restrición WiFi SSID precisa máis axustes Xestionar + Conectividade VPN + Requerida conexión non-VPN (recomendado) + VPN conta como conexión a internet Autenticación Volver a autenticar Intentar acceder con OAuth outra vez diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 58354eb0c..1d0a95e9e 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -25,7 +25,7 @@ ネットワークおよび I/O エラー タイムアウト、接続の問題など (多くの場合、一時的なもの) - あなたのデータはあなたの手で + あなたのデータはあなたの手に コントロールを始める 一定の間隔で同期 無効 (非推奨) diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index b6043a64f..cc52a95bb 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -262,6 +262,7 @@ Aktualne informacje można znaleźć na naszej stronie \"Testowano z Google\". Mogą wystąpić nieoczekiwane ostrzeżenia i/lub konieczność utworzenia własnego identyfikatora klienta. Konto Google + Zaloguj się za pomocą Google ID klienta (opcjonalnie) Polityce prywatności.]]> Zasadami dotyczącymi danych użytkownika usług interfejsu API Google, w tym wymaganiami dotyczącymi Ograniczonego użytkowania.]]> @@ -298,6 +299,9 @@ Oddzielone przecinkami nazwy (SSID) dozwolonych sieci Wi‑Fi (pozostaw puste dla wszystkich) Ograniczenie WiFi SSID wymaga dalszych ustawień Zarządzaj + Łączność VPN + Wymagane połączenie inne niż VPN (zalecane) + VPN zaliczyć jako połączenie internetowe Uwierzytelnianie Uwierzytelnij ponownie Wykonaj ponownie logowanie OAuth diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml new file mode 100644 index 000000000..28cd84d83 --- /dev/null +++ b/app/src/main/res/values-ro/strings.xml @@ -0,0 +1,443 @@ + + + + DAVx⁵ + Contul nu (mai) există + Agenda DAVx⁵ + Agende cu adrese + Elimină + Anulează + Acest câmp este obligatoriu + Ajutor + Gestionează conturile + Distribuie + Fără internet, programare sincronizare + Bază de date deteriorată + Toate conturile au fost eliminate local. + Depanare + Alte mesaje importante + Mesaje de stare cu prioritate redusă + Sincronizare + Erori de sincronizare + Erori importante care opresc sincronizarea, cum ar fi răspunsurile neașteptate ale serverului + Avertismente de sincronizare + Probleme de sincronizare non-fatale, cum ar fi anumite fișiere nevalide + Erori de rețea și I/O + Expirare, probleme de conexiune etc. (adesea temporare) + + Datele tale. Alegerea ta. + Preia controlul. + Intervale regulate de sincronizare + Dezactivat (nu este recomandat) + Activat (recomandat) + Pentru sincronizare la intervale regulate, %s trebuie să aibă voie să ruleze în fundal. În caz contrar, Android poate întrerupe sincronizarea în orice moment. + Nu am nevoie de intervale regulate de sincronizare.* + Compatibilitate %s + Acest dispozitiv probabil blochează sincronizarea. Dacă ești afectat, poți rezolva acest lucru numai manual. + Am făcut setările necesare. Nu-mi mai aminti.* + * Lasă nebifat pentru a fi reamintit mai târziu. Poate fi resetat în setările aplicației / %s. + Mai multe informații + Placă de bază jtx + + Suport pentru sarcini + Dacă sarcinile sunt acceptate de server, acestea pot fi sincronizate cu o aplicație de sarcini acceptată: + OpenTasks + Nu pare a mai fi dezvoltat – nu este recomandat. + Tasks.org + nu sunt acceptate (încă).]]> + Nu există un magazin de aplicații disponibil + Nu am nevoie de suport pentru sarcini.* + Software cu sursă deschisă + Ne bucurăm că utilizezi %s, care este un software open-source. Dezvoltarea, întreținerea și suportul sunt o muncă grea. Ia în considerare contribuția (există mai multe moduri) sau o donație. Ar fi foarte apreciat! + Cum să contribui/donezi + Nu afișa în viitorul apropiat + + Permisiuni + %s necesită permisiuni pentru a funcționa corect. + Toate cele de mai jos + Utilizează aceasta pentru a activa toate funcțiile (recomandat) + Toate permisiunile sunt acordate + Permisiuni Contacte + Fără sincronizare de contacte (nu este recomandat) + Este posibilă sincronizarea contactelor + Permisiuni pentru calendar + Fără sincronizare calendar (nu este recomandat) + Sincronizarea calendarului este posibilă + Permisiune de notificare + Notificări dezactivate (nu este recomandat) + Notificări activate + Permisiuni pentru jtx Board + Nicio sarcină, jurnale și note sincronizate (nu sunt instalate) + Nicio sarcină, jurnale și note sincronizate + Este posibilă sincronizarea sarcinilor, jurnalelor, notelor + Permisiuni OpenTasks + Permisiuni pentru sarcini + Nicio sincronizare a sarcinilor (nu este instalat) + Nicio sincronizare a sarcinilor + Este posibilă sincronizarea sarcinilor + Păstrează permisiunile + Permisiunile pot fi resetate automat (nu este recomandat) + Permisiunile nu vor fi resetate automat + Clic pe Permisiuni > debifează „Elimină permisiunile dacă aplicația nu este utilizată” + Dacă un comutator nu funcționează, utilizează setările/permisiunile aplicației. + Setările aplicației + + Permisiuni SSID WiFi + Pentru a putea accesa numele actual WiFi (SSID), trebuie îndeplinite următoarele condiții: + Permisiune de locație precisă + Permisiunea de locație acordată + Permisiunea de locație refuzată + Permisiunea de locație în fundal + Permite tot timpul + %s]]> + %s]]> + %s folosește permisiunea Locație numai pentru a determina SSID-ul WiFi actual pentru conturile restricționate de SSID. Acest lucru se va întâmpla chiar și atunci când aplicația este în fundal. Nu sunt colectate, stocate, procesate sau trimise nicăieri date despre locație. + Locația este întotdeauna activată + Serviciul de localizare este activat + Serviciul de localizare este dezactivat + + Traduceri + Biblioteci + Versiune %1$s (%2$d) + Compilată la %s + © Ricki Hirner, Bernhard Stockmann (inginerie web bitfire GmbH) și contribuitori + Această versiune este eligibilă pentru distribuție numai prin Google Play. + Acest program vine cu ABSOLUT NICIO GARANȚIE. Este software gratuit și ești binevenit să îl redistribui în anumite condiții. + Mulțumiri: %s]]> + + Nu s-a putut crea fișierul jurnal + Acum se înregistrează toate activitățile %s + Vizualizare/distribuire + Dezactivează + + Deschide sertarul de navigare + Închide sertarul de navigare + Adaptor de sincronizare CalDAV/CardDAV + Despre / Licență + Feedback beta + Instalează un client de e-mail + Instalează un browser web + Setări + Știri și actualizări + Instrumente + Link-uri externe + Pagină web + Manual + Întrebări frecvente + Comunitate + Donează + Politica de confidențialitate + Notificări dezactivate. Nu vei fi notificat despre erorile de sincronizare. + Fără conexiune la internet. Android nu va rula sincronizarea. + Gestionează conexiunile + Spațiu de depozitare redus. Android nu va rula sincronizarea. + Gestionează stocarea + Economizorul de date este activat. Sincronizarea în fundal este restricționată. + Gestionează economizorul de date + Bun venit la DAVx⁵!\n\nPoți adăuga acum un cont CalDAV/CardDAV. + Sincronizarea automată la nivel de sistem este dezactivată + Activează + Sincronizează toate conturile + + Detectarea serviciului a eșuat + Lista de colecții nu a putut fi actualizată + + Nu poate rula în prim-plan + Este necesară înscrierea în lista albă pentru optimizarea bateriei + + Rulează în prim-plan + Pe unele dispozitive, acest lucru este necesar pentru sincronizarea automată. + + Setări + Depanare + Afișează informațiile de depanare + Vizualizează/partajează software-ul și detaliile de configurare + Jurnalizare detaliată + Înregistrarea este activă + Înregistrarea este dezactivată + Optimizarea bateriei + Aplicația este inclusă în lista albă (recomandat) + Aplicația nu este inclusă în lista albă (nu este recomandat) + Păstrează în prim-plan + Poate fi de ajutor dacă dispozitivul împiedică sincronizarea automată + Conexiune + Tip proxy + + Implicit + Fără proxy + HTTP + SOCKS (pentru Orbot) + + Nume gazdă proxy + Port proxy + Securitate + Permisiunile aplicației + Examinează permisiunile necesare pentru sincronizare + Nu avea încredere în certificatele de sistem + CA de sistem și de utilizator nu vor fi de încredere + CA de sistem și de utilizator vor fi de încredere (recomandat) + Resetează certificatele de (ne)încredere + Resetează încrederea tuturor certificatelor personalizate + Toate certificatele personalizate au fost șterse + Interfață de utilizator + Setări de notificare + Gestionează canalele de notificare și setările acestora + Selectează tema + + Ca în sistem + Luminoasă + Întunecată + + Resetează sugestiile + Reactivează sugestiile care au fost respinse anterior + Toate sugestiile vor fi afișate din nou + Integrare + Aplicația de sarcini + Sincronizare cu %s + Nu a fost găsită nicio aplicație de sarcini compatibilă + + CardDAV + CalDAV + Webcal + Fără sincronizare contacte (permisiuni lipsă) + Fără sincronizare calendar (permisiuni lipsă) + Fără sincronizare sarcini (permisiuni lipsă) + Fără sincronizare calendar și sarcini (permisiuni lipsă) + Nu se pot accesa calendarele (permisiuni lipsă) + Permisiuni + Nu există (încă) agende de adrese. + Nu există calendare (încă). + Nu există abonamente la calendar (încă). + Glisează în jos pentru a reîmprospăta lista de pe server. + Sincronizează acum + Setările contului + Redenumește contul + Datele locale nesalvate pot fi respinse. Resincronizarea este necesară după redenumire. Numele nou al contului: + Redenumește + Numele contului este deja luat + Nu s-a putut redenumi contul + Șterge contul + Chiar ștergi contul? + Toate copiile locale ale agendelor, calendarelor și listelor de sarcini vor fi șterse. + sincronizează această colecție + numai pentru citire + calendar + lista de sarcini + jurnal + Afișează numai personal + Actualizează lista agendei de adrese + Creează o nouă agendă de adrese + Actualizează lista de calendare + Creează un calendar nou + Nu a fost găsită nicio aplicație compatibilă cu Webcal + Instalează ICSx⁵ + + Adaugă contul + Conectează-te cu adresa de e-mail + Adresa de e-mail + Este necesară o adresă de e-mail validă + Parolă + Este necesară parola + Conecteează-te cu adresa URL și numele de utilizator + Adresa URL trebuie să înceapă cu http(s):// + Nume de utilizator + Numele de utilizator este necesar + Adresa URL de bază + Selectează certificatul + Autentificare + Creează cont + Nume de cont + S-a raportat că utilizarea apostrofelor (\') cauzează probleme pe unele dispozitive. + Utilizează adresa de e-mail ca nume de cont, deoarece Android va folosi numele contului ca câmp ORGANIZATOR pentru evenimentele pe care le creezi. Nu poți avea două conturi cu același nume. + Metoda de grupare a contactelor: + Numele contului este necesar + Numele contului este deja luat + Contul nu a putut fi creat + Conectare avansată (cazuri speciale de utilizare) + Utilizează numele de utilizator/parola + Utilizează certificatul clientului + Nu a fost găsit niciun certificat + Instalare certificat + Contacte Google / Calendar + Consultă pagina noastră „Testat cu Google” pentru informații actualizate. + Este posibil să ai avertismente neașteptate și/sau să fii nevoit să creezi propriul ID de client. + Cont Google + Conectează-te cu Google + ID client (opțional) + Politica de confidențialitate pentru detalii.]]> + Politica privind datele utilizatorilor serviciilor API Google, inclusiv cerințele de utilizare limitată.]]> + Nu s-a putut obține codul de autorizare + Detectarea configurației + Se interoghează serverul… + Nu s-a putut găsi serviciul CalDAV sau CardDAV. + Nume de utilizator (adresă de e-mail)/parolă greșită? + Afișează detaliile + + Setări: %s + Sincronizare + Interval de sincronizare a contactelor + Doar manual + La fiecare %d minute + imediat la modificări locale + Interval de sincronizare a calendarelor + Interval de sincronizare a sarcinilor + + Doar manual + La fiecare 15 minute + La fiecare 30 de minute + La fiecare oră + La fiecare 2 ore + La fiecare 4 ore + O dată pe zi + + Sincronizare numai prin WiFi + Sincronizarea este limitată la conexiunile WiFi + Tipul de conexiune nu este luat în considerare + Restricție SSID WiFi + Se va sincroniza numai prin %s + Se va sincroniza numai prin %s (necesită servicii de localizare activate) + Toate conexiunile WiFi vor fi utilizate + Nume separate prin virgulă (SSID) ale rețelelor WiFi permise (lasă necompletat pentru toate) + Restricția SSID WiFi necesită setări suplimentare + Gestionează + Conectivitate VPN + Este necesară o conexiune non-VPN (recomandat) + VPN contează ca conexiune la internet + Autentificare + Reautentificare + Efectuează din nou autentificarea OAuth + nume de utilizator + Nume de utilizator + Introdu numele de utilizator: + Parolă + Actualizează parola în funcție de server. + Introdu parola: + Alias ​​certificat de client + Niciun certificat selectat + CalDAV + Limită de timp pentru evenimentele din trecut + Toate evenimentele vor fi sincronizate + + Evenimentele cu mai mult de o zi în trecut vor fi ignorate + Evenimentele cu peste %d zile în trecut vor fi ignorate + Evenimentele cu peste %d zile în trecut vor fi ignorate + + Evenimentele care depășesc acest număr de zile în trecut vor fi ignorate (poate fi 0). Lasă necompletat pentru a sincroniza toate evenimentele. + Memento implicit + + Memento implicit cu un minut înainte de eveniment + Memento implicit cu %d minute înainte de eveniment + Memento implicit cu %d minute înainte de eveniment + + Nu sunt create mementouri implicite + Dacă vor fi create memento-uri implicite pentru evenimente fără memento: numărul dorit de minute înainte de eveniment. Lasă necompletat pentru a dezactiva memento-urile implicite. + Gestionează culorile calendarului + Culorile calendarului sunt resetate la fiecare sincronizare + Culorile calendarului pot fi setate de alte aplicații + Suport pentru culoarea evenimentului + Culorile evenimentelor sunt sincronizate + Culorile evenimentelor nu sunt sincronizate + CardDAV + Metoda de grupare a contactelor + + Grupurile sunt vCard-uri separate + Grupurile sunt categorii per-contact + + + Creează agendă de adrese + Creează un calendar + Fus orar + Posibile intrări din calendar + Evenimente + Sarcini + Note/jurnal + Culoare + Creare colecție + Titlu + Titlul este obligatoriu + Descriere + opțional + Locația de stocare + Este necesară locația de stocare + Crează + Șterge colecția + Ești sigur? + Această colecție (%s) și toate datele sale vor fi eliminate definitiv. + Aceste date vor fi șterse de pe server. + Forțează numai citire + Proprietăți + Ultima sincronizare: + Nu s-a sincronizat niciodată + Adresă (URL): + Proprietar: + + Informații de depanare + Arhivă ZIP + Conține informații de depanare și jurnale + Partajează arhiva pentru a o transfera pe un computer, pentru a o trimite prin e-mail sau pentru a o atașa la un bilet de asistență. + Partajează arhiva + Informații de depanare atașate la acest mesaj (necesită suport pentru atașamentele aplicației care primește). + Eroare HTTP + Eroare de server + Eroare WebDAV + Eroare I/O + Solicitarea a fost respinsă. Verifică resursele implicate și informațiile de depanare pentru detalii. + Resursa solicitată nu mai există (mai mult). Verifică resursele implicate și informațiile de depanare pentru detalii. + A apărut o problemă la nivelul serverului. Contactează asistența serverului. + A apărut o eroare neașteptată. Vezi informațiile de depanare pentru detalii. + Vezi detaliile + Au fost colectate informații de depanare + Resurse implicate + Legat de problema + Resursa de la distanță: + Resursa locală: + Jurnale + Jurnalele detaliate sunt disponibile + Vezi jurnalele + + A avut loc o eroare. + A apărut o eroare HTTP. + A apărut o eroare I/O. + Afișează detaliile + + Sincronizarea a fost întreruptă + Aproape că nu a mai rămas spațiu liber + + Montări WebDAV + Cotă utilizată: %1$s / disponibilă: %2$s + Partajează conținutul + Demontează + Adaugă o montare WebDAV + Accesează direct fișierele din cloud adăugând o montare WebDAV! + cum funcționează montările WebDAV.]]> + Numele afișat + URL WebDAV + URL greșit + Nume de utilizator + Parolă + Adaugă montare + Niciun serviciu WebDAV la această adresă URL + Elimină punctul de montare + Detaliile conexiunii se vor pierde, dar niciun fișier nu va fi șters. + Se accesează fișierul WebDAV + Se descarcă fișierul WebDAV + Se actualizează fișierul WebDAV + Montare WebDAV + + Permisiuni DAVx⁵ + Sunt necesare permisiuni suplimentare + %s prea vechi + Versiunea minimă necesară: %1$s + Autentificare eșuată (verifică datele de conectare) + Eroare de rețea sau I/O – %s + Eroare de server HTTP – %s + Eroare de stocare locală – %s + Eroare soft (încercări maxime atinse) + Vezi elementul + S-a primit contact nevalid de la server + S-a primit eveniment nevalid de la server + S-a primit sarcină nevalidă de la server + Ignorarea uneia sau mai multor resurse nevalide + + DAVx⁵: Securitatea conexiunii + DAVx⁵ a întâlnit un certificat necunoscut. Vrei să ai încredere? + diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 6a3f77a8d..b194a3b53 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -299,6 +299,9 @@ Имена (SSID) разрешенных сетей WiFi, разделенные запятыми (оставьте пустым для всех) Ограничение WiFi SSID требует дополнительных настроек Управлять + VPN-подключение + Подключение без VPN (рекомендуется) + VPN считается подключением к интернету Аутентификация Повторная аутентификация Выполните вход через OAuth повторно diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index bd18a464a..0445d0cb5 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -299,6 +299,9 @@ 请用半角逗号分隔允许同步的 WiFi 网络名(SSID),留空则允许任意网络 WiFi SSID 限制需要进一步设置 管理 + VPN 连接性 + 必须使用非 VPN 连接(推荐) + 将 VPN 算作互联网连接 认证 重新验证身份 再次进行 OAuth 登录 diff --git a/fastlane/metadata/android/ro/short_description.txt b/fastlane/metadata/android/ro/short_description.txt new file mode 100644 index 000000000..b0424751d --- /dev/null +++ b/fastlane/metadata/android/ro/short_description.txt @@ -0,0 +1 @@ +Sincronizare și client CalDAV/CardDAV \ No newline at end of file -- GitLab