Compare commits

...

55 Commits

Author SHA1 Message Date
akwizgran
c6a284bd6d Bump version numbers for 1.5.0 release. 2023-04-19 14:23:20 +01:00
akwizgran
9d4d992009 Update translations. 2023-04-19 14:21:38 +01:00
Torsten Grote
e92eb1c699 Merge branch 'enable-mailbox-in-release-builds' into 'master'
Enable mailbox support in release builds

See merge request briar/briar!1789
2023-04-19 13:17:53 +00:00
akwizgran
07e56f7086 Remove mailbox feature flag. 2023-04-18 14:18:58 +01:00
akwizgran
fe31e60e66 Merge branch '2420-obsolete-bluetooth-permission-api-32' into 'master'
Require obsolete Bluetooth permission on API 32 (and counting)

Closes #2420

See merge request briar/briar!1782
2023-04-18 11:43:59 +00:00
akwizgran
7810e7e848 Enable mailbox support in release builds. 2023-04-18 12:37:33 +01:00
Torsten Grote
2566105f13 Merge branch 'tor-wrapper-library' into 'master'
Use Tor wrapper library

See merge request briar/briar!1787
2023-04-03 19:27:58 +00:00
akwizgran
cab8f834bd Convert onionwrapper from a submodule to a dependency. 2023-03-29 17:01:30 +01:00
akwizgran
ec0a754289 Remove BridgeTest from CI config. 2023-03-29 11:58:38 +01:00
akwizgran
e81fe44ea1 Update onionwrapper. 2023-03-28 18:09:43 +01:00
akwizgran
e399b9196a Merge branch 'tor-plugin-refactoring' into 'master'
Refactor Tor plugin to separate out reusable code

See merge request briar/briar!1786
2023-03-28 16:42:17 +00:00
akwizgran
aadbd3a662 Fix dependencies for headless jar tasks. 2023-03-28 17:41:22 +01:00
akwizgran
f4fd65aee4 Remove jtorctl dependency. 2023-03-28 17:28:15 +01:00
akwizgran
61e7d2ebf9 Move Tor wrapper to library. 2023-03-28 17:18:05 +01:00
akwizgran
06dd8c65aa Fix parsing of bootstrap percentage. 2023-03-28 15:44:25 +01:00
akwizgran
2f351b318e Move CircumventionProvider classes to wrapper package. 2023-03-28 15:40:48 +01:00
akwizgran
a468af94db Add bootstrap percentage and HS desc uploads to observer interface. 2023-03-28 11:31:20 +01:00
akwizgran
49f10e7e82 Move wake lock code to dont-kill-me-lib. 2023-03-28 10:58:45 +01:00
akwizgran
01b1741e83 Factor out Tor wrapper from plugin 2023-03-27 12:02:05 +01:00
akwizgran
b7003a3587 Update translations. 2023-03-20 10:59:32 +00:00
akwizgran
3dbf327937 Merge branch 'backport-os-check-algorithm' into 'master'
Backport OS-check logic from Compose Multiplatform

See merge request briar/briar!1785
2023-03-10 16:28:33 +00:00
Sebastian Kürten
73d806f8b9 Backport OS-check logic from Compose Multiplatform 2023-03-09 17:03:08 +01:00
akwizgran
f1ae57b213 Merge branch 'mailbox-fix' into 'master'
Fix mailbox integration tests

See merge request briar/briar!1784
2023-03-09 15:42:22 +00:00
Torsten Grote
cae9efb4bf Fix integration tests by using dynamic webserver port of mailbox 2023-03-09 12:29:48 -03:00
Torsten Grote
39ac737015 Merge branch 'no-personalized-learning' into 'master'
Set "no personalized learning" flag for all text input

See merge request briar/briar!1783
2023-03-09 14:14:11 +00:00
akwizgran
edd3310d03 Set "no personalized learning" flag for all text input. 2023-03-09 10:52:46 +00:00
akwizgran
a09d88daa8 Add Slovak to list of available languages. 2023-03-09 09:53:43 +00:00
akwizgran
3dc984659d Update translations. 2023-03-09 09:41:02 +00:00
akwizgran
f580525734 Require obsolete Bluetooth permission on API 32 (and counting). 2023-03-06 17:46:34 +00:00
akwizgran
fbf0f63ff7 Merge branch 'introduction-manager-txn' into 'master'
Transactional versions for introduction manager and private group invitation manager

See merge request briar/briar!1781
2023-03-06 12:08:34 +00:00
ialokim
ee9234e12e transactional versions for GroupInvitationManager 2023-03-05 22:10:50 +01:00
akwizgran
2657e2bc08 Merge branch '2245-toast-name-wrong' into 'master'
Remove wrong name from "Contact already exists"

Closes #2245

See merge request briar/briar!1780
2023-02-27 14:26:27 +00:00
Torsten Grote
3c40c11dfb remove wrong name from "Contact already exists" 2023-02-27 10:43:12 -03:00
akwizgran
3bdbabf38a Merge branch 'no-longer-use-deprecated-double-valueof' into 'master'
No longer use deprecated Double.valueOf()

See merge request briar/briar!1779
2023-02-27 12:45:01 +00:00
Sebastian Kürten
a378c24af8 No longer use deprecated Double.valueOf() 2023-02-27 12:22:27 +01:00
ialokim
b09ea495e7 add transactional versions to introductionManager and privateGroupManager 2023-02-24 18:43:08 +01:00
akwizgran
070165f608 Bump version numbers for 1.4.23 release. 2023-02-24 14:04:57 +00:00
Torsten Grote
445f174275 Merge branch 'update-tor-bridges' into 'master'
Update Tor bridges

See merge request briar/briar!1778
2023-02-24 13:28:27 +00:00
akwizgran
ea5af72878 Add some non-default bridges. 2023-02-24 12:31:22 +00:00
akwizgran
ecf2e75424 Remove some bridges not known to Onionoo. 2023-02-24 12:30:24 +00:00
akwizgran
feebd89029 Remove some failing bridges. 2023-02-24 12:23:37 +00:00
akwizgran
cf723f8002 Merge branch 'dont-unpack-tor' into 'master'
Upgrade tor, obfs4proxy, snoflake and convert tor to regular dependencies in bramble-java

See merge request briar/briar!1775
2023-02-24 12:13:31 +00:00
akwizgran
b8e743021c Update translations. 2023-02-24 12:11:58 +00:00
Sebastian Kürten
b785b6c10f Upgrade tor 2023-02-24 13:05:46 +01:00
Sebastian Kürten
26ec200f50 Convert tor to regular dependencies 2023-02-24 12:51:50 +01:00
akwizgran
82efb0d044 Upgrade Tor, obfs4 and snowflake; use new artifact layout. 2023-02-23 16:25:08 +01:00
akwizgran
4ac4ba13d4 Merge branch 'split-app' into 'master'
Split out APP for check_reproducibility CI job

See merge request briar/briar!1777
2023-02-22 17:06:31 +00:00
Torsten Grote
0844cd3547 Split out APP for check_reproducibility CI job 2023-02-21 16:14:02 -03:00
Torsten Grote
69e6648ded Merge branch '2415-check-bt-socket-streams-not-null' into 'master'
Check that BluetoothSocket's input and output streams aren't null

Closes #2415

See merge request briar/briar!1776
2023-02-21 13:38:49 +00:00
akwizgran
518aeb38b9 Check that BluetoothSocket's input and output streams aren't null. 2023-02-21 13:29:35 +00:00
akwizgran
7e5e61fc05 Merge branch 'dont-package-all-snowflake-architectures-into-headless-jars' into 'master'
Don't package all snowflake architectures into headless jars

See merge request briar/briar!1774
2023-02-21 11:34:04 +00:00
Sebastian Kürten
6ecb44bcaa Don't package all snowflake architectures into headless jars 2023-02-21 09:38:24 +01:00
akwizgran
f02bbebf6c Bump version numbers for 1.4.22 release. 2023-02-20 17:29:41 +00:00
akwizgran
b8612715f8 Merge branch 'check_repro' into 'master'
Fix variable substitution for check_reproducibility

See merge request briar/briar!1773
2023-02-20 17:26:25 +00:00
Torsten Grote
b86ddfa22f Fix variable substitution for check_reproducibility 2023-02-20 14:08:19 -03:00
113 changed files with 2294 additions and 2916 deletions

View File

@@ -83,30 +83,14 @@ android test:
test_reproducible:
stage: check_reproducibility
script:
- "curl -X POST -F token=${RELEASE_CHECK_TOKEN} -F ref=master -F variables[RELEASE_TAG]='briar ${CI_COMMIT_REF_NAME}' https://code.briarproject.org/api/v4/projects/61/trigger/pipeline"
- "curl -X POST -F token=${RELEASE_JAR_CHECK_TOKEN} -F ref=main -F variables[RELEASE_TAG]='briar-headless ${CI_COMMIT_REF_NAME}' https://code.briarproject.org/api/v4/projects/307/trigger/pipeline"
- "curl -X POST -F token=${RELEASE_CHECK_TOKEN} -F ref=master -F variables[APP]='briar' -F variables[RELEASE_TAG]=${CI_COMMIT_REF_NAME} https://code.briarproject.org/api/v4/projects/61/trigger/pipeline"
- "curl -X POST -F token=${RELEASE_JAR_CHECK_TOKEN} -F ref=main -F variables[APP]='briar-headless' -F variables[RELEASE_TAG]=${CI_COMMIT_REF_NAME} https://code.briarproject.org/api/v4/projects/307/trigger/pipeline"
only:
- tags
.optional_tests:
mailbox integration test:
stage: optional_tests
extends: .base-test
bridge test:
extends: .optional_tests
rules:
- if: '$CI_PIPELINE_SOURCE == "schedule"'
when: on_success
allow_failure: false
- if: '$CI_COMMIT_TAG == null'
when: manual
allow_failure: true
script:
- OPTIONAL_TESTS=org.briarproject.bramble.plugin.tor.BridgeTest ./gradlew --info bramble-java:test --tests BridgeTest
timeout: 4h
mailbox integration test:
extends: .optional_tests
rules:
- changes:
- mailbox-integration-tests/**/*

View File

@@ -1,28 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="BridgeTest" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="env">
<map>
<entry key="OPTIONAL_TESTS" value="org.briarproject.bramble.plugin.tor.BridgeTest" />
</map>
</option>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="--tests &quot;org.briarproject.bramble.plugin.tor.BridgeTest&quot;" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value=":bramble-java:test" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>false</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration>
</component>

View File

@@ -13,8 +13,8 @@ android {
defaultConfig {
minSdkVersion 16
targetSdkVersion 31
versionCode 10421
versionName "1.4.21"
versionCode 10500
versionName "1.5.0"
consumerProguardFiles 'proguard-rules.txt'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -40,6 +40,8 @@ configurations {
}
dependencies {
api 'org.briarproject:dont-kill-me-lib:0.2.6'
// In theory this dependency shouldn't be needed, but without it Android Studio's linter will
// complain about unresolved symbols for bramble-api test classes in bramble-android tests,
// even though the bramble-api test classes are provided by the testImplementation dependency
@@ -49,6 +51,7 @@ dependencies {
implementation project(':bramble-core')
implementation 'androidx.annotation:annotation:1.5.0'
implementation "org.briarproject:onionwrapper-android:$onionwrapper_version"
tor "org.briarproject:tor-android:$tor_version"
tor "org.briarproject:obfs4proxy-android:$obfs4proxy_version"
@@ -71,7 +74,7 @@ def torLibsDir = 'src/main/jniLibs'
task cleanTorBinaries {
outputs.dir torLibsDir
doLast {
delete fileTree(torLibsDir) { include '**/*.so' }
delete fileTree(torLibsDir)
}
}
@@ -80,34 +83,9 @@ clean.dependsOn cleanTorBinaries
task unpackTorBinaries {
outputs.dir torLibsDir
doLast {
configurations.tor.each { outer ->
zipTree(outer).each { inner ->
if (inner.name.endsWith('_arm_pie.zip')) {
copy {
from zipTree(inner)
into torLibsDir
rename '(.*)', 'armeabi-v7a/lib$1.so'
}
} else if (inner.name.endsWith('_arm64_pie.zip')) {
copy {
from zipTree(inner)
into torLibsDir
rename '(.*)', 'arm64-v8a/lib$1.so'
}
} else if (inner.name.endsWith('_x86_pie.zip')) {
copy {
from zipTree(inner)
into torLibsDir
rename '(.*)', 'x86/lib$1.so'
}
} else if (inner.name.endsWith('_x86_64_pie.zip')) {
copy {
from zipTree(inner)
into torLibsDir
rename '(.*)', 'x86_64/lib$1.so'
}
}
}
copy {
from configurations.tor.collect { zipTree(it) }
into torLibsDir
}
}
dependsOn cleanTorBinaries

View File

@@ -8,10 +8,10 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- The BLUETOOTH permission was supposed to be removed in API 31 but is still needed on some Xiaomi/Redmi/POCO devices running API 31 -->
<!-- The BLUETOOTH permission was supposed to be removed in API 31 but is still needed on some Xiaomi/Redmi/POCO devices running API 31 and Nubia devices running API 32 -->
<uses-permission
android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="31" />
android:maxSdkVersion="32" />
<uses-permission
android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30" />

View File

@@ -0,0 +1,17 @@
package org.briarproject.android.dontkillmelib.wakelock;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class AndroidWakeLockModule {
@Provides
@Singleton
AndroidWakeLockManager provideWakeLockManager(
AndroidWakeLockManagerImpl wakeLockManager) {
return wakeLockManager;
}
}

View File

@@ -1,15 +1,16 @@
package org.briarproject.bramble;
import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockModule;
import org.briarproject.bramble.battery.AndroidBatteryModule;
import org.briarproject.bramble.io.DnsModule;
import org.briarproject.bramble.network.AndroidNetworkModule;
import org.briarproject.bramble.plugin.tor.CircumventionModule;
import org.briarproject.bramble.reporting.ReportingModule;
import org.briarproject.bramble.socks.SocksModule;
import org.briarproject.bramble.system.AndroidSystemModule;
import org.briarproject.bramble.system.AndroidTaskSchedulerModule;
import org.briarproject.bramble.system.AndroidWakefulIoExecutorModule;
import org.briarproject.bramble.system.DefaultThreadFactoryModule;
import org.briarproject.onionwrapper.CircumventionModule;
import dagger.Module;
@@ -19,6 +20,7 @@ import dagger.Module;
AndroidSystemModule.class,
AndroidTaskSchedulerModule.class,
AndroidWakefulIoExecutorModule.class,
AndroidWakeLockModule.class,
DefaultThreadFactoryModule.class,
CircumventionModule.class,
DnsModule.class,

View File

@@ -1,19 +0,0 @@
package org.briarproject.bramble.api.system;
import org.briarproject.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface AndroidWakeLock {
/**
* Acquires the wake lock. This has no effect if the wake lock has already
* been acquired.
*/
void acquire();
/**
* Releases the wake lock. This has no effect if the wake lock has already
* been released.
*/
void release();
}

View File

@@ -1,38 +0,0 @@
package org.briarproject.bramble.api.system;
import org.briarproject.nullsafety.NotNullByDefault;
import java.util.concurrent.Executor;
@NotNullByDefault
public interface AndroidWakeLockManager {
/**
* Creates a wake lock with the given tag. The tag is only used for
* logging; the underlying OS wake lock will use its own tag.
*/
AndroidWakeLock createWakeLock(String tag);
/**
* Runs the given task while holding a wake lock.
*/
void runWakefully(Runnable r, String tag);
/**
* Submits the given task to the given executor while holding a wake lock.
* The lock is released when the task completes, or if an exception is
* thrown while submitting or running the task.
*/
void executeWakefully(Runnable r, Executor executor, String tag);
/**
* Starts a dedicated thread to run the given task asynchronously. A wake
* lock is acquired before starting the thread and released when the task
* completes, or if an exception is thrown while starting the thread or
* running the task.
* <p>
* This method should only be used for lifecycle management tasks that
* can't be run on an executor.
*/
void executeWakefully(Runnable r, String tag);
}

View File

@@ -2,10 +2,10 @@ package org.briarproject.bramble.plugin.bluetooth;
import android.bluetooth.BluetoothSocket;
import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager;
import org.briarproject.bramble.api.io.TimeoutMonitor;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.nullsafety.NotNullByDefault;
import java.io.IOException;

View File

@@ -3,6 +3,7 @@ package org.briarproject.bramble.plugin.bluetooth;
import android.app.Application;
import android.bluetooth.BluetoothSocket;
import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.io.TimeoutMonitor;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
@@ -13,7 +14,6 @@ import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.WakefulIoExecutor;
import org.briarproject.nullsafety.NotNullByDefault;

View File

@@ -2,11 +2,11 @@ package org.briarproject.bramble.plugin.bluetooth;
import android.bluetooth.BluetoothSocket;
import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLock;
import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager;
import org.briarproject.bramble.api.io.TimeoutMonitor;
import org.briarproject.bramble.api.plugin.Plugin;
import org.briarproject.bramble.api.plugin.duplex.AbstractDuplexTransportConnection;
import org.briarproject.bramble.api.system.AndroidWakeLock;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.nullsafety.NotNullByDefault;
import java.io.IOException;
@@ -33,8 +33,10 @@ class AndroidBluetoothTransportConnection
super(plugin);
this.connectionLimiter = connectionLimiter;
this.socket = socket;
in = timeoutMonitor.createTimeoutInputStream(
socket.getInputStream(), plugin.getMaxIdleTime() * 2);
InputStream socketIn = socket.getInputStream();
if (socketIn == null) throw new IOException();
in = timeoutMonitor.createTimeoutInputStream(socketIn,
plugin.getMaxIdleTime() * 2L);
wakeLock = wakeLockManager.createWakeLock("BluetoothConnection");
wakeLock.acquire();
String address = socket.getRemoteDevice().getAddress();
@@ -48,7 +50,9 @@ class AndroidBluetoothTransportConnection
@Override
protected OutputStream getOutputStream() throws IOException {
return socket.getOutputStream();
OutputStream socketOut = socket.getOutputStream();
if (socketOut == null) throw new IOException();
return socketOut;
}
@Override

View File

@@ -1,238 +0,0 @@
package org.briarproject.bramble.plugin.tor;
import android.app.Application;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.system.AndroidWakeLock;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.bramble.util.AndroidUtils;
import org.briarproject.nullsafety.MethodsNotNullByDefault;
import org.briarproject.nullsafety.ParametersNotNullByDefault;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import javax.net.SocketFactory;
import androidx.annotation.ChecksSdkIntAtLeast;
import static android.os.Build.VERSION.SDK_INT;
import static java.util.Arrays.asList;
import static java.util.logging.Level.INFO;
import static java.util.logging.Logger.getLogger;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
class AndroidTorPlugin extends TorPlugin {
private static final List<String> LIBRARY_ARCHITECTURES =
asList("armeabi-v7a", "arm64-v8a", "x86", "x86_64");
private static final String TOR_LIB_NAME = "libtor.so";
private static final String OBFS4_LIB_NAME = "libobfs4proxy.so";
private static final String SNOWFLAKE_LIB_NAME = "libsnowflake.so";
private static final Logger LOG =
getLogger(AndroidTorPlugin.class.getName());
private final Application app;
private final AndroidWakeLock wakeLock;
private final File torLib, obfs4Lib, snowflakeLib;
AndroidTorPlugin(Executor ioExecutor,
Executor wakefulIoExecutor,
Application app,
NetworkManager networkManager,
LocationUtils locationUtils,
SocketFactory torSocketFactory,
Clock clock,
ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider,
BatteryManager batteryManager,
AndroidWakeLockManager wakeLockManager,
Backoff backoff,
TorRendezvousCrypto torRendezvousCrypto,
PluginCallback callback,
String architecture,
long maxLatency,
int maxIdleTime,
File torDirectory,
int torSocksPort,
int torControlPort) {
super(ioExecutor, wakefulIoExecutor, networkManager, locationUtils,
torSocketFactory, clock, resourceProvider,
circumventionProvider, batteryManager, backoff,
torRendezvousCrypto, callback, architecture, maxLatency,
maxIdleTime, torDirectory, torSocksPort, torControlPort);
this.app = app;
wakeLock = wakeLockManager.createWakeLock("TorPlugin");
String nativeLibDir = app.getApplicationInfo().nativeLibraryDir;
torLib = new File(nativeLibDir, TOR_LIB_NAME);
obfs4Lib = new File(nativeLibDir, OBFS4_LIB_NAME);
snowflakeLib = new File(nativeLibDir, SNOWFLAKE_LIB_NAME);
}
@Override
protected int getProcessId() {
return android.os.Process.myPid();
}
@Override
protected long getLastUpdateTime() {
try {
PackageManager pm = app.getPackageManager();
PackageInfo pi = pm.getPackageInfo(app.getPackageName(), 0);
return pi.lastUpdateTime;
} catch (NameNotFoundException e) {
throw new AssertionError(e);
}
}
@Override
protected void enableNetwork(boolean enable) throws IOException {
if (enable) wakeLock.acquire();
super.enableNetwork(enable);
if (!enable) wakeLock.release();
}
@Override
@ChecksSdkIntAtLeast(api = 25)
protected boolean canVerifyLetsEncryptCerts() {
return SDK_INT >= 25;
}
@Override
public void stop() {
super.stop();
wakeLock.release();
}
@Override
protected File getTorExecutableFile() {
return torLib.exists() ? torLib : super.getTorExecutableFile();
}
@Override
protected File getObfs4ExecutableFile() {
return obfs4Lib.exists() ? obfs4Lib : super.getObfs4ExecutableFile();
}
@Override
protected File getSnowflakeExecutableFile() {
return snowflakeLib.exists()
? snowflakeLib : super.getSnowflakeExecutableFile();
}
@Override
protected void installTorExecutable() throws IOException {
installExecutable(super.getTorExecutableFile(), torLib, TOR_LIB_NAME);
}
@Override
protected void installObfs4Executable() throws IOException {
installExecutable(super.getObfs4ExecutableFile(), obfs4Lib,
OBFS4_LIB_NAME);
}
@Override
protected void installSnowflakeExecutable() throws IOException {
installExecutable(super.getSnowflakeExecutableFile(), snowflakeLib,
SNOWFLAKE_LIB_NAME);
}
private void installExecutable(File extracted, File lib, String libName)
throws IOException {
if (lib.exists()) {
// If an older version left behind a binary, delete it
if (extracted.exists()) {
if (extracted.delete()) LOG.info("Deleted old binary");
else LOG.info("Failed to delete old binary");
}
} else if (SDK_INT < 29) {
// The binary wasn't extracted at install time. Try to extract it
extractLibraryFromApk(libName, extracted);
} else {
// No point extracting the binary, we won't be allowed to execute it
throw new FileNotFoundException(lib.getAbsolutePath());
}
}
private void extractLibraryFromApk(String libName, File dest)
throws IOException {
File sourceDir = new File(app.getApplicationInfo().sourceDir);
if (sourceDir.isFile()) {
// Look for other APK files in the same directory, if we're allowed
File parent = sourceDir.getParentFile();
if (parent != null) sourceDir = parent;
}
List<String> libPaths = getSupportedLibraryPaths(libName);
for (File apk : findApkFiles(sourceDir)) {
ZipInputStream zin = new ZipInputStream(new FileInputStream(apk));
for (ZipEntry e = zin.getNextEntry(); e != null;
e = zin.getNextEntry()) {
if (libPaths.contains(e.getName())) {
if (LOG.isLoggable(INFO)) {
LOG.info("Extracting " + e.getName()
+ " from " + apk.getAbsolutePath());
}
extract(zin, dest); // Zip input stream will be closed
return;
}
}
zin.close();
}
throw new FileNotFoundException(libName);
}
/**
* Returns all files with the extension .apk or .APK under the given root.
*/
private List<File> findApkFiles(File root) {
List<File> files = new ArrayList<>();
findApkFiles(root, files);
return files;
}
private void findApkFiles(File f, List<File> files) {
if (f.isFile() && f.getName().toLowerCase().endsWith(".apk")) {
files.add(f);
} else if (f.isDirectory()) {
File[] children = f.listFiles();
if (children != null) {
for (File child : children) findApkFiles(child, files);
}
}
}
/**
* Returns the paths at which libraries with the given name would be found
* inside an APK file, for all architectures supported by the device, in
* order of preference.
*/
private List<String> getSupportedLibraryPaths(String libName) {
List<String> architectures = new ArrayList<>();
for (String abi : AndroidUtils.getSupportedArchitectures()) {
if (LIBRARY_ARCHITECTURES.contains(abi)) {
architectures.add("lib/" + abi + "/" + libName);
}
}
return architectures;
}
}

View File

@@ -2,9 +2,11 @@ package org.briarproject.bramble.plugin.tor;
import android.app.Application;
import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventExecutor;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.plugin.Backoff;
@@ -13,12 +15,13 @@ import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TorControlPort;
import org.briarproject.bramble.api.plugin.TorDirectory;
import org.briarproject.bramble.api.plugin.TorSocksPort;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.bramble.api.system.WakefulIoExecutor;
import org.briarproject.nullsafety.NotNullByDefault;
import org.briarproject.onionwrapper.AndroidTorWrapper;
import org.briarproject.onionwrapper.CircumventionProvider;
import org.briarproject.onionwrapper.TorWrapper;
import java.io.File;
import java.util.concurrent.Executor;
@@ -28,6 +31,7 @@ import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import javax.net.SocketFactory;
import static android.os.Build.VERSION.SDK_INT;
import static org.briarproject.bramble.util.AndroidUtils.getSupportedArchitectures;
@Immutable
@@ -39,13 +43,13 @@ public class AndroidTorPluginFactory extends TorPluginFactory {
@Inject
AndroidTorPluginFactory(@IoExecutor Executor ioExecutor,
@EventExecutor Executor eventExecutor,
@WakefulIoExecutor Executor wakefulIoExecutor,
NetworkManager networkManager,
LocationUtils locationUtils,
EventBus eventBus,
SocketFactory torSocketFactory,
BackoffFactory backoffFactory,
ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider,
BatteryManager batteryManager,
Clock clock,
@@ -55,8 +59,8 @@ public class AndroidTorPluginFactory extends TorPluginFactory {
@TorControlPort int torControlPort,
Application app,
AndroidWakeLockManager wakeLockManager) {
super(ioExecutor, wakefulIoExecutor, networkManager, locationUtils,
eventBus, torSocketFactory, backoffFactory, resourceProvider,
super(ioExecutor, eventExecutor, wakefulIoExecutor, networkManager,
locationUtils, eventBus, torSocketFactory, backoffFactory,
circumventionProvider, batteryManager, clock, crypto,
torDirectory, torSocksPort, torControlPort);
this.app = app;
@@ -79,12 +83,18 @@ public class AndroidTorPluginFactory extends TorPluginFactory {
TorPlugin createPluginInstance(Backoff backoff,
TorRendezvousCrypto torRendezvousCrypto, PluginCallback callback,
String architecture) {
return new AndroidTorPlugin(ioExecutor,
wakefulIoExecutor, app, networkManager, locationUtils,
torSocketFactory, clock, resourceProvider,
circumventionProvider, batteryManager, wakeLockManager,
backoff, torRendezvousCrypto, callback, architecture,
MAX_LATENCY, MAX_IDLE_TIME, torDirectory, torSocksPort,
torControlPort);
TorWrapper tor = new AndroidTorWrapper(app, wakeLockManager,
ioExecutor, eventExecutor, architecture, torDirectory,
torSocksPort, torControlPort);
// Android versions 7.1 and newer can verify Let's Encrypt TLS certs
// signed with the IdentTrust DST Root X3 certificate. Older versions
// of Android consider the certificate to have expired at the end of
// September 2021.
boolean canVerifyLetsEncryptCerts = SDK_INT >= 25;
return new TorPlugin(ioExecutor, wakefulIoExecutor,
networkManager, locationUtils, torSocketFactory,
circumventionProvider, batteryManager, backoff,
torRendezvousCrypto, tor, callback, MAX_LATENCY,
MAX_IDLE_TIME, canVerifyLetsEncryptCerts);
}
}

View File

@@ -3,7 +3,6 @@ package org.briarproject.bramble.system;
import org.briarproject.bramble.api.event.EventExecutor;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.bramble.api.system.SecureRandomProvider;
@@ -69,11 +68,4 @@ public class AndroidSystemModule {
ResourceProvider provideResourceProvider(AndroidResourceProvider provider) {
return provider;
}
@Provides
@Singleton
AndroidWakeLockManager provideWakeLockManager(
AndroidWakeLockManagerImpl wakeLockManager) {
return wakeLockManager;
}
}

View File

@@ -8,10 +8,10 @@ import android.content.Intent;
import android.os.Process;
import android.os.SystemClock;
import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager;
import org.briarproject.bramble.api.Cancellable;
import org.briarproject.bramble.api.lifecycle.Service;
import org.briarproject.bramble.api.system.AlarmListener;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.TaskScheduler;
import org.briarproject.bramble.api.system.Wakeful;
import org.briarproject.nullsafety.NotNullByDefault;

View File

@@ -2,9 +2,9 @@ package org.briarproject.bramble.system;
import android.app.Application;
import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.system.AlarmListener;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.TaskScheduler;
import java.util.concurrent.ScheduledExecutorService;

View File

@@ -1,74 +0,0 @@
package org.briarproject.bramble.system;
import org.briarproject.bramble.api.system.AndroidWakeLock;
import org.briarproject.nullsafety.NotNullByDefault;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import static java.util.logging.Level.FINE;
import static java.util.logging.Logger.getLogger;
/**
* A wrapper around a {@link SharedWakeLock} that provides the more convenient
* semantics of {@link AndroidWakeLock} (i.e. calls to acquire() and release()
* don't need to be balanced).
*/
@ThreadSafe
@NotNullByDefault
class AndroidWakeLockImpl implements AndroidWakeLock {
private static final Logger LOG =
getLogger(AndroidWakeLockImpl.class.getName());
private static final AtomicInteger INSTANCE_ID = new AtomicInteger(0);
private final SharedWakeLock sharedWakeLock;
private final String tag;
private final Object lock = new Object();
@GuardedBy("lock")
private boolean held = false;
AndroidWakeLockImpl(SharedWakeLock sharedWakeLock, String tag) {
this.sharedWakeLock = sharedWakeLock;
this.tag = tag + "_" + INSTANCE_ID.getAndIncrement();
}
@Override
public void acquire() {
synchronized (lock) {
if (held) {
if (LOG.isLoggable(FINE)) {
LOG.fine(tag + " already acquired");
}
} else {
if (LOG.isLoggable(FINE)) {
LOG.fine(tag + " acquiring shared wake lock");
}
held = true;
sharedWakeLock.acquire();
}
}
}
@Override
public void release() {
synchronized (lock) {
if (held) {
if (LOG.isLoggable(FINE)) {
LOG.fine(tag + " releasing shared wake lock");
}
held = false;
sharedWakeLock.release();
} else {
if (LOG.isLoggable(FINE)) {
LOG.fine(tag + " already released");
}
}
}
}
}

View File

@@ -1,125 +0,0 @@
package org.briarproject.bramble.system;
import android.app.Application;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.PowerManager;
import org.briarproject.bramble.api.system.AndroidWakeLock;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.nullsafety.NotNullByDefault;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import javax.inject.Inject;
import static android.content.Context.POWER_SERVICE;
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.briarproject.nullsafety.NullSafety.requireNonNull;
@NotNullByDefault
class AndroidWakeLockManagerImpl implements AndroidWakeLockManager {
/**
* How often to replace the wake lock.
*/
private static final long LOCK_DURATION_MS = MINUTES.toMillis(1);
/**
* Automatically release the lock this many milliseconds after it's due
* to have been replaced and released.
*/
private static final long SAFETY_MARGIN_MS = SECONDS.toMillis(30);
private final SharedWakeLock sharedWakeLock;
@Inject
AndroidWakeLockManagerImpl(Application app,
ScheduledExecutorService scheduledExecutorService) {
PowerManager powerManager = (PowerManager)
requireNonNull(app.getSystemService(POWER_SERVICE));
String tag = getWakeLockTag(app);
sharedWakeLock = new RenewableWakeLock(powerManager,
scheduledExecutorService, PARTIAL_WAKE_LOCK, tag,
LOCK_DURATION_MS, SAFETY_MARGIN_MS);
}
@Override
public AndroidWakeLock createWakeLock(String tag) {
return new AndroidWakeLockImpl(sharedWakeLock, tag);
}
@Override
public void runWakefully(Runnable r, String tag) {
AndroidWakeLock wakeLock = createWakeLock(tag);
wakeLock.acquire();
try {
r.run();
} finally {
wakeLock.release();
}
}
@Override
public void executeWakefully(Runnable r, Executor executor, String tag) {
AndroidWakeLock wakeLock = createWakeLock(tag);
wakeLock.acquire();
try {
executor.execute(() -> {
try {
r.run();
} finally {
// Release the wake lock if the task throws an exception
wakeLock.release();
}
});
} catch (Exception e) {
// Release the wake lock if the executor throws an exception when
// we submit the task (in which case the release() call above won't
// happen)
wakeLock.release();
throw e;
}
}
@Override
public void executeWakefully(Runnable r, String tag) {
AndroidWakeLock wakeLock = createWakeLock(tag);
wakeLock.acquire();
try {
new Thread(() -> {
try {
r.run();
} finally {
wakeLock.release();
}
}).start();
} catch (Exception e) {
wakeLock.release();
throw e;
}
}
private String getWakeLockTag(Context ctx) {
PackageManager pm = ctx.getPackageManager();
if (isInstalled(pm, "com.huawei.powergenie")) {
return "LocationManagerService";
} else if (isInstalled(pm, "com.evenwell.PowerMonitor")) {
return "AudioIn";
}
return ctx.getPackageName();
}
private boolean isInstalled(PackageManager pm, String packageName) {
try {
pm.getPackageInfo(packageName, 0);
return true;
} catch (PackageManager.NameNotFoundException e) {
return false;
}
}
}

View File

@@ -1,7 +1,7 @@
package org.briarproject.bramble.system;
import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.WakefulIoExecutor;
import java.util.concurrent.Executor;

View File

@@ -1,130 +0,0 @@
package org.briarproject.bramble.system;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import org.briarproject.nullsafety.NotNullByDefault;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.nullsafety.NullSafety.requireNonNull;
@ThreadSafe
@NotNullByDefault
class RenewableWakeLock implements SharedWakeLock {
private static final Logger LOG =
getLogger(RenewableWakeLock.class.getName());
private final PowerManager powerManager;
private final ScheduledExecutorService scheduledExecutorService;
private final int levelAndFlags;
private final String tag;
private final long durationMs, safetyMarginMs;
private final Object lock = new Object();
@GuardedBy("lock")
@Nullable
private WakeLock wakeLock;
@GuardedBy("lock")
@Nullable
private Future<?> future;
@GuardedBy("lock")
private int refCount = 0;
@GuardedBy("lock")
private long acquired = 0;
RenewableWakeLock(PowerManager powerManager,
ScheduledExecutorService scheduledExecutorService,
int levelAndFlags,
String tag,
long durationMs,
long safetyMarginMs) {
this.powerManager = powerManager;
this.scheduledExecutorService = scheduledExecutorService;
this.levelAndFlags = levelAndFlags;
this.tag = tag;
this.durationMs = durationMs;
this.safetyMarginMs = safetyMarginMs;
}
@Override
public void acquire() {
synchronized (lock) {
refCount++;
if (refCount == 1) {
if (LOG.isLoggable(INFO)) {
LOG.info("Acquiring wake lock " + tag);
}
wakeLock = powerManager.newWakeLock(levelAndFlags, tag);
// We do our own reference counting so we can replace the lock
// TODO: Check whether using a ref-counted wake lock affects
// power management apps
wakeLock.setReferenceCounted(false);
wakeLock.acquire(durationMs + safetyMarginMs);
future = scheduledExecutorService.schedule(this::renew,
durationMs, MILLISECONDS);
acquired = android.os.SystemClock.elapsedRealtime();
} else if (LOG.isLoggable(FINE)) {
LOG.fine("Wake lock " + tag + " has " + refCount + " holders");
}
}
}
private void renew() {
if (LOG.isLoggable(INFO)) LOG.info("Renewing wake lock " + tag);
synchronized (lock) {
if (wakeLock == null) {
LOG.info("Already released");
return;
}
if (LOG.isLoggable(FINE)) {
LOG.fine("Wake lock " + tag + " has " + refCount + " holders");
}
long now = android.os.SystemClock.elapsedRealtime();
long expiry = acquired + durationMs + safetyMarginMs;
if (now > expiry && LOG.isLoggable(WARNING)) {
LOG.warning("Wake lock expired " + (now - expiry) + " ms ago");
}
WakeLock oldWakeLock = wakeLock;
wakeLock = powerManager.newWakeLock(levelAndFlags, tag);
wakeLock.setReferenceCounted(false);
wakeLock.acquire(durationMs + safetyMarginMs);
oldWakeLock.release();
future = scheduledExecutorService.schedule(this::renew, durationMs,
MILLISECONDS);
acquired = now;
}
}
@Override
public void release() {
synchronized (lock) {
refCount--;
if (refCount == 0) {
if (LOG.isLoggable(INFO)) {
LOG.info("Releasing wake lock " + tag);
}
requireNonNull(future).cancel(false);
future = null;
requireNonNull(wakeLock).release();
wakeLock = null;
acquired = 0;
} else if (LOG.isLoggable(FINE)) {
LOG.fine("Wake lock " + tag + " has " + refCount + " holders");
}
}
}
}

View File

@@ -1,22 +0,0 @@
package org.briarproject.bramble.system;
import org.briarproject.bramble.api.system.AndroidWakeLock;
import org.briarproject.nullsafety.NotNullByDefault;
@NotNullByDefault
interface SharedWakeLock {
/**
* Acquires the wake lock. This increments the wake lock's reference count,
* so unlike {@link AndroidWakeLock#acquire()} every call to this method
* must be followed by a balancing call to {@link #release()}.
*/
void acquire();
/**
* Releases the wake lock. This decrements the wake lock's reference count,
* so unlike {@link AndroidWakeLock#release()} every call to this method
* must follow a balancing call to {@link #acquire()}.
*/
void release();
}

View File

@@ -24,9 +24,14 @@ dependencyVerification {
'net.jcip:jcip-annotations:1.0:jcip-annotations-1.0.jar:be5805392060c71474bf6c9a67a099471274d30b83eef84bfc4e0889a4f1dcc0',
'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd',
'org.apache-extras.beanshell:bsh:2.0b6:bsh-2.0b6.jar:a17955976070c0573235ee662f2794a78082758b61accffce8d3f8aedcd91047',
'org.briarproject:obfs4proxy-android:0.0.14-tor1:obfs4proxy-android-0.0.14-tor1.jar:8b08068778b133484b17956d8f7a7710739c33f671a26a68156f4d34e6f28c30',
'org.briarproject:snowflake-android:2.3.1:snowflake-android-2.3.1.jar:1f83c9a070f87b7074af13627709a8b5aced5460104be7166af736b1bb73c293',
'org.briarproject:tor-android:0.4.7.13:tor-android-0.4.7.13.jar:7852aab7d2298b80878c7719f34ce665725b494d673ecf2e6f9e697564638cc6',
'org.briarproject:dont-kill-me-lib:0.2.6:dont-kill-me-lib-0.2.6.aar:8a4cc201143227c0865c2edfba035f71109bf02e1ab26444fa3e42d3c569960f',
'org.briarproject:jtorctl:0.5:jtorctl-0.5.jar:43f8c7d390169772b9a2c82ab806c8414c136a2a8636c555e22754bb7260793b',
'org.briarproject:null-safety:0.1:null-safety-0.1.jar:161760de5e838cb982bafa973df820675d4397098e9a91637a36a306d43ba011',
'org.briarproject:obfs4proxy-android:0.0.14-tor2:obfs4proxy-android-0.0.14-tor2.jar:a0a93770d6760ce57d9dbd31cc7177687374e00c3361dac22ab75e3b6e0f289e',
'org.briarproject:onionwrapper-android:0.0.1:onionwrapper-android-0.0.1.aar:959115946586daa090f057645cf75992407a59025e221c3bf88d2aa930ef3919',
'org.briarproject:onionwrapper-core:0.0.1:onionwrapper-core-0.0.1.jar:a1937506b00ee6620e909a500e5d004be81f94a6f7d7c898e1a9e841a8ae8a2a',
'org.briarproject:snowflake-android:2.5.1:snowflake-android-2.5.1.jar:88ec81c17b1b6fa884d06839dec0330e328b45c89f88c970a213ce91ca8eac87',
'org.briarproject:tor-android:0.4.7.13-2:tor-android-0.4.7.13-2.jar:453fd463b234a2104edd7f0d02d0649cbb5c5efbe47a76df3828f55a3f90f8b5',
'org.checkerframework:checker-compat-qual:2.5.5:checker-compat-qual-2.5.5.jar:11d134b245e9cacc474514d2d66b5b8618f8039a1465cdc55bbc0b34e0008b7a',
'org.checkerframework:checker-qual:3.12.0:checker-qual-3.12.0.jar:ff10785ac2a357ec5de9c293cb982a2cbb605c0309ea4cc1cb9b9bc6dbe7f3cb',
'org.hamcrest:hamcrest-core:2.1:hamcrest-core-2.1.jar:e09109e54a289d88506b9bfec987ddd199f4217c9464132668351b9a4f00bee9',
@@ -37,11 +42,12 @@ dependencyVerification {
'org.jacoco:org.jacoco.core:0.8.7:org.jacoco.core-0.8.7.jar:ad7739b5fb5969aa1a8aead3d74ed54dc82ed012f1f10f336bd1b96e71c1a13c',
'org.jacoco:org.jacoco.report:0.8.7:org.jacoco.report-0.8.7.jar:cc89258623700a6c932592153cb528785876b6da183d5431f97efbba6f020e5b',
'org.jetbrains.kotlin:kotlin-stdlib-common:1.7.0:kotlin-stdlib-common-1.7.0.jar:59c6ff64fe9a6604afce03e8aaa75f83586c6030ac71fb0b34ee7cdefed3618f',
'org.jetbrains.kotlin:kotlin-stdlib-common:1.7.10:kotlin-stdlib-common-1.7.10.jar:19f102efe9629f8eabc63853ad15c533e47c47f91fca09285c5bde86e59f91d4',
'org.jetbrains.kotlin:kotlin-stdlib-common:1.8.0:kotlin-stdlib-common-1.8.0.jar:78ef93b59e603cc0fe51def9bd4c037b07cbace3b3b7806d1a490a42bc1f4cb2',
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.0:kotlin-stdlib-jdk7-1.7.0.jar:07e91be9b2ca20672d2bdb7e181b766e73453a2da13492b5ddaee8fa47aea239',
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0:kotlin-stdlib-jdk7-1.8.0.jar:4c889d1d9803f5f2eb6c1592a6b7e62369ac7660c9eee15aba16fec059163666',
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.0:kotlin-stdlib-jdk8-1.7.0.jar:cf058e11db1dfc9944680c8c61b95ac689aaaa8a3eb30bced028100f038f030b',
'org.jetbrains.kotlin:kotlin-stdlib:1.7.0:kotlin-stdlib-1.7.0.jar:aa88e9625577957f3249a46cb6e166ee09b369e600f7a11d148d16b0a6d87f05',
'org.jetbrains.kotlin:kotlin-stdlib:1.7.10:kotlin-stdlib-1.7.10.jar:e771fe74250a943e8f6346713201ff1d8cb95c3a5d1a91a22b65a9e04f6a8901',
'org.jetbrains.kotlin:kotlin-stdlib:1.8.0:kotlin-stdlib-1.8.0.jar:c77bef8774640b9fb9d6e217459ff220dae59878beb7d2e4b430506feffc654e',
'org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.5.0:kotlinx-metadata-jvm-0.5.0.jar:ca063a96639b08b9eaa0de4d65e899480740a6efbe28ab9a8681a2ced03055a4',
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
'org.jmock:jmock-imposters:2.12.0:jmock-imposters-2.12.0.jar:3b836269745a137c9b2347e8d7c2104845b126ef04f012d6bfd94f1a7dea7b09',

View File

@@ -11,8 +11,6 @@ public interface FeatureFlags {
boolean shouldEnableDisappearingMessages();
boolean shouldEnableMailbox();
boolean shouldEnablePrivateGroupsInCore();
boolean shouldEnableForumsInCore();

View File

@@ -4,6 +4,8 @@ import org.briarproject.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
import static org.briarproject.bramble.util.StringUtils.startsWithIgnoreCase;
@NotNullByDefault
public class OsUtils {
@@ -13,15 +15,15 @@ public class OsUtils {
private static final String vendor = System.getProperty("java.vendor");
public static boolean isWindows() {
return os != null && os.contains("Windows");
return os != null && startsWithIgnoreCase(os, "Win");
}
public static boolean isMac() {
return os != null && os.contains("Mac OS");
return os != null && os.equalsIgnoreCase("Mac OS X");
}
public static boolean isLinux() {
return os != null && os.contains("Linux") && !isAndroid();
return os != null && startsWithIgnoreCase(os, "Linux") && !isAndroid();
}
public static boolean isAndroid() {

View File

@@ -176,4 +176,9 @@ public class StringUtils {
}
return new String(c);
}
// see https://stackoverflow.com/a/38947571
static boolean startsWithIgnoreCase(String s, String prefix) {
return s.regionMatches(true, 0, prefix, 0, prefix.length());
}
}

View File

@@ -11,7 +11,7 @@ apply from: '../dagger.gradle'
dependencies {
api project(':bramble-api')
api 'org.briarproject:jtorctl:0.5'
api "org.briarproject:onionwrapper-core:$onionwrapper_version"
implementation "org.bouncycastle:bcprov-jdk15to18:$bouncy_castle_version"
//noinspection GradleDependency

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.mailbox;
import org.briarproject.bramble.api.FeatureFlags;
import org.briarproject.bramble.api.client.ClientHelper;
import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.data.MetadataEncoder;
@@ -76,14 +75,11 @@ public class MailboxModule {
ValidationManager validationManager,
ClientHelper clientHelper,
MetadataEncoder metadataEncoder,
Clock clock,
FeatureFlags featureFlags) {
Clock clock) {
MailboxUpdateValidator validator = new MailboxUpdateValidator(
clientHelper, metadataEncoder, clock);
if (featureFlags.shouldEnableMailbox()) {
validationManager.registerMessageValidator(CLIENT_ID,
MAJOR_VERSION, validator);
}
validationManager.registerMessageValidator(CLIENT_ID, MAJOR_VERSION,
validator);
return validator;
}
@@ -95,31 +91,26 @@ public class MailboxModule {
@Provides
@Singleton
MailboxUpdateManager provideMailboxUpdateManager(
FeatureFlags featureFlags,
LifecycleManager lifecycleManager,
ValidationManager validationManager, ContactManager contactManager,
ClientVersioningManager clientVersioningManager,
MailboxSettingsManager mailboxSettingsManager,
MailboxUpdateManagerImpl mailboxUpdateManager) {
if (featureFlags.shouldEnableMailbox()) {
lifecycleManager.registerOpenDatabaseHook(mailboxUpdateManager);
validationManager.registerIncomingMessageHook(CLIENT_ID,
MAJOR_VERSION, mailboxUpdateManager);
contactManager.registerContactHook(mailboxUpdateManager);
clientVersioningManager.registerClient(CLIENT_ID, MAJOR_VERSION,
MINOR_VERSION, mailboxUpdateManager);
mailboxSettingsManager.registerMailboxHook(mailboxUpdateManager);
}
lifecycleManager.registerOpenDatabaseHook(mailboxUpdateManager);
validationManager.registerIncomingMessageHook(CLIENT_ID, MAJOR_VERSION,
mailboxUpdateManager);
contactManager.registerContactHook(mailboxUpdateManager);
clientVersioningManager.registerClient(CLIENT_ID, MAJOR_VERSION,
MINOR_VERSION, mailboxUpdateManager);
mailboxSettingsManager.registerMailboxHook(mailboxUpdateManager);
return mailboxUpdateManager;
}
@Provides
@Singleton
MailboxFileManager provideMailboxFileManager(FeatureFlags featureFlags,
EventBus eventBus, MailboxFileManagerImpl mailboxFileManager) {
if (featureFlags.shouldEnableMailbox()) {
eventBus.addListener(mailboxFileManager);
}
MailboxFileManager provideMailboxFileManager(EventBus eventBus,
MailboxFileManagerImpl mailboxFileManager) {
eventBus.addListener(mailboxFileManager);
return mailboxFileManager;
}
@@ -160,17 +151,14 @@ public class MailboxModule {
MailboxUpdateManager mailboxUpdateManager,
MailboxClientFactory mailboxClientFactory,
TorReachabilityMonitor reachabilityMonitor,
FeatureFlags featureFlags,
LifecycleManager lifecycleManager,
EventBus eventBus) {
MailboxClientManager manager = new MailboxClientManager(eventExecutor,
dbExecutor, db, contactManager, pluginManager,
mailboxSettingsManager, mailboxUpdateManager,
mailboxClientFactory, reachabilityMonitor);
if (featureFlags.shouldEnableMailbox()) {
lifecycleManager.registerService(manager);
eventBus.addListener(manager);
}
lifecycleManager.registerService(manager);
eventBus.addListener(manager);
return manager;
}
}

View File

@@ -40,9 +40,9 @@ import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Logger;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Inject;
@@ -288,8 +288,10 @@ class PluginManagerImpl implements PluginManager, Service {
private class Callback implements PluginCallback {
private final TransportId id;
private final AtomicReference<State> state =
new AtomicReference<>(STARTING_STOPPING);
private final Object stateLock = new Object();
@GuardedBy("lock")
private State state = STARTING_STOPPING;
private Callback(TransportId id) {
this.id = id;
@@ -343,22 +345,26 @@ class PluginManagerImpl implements PluginManager, Service {
@Override
public void pluginStateChanged(State newState) {
State oldState = state.getAndSet(newState);
if (newState != oldState) {
if (LOG.isLoggable(INFO)) {
LOG.info(id + " changed from state " + oldState
+ " to " + newState);
synchronized (stateLock) {
if (newState != state) {
State oldState = state;
state = newState;
if (LOG.isLoggable(INFO)) {
LOG.info(id + " changed from state " + oldState
+ " to " + newState);
}
eventBus.broadcast(new TransportStateEvent(id, newState));
if (newState == ACTIVE) {
eventBus.broadcast(new TransportActiveEvent(id));
} else if (oldState == ACTIVE) {
eventBus.broadcast(new TransportInactiveEvent(id));
}
} else if (newState == DISABLED) {
// Broadcast an event even though the state hasn't changed,
// as the reasons for the plugin being disabled may have
// changed
eventBus.broadcast(new TransportStateEvent(id, newState));
}
eventBus.broadcast(new TransportStateEvent(id, newState));
if (newState == ACTIVE) {
eventBus.broadcast(new TransportActiveEvent(id));
} else if (oldState == ACTIVE) {
eventBus.broadcast(new TransportInactiveEvent(id));
}
} else if (newState == DISABLED) {
// Broadcast an event even though the state hasn't changed, as
// the reasons for the plugin being disabled may have changed
eventBus.broadcast(new TransportStateEvent(id, newState));
}
}

View File

@@ -1,75 +0,0 @@
package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.nullsafety.NotNullByDefault;
import java.util.List;
@NotNullByDefault
public interface CircumventionProvider {
enum BridgeType {
DEFAULT_OBFS4,
NON_DEFAULT_OBFS4,
VANILLA,
MEEK,
SNOWFLAKE
}
/**
* Countries where Tor is blocked, i.e. vanilla Tor connection won't work.
* <p>
* See https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
* and https://trac.torproject.org/projects/tor/wiki/doc/OONI/censorshipwiki
*/
String[] BLOCKED = {"BY", "CN", "EG", "IR", "RU", "TM", "VE"};
/**
* Countries where bridge connections are likely to work.
* Should be a subset of {@link #BLOCKED} and the union of
* {@link #DEFAULT_BRIDGES}, {@link #NON_DEFAULT_BRIDGES} and
* {@link #DPI_BRIDGES}.
*/
String[] BRIDGES = {"BY", "CN", "EG", "IR", "RU", "TM", "VE"};
/**
* Countries where default obfs4 or vanilla bridges are likely to work.
* Should be a subset of {@link #BRIDGES}.
*/
String[] DEFAULT_BRIDGES = {"EG", "VE"};
/**
* Countries where non-default obfs4 or vanilla bridges are likely to work.
* Should be a subset of {@link #BRIDGES}.
*/
String[] NON_DEFAULT_BRIDGES = {"BY", "RU"};
/**
* Countries where vanilla bridges are blocked via DPI but non-default
* obfs4 bridges, meek and snowflake may work. Should be a subset of
* {@link #BRIDGES}.
*/
String[] DPI_BRIDGES = {"CN", "IR", "TM"};
/**
* Returns true if vanilla Tor connections are blocked in the given country.
*/
boolean isTorProbablyBlocked(String countryCode);
/**
* Returns true if bridge connections of some type work in the given
* country.
*/
boolean doBridgesWork(String countryCode);
/**
* Returns the types of bridge connection that are suitable for the given
* country, or {@link #DEFAULT_BRIDGES} if no bridge type is known
* to work.
*/
List<BridgeType> getSuitableBridgeTypes(String countryCode);
@IoExecutor
List<String> getBridges(BridgeType type, String countryCode,
boolean letsEncrypt);
}

View File

@@ -1,129 +0,0 @@
package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.nullsafety.NotNullByDefault;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.TreeMap;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import static java.util.Arrays.asList;
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.DEFAULT_OBFS4;
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.MEEK;
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.NON_DEFAULT_OBFS4;
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.SNOWFLAKE;
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.VANILLA;
import static org.briarproject.nullsafety.NullSafety.requireNonNull;
@Immutable
@NotNullByDefault
class CircumventionProviderImpl implements CircumventionProvider {
private final static String BRIDGE_FILE_NAME = "bridges";
private final static String SNOWFLAKE_PARAMS_FILE_NAME = "snowflake-params";
private final static String DEFAULT_COUNTRY_CODE = "ZZ";
private static final Set<String> BLOCKED_IN_COUNTRIES =
new HashSet<>(asList(BLOCKED));
private static final Set<String> BRIDGE_COUNTRIES =
new HashSet<>(asList(BRIDGES));
private static final Set<String> DEFAULT_OBFS4_BRIDGE_COUNTRIES =
new HashSet<>(asList(DEFAULT_BRIDGES));
private static final Set<String> NON_DEFAULT_BRIDGE_COUNTRIES =
new HashSet<>(asList(NON_DEFAULT_BRIDGES));
private static final Set<String> DPI_COUNTRIES =
new HashSet<>(asList(DPI_BRIDGES));
@Inject
CircumventionProviderImpl() {
}
@Override
public boolean isTorProbablyBlocked(String countryCode) {
return BLOCKED_IN_COUNTRIES.contains(countryCode);
}
@Override
public boolean doBridgesWork(String countryCode) {
return BRIDGE_COUNTRIES.contains(countryCode);
}
@Override
public List<BridgeType> getSuitableBridgeTypes(String countryCode) {
if (DEFAULT_OBFS4_BRIDGE_COUNTRIES.contains(countryCode)) {
return asList(DEFAULT_OBFS4, VANILLA);
} else if (NON_DEFAULT_BRIDGE_COUNTRIES.contains(countryCode)) {
return asList(NON_DEFAULT_OBFS4, VANILLA);
} else if (DPI_COUNTRIES.contains(countryCode)) {
return asList(NON_DEFAULT_OBFS4, MEEK, SNOWFLAKE);
} else {
return asList(DEFAULT_OBFS4, VANILLA);
}
}
@Override
@IoExecutor
public List<String> getBridges(BridgeType type, String countryCode,
boolean letsEncrypt) {
InputStream is = requireNonNull(getClass().getClassLoader()
.getResourceAsStream(BRIDGE_FILE_NAME));
Scanner scanner = new Scanner(is);
List<String> bridges = new ArrayList<>();
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
if ((type == DEFAULT_OBFS4 && line.startsWith("d ")) ||
(type == NON_DEFAULT_OBFS4 && line.startsWith("n ")) ||
(type == VANILLA && line.startsWith("v ")) ||
(type == MEEK && line.startsWith("m "))) {
bridges.add(line.substring(2));
} else if (type == SNOWFLAKE && line.startsWith("s ")) {
String params = getSnowflakeParams(countryCode, letsEncrypt);
bridges.add(line.substring(2) + " " + params);
}
}
scanner.close();
return bridges;
}
// Package access for testing
@SuppressWarnings("WeakerAccess")
String getSnowflakeParams(String countryCode, boolean letsEncrypt) {
Map<String, String> params = loadSnowflakeParams();
if (countryCode.isEmpty()) countryCode = DEFAULT_COUNTRY_CODE;
// If we have parameters for this country code, return them
String value = params.get(makeKey(countryCode, letsEncrypt));
if (value != null) return value;
// Return the default parameters
value = params.get(makeKey(DEFAULT_COUNTRY_CODE, letsEncrypt));
return requireNonNull(value);
}
private Map<String, String> loadSnowflakeParams() {
InputStream is = requireNonNull(getClass().getClassLoader()
.getResourceAsStream(SNOWFLAKE_PARAMS_FILE_NAME));
Scanner scanner = new Scanner(is);
Map<String, String> params = new TreeMap<>();
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
if (line.length() < 5) continue;
String key = line.substring(0, 4); // Country code, space, digit
String value = line.substring(5);
params.put(key, value);
}
scanner.close();
return params;
}
private String makeKey(String countryCode, boolean letsEncrypt) {
return countryCode + " " + (letsEncrypt ? "1" : "0");
}
}

View File

@@ -1,8 +1,5 @@
package org.briarproject.bramble.plugin.tor;
import net.freehaven.tor.control.EventHandler;
import net.freehaven.tor.control.TorControlConnection;
import org.briarproject.bramble.PoliteExecutor;
import org.briarproject.bramble.api.Pair;
import org.briarproject.bramble.api.battery.BatteryManager;
@@ -27,35 +24,27 @@ import org.briarproject.bramble.api.rendezvous.KeyMaterialSource;
import org.briarproject.bramble.api.rendezvous.RendezvousEndpoint;
import org.briarproject.bramble.api.settings.Settings;
import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType;
import org.briarproject.nullsafety.MethodsNotNullByDefault;
import org.briarproject.nullsafety.InterfaceNotNullByDefault;
import org.briarproject.nullsafety.NotNullByDefault;
import org.briarproject.nullsafety.ParametersNotNullByDefault;
import org.briarproject.onionwrapper.CircumventionProvider;
import org.briarproject.onionwrapper.CircumventionProvider.BridgeType;
import org.briarproject.onionwrapper.TorWrapper;
import org.briarproject.onionwrapper.TorWrapper.HiddenServiceProperties;
import org.briarproject.onionwrapper.TorWrapper.Observer;
import org.briarproject.onionwrapper.TorWrapper.TorState;
import java.io.ByteArrayInputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import java.util.zip.ZipInputStream;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
@@ -64,13 +53,9 @@ import javax.net.SocketFactory;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static net.freehaven.tor.control.TorControlCommands.HS_ADDRESS;
import static net.freehaven.tor.control.TorControlCommands.HS_PRIVKEY;
import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE;
import static org.briarproject.bramble.api.plugin.Plugin.State.DISABLED;
import static org.briarproject.bramble.api.plugin.Plugin.State.ENABLING;
@@ -92,35 +77,19 @@ import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION_V3;
import static org.briarproject.bramble.api.plugin.TorConstants.REASON_BATTERY;
import static org.briarproject.bramble.api.plugin.TorConstants.REASON_COUNTRY_BLOCKED;
import static org.briarproject.bramble.api.plugin.TorConstants.REASON_MOBILE_DATA;
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.MEEK;
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.SNOWFLAKE;
import static org.briarproject.bramble.plugin.tor.TorRendezvousCrypto.SEED_BYTES;
import static org.briarproject.bramble.util.IoUtils.copyAndClose;
import static org.briarproject.bramble.util.IoUtils.tryToClose;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.PrivacyUtils.scrubOnion;
import static org.briarproject.bramble.util.StringUtils.UTF_8;
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
import static org.briarproject.onionwrapper.CircumventionProvider.BridgeType.MEEK;
import static org.briarproject.onionwrapper.CircumventionProvider.BridgeType.SNOWFLAKE;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
@InterfaceNotNullByDefault
class TorPlugin implements DuplexPlugin, EventListener {
protected static final Logger LOG = getLogger(TorPlugin.class.getName());
private static final String[] EVENTS = {
"CIRC",
"ORCONN",
"STATUS_GENERAL",
"STATUS_CLIENT",
"HS_DESC",
"NOTICE",
"WARN",
"ERR"
};
private static final String OWNER = "__OwningControllerProcess";
private static final int COOKIE_TIMEOUT_MS = 3000;
private static final int COOKIE_POLLING_INTERVAL_MS = 200;
private static final Pattern ONION_V3 = Pattern.compile("[a-z2-7]{56}");
protected final Executor ioExecutor;
@@ -129,91 +98,79 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private final NetworkManager networkManager;
private final LocationUtils locationUtils;
private final SocketFactory torSocketFactory;
private final Clock clock;
private final CircumventionProvider circumventionProvider;
private final BatteryManager batteryManager;
private final Backoff backoff;
private final TorRendezvousCrypto torRendezvousCrypto;
private final TorWrapper tor;
private final PluginCallback callback;
private final String architecture;
private final CircumventionProvider circumventionProvider;
private final ResourceProvider resourceProvider;
private final long maxLatency;
private final int maxIdleTime;
private final boolean canVerifyLetsEncryptCerts;
private final int socketTimeout;
private final File torDirectory;
private final File configFile;
private final int torSocksPort;
private final int torControlPort;
private final File doneFile, cookieFile;
private final AtomicBoolean used = new AtomicBoolean(false);
protected final PluginState state = new PluginState();
private volatile Socket controlSocket = null;
private volatile TorControlConnection controlConnection = null;
private volatile Settings settings = null;
protected abstract int getProcessId();
protected abstract long getLastUpdateTime();
TorPlugin(Executor ioExecutor,
Executor wakefulIoExecutor,
NetworkManager networkManager,
LocationUtils locationUtils,
SocketFactory torSocketFactory,
Clock clock,
ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider,
BatteryManager batteryManager,
Backoff backoff,
TorRendezvousCrypto torRendezvousCrypto,
TorWrapper tor,
PluginCallback callback,
String architecture,
long maxLatency,
int maxIdleTime,
File torDirectory,
int torSocksPort,
int torControlPort) {
boolean canVerifyLetsEncryptCerts) {
this.ioExecutor = ioExecutor;
this.wakefulIoExecutor = wakefulIoExecutor;
this.networkManager = networkManager;
this.locationUtils = locationUtils;
this.torSocketFactory = torSocketFactory;
this.clock = clock;
this.resourceProvider = resourceProvider;
this.circumventionProvider = circumventionProvider;
this.batteryManager = batteryManager;
this.backoff = backoff;
this.torRendezvousCrypto = torRendezvousCrypto;
this.tor = tor;
this.callback = callback;
this.architecture = architecture;
this.maxLatency = maxLatency;
this.maxIdleTime = maxIdleTime;
if (maxIdleTime > Integer.MAX_VALUE / 2)
this.canVerifyLetsEncryptCerts = canVerifyLetsEncryptCerts;
if (maxIdleTime > Integer.MAX_VALUE / 2) {
socketTimeout = Integer.MAX_VALUE;
else socketTimeout = maxIdleTime * 2;
this.torDirectory = torDirectory;
this.torSocksPort = torSocksPort;
this.torControlPort = torControlPort;
configFile = new File(torDirectory, "torrc");
doneFile = new File(torDirectory, "done");
cookieFile = new File(torDirectory, ".tor/control_auth_cookie");
} else {
socketTimeout = maxIdleTime * 2;
}
// Don't execute more than one connection status check at a time
connectionStatusExecutor =
new PoliteExecutor("TorPlugin", ioExecutor, 1);
}
tor.setObserver(new Observer() {
protected File getTorExecutableFile() {
return new File(torDirectory, "tor");
}
@Override
public void onState(TorState torState) {
State s = state.getState(torState);
if (s == ACTIVE) backoff.reset();
callback.pluginStateChanged(s);
}
protected File getObfs4ExecutableFile() {
return new File(torDirectory, "obfs4proxy");
}
@Override
public void onBootstrapPercentage(int percentage) {
}
protected File getSnowflakeExecutableFile() {
return new File(torDirectory, "snowflake");
@Override
public void onHsDescriptorUpload(String onion) {
}
@Override
public void onClockSkewDetected(long skewSeconds) {
}
});
}
@Override
@@ -234,89 +191,18 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
@Override
public void start() throws PluginException {
if (used.getAndSet(true)) throw new IllegalStateException();
if (!torDirectory.exists()) {
if (!torDirectory.mkdirs()) {
LOG.warning("Could not create Tor directory.");
throw new PluginException();
}
}
// Load the settings
settings = callback.getSettings();
// Start Tor
try {
// Install or update the assets if necessary
if (!assetsAreUpToDate()) installAssets();
// Start from the default config every time
extract(getConfigInputStream(), configFile);
} catch (IOException e) {
throw new PluginException(e);
}
if (cookieFile.exists() && !cookieFile.delete())
LOG.warning("Old auth cookie not deleted");
// Start a new Tor process
LOG.info("Starting Tor");
File torFile = getTorExecutableFile();
String torPath = torFile.getAbsolutePath();
String configPath = configFile.getAbsolutePath();
String pid = String.valueOf(getProcessId());
Process torProcess;
ProcessBuilder pb =
new ProcessBuilder(torPath, "-f", configPath, OWNER, pid);
Map<String, String> env = pb.environment();
env.put("HOME", torDirectory.getAbsolutePath());
pb.directory(torDirectory);
pb.redirectErrorStream(true);
try {
torProcess = pb.start();
} catch (SecurityException | IOException e) {
throw new PluginException(e);
}
try {
// Wait for the Tor process to start
waitForTorToStart(torProcess);
// Wait for the auth cookie file to be created/updated
long start = clock.currentTimeMillis();
while (cookieFile.length() < 32) {
if (clock.currentTimeMillis() - start > COOKIE_TIMEOUT_MS) {
LOG.warning("Auth cookie not created");
if (LOG.isLoggable(INFO)) listFiles(torDirectory);
throw new PluginException();
}
//noinspection BusyWait
Thread.sleep(COOKIE_POLLING_INTERVAL_MS);
}
LOG.info("Auth cookie created");
tor.start();
} catch (InterruptedException e) {
LOG.warning("Interrupted while starting Tor");
Thread.currentThread().interrupt();
throw new PluginException();
}
try {
// Open a control connection and authenticate using the cookie file
controlSocket = new Socket("127.0.0.1", torControlPort);
controlConnection = new TorControlConnection(controlSocket);
controlConnection.authenticate(read(cookieFile));
// Tell Tor to exit when the control connection is closed
controlConnection.takeOwnership();
controlConnection.resetConf(singletonList(OWNER));
// Register to receive events from the Tor process
controlConnection.setEventHandler(this);
controlConnection.setEvents(asList(EVENTS));
// Check whether Tor has already bootstrapped
String info = controlConnection.getInfo("status/bootstrap-phase");
if (info != null && info.contains("PROGRESS=100")) {
LOG.info("Tor has already bootstrapped");
state.setBootstrapped();
}
// Check whether Tor has already built a circuit
info = controlConnection.getInfo("status/circuit-established");
if ("1".equals(info)) {
LOG.info("Tor has already built a circuit");
state.setCircuitBuilt(true);
}
} catch (IOException e) {
throw new PluginException(e);
}
state.setStarted();
// Check whether we're online
updateConnectionStatus(networkManager.getNetworkStatus(),
batteryManager.isCharging());
@@ -324,140 +210,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
bind();
}
private boolean assetsAreUpToDate() {
return doneFile.lastModified() > getLastUpdateTime();
}
private void installAssets() throws IOException {
// The done file may already exist from a previous installation
//noinspection ResultOfMethodCallIgnored
doneFile.delete();
installTorExecutable();
installObfs4Executable();
installSnowflakeExecutable();
if (!doneFile.createNewFile())
LOG.warning("Failed to create done file");
}
protected void extract(InputStream in, File dest) throws IOException {
OutputStream out = new FileOutputStream(dest);
copyAndClose(in, out);
}
protected void installTorExecutable() throws IOException {
if (LOG.isLoggable(INFO))
LOG.info("Installing Tor binary for " + architecture);
File torFile = getTorExecutableFile();
extract(getTorInputStream(), torFile);
if (!torFile.setExecutable(true, true)) throw new IOException();
}
protected void installObfs4Executable() throws IOException {
if (LOG.isLoggable(INFO))
LOG.info("Installing obfs4proxy binary for " + architecture);
File obfs4File = getObfs4ExecutableFile();
extract(getObfs4InputStream(), obfs4File);
if (!obfs4File.setExecutable(true, true)) throw new IOException();
}
protected void installSnowflakeExecutable() throws IOException {
if (LOG.isLoggable(INFO))
LOG.info("Installing snowflake binary for " + architecture);
File snowflakeFile = getSnowflakeExecutableFile();
extract(getSnowflakeInputStream(), snowflakeFile);
if (!snowflakeFile.setExecutable(true, true)) throw new IOException();
}
private InputStream getTorInputStream() throws IOException {
return getZipInputStream("tor");
}
private InputStream getObfs4InputStream() throws IOException {
return getZipInputStream("obfs4proxy");
}
private InputStream getSnowflakeInputStream() throws IOException {
return getZipInputStream("snowflake");
}
private InputStream getZipInputStream(String basename) throws IOException {
InputStream in = resourceProvider
.getResourceInputStream(basename + "_" + architecture, ".zip");
ZipInputStream zin = new ZipInputStream(in);
if (zin.getNextEntry() == null) throw new IOException();
return zin;
}
private static void append(StringBuilder strb, String name, Object value) {
strb.append(name);
strb.append(" ");
strb.append(value);
strb.append("\n");
}
private InputStream getConfigInputStream() {
File dataDirectory = new File(torDirectory, ".tor");
StringBuilder strb = new StringBuilder();
append(strb, "ControlPort", torControlPort);
append(strb, "CookieAuthentication", 1);
append(strb, "DataDirectory", dataDirectory.getAbsolutePath());
append(strb, "DisableNetwork", 1);
append(strb, "RunAsDaemon", 1);
append(strb, "SafeSocks", 1);
append(strb, "SocksPort", torSocksPort);
strb.append("GeoIPFile\n");
strb.append("GeoIPv6File\n");
append(strb, "ConnectionPadding", 0);
String obfs4Path = getObfs4ExecutableFile().getAbsolutePath();
append(strb, "ClientTransportPlugin obfs4 exec", obfs4Path);
append(strb, "ClientTransportPlugin meek_lite exec", obfs4Path);
String snowflakePath = getSnowflakeExecutableFile().getAbsolutePath();
append(strb, "ClientTransportPlugin snowflake exec", snowflakePath);
return new ByteArrayInputStream(strb.toString().getBytes(UTF_8));
}
private void listFiles(File f) {
if (f.isDirectory()) {
File[] children = f.listFiles();
if (children != null) for (File child : children) listFiles(child);
} else {
LOG.info(f.getAbsolutePath() + " " + f.length());
}
}
private byte[] read(File f) throws IOException {
byte[] b = new byte[(int) f.length()];
FileInputStream in = new FileInputStream(f);
try {
int offset = 0;
while (offset < b.length) {
int read = in.read(b, offset, b.length - offset);
if (read == -1) throw new EOFException();
offset += read;
}
return b;
} finally {
tryToClose(in, LOG, WARNING);
}
}
protected void waitForTorToStart(Process torProcess)
throws InterruptedException, PluginException {
Scanner stdout = new Scanner(torProcess.getInputStream());
// Log the first line of stdout (contains Tor and library versions)
if (stdout.hasNextLine()) LOG.info(stdout.nextLine());
// Read the process's stdout (and redirected stderr) until it detaches
while (stdout.hasNextLine()) stdout.nextLine();
stdout.close();
// Wait for the process to detach or exit
int exit = torProcess.waitFor();
if (exit != 0) {
if (LOG.isLoggable(WARNING))
LOG.warning("Tor exited with value " + exit);
throw new PluginException();
}
}
private void bind() {
ioExecutor.execute(() -> {
// If there's already a port number stored in config, reuse it
@@ -481,9 +233,9 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
return;
}
// Store the port number
String localPort = String.valueOf(ss.getLocalPort());
int localPort = ss.getLocalPort();
Settings s = new Settings();
s.put(PREF_TOR_PORT, localPort);
s.put(PREF_TOR_PORT, String.valueOf(localPort));
callback.mergeSettings(s);
// Create a hidden service if necessary
ioExecutor.execute(() -> publishHiddenService(localPort));
@@ -493,48 +245,28 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
});
}
private void publishHiddenService(String port) {
if (!state.isTorRunning()) return;
String privKey3 = settings.get(HS_PRIVATE_KEY_V3);
publishV3HiddenService(port, privKey3);
}
private void publishV3HiddenService(String port, @Nullable String privKey) {
private void publishHiddenService(int localPort) {
if (!tor.isTorRunning()) return;
String privKey = settings.get(HS_PRIVATE_KEY_V3);
LOG.info("Creating v3 hidden service");
Map<Integer, String> portLines = singletonMap(80, "127.0.0.1:" + port);
Map<String, String> response;
HiddenServiceProperties hsProps;
try {
// Use the control connection to set up the hidden service
if (privKey == null) {
response = controlConnection.addOnion("NEW:ED25519-V3",
portLines, null);
} else {
response = controlConnection.addOnion(privKey, portLines);
}
hsProps = tor.publishHiddenService(localPort, 80, privKey);
} catch (IOException e) {
logException(LOG, WARNING, e);
return;
}
if (!response.containsKey(HS_ADDRESS)) {
LOG.warning("Tor did not return a hidden service address");
return;
}
if (privKey == null && !response.containsKey(HS_PRIVKEY)) {
LOG.warning("Tor did not return a private key");
return;
}
String onion3 = response.get(HS_ADDRESS);
if (LOG.isLoggable(INFO)) {
LOG.info("V3 hidden service " + scrubOnion(onion3));
LOG.info("V3 hidden service " + scrubOnion(hsProps.onion));
}
if (privKey == null) {
// Publish the hidden service's onion hostname in transport props
TransportProperties p = new TransportProperties();
p.put(PROP_ONION_V3, onion3);
p.put(PROP_ONION_V3, hsProps.onion);
callback.mergeLocalProperties(p);
// Save the hidden service's private key for next time
Settings s = new Settings();
s.put(HS_PRIVATE_KEY_V3, response.get(HS_PRIVKEY));
s.put(HS_PRIVATE_KEY_V3, hsProps.privKey);
callback.mergeSettings(s);
}
}
@@ -557,50 +289,28 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
}
}
protected void enableNetwork(boolean enable) throws IOException {
if (!state.enableNetwork(enable)) return; // Unchanged
controlConnection.setConf("DisableNetwork", enable ? "0" : "1");
}
private void enableBridges(List<BridgeType> bridgeTypes, String countryCode)
throws IOException {
if (!state.setBridgeTypes(bridgeTypes)) return; // Unchanged
if (bridgeTypes.isEmpty()) {
controlConnection.setConf("UseBridges", "0");
controlConnection.resetConf(singletonList("Bridge"));
tor.disableBridges();
} else {
Collection<String> conf = new ArrayList<>();
conf.add("UseBridges 1");
boolean letsEncrypt = canVerifyLetsEncryptCerts();
List<String> bridges = new ArrayList<>();
for (BridgeType bridgeType : bridgeTypes) {
conf.addAll(circumventionProvider
.getBridges(bridgeType, countryCode, letsEncrypt));
bridges.addAll(circumventionProvider.getBridges(bridgeType,
countryCode, canVerifyLetsEncryptCerts));
}
controlConnection.setConf(conf);
tor.enableBridges(bridges);
}
}
/**
* Returns true if this device can verify Let's Encrypt certificates signed
* with the IdentTrust DST Root X3 certificate, which expired at the end of
* September 2021.
*/
protected boolean canVerifyLetsEncryptCerts() {
return true;
}
@Override
public void stop() {
ServerSocket ss = state.setStopped();
tryToClose(ss, LOG, WARNING);
if (controlSocket != null && controlConnection != null) {
try {
LOG.info("Stopping Tor");
controlConnection.shutdownTor("TERM");
controlSocket.close();
} catch (IOException e) {
logException(LOG, WARNING, e);
}
try {
tor.stop();
} catch (IOException e) {
logException(LOG, WARNING, e);
}
}
@@ -711,6 +421,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
TransportProperties remoteProperties = new TransportProperties();
remoteProperties.put(PROP_ONION_V3, remoteOnion);
try {
@SuppressWarnings("resource")
ServerSocket ss = new ServerSocket();
ss.bind(new InetSocketAddress("127.0.0.1", 0));
int port = ss.getLocalPort();
@@ -727,9 +438,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
LOG.info("Rendezvous server socket closed");
}
});
Map<Integer, String> portLines =
singletonMap(80, "127.0.0.1:" + port);
controlConnection.addOnion(blob, portLines);
tor.publishHiddenService(port, 80, blob);
return new RendezvousEndpoint() {
@Override
@@ -739,8 +448,11 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
@Override
public void close() throws IOException {
controlConnection.delOnion(localOnion);
tryToClose(ss, LOG, WARNING);
try {
tor.removeHiddenService(localOnion);
} finally {
tryToClose(ss, LOG, WARNING);
}
}
};
} catch (IOException e) {
@@ -749,121 +461,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
}
}
@Override
public void circuitStatus(String status, String id, String path) {
// In case of races between receiving CIRCUIT_ESTABLISHED and setting
// DisableNetwork, set our circuitBuilt flag if not already set
if (status.equals("BUILT") && state.setCircuitBuilt(true)) {
LOG.info("Circuit built");
backoff.reset();
}
}
@Override
public void streamStatus(String status, String id, String target) {
}
@Override
public void orConnStatus(String status, String orName) {
if (LOG.isLoggable(INFO)) LOG.info("OR connection " + status);
if (status.equals("CONNECTED")) state.onOrConnectionConnected();
else if (status.equals("CLOSED")) state.onOrConnectionClosed();
}
@Override
public void bandwidthUsed(long read, long written) {
}
@Override
public void newDescriptors(List<String> orList) {
}
@Override
public void message(String severity, String msg) {
if (LOG.isLoggable(INFO)) LOG.info(severity + " " + msg);
}
@Override
public void unrecognized(String type, String msg) {
if (type.equals("STATUS_CLIENT")) {
handleClientStatus(removeSeverity(msg));
} else if (type.equals("STATUS_GENERAL")) {
handleGeneralStatus(removeSeverity(msg));
} else if (type.equals("HS_DESC") && msg.startsWith("UPLOADED")) {
String[] parts = msg.split(" ");
if (parts.length < 2) {
LOG.warning("Failed to parse HS_DESC UPLOADED event");
} else if (LOG.isLoggable(INFO)) {
LOG.info("V3 descriptor uploaded for " + scrubOnion(parts[1]));
}
}
}
@Override
public void controlConnectionClosed() {
if (state.isTorRunning()) {
// TODO: Restart the Tor process
LOG.warning("Control connection closed");
}
}
private String removeSeverity(String msg) {
return msg.replaceFirst("[^ ]+ ", "");
}
private void handleClientStatus(String msg) {
if (msg.startsWith("BOOTSTRAP PROGRESS=100")) {
LOG.info("Bootstrapped");
state.setBootstrapped();
backoff.reset();
} else if (msg.startsWith("CIRCUIT_ESTABLISHED")) {
if (state.setCircuitBuilt(true)) {
LOG.info("Circuit built");
backoff.reset();
}
} else if (msg.startsWith("CIRCUIT_NOT_ESTABLISHED")) {
if (state.setCircuitBuilt(false)) {
LOG.info("Circuit not built");
// TODO: Disable and re-enable network to prompt Tor to rebuild
// its guard/bridge connections? This will also close any
// established circuits, which might still be functioning
}
}
}
private void handleGeneralStatus(String msg) {
if (msg.startsWith("CLOCK_JUMPED")) {
Long time = parseLongArgument(msg, "TIME");
if (time != null && LOG.isLoggable(WARNING)) {
LOG.warning("Clock jumped " + time + " seconds");
}
} else if (msg.startsWith("CLOCK_SKEW")) {
Long skew = parseLongArgument(msg, "SKEW");
if (skew != null && LOG.isLoggable(WARNING)) {
LOG.warning("Clock is skewed by " + skew + " seconds");
}
}
}
@Nullable
private Long parseLongArgument(String msg, String argName) {
String[] args = msg.split(" ");
for (String arg : args) {
if (arg.startsWith(argName + "=")) {
try {
return Long.parseLong(arg.substring(argName.length() + 1));
} catch (NumberFormatException e) {
break;
}
}
}
if (LOG.isLoggable(WARNING)) {
LOG.warning("Failed to parse " + argName + " from '" + msg + "'");
}
return null;
}
@Override
public void eventOccurred(Event e) {
if (e instanceof SettingsUpdatedEvent) {
@@ -886,7 +483,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private void updateConnectionStatus(NetworkStatus status,
boolean charging) {
connectionStatusExecutor.execute(() -> {
if (!state.isTorRunning()) return;
if (!tor.isTorRunning()) return;
boolean online = status.isConnected();
boolean wifi = status.isWifi();
boolean ipv6Only = status.isIpv6Only();
@@ -970,41 +567,22 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
try {
if (enableNetwork) {
enableBridges(bridgeTypes, country);
enableConnectionPadding(enableConnectionPadding);
enableIpv6(ipv6Only);
tor.enableConnectionPadding(enableConnectionPadding);
tor.enableIpv6(ipv6Only);
}
enableNetwork(enableNetwork);
tor.enableNetwork(enableNetwork);
} catch (IOException e) {
logException(LOG, WARNING, e);
}
});
}
private void enableConnectionPadding(boolean enable) throws IOException {
if (!state.enableConnectionPadding(enable)) return; // Unchanged
controlConnection.setConf("ConnectionPadding", enable ? "1" : "0");
}
private void enableIpv6(boolean enable) throws IOException {
if (!state.enableIpv6(enable)) return; // Unchanged
controlConnection.setConf("ClientUseIPv4", enable ? "0" : "1");
controlConnection.setConf("ClientUseIPv6", enable ? "1" : "0");
}
@ThreadSafe
@NotNullByDefault
protected class PluginState {
private class PluginState {
@GuardedBy("this")
private boolean started = false,
stopped = false,
networkInitialised = false,
networkEnabled = false,
paddingEnabled = false,
ipv6Enabled = false,
bootstrapped = false,
circuitBuilt = false,
settingsChecked = false;
private boolean settingsChecked = false;
@GuardedBy("this")
private int reasonsDisabled = 0;
@@ -1013,84 +591,13 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
@Nullable
private ServerSocket serverSocket = null;
@GuardedBy("this")
private int orConnectionsConnected = 0;
@GuardedBy("this")
private List<BridgeType> bridgeTypes = emptyList();
private synchronized void setStarted() {
started = true;
callback.pluginStateChanged(getState());
}
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private synchronized boolean isTorRunning() {
return started && !stopped;
}
@Nullable
private synchronized ServerSocket setStopped() {
stopped = true;
ServerSocket ss = serverSocket;
serverSocket = null;
callback.pluginStateChanged(getState());
return ss;
}
private synchronized void setBootstrapped() {
boolean wasBootstrapped = bootstrapped;
bootstrapped = true;
if (!wasBootstrapped) callback.pluginStateChanged(getState());
}
/**
* Sets the `circuitBuilt` flag and returns true if the flag has
* changed.
*/
private synchronized boolean setCircuitBuilt(boolean built) {
if (built == circuitBuilt) return false; // Unchanged
circuitBuilt = built;
callback.pluginStateChanged(getState());
return true; // Changed
}
/**
* Sets the `networkEnabled` flag and returns true if the flag has
* changed.
*/
private synchronized boolean enableNetwork(boolean enable) {
boolean wasInitialised = networkInitialised;
boolean wasEnabled = networkEnabled;
networkInitialised = true;
networkEnabled = enable;
if (!enable) circuitBuilt = false;
if (!wasInitialised || enable != wasEnabled) {
callback.pluginStateChanged(getState());
}
return enable != wasEnabled;
}
/**
* Sets the `paddingEnabled` flag and returns true if the flag has
* changed. Doesn't affect getState().
*/
private synchronized boolean enableConnectionPadding(boolean enable) {
if (enable == paddingEnabled) return false; // Unchanged
paddingEnabled = enable;
return true; // Changed
}
/**
* Sets the `ipv6Enabled` flag and returns true if the flag has
* changed. Doesn't affect getState().
*/
private synchronized boolean enableIpv6(boolean enable) {
if (enable == ipv6Enabled) return false; // Unchanged
ipv6Enabled = enable;
return true; // Changed
}
private synchronized void setReasonsDisabled(int reasons) {
boolean wasChecked = settingsChecked;
settingsChecked = true;
@@ -1103,7 +610,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
// Doesn't affect getState()
private synchronized boolean setServerSocket(ServerSocket ss) {
if (stopped || serverSocket != null) return false;
if (serverSocket != null || !tor.isTorRunning()) return false;
serverSocket = ss;
return true;
}
@@ -1113,57 +620,22 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
if (serverSocket == ss) serverSocket = null;
}
/**
* Sets the list of bridge types being used and returns true if the
* list has changed. The list is empty if bridges are disabled.
* Doesn't affect getState().
*/
private synchronized boolean setBridgeTypes(List<BridgeType> types) {
if (types.equals(bridgeTypes)) return false; // Unchanged
bridgeTypes = types;
return true; // Changed
private synchronized State getState() {
return getState(tor.getTorState());
}
private synchronized State getState() {
if (!started || stopped || !settingsChecked) {
private synchronized State getState(TorState torState) {
if (torState == TorState.STARTING_STOPPING || !settingsChecked) {
return STARTING_STOPPING;
}
if (reasonsDisabled != 0) return DISABLED;
if (!networkInitialised) return ENABLING;
if (!networkEnabled) return INACTIVE;
return bootstrapped && circuitBuilt && orConnectionsConnected > 0
? ACTIVE : ENABLING;
if (torState == TorState.CONNECTING) return ENABLING;
if (torState == TorState.CONNECTED) return ACTIVE;
return INACTIVE;
}
private synchronized int getReasonsDisabled() {
return getState() == DISABLED ? reasonsDisabled : 0;
}
private synchronized void onOrConnectionConnected() {
int oldConnected = orConnectionsConnected;
orConnectionsConnected++;
logOrConnections();
if (oldConnected == 0) callback.pluginStateChanged(getState());
}
private synchronized void onOrConnectionClosed() {
int oldConnected = orConnectionsConnected;
orConnectionsConnected--;
if (orConnectionsConnected < 0) {
LOG.warning("Count was zero before connection closed");
orConnectionsConnected = 0;
}
logOrConnections();
if (orConnectionsConnected == 0 && oldConnected != 0) {
callback.pluginStateChanged(getState());
}
}
@GuardedBy("this")
private void logOrConnections() {
if (LOG.isLoggable(INFO)) {
LOG.info(orConnectionsConnected + " OR connections connected");
}
}
}
}

View File

@@ -3,6 +3,7 @@ package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventExecutor;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.plugin.Backoff;
@@ -17,9 +18,9 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.bramble.api.system.WakefulIoExecutor;
import org.briarproject.nullsafety.NotNullByDefault;
import org.briarproject.onionwrapper.CircumventionProvider;
import java.io.File;
import java.util.concurrent.Executor;
@@ -45,13 +46,12 @@ abstract class TorPluginFactory implements DuplexPluginFactory {
private static final int MAX_POLLING_INTERVAL = 10 * 60 * 1000; // 10 mins
private static final double BACKOFF_BASE = 1.2;
protected final Executor ioExecutor, wakefulIoExecutor;
protected final Executor ioExecutor, eventExecutor, wakefulIoExecutor;
protected final NetworkManager networkManager;
protected final LocationUtils locationUtils;
protected final EventBus eventBus;
protected final SocketFactory torSocketFactory;
protected final BackoffFactory backoffFactory;
protected final ResourceProvider resourceProvider;
protected final CircumventionProvider circumventionProvider;
protected final BatteryManager batteryManager;
protected final Clock clock;
@@ -61,13 +61,13 @@ abstract class TorPluginFactory implements DuplexPluginFactory {
protected final int torControlPort;
TorPluginFactory(@IoExecutor Executor ioExecutor,
@EventExecutor Executor eventExecutor,
@WakefulIoExecutor Executor wakefulIoExecutor,
NetworkManager networkManager,
LocationUtils locationUtils,
EventBus eventBus,
SocketFactory torSocketFactory,
BackoffFactory backoffFactory,
ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider,
BatteryManager batteryManager,
Clock clock,
@@ -76,13 +76,13 @@ abstract class TorPluginFactory implements DuplexPluginFactory {
@TorSocksPort int torSocksPort,
@TorControlPort int torControlPort) {
this.ioExecutor = ioExecutor;
this.eventExecutor = eventExecutor;
this.wakefulIoExecutor = wakefulIoExecutor;
this.networkManager = networkManager;
this.locationUtils = locationUtils;
this.eventBus = eventBus;
this.torSocketFactory = torSocketFactory;
this.backoffFactory = backoffFactory;
this.resourceProvider = resourceProvider;
this.circumventionProvider = circumventionProvider;
this.batteryManager = batteryManager;
this.clock = clock;

View File

@@ -1,4 +1,4 @@
package org.briarproject.bramble.plugin.tor;
package org.briarproject.onionwrapper;
import javax.inject.Singleton;

View File

@@ -1,36 +0,0 @@
d Bridge obfs4 192.95.36.142:443 CDF2E852BF539B82BD10E27E9115A31734E378C2 cert=qUVQ0srL1JI/vO6V6m/24anYXiJD3QP2HgzUKQtQ7GRqqUvs7P+tG43RtAqdhLOALP7DJQ iat-mode=1
d Bridge obfs4 37.218.245.14:38224 D9A82D2F9C2F65A18407B1D2B764F130847F8B5D cert=bjRaMrr1BRiAW8IE9U5z27fQaYgOhX1UCmOpg2pFpoMvo6ZgQMzLsaTzzQNTlm7hNcb+Sg iat-mode=0
d Bridge obfs4 85.31.186.98:443 011F2599C0E9B27EE74B353155E244813763C3E5 cert=ayq0XzCwhpdysn5o0EyDUbmSOx3X/oTEbzDMvczHOdBJKlvIdHHLJGkZARtT4dcBFArPPg iat-mode=0
d Bridge obfs4 85.31.186.26:443 91A6354697E6B02A386312F68D82CF86824D3606 cert=PBwr+S8JTVZo6MPdHnkTwXJPILWADLqfMGoVvhZClMq/Urndyd42BwX9YFJHZnBB3H0XCw iat-mode=0
d Bridge obfs4 193.11.166.194:27015 2D82C2E354D531A68469ADF7F878FA6060C6BACA cert=4TLQPJrTSaDffMK7Nbao6LC7G9OW/NHkUwIdjLSS3KYf0Nv4/nQiiI8dY2TcsQx01NniOg iat-mode=0
d Bridge obfs4 193.11.166.194:27020 86AC7B8D430DAC4117E9F42C9EAED18133863AAF cert=0LDeJH4JzMDtkJJrFphJCiPqKx7loozKN7VNfuukMGfHO0Z8OGdzHVkhVAOfo1mUdv9cMg iat-mode=0
d Bridge obfs4 193.11.166.194:27025 1AE2C08904527FEA90C4C4F8C1083EA59FBC6FAF cert=ItvYZzW5tn6v3G4UnQa6Qz04Npro6e81AP70YujmK/KXwDFPTs3aHXcHp4n8Vt6w/bv8cA iat-mode=0
d Bridge obfs4 209.148.46.65:443 74FAD13168806246602538555B5521A0383A1875 cert=ssH+9rP8dG2NLDN2XuFw63hIO/9MNNinLmxQDpVa+7kTOa9/m+tGWT1SmSYpQ9uTBGa6Hw iat-mode=0
d Bridge obfs4 146.57.248.225:22 10A6CD36A537FCE513A322361547444B393989F0 cert=K1gDtDAIcUfeLqbstggjIw2rtgIKqdIhUlHp82XRqNSq/mtAjp1BIC9vHKJ2FAEpGssTPw iat-mode=0
d Bridge obfs4 45.145.95.6:27015 C5B7CD6946FF10C5B3E89691A7D3F2C122D2117C cert=TD7PbUO0/0k6xYHMPW3vJxICfkMZNdkRrb63Zhl5j9dW3iRGiCx0A7mPhe5T2EDzQ35+Zw iat-mode=0
d Bridge obfs4 51.222.13.177:80 5EDAC3B810E12B01F6FD8050D2FD3E277B289A08 cert=2uplIpLQ0q9+0qMFrK5pkaYRDOe460LL9WHBvatgkuRr/SL31wBOEupaMMJ6koRE6Ld0ew iat-mode=0
n Bridge obfs4 185.181.11.86:443 A961609729E7FDF520B4E81F1F1B8FA1045285C3 cert=e5faG9Zk4Ni+e7z2YgGfevyKPQlMvkVGi4ublSsHYjaBovKeNXpOhbeFxzbZZoAzxAoGUQ iat-mode=0
n Bridge obfs4 93.95.226.151:41185 460B0CFFC0CF1D965F3DE064E08BA1915E7C916A cert=inluPzp5Jp5OzZar1eQb4dcQ/YlAj/v0kHAUCoCr3rmLt03+pVuVTjoH4mRy4+acXpn+Gw iat-mode=0
n Bridge obfs4 120.29.217.52:5223 40FE3DB9800272F9CDC76422F8ED7883280EE96D cert=/71PS4l8c/XJ4DIItlH9xMqNvPFg2RUTrHvPlQWh48u5et8h/yyyjCcYphUadDsfBWpaGQ iat-mode=0
n Bridge obfs4 185.177.207.138:8443 53716FE26F23C8C6A71A2BC5D9D8DC64747278C7 cert=6jcYVilMEzxdsWghSrQFpYYJlkkir/GPIXw/EnddUK3S8ToVpMG8u1SwMOEdEs735RrMHw iat-mode=0
n Bridge obfs4 104.168.68.90:443 ED55B3C321E44EA7E50EF568C8A63CF75E89A58C cert=fgonxDvltTp8nmcOE9sUG94eOAALxETVVXAwnTZJLPpf7rjPuTp+abKl4VyFkxfcLRr5KQ iat-mode=0
n Bridge obfs4 45.142.181.131:42069 6EBCF6B02DA2B982F4080A7119D737366AFB74FA cert=9HyWH/BCwWzNirZdTQtluCgJk+gFhpOqydIuyQ1iDvpnqsAynKF+zcPE/INZFefm86UlBg iat-mode=0
n Bridge obfs4 85.214.28.204:47111 78A36E46BB082A471848239D3F4390A8F8C6084D cert=96sr3eaUFBDu4wFVAQIfNFElh0UNuutJ/3/Fh2Vu2PHfacQ8bwfY02bwG351U8BZpLnfUQ iat-mode=0
n Bridge obfs4 152.67.77.101:4096 B82DB9CDDF887AB8A859420E07DF298E30AF8A6E cert=21OWn3yFo+hulmQNAOtF5uwwOqWtdT5PrLhk8BG9DpOd0/k5DEkQEYPyDdXbS9nZ0E5BJA iat-mode=0
n Bridge obfs4 185.103.252.72:443 75F15E9339FF572F88F5588D429FEA379744BC53 cert=nOZ/SaRE3L1dChvjfe0Ks/wM/F8iFhwd3g2G5zgtcLB8x+wiZRWCwjRrbbiQyb3Gh2mxRQ iat-mode=0
n Bridge obfs4 76.255.201.112:8888 96CF36C2ECCFB7376AB6BE905BECD2C2AE8AEFCD cert=+q0pjaiM0JMqHL/BKqCRD+pjflaw/S406eUDF7CnFgamvQW3l2HVLJhQ6uX9P8zff0PLGg iat-mode=0
n Bridge obfs4 94.142.246.132:8088 135C158527AA9FE9A2F26EC515EB6999D813D347 cert=wTUz0/5FhAZRkitil5MprGbSF3JzjxjxI1kAmxAdSeDy98NgcLr11f/qUXWDC76Y97RiSg iat-mode=0
n Bridge obfs4 20.102.79.78:22022 B5705F7E616DAB0F477E3E1ADC23E40413F683FE cert=1Cc/hwPtPjzFKGHVOP0j/qmBgnvquRx8+im35/u5TIYjDQ3FlMfA5VvTrQ/hbX8BZZooLQ iat-mode=0
n Bridge obfs4 152.70.180.20:1993 3327C43587E66AD5F874C4234A1D72C938AD7318 cert=s7xLRUO2psaX7TMUP2YhXdxItR4U6K7D+E3gQaS/+yWUppevtazIibq4dN1g5Reu6dD2QQ iat-mode=0
n Bridge obfs4 144.202.12.254:10002 4E220F45CD404C8A3082A36326A5ED19BB8D4404 cert=iLz5YYWO4pUw7U7MRNOSvE0qO+IVeE4kVfFVWPO3coH3FmZtrkvlaTklfXxHZaCcXWBgaA iat-mode=0
n Bridge obfs4 109.14.168.159:5082 BFE1416DEFFE969581F016A4A319A87FFB26BA91 cert=n3X1CDdKBPXPIzfKh83p3ydfMzb0AD9gKC+/gIpHb7+xjjAnYO9x3LT+T/MvOIfAXxYySg iat-mode=0
n Bridge obfs4 45.150.172.16:80 82849E69CBB25EA7F479155F7DCD89D85717FF47 cert=+Krdu1jmVQOxWkMj0mqJHgwbQV49eyD6mZDS+mRExssWNHosa60g4P5Gp81sBJKzN8NrSw iat-mode=0
n Bridge obfs4 185.177.207.132:8443 4FB781F7A9DD39DA53A7996907817FC479874D19 cert=UL2gCAXWW5kEWY4TQ0lNeu6OAmzh40bXYVhMnTWVG8USnyy/zEKGSIPgmwTDMumWr9c1Pg iat-mode=0
v Bridge 92.243.15.235:9001 477EAD3C04036B48235F1F27FC91420A286A4B7F
v Bridge 213.108.108.145:17674 A39C0FE47963B6E8CFE9815549864DE544935A31
v Bridge 213.196.191.96:9060 05E222E2A8C234234FE0CEB58B08A93B8FC360DB
v Bridge 75.100.92.154:22815 465E990FA8A752DDE861EDF31E42454ACC037AB4
v Bridge 87.100.193.2:9010 13FB63452AADFA082BD2BC3E1E320AD301F07877
v Bridge 65.21.240.163:33245 20BD59649212CFE7412BFC9B94C3CCCFD8F807A8
m Bridge meek_lite 192.0.2.18:80 BE776A53492E1E044A26F17306E1BC46A55A1625 url=https://meek.azureedge.net/ front=ajax.aspnetcdn.com utls=hellochrome_auto
s Bridge snowflake 192.0.2.3:80 2B280B23E1107BB62ABFC40DDCC8824814F80A72

View File

@@ -1,4 +0,0 @@
ZZ 1 url=https://snowflake-broker.torproject.net.global.prod.fastly.net/ front=cdn.sstatic.net ice=stun:stun.l.google.com:19302,stun:stun.voip.blackberry.com:3478,stun:stun.altar.com.pl:3478,stun:stun.antisip.com:3478,stun:stun.bluesip.net:3478,stun:stun.dus.net:3478,stun:stun.epygi.com:3478,stun:stun.sonetel.com:3478,stun:stun.sonetel.net:3478,stun:stun.stunprotocol.org:3478,stun:stun.uls.co.za:3478,stun:stun.voipgate.com:3478,stun:stun.voys.nl:3478 utls-imitate=hellochrome_auto
ZZ 0 url=https://snowflake-broker.azureedge.net/ front=ajax.aspnetcdn.com ice=stun:stun.l.google.com:19302,stun:stun.voip.blackberry.com:3478,stun:stun.altar.com.pl:3478,stun:stun.antisip.com:3478,stun:stun.bluesip.net:3478,stun:stun.dus.net:3478,stun:stun.epygi.com:3478,stun:stun.sonetel.com:3478,stun:stun.sonetel.net:3478,stun:stun.stunprotocol.org:3478,stun:stun.uls.co.za:3478,stun:stun.voipgate.com:3478,stun:stun.voys.nl:3478 utls-imitate=hellochrome_auto
TM 1 url=https://snowflake-broker.azureedge.net/ front=ajax.aspnetcdn.com ice=stun:206.53.159.130:3479,stun:176.119.42.11:3479,stun:94.23.17.185:3479,stun:217.74.179.29:3479,stun:83.125.8.47:3479,stun:23.253.102.137:3479,stun:52.26.251.34:3479,stun:52.26.251.34:3479,stun:18.191.223.12:3479,stun:154.73.34.8:3479,stun:185.125.180.70:3479,stun:195.35.115.37:3479 utls-imitate=hellochrome_auto
TM 0 url=https://snowflake-broker.azureedge.net/ front=ajax.aspnetcdn.com ice=stun:206.53.159.130:3479,stun:176.119.42.11:3479,stun:94.23.17.185:3479,stun:217.74.179.29:3479,stun:83.125.8.47:3479,stun:23.253.102.137:3479,stun:52.26.251.34:3479,stun:52.26.251.34:3479,stun:18.191.223.12:3479,stun:154.73.34.8:3479,stun:185.125.180.70:3479,stun:195.35.115.37:3479 utls-imitate=hellochrome_auto

View File

@@ -1,92 +0,0 @@
package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.test.BrambleTestCase;
import org.junit.Test;
import java.util.HashSet;
import java.util.Set;
import static java.util.Arrays.asList;
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BLOCKED;
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BRIDGES;
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.DEFAULT_OBFS4;
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.MEEK;
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.NON_DEFAULT_OBFS4;
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.SNOWFLAKE;
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.VANILLA;
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.DEFAULT_BRIDGES;
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.DPI_BRIDGES;
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.NON_DEFAULT_BRIDGES;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
public class CircumventionProviderImplTest extends BrambleTestCase {
private final CircumventionProviderImpl provider =
new CircumventionProviderImpl();
@Test
public void testInvariants() {
Set<String> blocked = new HashSet<>(asList(BLOCKED));
Set<String> bridges = new HashSet<>(asList(BRIDGES));
Set<String> defaultBridges = new HashSet<>(asList(DEFAULT_BRIDGES));
Set<String> nonDefaultBridges =
new HashSet<>(asList(NON_DEFAULT_BRIDGES));
Set<String> dpiBridges = new HashSet<>(asList(DPI_BRIDGES));
// BRIDGES should be a subset of BLOCKED
assertTrue(blocked.containsAll(bridges));
// BRIDGES should be the union of the bridge type sets
Set<String> union = new HashSet<>(defaultBridges);
union.addAll(nonDefaultBridges);
union.addAll(dpiBridges);
assertEquals(bridges, union);
// The bridge type sets should not overlap
assertEmptyIntersection(defaultBridges, nonDefaultBridges);
assertEmptyIntersection(defaultBridges, dpiBridges);
assertEmptyIntersection(nonDefaultBridges, dpiBridges);
}
@Test
public void testGetBestBridgeType() {
for (String country : DEFAULT_BRIDGES) {
assertEquals(asList(DEFAULT_OBFS4, VANILLA),
provider.getSuitableBridgeTypes(country));
}
for (String country : NON_DEFAULT_BRIDGES) {
assertEquals(asList(NON_DEFAULT_OBFS4, VANILLA),
provider.getSuitableBridgeTypes(country));
}
for (String country : DPI_BRIDGES) {
assertEquals(asList(NON_DEFAULT_OBFS4, MEEK, SNOWFLAKE),
provider.getSuitableBridgeTypes(country));
}
assertEquals(asList(DEFAULT_OBFS4, VANILLA),
provider.getSuitableBridgeTypes("ZZ"));
}
@Test
public void testHasSnowflakeParamsWithLetsEncrypt() {
testHasSnowflakeParams(true);
}
@Test
public void testHasSnowflakeParamsWithoutLetsEncrypt() {
testHasSnowflakeParams(false);
}
private void testHasSnowflakeParams(boolean letsEncrypt) {
String tmParams = provider.getSnowflakeParams("TM", letsEncrypt);
String defaultParams = provider.getSnowflakeParams("ZZ", letsEncrypt);
assertFalse(tmParams.isEmpty());
assertFalse(defaultParams.isEmpty());
assertNotEquals(defaultParams, tmParams);
}
private <T> void assertEmptyIntersection(Set<T> a, Set<T> b) {
Set<T> intersection = new HashSet<>(a);
intersection.retainAll(b);
assertTrue(intersection.isEmpty());
}
}

View File

@@ -25,11 +25,6 @@ public class TestFeatureFlagModule {
return true;
}
@Override
public boolean shouldEnableMailbox() {
return true;
}
@Override
public boolean shouldEnablePrivateGroupsInCore() {
return true;

View File

@@ -10,6 +10,8 @@ import java.util.List;
import javax.annotation.Nonnull;
import static java.lang.Double.compare;
import static java.lang.Double.parseDouble;
import static org.briarproject.bramble.test.UTest.Result.INCONCLUSIVE;
import static org.briarproject.bramble.test.UTest.Result.LARGER;
import static org.briarproject.bramble.test.UTest.Result.SMALLER;
@@ -134,7 +136,7 @@ public class UTest {
if (nA < 5 || nB < 5) die("Too few values for U test\n");
double zCritical;
if (args.length == 3) zCritical = Double.valueOf(args[2]);
if (args.length == 3) zCritical = parseDouble(args[2]);
else zCritical = Z_CRITICAL_0_01;
switch (test(a, b, zCritical)) {
@@ -161,7 +163,7 @@ public class UTest {
BufferedReader in;
in = new BufferedReader(new FileReader(filename));
String s;
while ((s = in.readLine()) != null) values.add(new Double(s));
while ((s = in.readLine()) != null) values.add(parseDouble(s));
in.close();
} catch (FileNotFoundException fnf) {
die(filename + " not found");
@@ -187,9 +189,7 @@ public class UTest {
@Override
public int compareTo(@Nonnull Value v) {
if (value < v.value) return -1;
if (value > v.value) return 1;
return 0;
return compare(value, v.value);
}
}
}

View File

@@ -37,6 +37,7 @@ dependencyVerification {
'org.bouncycastle:bcprov-jdk15to18:1.71:bcprov-jdk15to18-1.71.jar:143aaa4a40edd5fc2a18db7900059f6c16f4d931b94b94b20f7e2238e6662886',
'org.briarproject:jtorctl:0.5:jtorctl-0.5.jar:43f8c7d390169772b9a2c82ab806c8414c136a2a8636c555e22754bb7260793b',
'org.briarproject:null-safety:0.1:null-safety-0.1.jar:161760de5e838cb982bafa973df820675d4397098e9a91637a36a306d43ba011',
'org.briarproject:onionwrapper-core:0.0.1:onionwrapper-core-0.0.1.jar:a1937506b00ee6620e909a500e5d004be81f94a6f7d7c898e1a9e841a8ae8a2a',
'org.briarproject:socks-socket:0.1:socks-socket-0.1.jar:e5898822d10f5390363c5dddb945891648c92cf93ba50709e07f0d173ec0eb4b',
'org.checkerframework:checker-compat-qual:2.5.5:checker-compat-qual-2.5.5.jar:11d134b245e9cacc474514d2d66b5b8618f8039a1465cdc55bbc0b34e0008b7a',
'org.checkerframework:checker-qual:3.12.0:checker-qual-3.12.0.jar:ff10785ac2a357ec5de9c293cb982a2cbb605c0309ea4cc1cb9b9bc6dbe7f3cb',

View File

@@ -7,10 +7,6 @@ apply plugin: 'witness'
apply from: 'witness.gradle'
apply from: '../dagger.gradle'
configurations {
tor
}
dependencies {
implementation project(':bramble-core')
@@ -18,13 +14,7 @@ dependencies {
def jna_version = '4.5.2'
implementation "net.java.dev.jna:jna:$jna_version"
implementation "net.java.dev.jna:jna-platform:$jna_version"
tor "org.briarproject:tor-linux:$tor_version"
tor "org.briarproject:tor-windows:$tor_version"
tor "org.briarproject:obfs4proxy-linux:$obfs4proxy_version"
tor "org.briarproject:obfs4proxy-windows:$obfs4proxy_version"
tor "org.briarproject:snowflake-linux:$snowflake_version"
tor "org.briarproject:snowflake-windows:$snowflake_version"
implementation "org.briarproject:onionwrapper-java:$onionwrapper_version"
annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"
@@ -34,34 +24,6 @@ dependencies {
testImplementation "junit:junit:$junit_version"
testImplementation "org.jmock:jmock:$jmock_version"
testImplementation "org.jmock:jmock-junit4:$jmock_version"
testImplementation "com.squareup.okhttp3:okhttp:$okhttp_version"
testAnnotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"
}
def torBinariesDir = 'src/main/resources'
task cleanTorBinaries {
doLast {
delete fileTree(torBinariesDir) { include '*.zip' }
}
}
clean.dependsOn cleanTorBinaries
task unpackTorBinaries {
doLast {
copy {
from configurations.tor.collect { zipTree(it) }
into torBinariesDir
}
}
dependsOn cleanTorBinaries
}
processResources {
inputs.dir torBinariesDir
dependsOn unpackTorBinaries
}
tasks.withType(Test) {

View File

@@ -3,9 +3,9 @@ package org.briarproject.bramble;
import org.briarproject.bramble.io.DnsModule;
import org.briarproject.bramble.mailbox.ModularMailboxModule;
import org.briarproject.bramble.network.JavaNetworkModule;
import org.briarproject.bramble.plugin.tor.CircumventionModule;
import org.briarproject.bramble.socks.SocksModule;
import org.briarproject.bramble.system.JavaSystemModule;
import org.briarproject.onionwrapper.CircumventionModule;
import dagger.Module;

View File

@@ -1,62 +0,0 @@
package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.nullsafety.NotNullByDefault;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.CodeSource;
import java.util.concurrent.Executor;
import javax.net.SocketFactory;
@NotNullByDefault
abstract class JavaTorPlugin extends TorPlugin {
JavaTorPlugin(Executor ioExecutor,
Executor wakefulIoExecutor,
NetworkManager networkManager,
LocationUtils locationUtils,
SocketFactory torSocketFactory,
Clock clock,
ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider,
BatteryManager batteryManager,
Backoff backoff,
TorRendezvousCrypto torRendezvousCrypto,
PluginCallback callback,
String architecture,
long maxLatency,
int maxIdleTime,
File torDirectory,
int torSocksPort,
int torControlPort) {
super(ioExecutor, wakefulIoExecutor, networkManager, locationUtils,
torSocketFactory, clock, resourceProvider,
circumventionProvider, batteryManager, backoff,
torRendezvousCrypto, callback, architecture,
maxLatency, maxIdleTime, torDirectory, torSocksPort,
torControlPort);
}
@Override
protected long getLastUpdateTime() {
CodeSource codeSource =
getClass().getProtectionDomain().getCodeSource();
if (codeSource == null) throw new AssertionError("CodeSource null");
try {
URI path = codeSource.getLocation().toURI();
File file = new File(path);
return file.lastModified();
} catch (URISyntaxException e) {
throw new AssertionError(e);
}
}
}

View File

@@ -1,60 +0,0 @@
package org.briarproject.bramble.plugin.tor;
import com.sun.jna.Library;
import com.sun.jna.Native;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.nullsafety.NotNullByDefault;
import java.io.File;
import java.util.concurrent.Executor;
import javax.net.SocketFactory;
@NotNullByDefault
class UnixTorPlugin extends JavaTorPlugin {
UnixTorPlugin(Executor ioExecutor,
Executor wakefulIoExecutor,
NetworkManager networkManager,
LocationUtils locationUtils,
SocketFactory torSocketFactory,
Clock clock,
ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider,
BatteryManager batteryManager,
Backoff backoff,
TorRendezvousCrypto torRendezvousCrypto,
PluginCallback callback,
String architecture,
long maxLatency,
int maxIdleTime,
File torDirectory,
int torSocksPort,
int torControlPort) {
super(ioExecutor, wakefulIoExecutor, networkManager, locationUtils,
torSocketFactory, clock, resourceProvider,
circumventionProvider, batteryManager, backoff,
torRendezvousCrypto, callback, architecture,
maxLatency, maxIdleTime, torDirectory, torSocksPort,
torControlPort);
}
@Override
protected int getProcessId() {
return CLibrary.INSTANCE.getpid();
}
private interface CLibrary extends Library {
CLibrary INSTANCE = Native.loadLibrary("c", CLibrary.class);
int getpid();
}
}

View File

@@ -3,6 +3,7 @@ package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventExecutor;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.plugin.Backoff;
@@ -13,9 +14,11 @@ import org.briarproject.bramble.api.plugin.TorDirectory;
import org.briarproject.bramble.api.plugin.TorSocksPort;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.bramble.api.system.WakefulIoExecutor;
import org.briarproject.nullsafety.NotNullByDefault;
import org.briarproject.onionwrapper.CircumventionProvider;
import org.briarproject.onionwrapper.TorWrapper;
import org.briarproject.onionwrapper.UnixTorWrapper;
import java.io.File;
import java.util.concurrent.Executor;
@@ -34,13 +37,13 @@ public class UnixTorPluginFactory extends TorPluginFactory {
@Inject
UnixTorPluginFactory(@IoExecutor Executor ioExecutor,
@EventExecutor Executor eventExecutor,
@WakefulIoExecutor Executor wakefulIoExecutor,
NetworkManager networkManager,
LocationUtils locationUtils,
EventBus eventBus,
SocketFactory torSocketFactory,
BackoffFactory backoffFactory,
ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider,
BatteryManager batteryManager,
Clock clock,
@@ -48,8 +51,8 @@ public class UnixTorPluginFactory extends TorPluginFactory {
@TorDirectory File torDirectory,
@TorSocksPort int torSocksPort,
@TorControlPort int torControlPort) {
super(ioExecutor, wakefulIoExecutor, networkManager, locationUtils,
eventBus, torSocketFactory, backoffFactory, resourceProvider,
super(ioExecutor, eventExecutor, wakefulIoExecutor, networkManager,
locationUtils, eventBus, torSocketFactory, backoffFactory,
circumventionProvider, batteryManager, clock, crypto,
torDirectory, torSocksPort, torControlPort);
}
@@ -62,9 +65,10 @@ public class UnixTorPluginFactory extends TorPluginFactory {
if (LOG.isLoggable(INFO)) {
LOG.info("System's os.arch is " + arch);
}
if (arch.equals("amd64")) return "linux-x86_64";
else if (arch.equals("aarch64")) return "linux-aarch64";
else if (arch.equals("arm")) return "linux-armhf";
//noinspection IfCanBeSwitch
if (arch.equals("amd64")) return "x86_64";
else if (arch.equals("aarch64")) return "aarch64";
else if (arch.equals("arm")) return "armhf";
return null;
}
@@ -72,11 +76,11 @@ public class UnixTorPluginFactory extends TorPluginFactory {
TorPlugin createPluginInstance(Backoff backoff,
TorRendezvousCrypto torRendezvousCrypto, PluginCallback callback,
String architecture) {
return new UnixTorPlugin(ioExecutor, wakefulIoExecutor,
networkManager, locationUtils, torSocketFactory, clock,
resourceProvider, circumventionProvider, batteryManager,
backoff, torRendezvousCrypto, callback, architecture,
MAX_LATENCY, MAX_IDLE_TIME, torDirectory, torSocksPort,
torControlPort);
TorWrapper tor = new UnixTorWrapper(ioExecutor, eventExecutor,
architecture, torDirectory, torSocksPort, torControlPort);
return new TorPlugin(ioExecutor, wakefulIoExecutor, networkManager,
locationUtils, torSocketFactory, circumventionProvider,
batteryManager, backoff, torRendezvousCrypto, tor, callback,
MAX_LATENCY, MAX_IDLE_TIME, true);
}
}

View File

@@ -1,97 +0,0 @@
package org.briarproject.bramble.plugin.tor;
import com.sun.jna.platform.win32.Kernel32;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.PluginException;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.nullsafety.NotNullByDefault;
import java.io.File;
import java.util.Scanner;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import javax.net.SocketFactory;
import static java.util.logging.Level.INFO;
@NotNullByDefault
class WindowsTorPlugin extends JavaTorPlugin {
WindowsTorPlugin(Executor ioExecutor,
Executor wakefulIoExecutor,
NetworkManager networkManager,
LocationUtils locationUtils,
SocketFactory torSocketFactory,
Clock clock,
ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider,
BatteryManager batteryManager,
Backoff backoff,
TorRendezvousCrypto torRendezvousCrypto,
PluginCallback callback,
String architecture,
long maxLatency,
int maxIdleTime,
File torDirectory,
int torSocksPort,
int torControlPort) {
super(ioExecutor, wakefulIoExecutor, networkManager, locationUtils,
torSocketFactory, clock, resourceProvider,
circumventionProvider, batteryManager, backoff,
torRendezvousCrypto, callback, architecture,
maxLatency, maxIdleTime, torDirectory, torSocksPort,
torControlPort);
}
@Override
protected int getProcessId() {
return Kernel32.INSTANCE.GetCurrentProcessId();
}
@Override
protected void waitForTorToStart(Process torProcess)
throws InterruptedException, PluginException {
// On Windows the RunAsDaemon option has no effect, so Tor won't detach.
// Wait for the control port to be opened, then continue to read its
// stdout and stderr in a background thread until it exits.
BlockingQueue<Boolean> success = new ArrayBlockingQueue<>(1);
ioExecutor.execute(() -> {
boolean started = false;
// Read the process's stdout (and redirected stderr)
Scanner stdout = new Scanner(torProcess.getInputStream());
// Log the first line of stdout (contains Tor and library versions)
if (stdout.hasNextLine()) LOG.info(stdout.nextLine());
// Startup has succeeded when the control port is open
while (stdout.hasNextLine()) {
String line = stdout.nextLine();
if (!started && line.contains("Opened Control listener")) {
success.add(true);
started = true;
}
}
stdout.close();
// If the control port wasn't opened, startup has failed
if (!started) success.add(false);
// Wait for the process to exit
try {
int exit = torProcess.waitFor();
if (LOG.isLoggable(INFO))
LOG.info("Tor exited with value " + exit);
} catch (InterruptedException e1) {
LOG.warning("Interrupted while waiting for Tor to exit");
Thread.currentThread().interrupt();
}
});
// Wait for the startup result
if (!success.take()) throw new PluginException();
}
}

View File

@@ -3,6 +3,7 @@ package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventExecutor;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.plugin.Backoff;
@@ -13,9 +14,11 @@ import org.briarproject.bramble.api.plugin.TorDirectory;
import org.briarproject.bramble.api.plugin.TorSocksPort;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.bramble.api.system.WakefulIoExecutor;
import org.briarproject.nullsafety.NotNullByDefault;
import org.briarproject.onionwrapper.CircumventionProvider;
import org.briarproject.onionwrapper.TorWrapper;
import org.briarproject.onionwrapper.WindowsTorWrapper;
import java.io.File;
import java.util.concurrent.Executor;
@@ -34,13 +37,13 @@ public class WindowsTorPluginFactory extends TorPluginFactory {
@Inject
WindowsTorPluginFactory(@IoExecutor Executor ioExecutor,
@EventExecutor Executor eventExecutor,
@WakefulIoExecutor Executor wakefulIoExecutor,
NetworkManager networkManager,
LocationUtils locationUtils,
EventBus eventBus,
SocketFactory torSocketFactory,
BackoffFactory backoffFactory,
ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider,
BatteryManager batteryManager,
Clock clock,
@@ -48,8 +51,8 @@ public class WindowsTorPluginFactory extends TorPluginFactory {
@TorDirectory File torDirectory,
@TorSocksPort int torSocksPort,
@TorControlPort int torControlPort) {
super(ioExecutor, wakefulIoExecutor, networkManager, locationUtils,
eventBus, torSocketFactory, backoffFactory, resourceProvider,
super(ioExecutor, eventExecutor, wakefulIoExecutor, networkManager,
locationUtils, eventBus, torSocketFactory, backoffFactory,
circumventionProvider, batteryManager, clock, crypto,
torDirectory, torSocksPort, torControlPort);
}
@@ -62,7 +65,7 @@ public class WindowsTorPluginFactory extends TorPluginFactory {
if (LOG.isLoggable(INFO)) {
LOG.info("System's os.arch is " + arch);
}
if (arch.equals("amd64")) return "windows-x86_64";
if (arch.equals("amd64")) return "x86_64";
return null;
}
@@ -70,11 +73,11 @@ public class WindowsTorPluginFactory extends TorPluginFactory {
TorPlugin createPluginInstance(Backoff backoff,
TorRendezvousCrypto torRendezvousCrypto, PluginCallback callback,
String architecture) {
return new WindowsTorPlugin(ioExecutor, wakefulIoExecutor,
networkManager, locationUtils, torSocketFactory, clock,
resourceProvider, circumventionProvider, batteryManager,
backoff, torRendezvousCrypto, callback, architecture,
MAX_LATENCY, MAX_IDLE_TIME, torDirectory, torSocksPort,
torControlPort);
TorWrapper tor = new WindowsTorWrapper(ioExecutor, eventExecutor,
architecture, torDirectory, torSocksPort, torControlPort);
return new TorPlugin(ioExecutor, wakefulIoExecutor, networkManager,
locationUtils, torSocketFactory, circumventionProvider,
batteryManager, backoff, torRendezvousCrypto, tor, callback,
MAX_LATENCY, MAX_IDLE_TIME, true);
}
}

View File

@@ -1,283 +0,0 @@
package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.BrambleCoreIntegrationTestEagerSingletons;
import org.briarproject.bramble.api.Multiset;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.bramble.api.plugin.TorControlPort;
import org.briarproject.bramble.api.plugin.TorSocksPort;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.bramble.api.system.WakefulIoExecutor;
import org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType;
import org.briarproject.bramble.test.BrambleJavaIntegrationTestComponent;
import org.briarproject.bramble.test.BrambleTestCase;
import org.briarproject.bramble.test.DaggerBrambleJavaIntegrationTestComponent;
import org.briarproject.bramble.util.OsUtils;
import org.briarproject.nullsafety.NotNullByDefault;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
import javax.annotation.concurrent.GuardedBy;
import javax.inject.Inject;
import javax.net.SocketFactory;
import static java.util.Collections.singletonList;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE;
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.DEFAULT_OBFS4;
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.MEEK;
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.NON_DEFAULT_OBFS4;
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.SNOWFLAKE;
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.VANILLA;
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
import static org.briarproject.bramble.test.TestUtils.isOptionalTestEnabled;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
@RunWith(Parameterized.class)
public class BridgeTest extends BrambleTestCase {
private static final String[] SNOWFLAKE_COUNTRY_CODES = {"TM", "ZZ"};
@Parameters
public static Iterable<Params> data() {
BrambleJavaIntegrationTestComponent component =
DaggerBrambleJavaIntegrationTestComponent.builder().build();
BrambleCoreIntegrationTestEagerSingletons.Helper
.injectEagerSingletons(component);
// Share stats among all the test instances
Stats stats = new Stats();
CircumventionProvider provider = component.getCircumventionProvider();
List<Params> states = new ArrayList<>();
for (int i = 0; i < ATTEMPTS_PER_BRIDGE; i++) {
for (String bridge :
provider.getBridges(DEFAULT_OBFS4, "", true)) {
states.add(new Params(bridge, DEFAULT_OBFS4, stats, false));
}
for (String bridge :
provider.getBridges(NON_DEFAULT_OBFS4, "", true)) {
states.add(new Params(bridge, NON_DEFAULT_OBFS4, stats,
false));
}
for (String bridge : provider.getBridges(VANILLA, "", true)) {
states.add(new Params(bridge, VANILLA, stats, false));
}
for (String bridge : provider.getBridges(MEEK, "", true)) {
states.add(new Params(bridge, MEEK, stats, true));
}
for (String countryCode : SNOWFLAKE_COUNTRY_CODES) {
for (String bridge :
provider.getBridges(SNOWFLAKE, countryCode, true)) {
states.add(new Params(bridge, SNOWFLAKE, stats, true));
}
for (String bridge :
provider.getBridges(SNOWFLAKE, countryCode, false)) {
states.add(new Params(bridge, SNOWFLAKE, stats, true));
}
}
}
return states;
}
private final static long TIMEOUT = MINUTES.toMillis(2);
private final static long MEEK_TIMEOUT = MINUTES.toMillis(6);
private final static int UNREACHABLE_BRIDGES_ALLOWED = 6;
private final static int ATTEMPTS_PER_BRIDGE = 5;
private final static Logger LOG = getLogger(BridgeTest.class.getName());
@Inject
@IoExecutor
Executor ioExecutor;
@Inject
@WakefulIoExecutor
Executor wakefulIoExecutor;
@Inject
NetworkManager networkManager;
@Inject
ResourceProvider resourceProvider;
@Inject
BatteryManager batteryManager;
@Inject
EventBus eventBus;
@Inject
BackoffFactory backoffFactory;
@Inject
Clock clock;
@Inject
CryptoComponent crypto;
@Inject
@TorSocksPort
int torSocksPort;
@Inject
@TorControlPort
int torControlPort;
private final File torDir = getTestDirectory();
private final Params params;
private UnixTorPluginFactory factory;
public BridgeTest(Params params) {
this.params = params;
}
@Before
public void setUp() {
// Skip this test unless it's explicitly enabled in the environment
assumeTrue(isOptionalTestEnabled(BridgeTest.class));
// TODO: Remove this assumption when the plugin supports other platforms
assumeTrue(OsUtils.isLinux());
BrambleJavaIntegrationTestComponent component =
DaggerBrambleJavaIntegrationTestComponent.builder().build();
BrambleCoreIntegrationTestEagerSingletons.Helper
.injectEagerSingletons(component);
component.inject(this);
LocationUtils locationUtils = () -> "US";
SocketFactory torSocketFactory = SocketFactory.getDefault();
@NotNullByDefault
CircumventionProvider bridgeProvider = new CircumventionProvider() {
@Override
public boolean isTorProbablyBlocked(String countryCode) {
return true;
}
@Override
public boolean doBridgesWork(String countryCode) {
return true;
}
@Override
public List<BridgeType> getSuitableBridgeTypes(String countryCode) {
return singletonList(params.bridgeType);
}
@Override
public List<String> getBridges(BridgeType bridgeType,
String countryCode, boolean letsEncrypt) {
return singletonList(params.bridge);
}
};
factory = new UnixTorPluginFactory(ioExecutor, wakefulIoExecutor,
networkManager, locationUtils, eventBus, torSocketFactory,
backoffFactory, resourceProvider, bridgeProvider,
batteryManager, clock, crypto, torDir, torSocksPort,
torControlPort);
}
@After
public void tearDown() {
deleteTestDirectory(torDir);
}
@Test
public void testBridges() throws Exception {
if (params.stats.hasSucceeded(params.bridge)) {
LOG.info("Skipping previously successful bridge: " + params.bridge);
return;
}
DuplexPlugin duplexPlugin =
factory.createPlugin(new TestPluginCallback());
assertNotNull(duplexPlugin);
UnixTorPlugin plugin = (UnixTorPlugin) duplexPlugin;
LOG.warning("Testing " + params.bridge);
try {
plugin.start();
long start = clock.currentTimeMillis();
long timeout = params.bridgeType == MEEK ? MEEK_TIMEOUT : TIMEOUT;
while (clock.currentTimeMillis() - start < timeout) {
if (plugin.getState() == ACTIVE) break;
clock.sleep(500);
}
if (plugin.getState() == ACTIVE) {
LOG.info("Connected to Tor: " + params.bridge);
params.stats.countSuccess(params.bridge);
} else {
LOG.warning("Could not connect to Tor within timeout: "
+ params.bridge);
params.stats.countFailure(params.bridge, params.essential);
}
} finally {
plugin.stop();
}
}
private static class Params {
private final String bridge;
private final BridgeType bridgeType;
private final Stats stats;
private final boolean essential;
private Params(String bridge, BridgeType bridgeType,
Stats stats, boolean essential) {
this.bridge = bridge;
this.bridgeType = bridgeType;
this.stats = stats;
this.essential = essential;
}
}
private static class Stats {
@GuardedBy("this")
private final Set<String> successes = new HashSet<>();
@GuardedBy("this")
private final Multiset<String> failures = new Multiset<>();
@GuardedBy("this")
private final Set<String> unreachable = new TreeSet<>();
private synchronized boolean hasSucceeded(String bridge) {
return successes.contains(bridge);
}
private synchronized void countSuccess(String bridge) {
successes.add(bridge);
}
private synchronized void countFailure(String bridge,
boolean essential) {
if (failures.add(bridge) == ATTEMPTS_PER_BRIDGE) {
LOG.warning("Bridge is unreachable after "
+ ATTEMPTS_PER_BRIDGE + " attempts: " + bridge);
unreachable.add(bridge);
if (unreachable.size() > UNREACHABLE_BRIDGES_ALLOWED) {
fail(unreachable.size() + " bridges are unreachable: "
+ unreachable);
}
if (essential) {
fail("essential bridge is unreachable");
}
}
}
}
}

View File

@@ -1,57 +0,0 @@
package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.api.plugin.Plugin.State;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TransportConnectionReader;
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.settings.Settings;
import org.briarproject.nullsafety.NotNullByDefault;
import java.util.Collection;
import static java.util.Collections.emptyList;
@NotNullByDefault
public class TestPluginCallback implements PluginCallback {
@Override
public Settings getSettings() {
return new Settings();
}
@Override
public TransportProperties getLocalProperties() {
return new TransportProperties();
}
@Override
public Collection<TransportProperties> getRemoteProperties() {
return emptyList();
}
@Override
public void mergeSettings(Settings s) {
}
@Override
public void mergeLocalProperties(TransportProperties p) {
}
@Override
public void pluginStateChanged(State state) {
}
@Override
public void handleConnection(DuplexTransportConnection c) {
}
@Override
public void handleReader(TransportConnectionReader r) {
}
@Override
public void handleWriter(TransportConnectionWriter w) {
}
}

View File

@@ -1,29 +0,0 @@
package org.briarproject.bramble.test;
import org.briarproject.bramble.BrambleCoreIntegrationTestEagerSingletons;
import org.briarproject.bramble.BrambleCoreModule;
import org.briarproject.bramble.BrambleJavaModule;
import org.briarproject.bramble.mailbox.ModularMailboxModule;
import org.briarproject.bramble.plugin.tor.BridgeTest;
import org.briarproject.bramble.plugin.tor.CircumventionProvider;
import javax.inject.Singleton;
import dagger.Component;
@Singleton
@Component(modules = {
BrambleCoreIntegrationTestModule.class,
BrambleCoreModule.class,
BrambleJavaModule.class,
ModularMailboxModule.class,
TestTorPortsModule.class,
TestPluginConfigModule.class,
})
public interface BrambleJavaIntegrationTestComponent
extends BrambleCoreIntegrationTestEagerSingletons {
void inject(BridgeTest init);
CircumventionProvider getCircumventionProvider();
}

View File

@@ -1,26 +0,0 @@
package org.briarproject.bramble.test;
import org.briarproject.bramble.api.plugin.TorControlPort;
import org.briarproject.bramble.api.plugin.TorSocksPort;
import dagger.Module;
import dagger.Provides;
import static org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_CONTROL_PORT;
import static org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_SOCKS_PORT;
@Module
class TestTorPortsModule {
@Provides
@TorSocksPort
int provideTorSocksPort() {
return DEFAULT_SOCKS_PORT + 10;
}
@Provides
@TorControlPort
int provideTorControlPort() {
return DEFAULT_CONTROL_PORT + 10;
}
}

View File

@@ -15,8 +15,6 @@ dependencyVerification {
'com.google.guava:guava:31.0.1-jre:guava-31.0.1-jre.jar:d5be94d65e87bd219fb3193ad1517baa55a3b88fc91d21cf735826ab5af087b9',
'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava:listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar:b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99',
'com.google.j2objc:j2objc-annotations:1.3:j2objc-annotations-1.3.jar:21af30c92267bd6122c0e0b4d20cccb6641a37eaf956c6540ec471d584e64a7b',
'com.squareup.okhttp3:okhttp:3.12.13:okhttp-3.12.13.jar:508234e024ef7e270ab1a6d5b356f5b98e786511239ca986d684fd1e2cf7bc82',
'com.squareup.okio:okio:1.15.0:okio-1.15.0.jar:693fa319a7e8843300602b204023b7674f106ebcb577f2dd5807212b66118bd2',
'com.squareup:javapoet:1.13.0:javapoet-1.13.0.jar:4c7517e848a71b36d069d12bb3bf46a70fd4cda3105d822b0ed2e19c00b69291',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'junit:junit:4.13.2:junit-4.13.2.jar:8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3',
@@ -26,12 +24,10 @@ dependencyVerification {
'net.jcip:jcip-annotations:1.0:jcip-annotations-1.0.jar:be5805392060c71474bf6c9a67a099471274d30b83eef84bfc4e0889a4f1dcc0',
'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd',
'org.apache-extras.beanshell:bsh:2.0b6:bsh-2.0b6.jar:a17955976070c0573235ee662f2794a78082758b61accffce8d3f8aedcd91047',
'org.briarproject:obfs4proxy-linux:0.0.14-tor1:obfs4proxy-linux-0.0.14-tor1.jar:9783b9c7ec588a5246f534a9c5782783c8c9821825f81c3e0c6f1ecee61cfcbb',
'org.briarproject:obfs4proxy-windows:0.0.14-tor1:obfs4proxy-windows-0.0.14-tor1.jar:9dd122b31b3cd1616f168091dcdb01de049d1e052fe5c089b7627618a8a2694b',
'org.briarproject:snowflake-linux:2.3.1:snowflake-linux-2.3.1.jar:99ecf4546d8f79eb8408168c09380fec596558ac934554bf7d4247ea7ef2c9f3',
'org.briarproject:snowflake-windows:2.3.1:snowflake-windows-2.3.1.jar:d011f1a72c00a221f56380c19aad8ff11db8c2bb1adb0784125572d80b4d275a',
'org.briarproject:tor-linux:0.4.7.13:tor-linux-0.4.7.13.jar:9819ee973cbcdc133f7d04aef9d4b957a35087627a790e532142d15412a9636f',
'org.briarproject:tor-windows:0.4.7.13:tor-windows-0.4.7.13.jar:853d2769665614e26703cbe02e43b218b064c04a0bcd120fdc459cda45bd2606',
'org.briarproject:jtorctl:0.5:jtorctl-0.5.jar:43f8c7d390169772b9a2c82ab806c8414c136a2a8636c555e22754bb7260793b',
'org.briarproject:null-safety:0.1:null-safety-0.1.jar:161760de5e838cb982bafa973df820675d4397098e9a91637a36a306d43ba011',
'org.briarproject:onionwrapper-core:0.0.1:onionwrapper-core-0.0.1.jar:a1937506b00ee6620e909a500e5d004be81f94a6f7d7c898e1a9e841a8ae8a2a',
'org.briarproject:onionwrapper-java:0.0.1:onionwrapper-java-0.0.1.jar:102ccea934d02b13702fd28e890e27e342db8b669a4c84bb54a3783cb8926552',
'org.checkerframework:checker-compat-qual:2.5.5:checker-compat-qual-2.5.5.jar:11d134b245e9cacc474514d2d66b5b8618f8039a1465cdc55bbc0b34e0008b7a',
'org.checkerframework:checker-qual:3.12.0:checker-qual-3.12.0.jar:ff10785ac2a357ec5de9c293cb982a2cbb605c0309ea4cc1cb9b9bc6dbe7f3cb',
'org.hamcrest:hamcrest-core:2.1:hamcrest-core-2.1.jar:e09109e54a289d88506b9bfec987ddd199f4217c9464132668351b9a4f00bee9',

View File

@@ -26,8 +26,8 @@ android {
defaultConfig {
minSdkVersion 16
targetSdkVersion 31
versionCode 10421
versionName "1.4.21"
versionCode 10500
versionName "1.5.0"
applicationId "org.briarproject.briar.android"
buildConfigField "String", "TorVersion", "\"$tor_version\""
@@ -116,7 +116,6 @@ dependencies {
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.recyclerview:recyclerview-selection:1.1.0'
implementation 'org.briarproject:dont-kill-me-lib:0.2.5'
implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
implementation "org.jsoup:jsoup:$jsoup_version"
implementation 'info.guardianproject.panic:panic:1.0'

View File

@@ -1,5 +1,6 @@
package org.briarproject.briar.android;
import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager;
import org.briarproject.bramble.BrambleAndroidEagerSingletons;
import org.briarproject.bramble.BrambleAndroidModule;
import org.briarproject.bramble.BrambleAppComponent;
@@ -25,12 +26,10 @@ import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.plugin.PluginManager;
import org.briarproject.bramble.api.settings.SettingsManager;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.mailbox.ModularMailboxModule;
import org.briarproject.bramble.plugin.file.RemovableDriveModule;
import org.briarproject.bramble.plugin.tor.CircumventionProvider;
import org.briarproject.bramble.system.ClockModule;
import org.briarproject.briar.BriarCoreEagerSingletons;
import org.briarproject.briar.BriarCoreModule;
@@ -84,6 +83,7 @@ import org.briarproject.briar.api.privategroup.PrivateGroupManager;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationFactory;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager;
import org.briarproject.briar.api.test.TestDataCreator;
import org.briarproject.onionwrapper.CircumventionProvider;
import java.util.concurrent.Executor;

View File

@@ -33,7 +33,6 @@ import org.briarproject.bramble.plugin.tcp.AndroidLanTcpPluginFactory;
import org.briarproject.bramble.plugin.tor.AndroidTorPluginFactory;
import org.briarproject.bramble.util.AndroidUtils;
import org.briarproject.bramble.util.StringUtils;
import org.briarproject.briar.BuildConfig;
import org.briarproject.briar.android.account.DozeHelperModule;
import org.briarproject.briar.android.account.LockManagerImpl;
import org.briarproject.briar.android.account.SetupModule;
@@ -212,7 +211,7 @@ public class AppModule {
@Override
public Collection<SimplexPluginFactory> getSimplexFactories() {
List<SimplexPluginFactory> simplex = new ArrayList<>();
if (featureFlags.shouldEnableMailbox()) simplex.add(mailbox);
simplex.add(mailbox);
if (SDK_INT >= 19) simplex.add(drive);
return simplex;
}
@@ -353,11 +352,6 @@ public class AppModule {
return true;
}
@Override
public boolean shouldEnableMailbox() {
return BuildConfig.DEBUG;
}
@Override
public boolean shouldEnablePrivateGroupsInCore() {
return true;

View File

@@ -15,12 +15,12 @@ import android.os.IBinder;
import com.bumptech.glide.Glide;
import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager;
import org.briarproject.bramble.api.account.AccountManager;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.briar.R;
import org.briarproject.briar.android.logout.HideUiActivity;

View File

@@ -65,7 +65,8 @@ public class SetPasswordFragment extends SetupFragment {
if (!viewModel.needToShowDozeFragment()) {
nextButton.setText(R.string.create_account_button);
passwordConfirmation.setImeOptions(IME_ACTION_DONE);
int options = passwordConfirmation.getImeOptions();
passwordConfirmation.setImeOptions(options | IME_ACTION_DONE);
}
viewModel.getIsCreatingAccount()

View File

@@ -5,7 +5,7 @@ import android.transition.Transition;
import android.view.Window;
import android.widget.CheckBox;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.Wakeful;
import org.briarproject.briar.R;
import org.briarproject.briar.android.BriarApplication;

View File

@@ -171,7 +171,7 @@ public class NicknameFragment extends BaseFragment {
private void handleExistingContact(String name, Author existing) {
OnClickListener listener = (d, w) -> {
d.dismiss();
String str = getString(R.string.contact_already_exists, name);
String str = getString(R.string.contact_already_exists_general);
Toast.makeText(getContext(), str, LENGTH_LONG).show();
finish();
};

View File

@@ -4,13 +4,13 @@ import android.app.Activity;
import android.content.Intent;
import android.os.IBinder;
import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager;
import org.briarproject.bramble.api.account.AccountManager;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.settings.Settings;
import org.briarproject.bramble.api.settings.SettingsManager;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.briar.android.BriarApplication;
import org.briarproject.briar.android.BriarService;
import org.briarproject.briar.android.BriarService.BriarServiceConnection;

View File

@@ -83,15 +83,11 @@ public class SettingsFragment extends PreferenceFragmentCompat {
Preference prefMailbox =
requireNonNull(findPreference(PREF_KEY_MAILBOX));
if (viewModel.shouldEnableMailbox()) {
prefMailbox.setOnPreferenceClickListener(preference -> {
Intent i = new Intent(requireContext(), MailboxActivity.class);
startActivity(i);
return true;
});
} else {
prefMailbox.setVisible(false);
}
prefMailbox.setOnPreferenceClickListener(preference -> {
Intent i = new Intent(requireContext(), MailboxActivity.class);
startActivity(i);
return true;
});
Preference prefFeedback =
requireNonNull(findPreference(PREF_KEY_FEEDBACK));

View File

@@ -24,7 +24,6 @@ import org.briarproject.bramble.api.settings.SettingsManager;
import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.plugin.tor.CircumventionProvider;
import org.briarproject.briar.R;
import org.briarproject.briar.android.attachment.UnsupportedMimeTypeException;
import org.briarproject.briar.android.attachment.media.ImageCompressor;
@@ -34,6 +33,7 @@ import org.briarproject.briar.api.identity.AuthorInfo;
import org.briarproject.briar.api.identity.AuthorManager;
import org.briarproject.nullsafety.MethodsNotNullByDefault;
import org.briarproject.nullsafety.ParametersNotNullByDefault;
import org.briarproject.onionwrapper.CircumventionProvider;
import java.io.IOException;
import java.io.InputStream;
@@ -161,10 +161,6 @@ class SettingsViewModel extends DbViewModel implements EventListener {
return featureFlags.shouldEnableProfilePictures();
}
boolean shouldEnableMailbox() {
return featureFlags.shouldEnableMailbox();
}
private void loadOwnIdentityInfo() {
runOnDbThread(() -> {
try {

View File

@@ -3,9 +3,9 @@ package org.briarproject.briar.android.settings;
import android.content.Context;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.plugin.tor.CircumventionProvider;
import org.briarproject.briar.R;
import org.briarproject.nullsafety.NotNullByDefault;
import org.briarproject.onionwrapper.CircumventionProvider;
import androidx.preference.ListPreference;
import androidx.preference.Preference.SummaryProvider;

View File

@@ -3,7 +3,7 @@ package org.briarproject.briar.android.splash;
import android.content.Intent;
import android.os.Bundle;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BaseActivity;

View File

@@ -33,6 +33,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/current_password"
android:imeOptions="flagNoPersonalizedLearning"
android:importantForAutofill="no"
android:inputType="textPassword"
android:maxLines="1" />
@@ -57,6 +58,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/choose_new_password"
android:imeOptions="flagNoPersonalizedLearning"
android:importantForAutofill="no"
android:inputType="textPassword"
android:maxLines="1" />
@@ -78,7 +80,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/confirm_new_password"
android:imeOptions="actionDone"
android:imeOptions="flagNoPersonalizedLearning|actionDone"
android:importantForAutofill="no"
android:inputType="textPassword"
android:maxLines="1" />

View File

@@ -19,6 +19,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/choose_forum_hint"
android:imeOptions="flagNoPersonalizedLearning"
android:importantForAutofill="no"
android:inputType="text|textCapSentences"
android:maxLines="1" />

View File

@@ -25,7 +25,7 @@
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="@android:color/transparent"
android:imeOptions="actionSend"
android:imeOptions="flagNoPersonalizedLearning|actionSend"
android:inputType="textMultiLine|textCapSentences|textAutoCorrect"
android:minHeight="@dimen/text_input_height"
android:textColor="?android:attr/textColorPrimary"

View File

@@ -30,6 +30,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:hint="@string/set_contact_alias_hint"
android:imeOptions="flagNoPersonalizedLearning"
android:inputType="text|textCapWords"
android:textColor="?android:attr/textColorPrimary"
android:textSize="@dimen/text_size_medium" />

View File

@@ -19,6 +19,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/groups_create_group_hint"
android:imeOptions="flagNoPersonalizedLearning"
android:importantForAutofill="no"
android:inputType="text|textCapSentences"
android:maxLines="1" />

View File

@@ -205,6 +205,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hint="@string/contact_link_hint"
android:imeOptions="flagNoPersonalizedLearning"
android:importantForAutofill="no"
android:inputType="textUri" />

View File

@@ -136,6 +136,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hint="@string/add_contact_choose_a_nickname"
android:imeOptions="flagNoPersonalizedLearning"
android:importantForAutofill="no"
android:inputType="text|textCapWords" />

View File

@@ -27,7 +27,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/enter_password"
android:imeOptions="actionDone"
android:imeOptions="flagNoPersonalizedLearning|actionDone"
android:inputType="textPassword"
android:maxLines="1" />

View File

@@ -28,6 +28,7 @@
android:id="@+id/user_comment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="flagNoPersonalizedLearning"
android:inputType="textMultiLine|textCapSentences"
tools:hint="@string/describe_crash" />
@@ -51,6 +52,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/optional_contact_email"
android:imeOptions="flagNoPersonalizedLearning"
android:inputType="textEmailAddress"
android:maxLines="1" />
@@ -61,8 +63,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_large"
android:layout_marginRight="@dimen/margin_large"
android:layout_marginTop="@dimen/margin_large"
android:layout_marginRight="@dimen/margin_large"
android:text="@string/privacy_policy"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
app:layout_constraintStart_toStartOf="parent"

View File

@@ -23,7 +23,7 @@
android:background="@android:color/transparent"
android:gravity="top"
android:hint="@string/blogs_rss_feeds_import_hint"
android:imeOptions="actionDone"
android:imeOptions="flagNoPersonalizedLearning|actionDone"
android:importantForAutofill="no"
android:inputType="textUri"
android:padding="@dimen/margin_medium"

View File

@@ -32,7 +32,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/choose_nickname"
android:imeOptions="actionNext"
android:imeOptions="flagNoPersonalizedLearning|actionNext"
android:inputType="text|textCapWords"
android:maxLines="1" />

View File

@@ -33,7 +33,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/choose_password"
android:imeOptions="actionNext"
android:imeOptions="flagNoPersonalizedLearning|actionNext"
android:inputType="textPassword"
android:maxLines="1">
@@ -71,7 +71,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/confirm_password"
android:imeOptions="actionNext"
android:imeOptions="flagNoPersonalizedLearning|actionNext"
android:inputType="textPassword"
android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout>

View File

@@ -232,11 +232,12 @@
<string name="exchanging_contact_details">Обмяна на данни за контакт\u2026</string>
<string name="contact_added_toast">Добавен контакт: %s</string>
<string name="contact_already_exists">Контактът %s вече съществува</string>
<string name="contact_already_exists_general">Контактът вече съществува</string>
<string name="qr_code_invalid">Кодът за QR е недействителен</string>
<string name="qr_code_too_old_1">Сканираният код за QR е от по-ранно издание на Briar.\n\nНека вашия контакт инсталира последното издание и да пробва отново.</string>
<string name="qr_code_too_new_1">Сканираният код за QR е от по-ново издание на Briar.\n\nИнсталирайте последното издание и пробвайте отново.</string>
<string name="mailbox_qr_code_for_contact">Сканираният код за QR е от Briar Пощенска кутия.\n\nАко искате да свържете Пощенска кутия използвайте Настройки &gt; Пощенска кутия от менюто.</string>
<string name="qr_code_format_unknown">Сканираният код за QR не предназначен за добавяне на контакт в Briar.\n\nЗа тази цел използвайте кода, на екрана на контакта ви.</string>
<string name="qr_code_format_unknown">Сканираният код за QR не е предназначен за добавяне на контакт в Briar.\n\nЗа тази цел използвайте кода, на екрана на контакта ви.</string>
<string name="camera_error">Грешка в камерата</string>
<string name="connecting_to_device">Свързване с устройство\u2026</string>
<string name="authenticating_with_device">Удостоверяване с устройство\u2026</string>
@@ -431,6 +432,10 @@
<string name="forum_declined_toast">Поканата е отказана</string>
<string name="shared_by_format">Споделен от %s</string>
<string name="forum_invitation_already_sharing">Вече е споделен</string>
<string name="forum_invitation_already_invited">Поканата вече е изпратена</string>
<string name="forum_invitation_invite_received">Поканата вече е получена</string>
<string name="forum_invitation_not_supported">Не се поддържа от този контакт</string>
<string name="forum_invitation_error">Грешка. Това е дефект и не е причинено от вас</string>
<string name="forum_invitation_response_accepted_sent">Приехте поканата от %s за членство във форум.</string>
<string name="forum_invitation_response_declined_sent">Отказахте поканата на %s за членство във форум.</string>
<string name="forum_invitation_response_declined_auto">Поканата от %s за членство във форум е отказана автоматично.</string>
@@ -481,7 +486,9 @@
<string name="blogs_rss_feeds_import">Внасяне на емисия на RSS</string>
<string name="blogs_rss_feeds_import_button">Внасяне</string>
<string name="blogs_rss_feeds_import_hint">рес на емисия</string>
<string name="blogs_rss_feeds_import_progress">Внасяне на емисия на RSS</string>
<string name="blogs_rss_feeds_import_error">Грешка при внасяне на емисията.</string>
<string name="blogs_rss_feeds_import_title">Внасяне на емисия от файл</string>
<string name="blogs_rss_feeds">Емисии на RSS</string>
<string name="blogs_rss_feeds_manage_imported">Внесена:</string>
<string name="blogs_rss_feeds_manage_author">Автор:</string>
@@ -595,6 +602,10 @@
<string name="mailbox_setup_connecting">Свързване с Пощенска кутия…</string>
<!--This string is shown when connecting to a Mailbox for the first time. The placeholder will be replaced with a duration, e.g. "2 minutes".-->
<string name="mailbox_setup_connecting_info">Може да отнеме %1s</string>
<string name="mailbox_qr_code_too_old">Сканираният код за QR е от по-ранно издание на Briar Пощенска кутия.\n\nИнсталирайте последното издание и пробвайте отново.</string>
<string name="mailbox_qr_code_too_new">Сканираният код за QR е от по-ново издание на Briar Пощенска кутия.\n\nИнсталирайте последното издание на Briar и пробвайте отново.</string>
<string name="contact_qr_code_for_mailbox">Сканираният код за QR е предназначен за добавяне на контакт в Briar.\n\nАко желаете да добавите контакт отворете списъка с контакти и дикоснете иконата с +.</string>
<string name="mailbox_setup_qr_code_wrong_description">Сканираният код за QR не е от Briar Пощенска кутия.\n\n Отворете приложението Briar Пощенска кутия на устройството, на което е инсталирано и сканирайте кода зя QR, който то предостави.</string>
<string name="mailbox_setup_already_paired_title">Пощенската кутия е вече свързана</string>
<string name="mailbox_setup_already_paired_description">Прекъснете връзката с пощенската кутия от другото устройство и опитайте отново.</string>
<string name="mailbox_setup_io_error_title">Грешка при свързване</string>

View File

@@ -6,7 +6,7 @@
<string name="setup_next">Següent</string>
<string name="setup_password_intro">Establiu una contrasenya</string>
<string name="setup_password_explanation">El compte de Briar s\'emmagatzema xifrat en el vostre dispositiu, no en el núvol. Si oblideu la contrasenya o desinstal·leu Briar no podreu recuperar el vostre compte ni les dades associades.\n\nTrieu una contrasenya llarga que sigui difícil d\'endevinar, com ara quatre paraules aleatòries o deu lletres, números i símbols aleatoris.</string>
<string name="dnkm_doze_intro">Per rebre missatges Briar necessita estar connectat en segon pla.</string>
<string name="dnkm_doze_intro">Per rebre missatges, Briar necessita estar connectat en segon pla.</string>
<string name="dnkm_doze_explanation">Per rebre missatges Briar necessita estar connectat en segon pla. Desactiveu les optimitzacions de la bateria per permetre que Briar resti sempre connectat.</string>
<string name="choose_nickname">Trieu el sobrenom</string>
<string name="choose_password">Trieu la contrasenya</string>
@@ -19,10 +19,10 @@
<string name="don_t_ask_again">No tornis a preguntar-ho</string>
<string name="dnkm_huawei_protected_text">Feu un toc sobre el botó següent i assegureu-vos de que Briar consta com a protegit a la pantalla «Aplicacions protegides».</string>
<string name="dnkm_huawei_protected_button">Protegeix Briar</string>
<string name="dnkm_huawei_protected_help">Si no afegiu Briar a la llista d\'aplicacions protegides, s\'evitarà que Briar s\'executi en segon pla.</string>
<string name="dnkm_huawei_protected_help">Si no afegeixes Briar a la llista d\'aplicacions protegides, no podrà executar-se en segon pla.</string>
<string name="dnkm_huawei_app_launch_text">Premeu el botó, obriu la pantalla «Llença app» i assegureu-vos que Briar està configurat com «Gestiona a ma».</string>
<string name="dnkm_huawei_app_launch_help">Si Briar no està configurat com a «Gestiona manualment» a la pantalla «Llença app», no podrà executar-se en segon pla.</string>
<string name="dnkm_xiaomi_text">Per executar-se en segon pla, Briar necessita ser blocat en la llista d\'aplicacions recents.</string>
<string name="dnkm_xiaomi_text">Per executar-se en segon pla, Briar necessita ser fixat en la llista d\'aplicacions recents.</string>
<string name="dnkm_xiaomi_button">Protegeix Briar</string>
<string name="dnkm_xiaomi_help">Si Briar no està blocat a la llista d\'aplicacions recents, no podrà executar-se en segon pla.</string>
<string name="dnkm_xiaomi_dialog_body_old">1. Obriu la llista d\'aplicacions recents (de canvi d\'aplicació)\n\n2. Desplaceu avall la icona de Briar per mostrar la icona del cadenat\n\n3. Si el cadenat és obert, premeu per tancar-lo.</string>
@@ -235,6 +235,7 @@ Així que l\'actualitzi li veureu una icona diferent .</string>
<string name="exchanging_contact_details">Intercanviant els detalls del contacte\u2026</string>
<string name="contact_added_toast">S\'ha afegit el contacte %s</string>
<string name="contact_already_exists">El contacte %s ja existia</string>
<string name="contact_already_exists_general">El contacte ja existeix</string>
<string name="qr_code_invalid">El codi QR és invàlid</string>
<string name="qr_code_too_old_1">El codi QR que heu escanejat prové d\'una versió anterior del Briar.\n\nDemaneu al vostre contacte que actualitzi a la versió més recent i, a continuació, torneu-ho a provar.</string>
<string name="qr_code_too_new_1">El codi QR que heu escanejat prové d\'una versió més recent del Briar.\n\nActualitzeu a la darrera versió i torneu-ho a provar.</string>
@@ -488,7 +489,9 @@ Així que l\'actualitzi li veureu una icona diferent .</string>
<string name="blogs_rss_feeds_import">Subscriure\'s al canal de notícies RSS</string>
<string name="blogs_rss_feeds_import_button">Subscriu-me</string>
<string name="blogs_rss_feeds_import_hint">Escriviu l\'URL del canal de notícies RSS</string>
<string name="blogs_rss_feeds_import_progress">Important fil d\'actualitat RSS...</string>
<string name="blogs_rss_feeds_import_error">Ens sap greu! S\'ha produït un error en subscriure-us al vostre canal de notícies.</string>
<string name="blogs_rss_feeds_import_title">Importa fil d\'actualitat des d\'un fitxer</string>
<string name="blogs_rss_feeds">Canals RSS</string>
<string name="blogs_rss_feeds_manage_imported">Importat:</string>
<string name="blogs_rss_feeds_manage_author">Autor:</string>

View File

@@ -1,55 +1,72 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<!--Setup-->
<string name="setup_title">Vítejte v Briar</string>
<string name="setup_name_explanation">Vaše uživatelské jméno bude zobrazeno u jakéhokoli obsahu, který zveřejníte. Následná změna již nebude možná.</string>
<string name="setup_next">Další</string>
<string name="setup_password_intro">Zvolte heslo</string>
<string name="setup_password_explanation">Váš Briar účet je šifrován a uložen ve vašem zařízení, nikoli v cloudu. Pokud zapomenete své heslo nebo odinstalujete Briar, obnovit Váš účet již nebude možné.\n\nZvolte si dlouhé heslo, které je těžké uhádnout, například čtyři náhodné fráze nebo deset náhodných písmen, čísel a symbolů.</string>
<string name="dnkm_doze_title">Připojení na pozadí</string>
<string name="dnkm_doze_intro">Pro příjem zpráv je nutné, aby byl Briar stále spuštěn na pozadí.</string>
<string name="dnkm_doze_explanation">Pro příjem zpráv je nutné, aby byl Briar spuštěn na pozadí. Prosím, vypněte optimalizaci baterie, jedině tak bude Briar stále připojen.</string>
<string name="dnkm_doze_button">Povolit připojení</string>
<string name="choose_nickname">Zvolte si uživatelské jméno</string>
<string name="choose_password">Zvolte si heslo</string>
<string name="confirm_password">Potvrďte své heslo</string>
<string name="name_too_long">Jméno je příliš dlouhé</string>
<string name="password_too_weak">Heslo je příliš slabé</string>
<string name="passwords_do_not_match">Zadaná hesla se neshodují</string>
<string name="create_account_button">Vytvořit účet</string>
<string name="more_info">Další informace</string>
<string name="don_t_ask_again">Znovu se již neptat</string>
<string name="dnkm_huawei_protected_text">Klikněte na níže uvedené tlačítko a ujistěte se, že byl Briar zařazen mezi \"Chráněné aplikace\".</string>
<string name="dnkm_huawei_protected_button">Chránit Briar</string>
<string name="dnkm_huawei_protected_help">Pokud nebyl Briar přidán mezi chráněné aplikace, nebude ho možné spustit na pozadí.</string>
<string name="dnkm_warning_dozed">%s nebylo možné spustit na pozadí</string>
<!--Login-->
<string name="enter_password">Heslo</string>
<string name="try_again">Zadali jste špatné heslo, zkuste to znovu</string>
<string name="sign_in_button">Přihlásit se</string>
<string name="forgotten_password">Nepamatuji si své heslo</string>
<string name="dialog_title_lost_password">Ztracené heslo</string>
<string name="dialog_message_lost_password">Váš Briar účet je šifrován a uložen ve vašem zařízení, nikoli v cloudu, z tohoto důvodu není možné obnovit Vaše heslo. Chcete odstranit svůj účet a začít znovu?\n\nUpozornění: Vaše identita, kontakty a zprávy budou permanentně ztraceny.</string>
<string name="startup_failed_notification_title">Briar nemohl být spuštěn</string>
<string name="startup_failed_notification_text">Klikněte pro více informací</string>
<resources xmlns:tools="http://schemas.android.com/tools">
<!--Setup-->
<string name="setup_title">Vítejte v aplikaci Briar</string>
<string name="setup_name_explanation">Vaše uživatelské jméno bude zobrazeno u jakéhokoli obsahu, který zveřejníte. Následná změna již nebude možná.</string>
<string name="setup_next">Další</string>
<string name="setup_password_intro">Zvolte heslo</string>
<string name="setup_password_explanation">Váš Briar účet je šifrován a uložen ve vašem zařízení, nikoli v cloudu. Pokud zapomenete své heslo nebo odinstalujete Briar, obnovit Váš účet již nebude možné.\n\nZvolte si dlouhé heslo, které je těžké uhádnout, například čtyři náhodné fráze nebo deset náhodných písmen, čísel a znaků.</string>
<string name="dnkm_doze_intro">Pro příjem zpráv je nutné, aby byl Briar stále spuštěn na pozadí.</string>
<string name="dnkm_doze_explanation">Pro příjem zpráv je nutné, aby byl Briar spuštěn na pozadí. Vypněte prosím optimalizaci baterie, aby mohl být Briar stále připojen.</string>
<string name="choose_nickname">Zvolte si uživatelské jméno</string>
<string name="choose_password">Zvolte si heslo</string>
<string name="confirm_password">Potvrďte své heslo</string>
<string name="name_too_long">Jméno je příliš dlouhé</string>
<string name="password_too_weak">Heslo je příliš slabé</string>
<string name="passwords_do_not_match">Zadaná hesla se neshodují</string>
<string name="create_account_button">Vytvořit účet</string>
<string name="more_info">Další informace</string>
<string name="don_t_ask_again">Znovu se neptat</string>
<string name="dnkm_huawei_protected_text">Klepněte na tlačítko níže a ujistěte se, že byl Briar zařazen mezi „Chráněné aplikace“.</string>
<string name="dnkm_huawei_protected_button">Chránit Briar</string>
<string name="dnkm_huawei_protected_help">Pokud nebyl Briar přidán mezi chráněné aplikace, nebude ho možné spustit na pozadí.</string>
<string name="dnkm_huawei_app_launch_text">Klepněte na tlačítko níže, otevřete nabídku „Spouštění aplikací“ a ujistěte se, že je Briar nastaven na „Ruční správa“.</string>
<string name="dnkm_huawei_app_launch_help">Pokud Briar není na obrazovce „Spouštění aplikací“ nastaven na „Ruční správa“, nebude moci běžet na pozadí.</string>
<string name="dnkm_xiaomi_text">Aby mohl Briar běžet na pozadí, musí být uzamčen v seznamu nedávných aplikací.</string>
<string name="dnkm_xiaomi_button">Chránit Briar</string>
<string name="dnkm_xiaomi_help">Pokud není Briar uzamčen v seznamu nedávných aplikací, nebude moci běžet na pozadí.</string>
<string name="dnkm_xiaomi_dialog_body_old">1. Otevřete seznam nedávných aplikací (také známý jako přepínač aplikací)\n\n2. Přejeďte prstem dolů po obrazu Briaru pro zobrazení ikony zámku\n\n3. Pokud není zámek uzamčen, uzamkněte ho klepnutím na něj</string>
<string name="dnkm_xiaomi_dialog_body_new">1. Otevřete seznam nedávných aplikací (také známý jako přepínač aplikací)\n\n2. Pokud má Briar vedle svého názvu malý obrázek zámku, nemusíte nic dělat\n\n3. Pokud tam žádný zámek není, stiskněte a podržte obraz Briaru, dokud se nezobrazí tlačítko visacího zámku, a pak na něj klepněte</string>
<string name="dnkm_xiaomi_lock_apps_text">Klepněte na tlačítko níže pro otevření nastavení zabezpečení. Klepněte na „Zvýšení rychlosti“, poté na „Uzamčení aplikací“ a ujistěte se, že je Briar nastaven na „Uzamčeno“.</string>
<string name="dnkm_xiaomi_lock_apps_help">Pokud není Briar na obrazovce „Uzamčení aplikací“ nastaven na „Uzamčeno“, nebude moci běžet na pozadí.</string>
<string name="dnkm_warning_dozed_1">Briar nemůže běžet na pozadí</string>
<!--Login-->
<string name="enter_password">Heslo</string>
<string name="try_again">Zadali jste špatné heslo, zkuste to znovu</string>
<string name="dialog_title_cannot_check_password">Nepodařilo se zkontrolovat heslo</string>
<string name="dialog_message_cannot_check_password">Briar nemůže zkontrolovat vaše heslo. Zkuste tento problém vyřešit restartováním zařízení.</string>
<string name="sign_in_button">Přihlásit se</string>
<string name="forgotten_password">Nepamatuji si své heslo</string>
<string name="dialog_title_lost_password">Ztracené heslo</string>
<string name="dialog_message_lost_password">Váš Briar účet je šifrován a uložen ve vašem zařízení, nikoli v cloudu, z tohoto důvodu není možné obnovit Vaše heslo. Chcete odstranit svůj účet a začít znovu?\n\nUpozornění: Vaše identita, kontakty a zprávy budou permanentně ztraceny.</string>
<string name="startup_failed_activity_title">Spuštění Briar selhalo.</string>
<string name="startup_failed_db_error">Z nějakého důvodu je vaše databáze Briar poškozena. Váš účet, vaše data a všechny vaše kontakty budou ztraceny. Bohužel musíte přeinstalovat Briar nebo nastavit nový účet výběrem položky \'Zapomněl jsem heslo\' v řádku zadat heslo.</string>
<string name="startup_failed_data_too_old_error">Váš účet byl vytvořen se starou verzí aplikace a nemůže být otevřen v této verzi. Musíte přeinstalovat starou verzi nebo nastavit nový účet vybráním \'Zapomněl jsem své heslo v nabídce hesla.</string>
<string name="startup_failed_data_too_new_error">Tato verze aplikace je zastaralá. Prosím aktualizujte na nejvyšší verzi a zkuste to znovu.</string>
<string name="startup_failed_service_error">Briar nemohl spustit vyžadovaný plugin. Tento problém vyřeší přeinstalování Briar. Mějte prosím na vědomí, že přeinstalováním ztratíte veškerá data pro váš účet, protože Briar nepoužívá centralizované ukládání vašich dat na serverech.</string>
<string name="startup_failed_clock_error">Nepodařilo se spustit Briar, protože hodiny vašeho zařízení jsou špatně nastavené.\n\nNastavte prosím hodiny vašeho zařízení na správný čas a zkuste to znovu.</string>
<string name="startup_failed_db_error">Aplikaci Briar se nepodařilo otevřít databázi obsahující váš účet, kontakty a zprávy.\n\nPřejděte na nejnovější verzi aplikace a zkuste to znovu, nebo si nastavte nový účet tak, že na výzvu k zadání hesla zvolíte „Zapomněl jsem heslo.</string>
<string name="startup_failed_data_too_old_error">Váš účet byl vytvořen ve starší verzi této aplikace a v této verzi jej nelze otevřít.\n\nMusíte buď přeinstalovat starou verzi, nebo nastavit nový účet tak, že na výzvu k zadání hesla vyberete možnost „Zapomněl jsem heslo“.</string>
<string name="startup_failed_data_too_new_error">Váš účet byl vytvořen s novější verzí této aplikace a s touto verzí jej nelze otevřít.\n\nPřejděte prosím na nejnovější verzi a zkuste to znovu.</string>
<string name="startup_failed_service_error">Aplikaci Briar se nepodařilo spustit požadovanou komponentu.\n\nAktualizujte prosím aplikaci na nejnovější verzi a zkuste to znovu.</string>
<plurals name="expiry_warning">
<item quantity="one">Toto je testovací verze Briar. Váš účet a jeho platnost vyprší po %d dnech a není možné ho obnovit.</item>
<item quantity="few">Toto je testovací verze Briar. Váš účet a jeho platnost vyprší po %d dnech a není možné ho obnovit.</item>
<item quantity="many">Toto je testovací verze Briar. Váš účet a jeho platnost vyprší po %d dnech a není možné ho obnovit.</item>
<item quantity="other">Toto je testovací verze Briar. Váš účet a jeho platnost vyprší po %d dnech a není možné ho obnovit.</item>
</plurals>
<string name="expiry_update">Datum expirace pro testování bylo prodlouženo. Váš účet nyní bude expirovat po %d dnech.</string>
<plurals name="old_android_expiry_warning">
<item quantity="one">Systém Android 4 již není podporován. Briar přestane fungovat %s (za %d den). Nainstalujte si prosím Briar na novější zařízení a vytvořte si nový účet.</item>
<item quantity="few">Systém Android 4 již není podporován. Briar přestane fungovat %s (za %d dny). Nainstalujte si prosím Briar na novější zařízení a vytvořte si nový účet.</item>
<item quantity="many">Systém Android 4 již není podporován. Briar přestane fungovat %s (za %d dní). Nainstalujte si prosím Briar na novější zařízení a vytvořte si nový účet.</item>
<item quantity="other">Systém Android 4 již není podporován. Briar přestane fungovat %s (za %d dní). Nainstalujte si prosím Briar na novější zařízení a vytvořte si nový účet.</item>
</plurals>
<string name="expiry_date_reached">Platnost tohoto software vypršela.\nDěkujeme za jeho otestování!</string>
<string name="download_briar">Pro pokračování používání Briar, stáhněte si prosím verzi 1.0.</string>
<string name="download_briar">Pro pokračování v používání aplikace Briar si prosím stáhněte její nejnovější verzi.</string>
<string name="create_new_account">Budete potřebovat vytvořit nový účet, ale můžete použít stejné uživatelské jméno.</string>
<string name="download_briar_button">Stáhnout Briar 1.0</string>
<string name="download_briar_button">Stáhnout nejnovější vydání</string>
<string name="old_android_expiry_date_reached">Briar již neběží na systému Android 4.\nNainstalujte prosím Briar na novější zařízení.</string>
<string name="old_android_delete_account">Klepnutím na tlačítko níže odstraníte svůj účet z tohoto zařízení.</string>
<string name="delete_account_button">Odstranit účet</string>
<string name="startup_open_database">Dešifrování databáze...</string>
<string name="startup_migrate_database">Aktualizování databáze...</string>
<string name="startup_compact_database">Komprimování databáze…</string>
<!--Navigation Drawer-->
<string name="nav_drawer_open_description">Otevřít navigační lištu</string>
<string name="nav_drawer_close_description">Zavřít navigační lištu</string>
@@ -58,13 +75,44 @@
<string name="forums_button">Fóra</string>
<string name="blogs_button">Blogy</string>
<!--This is part of the main menu. The app will be locked when this is tapped.-->
<string name="lock_button">Zamknout aplikaci</string>
<string name="settings_button">Nastavení</string>
<string name="sign_out_button">Odhlásit se</string>
<!--Transports-->
<string name="transports_onboarding_text">Klepněte sem pro ovládání způsobu, kterým se Briar připojuje k vašim kontaktům.</string>
<!--Transports: Tor-->
<string name="transport_tor">Internet</string>
<string name="transport_bt">Bluetooth</string>
<string name="tor_device_status_online_wifi">Váš mobil má přístup k internetu přes Wi-Fi</string>
<string name="tor_device_status_online_mobile">Váš mobil má přístup k internetu přes mobilní data</string>
<string name="tor_device_status_offline">Váš mobil nemá přístup k internetu</string>
<string name="tor_plugin_status_enabling">Briar se připojuje k internetu</string>
<string name="tor_plugin_status_active">Briar je připojen k internetu</string>
<string name="tor_plugin_status_inactive">Briar se nemůže připojit k internetu</string>
<string name="tor_plugin_status_disabled">Briar je nastaven tak, aby nepoužíval internet</string>
<string name="tor_plugin_status_disabled_mobile_data">Briar je nastaven tak, aby nepoužíval mobilní data</string>
<string name="tor_plugin_status_disabled_battery">Briar je nastaven tak, aby nepoužíval internet při provozu na baterii</string>
<string name="tor_plugin_status_disabled_country_blocked">Briar je nastaven tak, aby v této zemi nepoužíval internet</string>
<!--Transports: Wi-Fi-->
<string name="transport_lan">Wi-Fi</string>
<string name="transport_lan_long">Stejná síť Wi-Fi</string>
<string name="lan_device_status_on">Váš mobil je připojen k síti Wi-Fi</string>
<string name="lan_device_status_off">Váš mobil není připojen k síti Wi-Fi</string>
<string name="lan_plugin_status_enabling">Briar se připojuje k síti Wi-Fi</string>
<string name="lan_plugin_status_active">Briar se připojuje k síti Wi-Fi</string>
<string name="lan_plugin_status_inactive">Briar se nemůže připojit k síti Wi-Fi</string>
<string name="lan_plugin_status_disabled">Briar je nastaven tak, aby nepoužíval síť Wi-Fi</string>
<!--Transports: Bluetooth-->
<string name="transport_bt">Bluetooth</string>
<string name="bt_device_status_on">Bluetooth v mobilu je zapnutý</string>
<string name="bt_device_status_off">Bluetooth v mobilu je vypnutý</string>
<string name="bt_plugin_status_enabling">Briar se připojuje k Bluetooth</string>
<string name="bt_plugin_status_active">Briar je připojen k Bluetooth</string>
<string name="bt_plugin_status_inactive">Briar se nemůže připojit k Bluetooth</string>
<string name="bt_plugin_status_disabled">Briar je nastaven tak, aby nepoužíval Bluetooth</string>
<!--Notifications-->
<string name="reminder_notification_title">Byl jste odhlášen z Briar</string>
<string name="reminder_notification_text">Klepněte pro opětovné přihlášení.</string>
<string name="reminder_notification_channel_title">Připomenutí k přihlášení Briar</string>
<string name="reminder_notification_dismiss">Zavřít</string>
<string name="ongoing_notification_title">Přihlásit se do Briar</string>
<string name="ongoing_notification_text">Kliknutím otevřít Briar</string>
<plurals name="private_message_notification_text">
@@ -93,39 +141,110 @@
</plurals>
<!--Misc-->
<string name="now">nyní</string>
<string name="show">Ukázat</string>
<string name="show">Zobrazit</string>
<string name="hide">Skrýt</string>
<string name="ok">Ok</string>
<string name="ok">OK</string>
<string name="cancel">Zrušit</string>
<string name="got_it">Chápu</string>
<string name="delete">Odstranit</string>
<string name="accept">Přijmout</string>
<string name="decline">Odmítnout</string>
<string name="options">Možnosti</string>
<string name="online">Online</string>
<string name="offline">Offline</string>
<string name="send">Odeslat</string>
<string name="allow">Povolit</string>
<string name="open">Otevřít</string>
<string name="change">Změnit</string>
<string name="start">Zapnout</string>
<string name="finish">Dokončit</string>
<string name="no_data">Žádná data</string>
<string name="ellipsis">...</string>
<string name="text_too_long">Zadaný text je příliš dlouhý</string>
<string name="show_onboarding">Zobrazit dialog pro pomoc</string>
<string name="show_onboarding">Zobrazit nabídku nápovědy</string>
<string name="fix">Opravit</string>
<string name="help">Pomoc</string>
<string name="sorry">Promiňte</string>
<string name="error_start_activity">Ve vašem systému není dostupné</string>
<string name="status_heading">Stav</string>
<string name="error">Chyba</string>
<string name="info">Informace</string>
<!--Contacts and Private Conversations-->
<string name="no_contacts">Žádné kontakty k zobrazení</string>
<string name="no_contacts_action">Klepněte na ikonu + pro přidání kontaktu</string>
<string name="date_no_private_messages">Žádné zprávy</string>
<string name="no_private_messages">Žádné zprávy k zobrazení</string>
<string name="message_hint">Psát zprávu</string>
<string name="message_hint">Nová zpráva</string>
<string name="message_hint_auto_delete">Nová mizející zpráva</string>
<string name="message_error">Chyba při odesílání zprávy</string>
<string name="image_caption_hint">Přidat popisek (nepovinné)</string>
<string name="image_attach">Připojit obrázek</string>
<string name="image_attach_error">Nepodařilo se připojit obrázek*ky</string>
<string name="image_attach_error_too_big">Obrázek je příliš velký. Limit je %d MB.</string>
<string name="image_attach_error_invalid_mime_type">Nepodporovaný formát obrázku: %s</string>
<string name="set_contact_alias">Změnit jméno kontaktu</string>
<string name="set_contact_alias_hint">Jméno kontaktu</string>
<string name="menu_item_disappearing_messages">Mizející zprávy</string>
<!--The first placeholder will show a duration like "7 days". The second placeholder at the end will add "Tap to learn more."-->
<string name="auto_delete_msg_you_enabled">Vaše zprávy zmizí za %1$s. %2$s</string>
<!--The placeholder at the end will add "Tap to learn more."-->
<string name="auto_delete_msg_you_disabled">Vaše zprávy nebudou mizet. %1$s</string>
<!--The first placeholder will show a contact's name. The second placeholder will show a duration like "7 days". The third placeholder at the end will add "Tap to learn more."-->
<string name="auto_delete_msg_contact_enabled">Zprávy kontaktu %1$s zmizí za %2$s. %3$s</string>
<plurals name="duration_minutes">
<item quantity="one">%d minutu</item>
<item quantity="few">%d minuty</item>
<item quantity="many">%d minut</item>
<item quantity="other">%d minut</item>
</plurals>
<plurals name="duration_hours">
<item quantity="one">%d hodinu</item>
<item quantity="few">%d hodiny</item>
<item quantity="many">%d hodin</item>
<item quantity="other">%d hodin</item>
</plurals>
<plurals name="duration_days">
<item quantity="one">%d den</item>
<item quantity="few">%d dny</item>
<item quantity="many">%d dní</item>
<item quantity="other">%d dní</item>
</plurals>
<!--The first placeholder will show a contact's name. The second placeholder at the end will add "Tap to learn more."-->
<string name="auto_delete_msg_contact_disabled">Zprávy kontaktu %1$s nebudou mizet. %2$s</string>
<string name="tap_to_learn_more">Klepněte pro více informací.</string>
<string name="auto_delete_changed_warning_title">Mizející zprávy změněny</string>
<string name="auto_delete_changed_warning_message_enabled">Od doby, kdy jste začali psát svou zprávu, byly povoleny mizející zprávy.</string>
<string name="auto_delete_changed_warning_message_disabled">Od doby, kdy jste začali psát svou zprávu, byly povoleny mizející zprávy.</string>
<string name="auto_delete_changed_warning_send">Přesto odeslat</string>
<string name="delete_all_messages">Odstranit všechny zprávy</string>
<string name="dialog_title_delete_all_messages">Potvrdit odstranění zprávy</string>
<string name="dialog_message_delete_all_messages">Opravdu chcete odstranit všechny zprávy?</string>
<string name="dialog_title_not_all_messages_deleted">Nepodařilo se odstranit všechny zprávy</string>
<string name="dialog_message_not_deleted_ongoing_both">Zprávy související s aktuálními pozvánkami a představeními nemohou být smazány dokud nejsou uzavřeny.</string>
<string name="dialog_message_not_deleted_ongoing_introductions">Zprávy související s aktuálními představeními nemohou být smazány dokud nejsou uzavřeny.</string>
<string name="dialog_message_not_deleted_ongoing_invitations">Zprávy související s aktuálními pozvánkami nemohou být smazány dokud nejsou uzavřeny.</string>
<string name="dialog_message_not_deleted_not_all_selected_both">Pro smazání pozvánky nebo představení musíte vybrat žádost a odpověď.</string>
<string name="dialog_message_not_deleted_not_all_selected_introductions">Pro smazání představení musíte vybrat žádost a odpověď.</string>
<string name="dialog_message_not_deleted_not_all_selected_invitations">Pro smazání pozvánky musíte vybrat žádost a odpověď.</string>
<string name="delete_contact">Odstranit kontakt</string>
<string name="dialog_title_delete_contact">Potvrdit odstranění kontaktu</string>
<string name="dialog_message_delete_contact">Jste si jisti, že chcete odstranit kontakt a všechny související zprávy s tímto kontaktem?</string>
<string name="contact_deleted_toast">Kontakt odstraněn</string>
<!--This is shown in the action bar when opening an image in fullscreen that the user sent-->
<string name="you">Vy</string>
<string name="save_image">Uložit obrázek</string>
<string name="dialog_title_save_image">Uložit obrázek?</string>
<string name="dialog_message_save_image">Uložení tohoto obrázku umožní ostatním aplikacím k němu přistupovat.\n\nJste si jisti, že ho chcete uložit?</string>
<string name="save_image_success">Obrázek byl uložen</string>
<string name="save_image_error">Nebylo možné uložit obrázek</string>
<string name="dialog_title_no_image_support">Obrázky jsou nedostupné</string>
<string name="dialog_message_no_image_support">Briar vašich kontaktů ještě nepodporuje obrázkové přílohy. Jakmile navýší na odpovídající verzi aplikace, uvidíte odlišnou ikonu.</string>
<string name="dialog_title_image_support">Nyní můžete tomuto kontaktu posílat obrázky</string>
<string name="dialog_message_image_support">Klepněte na tuto ikonu pro připojení obrázků.</string>
<string name="messaging_too_many_attachments_toast">Pouze prvních %d obrázků bude odesláno</string>
<string name="menu_contact">Kontakt</string>
<!--Adding Contacts-->
<string name="add_contact_title">Přidat kontakt</string>
<string name="add_contact_title">Přidat kontakt v okolí</string>
<string name="add_contact_error_two_way">Oskenovali jste vy i druhá strana QR kód toho druhého?</string>
<string name="face_to_face">Musíte se osobně setkat s osobou, kterou si chcete přidat jako kontakt.\n\nToto v budoucnu zabrání komukoli, aby se za vás vydával nebo četl Vaše zprávy.</string>
<string name="continue_button">Pokračovat</string>
<string name="try_again_button">Zkusit znovu</string>
@@ -133,37 +252,119 @@
<string name="exchanging_contact_details">Výměna detailů kontaktu\u2026</string>
<string name="contact_added_toast">Kontakt byl přidán: %s</string>
<string name="contact_already_exists">Kontakt %s již existuje</string>
<string name="contact_already_exists_general">Kontakt již existuje</string>
<string name="qr_code_invalid">QR kód je neplatný</string>
<string name="qr_code_too_old_1">QR kód, který jste oskenovali pochází ze starší verze Briaru.\n\nProsím požádejte svůj kontakt, aby aktualizoval aplikaci na nejnovější verzi a zkuste to znovu.</string>
<string name="qr_code_too_new_1">QR kód, který jste oskenovali pochází z novější verze Briaru.\n\nProsím aktualizujte Briar na nejnovější verzi a zkuste to znovu.</string>
<string name="mailbox_qr_code_for_contact">QR kód, který jste oskenovali pochází z Briar Mailbox.\n\nPokud chcete odkázat Mailbox, vyberte Nastavení &gt; Mailbox z nabídky Briar.</string>
<string name="qr_code_format_unknown">QR kód, který jste oskenovali není určen pro přidávání Briar kontaktu.\n\nProsím oskenujte QR kód, který je zobrazen na obrazovce vašeho kontaktu.</string>
<string name="camera_error">Vyskytla se chyba fotoaparátu</string>
<string name="connecting_to_device">Připojování k zařízení\u2026</string>
<string name="authenticating_with_device">Ověřování se zařízením\u2026</string>
<string name="connection_error_title">Nebylo možné se připojit k vašemu kontaktu</string>
<string name="connection_error_feedback">Pokud tento problém přetrvává, prosím <a href="feedback">odešlete zpětnou vazbu</a> abyste nám pomohli vylepšit aplikaci.</string>
<string name="info_both_must_scan">Vy i kontakt musíte oskenovat QR kód toho druhého</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Přidat vzdálený kontakt</string>
<string name="add_contact_nearby_title">Přidat kontakt v okolí</string>
<string name="add_contact_remotely_title">Přidat vzdálený kontakt</string>
<string name="contact_link_intro">Sem vložte odkaz od vašeho kontaktu</string>
<string name="contact_link_hint">Odkaz kontaktu</string>
<string name="paste_button">Vložit</string>
<string name="add_contact_button">Přidat kontakt</string>
<string name="copy_button">Kopírovat</string>
<string name="share_button">Sdílet</string>
<string name="send_link_title">Vyměnit odkazy</string>
<string name="add_contact_choose_nickname">Vybrat přezdívku</string>
<string name="add_contact_choose_a_nickname">Vložit přezdívku</string>
<string name="nickname_intro">Dejte vašemu kontaktu přezdívku. Jen vy ji uvidíte.</string>
<string name="your_link">Dejte tento odkaz kontaktu, který chcete přidat</string>
<string name="link_clip_label">Briar link</string>
<string name="link_copied_toast">Odkaz zkopírován</string>
<string name="adding_contact_error">Došlo k chybě přidávání kontaktu.</string>
<string name="pending_contact_requests_snackbar">Existují čekající žádosti o kontakt</string>
<string name="pending_contact_requests">Čekající žádosti o kontakt</string>
<string name="no_pending_contacts">Žádné čekající kontakty</string>
<string name="waiting_for_contact_to_come_online">Čekání až kontakt bude online...</string>
<string name="connecting">Spojuji...</string>
<string name="adding_contact">Přidávání kontaktu...</string>
<string name="adding_contact_failed">Přidávání kontaktu selhalo</string>
<string name="dialog_title_remove_pending_contact">Potvrdit odebrání</string>
<string name="dialog_message_remove_pending_contact">Tento kontakt je stále přidáván. Pokud ho teď odeberete, nebude přidán.</string>
<string name="own_link_error">Zadejte odkaz vašeho kontaktu, ne svůj.</string>
<string name="nickname_missing">Prosím zadejte přezdívku</string>
<string name="invalid_link">Neplatný odkaz</string>
<string name="unsupported_link">Tento odkaz pochází z novější verze Briaru. Prosím proveďte aktualizaci na nejnovější verzi a zkuste to znovu.</string>
<string name="intent_own_link">Otevřeli jste váš odkaz. Použijte odkaz kontaktu, který chcete přidat.</string>
<string name="missing_link">Prosím zadejte odkaz</string>
<!--This is a numeral indicating the first step in a series of screens-->
<string name="step_1">1</string>
<!--This is a numeral indicating the second step in a series of screens-->
<string name="step_2">2</string>
<plurals name="contact_added_notification_text">
<item quantity="one">Nový kontakt přidán.</item>
<item quantity="few">%d nové kontakty přidány.</item>
<item quantity="many">%d nových kontaktů přidáno.</item>
<item quantity="other">%d nových kontaktů přidáno.</item>
</plurals>
<string name="offline_state">Žádné internetové připojení</string>
<string name="duplicate_link_dialog_title">Duplicitní odkaz</string>
<string name="duplicate_link_dialog_text_1">Již máte čekající kontakt s tímto odkazem: %s</string>
<string name="duplicate_link_dialog_text_1_contact">Již máte kontakt s tímto odkazem: %s</string>
<!--This is a question asking whether two nicknames refer to the same person-->
<string name="duplicate_link_dialog_text_2">Je %1$s a %2$s stejná osoba?</string>
<!--This is a button for answering that two nicknames do indeed refer to the same person. This
string will be used in a dialog button, so if the translation of this string is longer than 20
characters, please use "Yes" instead, and use "No" for the "Different Person" button-->
<string name="same_person_button">Stejná osoba</string>
<!--This is a button for answering that two nicknames refer to different people. This string
will be used in a dialog button, so if the translation of this string longer than 20 characters,
please use "No" instead, and use "Yes" for the "Same Person" button-->
<string name="different_person_button">Jiná osoba</string>
<string name="duplicate_link_dialog_text_3">%1$s a %2$s vám poslali stejný odkaz.\n\nJeden z nich se možná snaží zjistit kdo jsou vaše kontakty.\n\nNeříkejte jim, že jste dostali stejný odkaz od někoho jiného.</string>
<string name="pending_contact_updated_toast">Čekající kontakt aktualizován</string>
<string name="info_both_must_enter_links">Oba kontakty musí přidat odkaz toho druhého</string>
<!--Peer trust levels-->
<string name="peer_trust_level_unverified">Neověřený kontakt</string>
<string name="peer_trust_level_verified">Ověřený kontakt</string>
<string name="peer_trust_level_ourselves"></string>
<string name="peer_trust_level_stranger">Neznámý</string>
<!--Introductions-->
<string name="introduction_onboarding_title">Uvést vaše kontakty</string>
<string name="introduction_onboarding_text">Můžete si navzájem představit své kontakty, takže se následně nemusejí setkat osobně, aby se připojili k Briar.</string>
<string name="introduction_menu_item">Vytvořit pozvání</string>
<string name="introduction_onboarding_text">Představte vzájemně vaše kontakty, aby se spolu mohly spojit.</string>
<string name="introduction_menu_item">Představit</string>
<string name="introduction_activity_title">Vybrat kontakt</string>
<string name="introduction_not_possible">Již máte jedno představení v běhu s těmito kontakty. Prosím nejprve nechte toto dokončit. Pokud vy nebo vaše kontakty nejste často online, může to nějakou dobu trvat.</string>
<string name="introduction_message_title">Pozvat kontakty</string>
<string name="introduction_message_hint">Přidat zprávu (volitelné)</string>
<string name="introduction_button">Vytvořit pozvání</string>
<string name="introduction_sent">Vaše pozvání bylo odesláno.</string>
<string name="introduction_error">Vyskytla se chyba při tvorbě pozvání.</string>
<string name="introduction_response_error">Chyba při odpovědi na pozvání.</string>
<string name="introduction_button">Představit</string>
<string name="introduction_sent">Vaše představení bylo odesláno.</string>
<string name="introduction_error">Vyskytla se chyba při tvorbě představení.</string>
<string name="introduction_request_sent">Požádali jste o pozvání %1$s do %2$s.</string>
<string name="introduction_request_received">%1$s vás požádal o uvedení do %2$s. Chcete přidat %2$s mezi vaše kontakty?</string>
<string name="introduction_request_exists_received">%1$s vás požádal o představení s %2$s, ale %2$s je již ve vašich kontaktech. Pravděpodobně to %1$s neví, ale stále můžete odpovědět:</string>
<string name="introduction_request_answered_received">%1$s vás žádá o pozvání do %2$s.</string>
<string name="introduction_response_accepted_sent">Přijali jste pozvání do %1$s.</string>
<string name="introduction_response_declined_sent">Odmítli jste představení do %1$s.</string>
<string name="introduction_response_accepted_received">%1$s přijal pozvání do %2$s.</string>
<string name="introduction_response_declined_received">%1$s odmítl pozvání do %2$s.</string>
<string name="introduction_response_declined_received_by_introducee">%1$s řekl, že %2$s odmítl pozvání.</string>
<plurals name="contact_added_notification_text">
<item quantity="one">Nový kontakt byl přidán.</item>
<item quantity="few">Bylo přidáno %d nových kontaktů.</item>
<item quantity="many">%d nových kontaktů bylo přidáno.</item>
<item quantity="other">%d nových kontaktů bylo přidáno.</item>
</plurals>
<string name="introduction_response_accepted_sent">Přijali jste představení %1$s.</string>
<string name="introduction_response_accepted_sent_info">Před tím, než bude %1$s přidán(a) do kontaktů, musí přijmout představení. Toto může nějakou dobu trvat.</string>
<string name="introduction_response_declined_sent">Odmítli jste představení %1$s.</string>
<string name="introduction_response_declined_auto">Představení %1$s bylo automaticky zamítnuto.</string>
<string name="introduction_response_accepted_received">%1$s přijal(a) představení %2$s.</string>
<string name="introduction_response_declined_received">%1$s odmítl(a) představení %2$s.</string>
<string name="introduction_response_declined_received_by_introducee">%1$s řekl(a), že %2$s odmítl(a) představení.</string>
<!--Connect via Bluetooth-->
<string name="menu_item_connect_via_bluetooth">Připojit přes Bluetooth</string>
<string name="connect_via_bluetooth_title">Připojit přes Bluetooth</string>
<string name="connect_via_bluetooth_intro">V případě, že Bluetooth připojení nefunguje automaticky, můžete použít tuto obrazovku pro ruční připojení.\n\nVáš kontakt musí být v okolí, aby to fungovalo.\n\nVy i váš kontakt musíte klepnout na \"Start\" ve stejný čas.</string>
<string name="connect_via_bluetooth_already_discovering">Již se pokoušíte o připojení přes Bluetooth. Zkuste to znovu za chvíli.</string>
<string name="connect_via_bluetooth_no_location_permission">Není možné pokračovat bez povolení znát umístění</string>
<string name="connect_via_bluetooth_no_bluetooth_permission">Není možné pokračovat bez povolení přístupu k zařízením v okolí</string>
<string name="connect_via_bluetooth_start">Připojování přes Bluetooth...</string>
<string name="connect_via_bluetooth_success">Úspěšně připojeno přes Bluetooth</string>
<string name="connect_via_bluetooth_error">Nebylo možné se připojit přes Bluetooth.</string>
<string name="connect_via_bluetooth_error_not_supported">Bluetooth není podporován zařízením.</string>
<!--Private Groups-->
<string name="groups_list_empty">Žádné skupiny k zobrazení</string>
<string name="groups_list_empty_action">Klepněte na ikonu + pro vytvoření skupiny a nebo požádejte své kontakty, aby s vámi skupiny sdílely</string>
<string name="groups_created_by">Vytvořeno %s</string>
<plurals name="messages">
<item quantity="one">%d zpráva</item>
@@ -179,7 +380,6 @@
<string name="groups_create_group_invitation_button">Poslat pozvánku</string>
<string name="groups_create_group_hint">Vyberte jméno pro vaši soukromou skupinu</string>
<string name="groups_invitation_sent">Skupinová pozvánka byla odeslána</string>
<string name="groups_message_sent">Zpráva odeslána</string>
<string name="groups_member_list">Seznam členů</string>
<string name="groups_invite_members">Pozvat členy</string>
<string name="groups_member_created_you">Vytvořili jste skupinu</string>
@@ -209,17 +409,20 @@
</plurals>
<string name="groups_invitations_response_accepted_sent">Přijali jste pozvání do skupiny od %s.</string>
<string name="groups_invitations_response_declined_sent">Odmítli jste pozvání do skupiny od %s.</string>
<string name="groups_invitations_response_declined_auto">Pozvánka do skupiny od %s byla automaticky zamítnuta.</string>
<string name="groups_invitations_response_accepted_received">%s přijatých pozvání ke skupině.</string>
<string name="groups_invitations_response_declined_received">%s odmítnutých pozvání ke skupině.</string>
<string name="sharing_status_groups">Pouze zakladatel může pozvat nové členy do skupiny. Níže jsou všichni současní členové skupiny.</string>
<!--Private Groups Revealing Contacts-->
<string name="groups_reveal_contacts">Odkrýt kontakty</string>
<string name="groups_reveal_dialog_message">Můžete si vybrat, zda chcete své kontakty odhalit všem současným i budoucím členům této skupiny.\n\nPřidáním kontaktů je vaše připojení ke skupině rychlejší a spolehlivější, protože můžete komunikovat s odhalenými kontakty i když je tvůrce skupiny offline.</string>
<string name="groups_reveal_dialog_message">Můžete si vybrat, zda chcete své kontakty odhalit všem současným i budoucím členům této skupiny.\n\nPřidáním kontaktů je vaše připojení ke skupině rychlejší a spolehlivější, protože můžete komunikovat s odhalenými kontakty i když je zakladatel skupiny offline.</string>
<string name="groups_reveal_visible">Vztah s kontaktem je viditelný ve skupině</string>
<string name="groups_reveal_visible_revealed_by_us">Vztah s kontaktem je viditelný ve skupině (Tebou odkrytý)</string>
<string name="groups_reveal_visible_revealed_by_contact">Vztah s kontaktem je viditelný ve skupině (byl odkrytý %s)</string>
<string name="groups_reveal_invisible">Vztah s kontaktem není viditelný ve skupině</string>
<!--Forums-->
<string name="no_forums">Žádná fóra k zobrazení</string>
<string name="no_forums_action">Klepněte na ikonu + pro vytvoření fóra a nebo požádejte své kontakty, aby s vámi fóra sdílely</string>
<string name="create_forum_title">Vytvořit fórum</string>
<string name="choose_forum_hint">Vybrat jméno pro vaše fórum</string>
<string name="create_forum_button">Vytvořit fórum</string>
@@ -232,6 +435,7 @@
<item quantity="many">%d příspěvků</item>
<item quantity="other">%d příspěvků</item>
</plurals>
<string name="forum_new_message_hint">Nový příspěvek</string>
<string name="forum_message_reply_hint">Nová odpověď</string>
<string name="btn_reply">Odpověď</string>
<string name="forum_leave">Opustit fórum</string>
@@ -243,18 +447,26 @@
<string name="forum_share_button">Sdílet fórum</string>
<string name="contacts_selected">Zvolené kontakty</string>
<string name="activity_share_toolbar_header">Zvolit kontakty</string>
<string name="no_contacts_selector">Žádné kontakty k zobrazení</string>
<string name="no_contacts_selector_action">Prosím vraťte se sem po přidání kontaktu</string>
<string name="forum_shared_snackbar">Fórum sdíleno s vybranými kontakty</string>
<string name="forum_share_message">Přidat zprávu (volitelné)</string>
<string name="forum_share_error">Při sdílení tohoto fóra nastala chyba.</string>
<string name="forum_invitation_received">%1$s sdílel fórum \"%2$s\" s vámi.</string>
<string name="forum_invitation_sent">Sdíleli jste fórum \"%1$s\" s %2$s.</string>
<string name="forum_invitations_title">Pozvání do fóra</string>
<string name="forum_invitation_exists">Již jste přijali pozvání do tohoto fóra.\n\nPřijetí dalších pozvání zajistí rychlejší a spolehlivější připojení k fóru.</string>
<string name="forum_joined_toast">Vstup do fóra</string>
<string name="forum_declined_toast">Pozvání zamítnuto</string>
<string name="shared_by_format">Sdíleno %s</string>
<string name="forum_invitation_already_sharing">Již sdílené</string>
<string name="forum_invitation_already_invited">Pozvánka již byla odeslána</string>
<string name="forum_invitation_invite_received">Pozvánka již byla obdržena</string>
<string name="forum_invitation_not_supported">Nepodporováno tímto kontaktem</string>
<string name="forum_invitation_error">Chyba. Jde o poruchu, která není vaší vinou</string>
<string name="forum_invitation_response_accepted_sent">Přijali jste pozvání do fóra od %s.</string>
<string name="forum_invitation_response_declined_sent">Odmítli jste pozvání do fóra od %s.</string>
<string name="forum_invitation_response_declined_auto">Pozvánka do fóra od %s byla automaticky zamítnuta.</string>
<string name="forum_invitation_response_accepted_received">%s přijatých pozvání do fóra.</string>
<string name="forum_invitation_response_declined_received">%s odmítnutých pozvání do fóra.</string>
<string name="sharing_status">Sdílet status</string>
@@ -277,11 +489,13 @@
<string name="blogs_blog_post_received">Přijatý nový příspěvek v blogu.</string>
<string name="blogs_blog_post_scroll_to">Přejít na</string>
<string name="blogs_feed_empty_state">Žádné příspěvky k zobrazení</string>
<string name="blogs_feed_empty_state_action">Příspěvky od vašich kontaktů a z blogů, které odebíráte se zobrazí zde\n\nKlepněte na ikonu pera pro napsání příspěvku</string>
<string name="blogs_remove_blog">Odstranit blog</string>
<string name="blogs_remove_blog_dialog_message">Jste si jisti, že chcete odebrat tento blog?\n\nPříspěvky budou smazány z vašeho zařízení ale ne ze zařízení ostatních lidí.\n\nKontakty, se kterými jste sdíleli tento blog mohou přestat dostávat aktualizace.</string>
<string name="blogs_remove_blog_ok">Odstranit</string>
<string name="blogs_blog_removed">Blog odstraněn</string>
<string name="blogs_reblog_comment_hint">Přidat komentář (volitelné)</string>
<string name="blogs_reblog_button">Reblog</string>
<string name="blogs_reblog_button">Znovu-zveřejnit</string>
<!--Blog Sharing-->
<string name="blogs_sharing_share">Sdílet blog</string>
<string name="blogs_sharing_error">Vyskytla se chyba při sdílení tohoto blogu.</string>
@@ -289,6 +503,7 @@
<string name="blogs_sharing_snackbar">Blog sdílen s vybranými kontakty.</string>
<string name="blogs_sharing_response_accepted_sent">Přijali jste pozvání do blogu od %s.</string>
<string name="blogs_sharing_response_declined_sent">Odmítli jste pozvání do blogu od %s.</string>
<string name="blogs_sharing_response_declined_auto">Pozvánka k blogu od %s byla automaticky zamítnuta.</string>
<string name="blogs_sharing_response_accepted_received">%s schválených pozvání do blogu.</string>
<string name="blogs_sharing_response_declined_received">%s odmítnutých pozvání do blogu.</string>
<string name="blogs_sharing_invitation_received">%1$s sdílel blog \"%2$s\" s vámi.</string>
@@ -301,59 +516,92 @@
<string name="blogs_rss_feeds_import">Import RSS kanálu</string>
<string name="blogs_rss_feeds_import_button">Import</string>
<string name="blogs_rss_feeds_import_hint">Zadejte URL adresu RSS kanálu</string>
<string name="blogs_rss_feeds_import_progress">Importování RSS kanálu...</string>
<string name="blogs_rss_feeds_import_error">Omlouváme se! Vyskytla se chyba při importu vašeho kanálu.</string>
<string name="blogs_rss_feeds_import_title">Import kanálu ze souboru</string>
<string name="blogs_rss_feeds">RSS kanály</string>
<string name="blogs_rss_feeds_manage_imported">Importováno:</string>
<string name="blogs_rss_feeds_manage_author">Autor:</string>
<string name="blogs_rss_feeds_manage_updated">Naposledy aktualizováno:</string>
<string name="blogs_rss_remove_feed">Odstranit kanál</string>
<string name="blogs_rss_remove_feed_dialog_message">Jste si jisti, že chcete odebrat tento kanál?\n\nPříspěvky budou odebrány z vašeho zařízení ale zůstanou na zařízeních jiných lidí.\n\nKontakty, se kterými jste tento kanál sdíleli, mohou přestat dostávat aktualizace.</string>
<string name="blogs_rss_remove_feed_ok">Odstranit</string>
<string name="blogs_rss_feeds_manage_empty_state">Žádné RSS kanály k zobrazení\n\nKlikněte na ikonu + pro nahrání příspěvků</string>
<string name="blogs_rss_feeds_manage_error">Vyskytl se problém s načtením vašeho kanálu příspěvků. Zkuste to prosím později.</string>
<string name="blogs_rss_feeds_manage_error">Vyskytl se problém při načtení vašich kanálů. Zkuste to prosím později.</string>
<!--Settings Profile Picture-->
<string name="change_profile_picture">Klepněte pro změnu svého profilového obrázku</string>
<string name="dialog_confirm_profile_picture_title">Změnit profilový obrázek</string>
<string name="dialog_confirm_profile_picture_remark">Pouze vaše kontakty uvidí tento obrázek</string>
<string name="change_profile_picture_failed_message">Omlouváme se, ale něco se pokazilo při aktualizaci vašeho profilového obrázku</string>
<!--Settings Display-->
<string name="pref_language_title">Jazyk &amp; region</string>
<string name="pref_language_title">Jazyk a oblast</string>
<string name="pref_language_changed">Toto nastavení bude mít efekt když vykonáre restart svého Briar. Prosím odhlaste se a restartujte Briar.</string>
<string name="pref_language_default">Výchozí systému</string>
<string name="display_settings_title">Zobrazit</string>
<string name="pref_theme_title">Vzhled</string>
<string name="pref_language_default">Podle systému</string>
<string name="display_settings_title">Zobrazení</string>
<string name="pref_theme_title">Motiv</string>
<string name="pref_theme_light">Světlý</string>
<string name="pref_theme_dark">Temný</string>
<!--Settings Network-->
<string name="network_settings_title">Sítě</string>
<string name="bluetooth_setting">Spojení přes Bluetooth</string>
<string name="bluetooth_setting_enabled">Vždy, když jsou kontakty v blízkosti</string>
<string name="bluetooth_setting_disabled">Jen když přidáte kontakty</string>
<!--How and when Tor will connect after Automatic: E.g. Don't connect (in China) or Use Tor with bridges (in Belarus)-->
<string name="pref_theme_auto">Automaticky (denní doba)</string>
<string name="pref_theme_system">Podle systému</string>
<!--Settings Connections-->
<string name="network_settings_title">Spojení</string>
<string name="bluetooth_setting">Připojit se ke kontaktům přes Bluetooth</string>
<string name="wifi_setting">Připojte se ke kontaktům na stejné Wi-Fi síti</string>
<string name="tor_enable_title">Připojte se ke kontaktům přes internet</string>
<string name="tor_enable_summary">Všechna spojení jdou skrze síť Tor kvůli soukromí</string>
<string name="tor_network_setting">Způsob připojení k síti Tor</string>
<string name="tor_network_setting_automatic">Automatické v závislosti na umístění</string>
<string name="tor_network_setting_without_bridges">Použít síť Tor bez mostů</string>
<string name="tor_network_setting_with_bridges">Použít síť Tor s mosty</string>
<string name="tor_network_setting_never">Nepřipojovat se k internetu</string>
<!--How and when Briar will connect to Tor: E.g. "Don't connect to the Internet (in China)" or "Use Tor network with bridges (in Belarus)"-->
<string name="tor_network_setting_summary">Automatické: %1$s (v %2$s)</string>
<string name="tor_mobile_data_title">Použít mobilní data</string>
<string name="tor_only_when_charging_title">Připojit se k internetu pouze při nabíjení</string>
<string name="tor_only_when_charging_summary">Vypne internetové připojení když zařízení není nabíjeno ze sítě</string>
<!--Settings Security and Panic-->
<string name="security_settings_title">Zabezpečení</string>
<string name="pref_lock_title">Zamčení aplikace</string>
<string name="pref_lock_summary">Použít zamčení obrazovky zařízení pro ochranu Briaru po přihlášení</string>
<string name="pref_lock_disabled_summary">Pro použité této funkce nastavte zamčení obrazovky zařízení</string>
<string name="pref_lock_timeout_title">Doba neaktivity pro zamčení aplikace</string>
<!--The %s placeholder is replaced with the following time spans, e.g. 5 Minutes, 1 Hour-->
<string name="pref_lock_timeout_summary">Když Briar není používán, automaticky ho zamknou po %s</string>
<!--Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s"-->
<string name="pref_lock_timeout_1">1 minutě</string>
<!--Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s"-->
<string name="pref_lock_timeout_5">5 minutách</string>
<!--Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s"-->
<string name="pref_lock_timeout_15">15 minutách</string>
<!--Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s"-->
<string name="pref_lock_timeout_30">30 minutách</string>
<!--Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s"-->
<string name="pref_lock_timeout_60">1 hodina</string>
<string name="pref_lock_timeout_never">Nikdy</string>
<string name="pref_lock_timeout_never_summary">Nikdy nezamykat Briar automaticky</string>
<string name="change_password">Změnit heslo</string>
<string name="current_password">Současné heslo</string>
<string name="choose_new_password">Nové heslo</string>
<string name="confirm_new_password">Potvrdit nové heslo</string>
<string name="password_changed">Heslo bylo změněno.</string>
<string name="panic_setting">Nastavení tlačítka Paniky</string>
<string name="panic_setting_title">Tlačítko Paniky</string>
<string name="panic_setting">Nastavení tlačítka paniky</string>
<string name="panic_setting_title">Tlačítko paniky</string>
<string name="panic_setting_hint">Nastavte, jak bude Briar reagovat, když použijete aplikaci tlačítka paniky</string>
<string name="panic_app_setting_title">Aplikace Panik tlačítko</string>
<string name="panic_app_setting_title">Aplikace paniky</string>
<string name="unknown_app">neznámá aplikace</string>
<string name="panic_app_setting_summary">Žádná aplikace nebyla nastavena</string>
<string name="panic_app_setting_none">Žádný</string>
<string name="dialog_title_connect_panic_app">Potvrdit aplikaci Paniky</string>
<string name="dialog_title_connect_panic_app">Potvrdit aplikaci paniky</string>
<string name="dialog_message_connect_panic_app">Jste si jisti, že chcete povolit %1$s spustit akci zneškodnění pomocí tlačítka paniky?</string>
<string name="panic_setting_destructive_action">Destruktivní akce</string>
<string name="panic_setting_signout_title">Odhlásit se</string>
<string name="panic_setting_signout_summary">Odhlásit se z Briar, pokud je stisknuto tlačítko paniky</string>
<string name="purge_setting_title">Odstranit účet</string>
<string name="purge_setting_summary">Vymazat váš Briar účet pokud je stlačeno tlačítko paniky. Upozornění: Toto trvale vymaže vaši identitu, kontakty a zprávy</string>
<string name="uninstall_setting_title">Odinstalovat Briar</string>
<string name="uninstall_setting_summary">Toto vyžaduje manuální potvrzení v události paniky</string>
<string name="purge_setting_summary">Při stisknutí tlačítka paniky odstranit váš účet Briar. Varování: tato akce trvale vymaže vaše identity, kontakty a zprávy</string>
<!--Settings Notifications-->
<string name="notification_settings_title">Oznáme</string>
<string name="notification_settings_title">Upozorně</string>
<string name="notify_sign_in_title">Připomenout mi, abych se přihlásil/a</string>
<string name="notify_sign_in_summary">Zobrazit připomínku po startu telefonu nebo po aktualizaci aplikace</string>
<string name="notify_private_messages_setting_title">Soukromé zprávy</string>
<string name="notify_private_messages_setting_summary">Zobrazit upozornění pro soukromé zprávy</string>
<string name="notify_private_messages_setting_summary_26">Nastavení upozornění pro soukromé zprávy</string>
@@ -372,17 +620,116 @@
<string name="notify_sound_setting_disabled">Žádný</string>
<string name="choose_ringtone_title">Zvolit vyzváněcí tón</string>
<string name="cannot_load_ringtone">Nelze načíst vyzváněcí tón</string>
<!--Settings Feedback-->
<string name="feedback_settings_title">Zpětná vazba</string>
<!--Mailbox-->
<string name="mailbox_settings_title">Mailbox</string>
<string name="mailbox_setup_title">Mailbox nastavení</string>
<string name="mailbox_setup_intro">Mailbox umožňuje vašim kontaktům posílat vám zprávy když jste offline. Mailbox obdrží vaše zprávy a uchová je dokud nebudete online.\n
\nBriar Mailbox aplikaci můžete nainstalovat na nevyužité zařízení. Nechte ho připojené do elektrické sítě a k Wi-Fi aby bylo neustále online.</string>
<string name="mailbox_setup_download">Nejprve nainstalujte aplikaci Mailbox na jiné zařízení tak, že si vyhledáte \"Briar Mailbox\" na Google Play nebo jinde odkud stahujete Briar.\n
\nPotom spojte váš Mailbox s Briarem oskenováním QR kódu zobrazeném aplikací Mailbox.</string>
<string name="mailbox_setup_download_link">Sdílet odkaz pro stažení</string>
<string name="mailbox_setup_button_scan">Skenovat Mailbox QR kód</string>
<string name="permission_camera_qr_denied_body">Přístup k fotoaparátu máte zakázaný ale skenování QR kódu vyžaduje použití fotoaparátu.\n\nProsím zvažte povolení přístupu.</string>
<string name="mailbox_setup_connecting">Připojování k Mailboxu...</string>
<!--This string is shown when connecting to a Mailbox for the first time. The placeholder will be replaced with a duration, e.g. "2 minutes".-->
<string name="mailbox_setup_connecting_info">Toto může trvat až %1s</string>
<string name="mailbox_qr_code_too_old">QR kód, který jste oskenovali, pochází ze starší verze Briar Mailboxu.\n\nProsím aktualizujte Briar Mailbox na nejnovější verzi a pak akci opakujte.</string>
<string name="mailbox_qr_code_too_new">QR kód, který jste oskenovali, pochází z novější verze Briar Mailboxu.\n\nProsím aktualizujte Briar Mailbox na nejnovější verzi a pak akci opakujte.</string>
<string name="contact_qr_code_for_mailbox">QR kód, který jste oskenovali, je určen k přidání kontaktu Briar.\n\nPokud chcete přidat kontakt, prosím jděte do seznamu kontaktů a klepněte na ikonu +.</string>
<string name="mailbox_setup_qr_code_wrong_description">QR kód, který jste oskenovali, nepochází z Briar Mailboxu.\n\nProsím otevřete Briar Mailbox aplikaci na vašem Mailbox zařízení a oskenujte QR kód který vám zobrazí.</string>
<string name="mailbox_setup_already_paired_title">Mailbox již byl spojen</string>
<string name="mailbox_setup_already_paired_description">Odpojte Mailbox na vašem dalším zařízení a akci opakujte.</string>
<string name="mailbox_setup_io_error_title">Nebylo možné se připojit</string>
<string name="mailbox_setup_io_error_description">Ujistěte se, že obě zařízení jsou připojena k internetu a akci opakujte.</string>
<string name="mailbox_setup_assertion_error_title">Chyba Mailboxu</string>
<string name="mailbox_setup_assertion_error_description">Pokud problém přetrvává, použijte prosím aplikaci Briar k odeslání zpětné vazby (s anonymizovanými daty).</string>
<string name="mailbox_setup_camera_error_description">Nebylo možné získat přístup k fotoaparátu. Možná zkuste restartovat zařízení a opakovat akci.</string>
<string name="mailbox_setup_paired_title">Připojeno</string>
<string name="mailbox_setup_paired_description">Váš Mailbox byl úspěšně spojen s Briarem.\n
\nNechte Mailbox připojený k elektrické síti a k Wi-Fi aby byl neustále online.</string>
<string name="tor_offline_title">Offline</string>
<string name="tor_offline_description">Ujistěte se, že toto zařízení je online a přístup k internetu je povolen.\n
\nNásledně vyčkejte až se ikona zeměkoule změní na zelenou.</string>
<string name="tor_offline_button_check">Zkontrolujte nastavení připojení</string>
<string name="mailbox_status_title">Stav Mailboxu</string>
<string name="mailbox_status_connected_title">Mailbox běží</string>
<string name="mailbox_status_problem_title">Briar má problém s připojením k Mailboxu</string>
<string name="mailbox_status_failure_title">Mailbox je nedostupný</string>
<string name="mailbox_status_app_too_old_title">Briar je příliš zastaralý</string>
<string name="mailbox_status_app_too_old_message">Aktualizujte Briar na nejnovější verzi aplikace a opakujte akci.</string>
<string name="mailbox_status_mailbox_too_old_title">Mailbox je příliš zastaralý</string>
<string name="mailbox_status_mailbox_too_old_message">Aktualizujte váš Mailbox na nejnovější verzi aplikace a zkuste to znovu.</string>
<string name="mailbox_status_check_button">Zkontrolujte připojení</string>
<!--Example for string substitution: Last connection: 3min ago-->
<string name="mailbox_status_connected_info">Poslední připojení: %s</string>
<!--Indicates that there never was a connection to the mailbox. Last connection: Never-->
<string name="mailbox_status_connected_never">Nikdy</string>
<string name="mailbox_status_unlink_button">Odpojit</string>
<string name="mailbox_status_unlink_dialog_title">Odpojit Mailbox?</string>
<string name="mailbox_status_unlink_dialog_question">Jste si jisti, že si přejete odpojit váš Mailbox?</string>
<string name="mailbox_status_unlink_dialog_warning">Pokud odpojíte svůj Mailbox, nebudete moci obdržet zprávy když bude Briar nedostupný/offline.</string>
<string name="mailbox_status_unlink_no_wipe_title">Váš Mailbox byl odpojen</string>
<string name="mailbox_status_unlink_no_wipe_message">Až budete mít příště přístup do vašeho Mailbox zařízení, otevřete prosím Mailbox aplikaci a klepněte na tlačítko \"Odpojit\" pro dokončení procesu.\n\nPokud již nemáte přístup k vašemu Mailbox zařízení, nezoufejte. Vaše data jsou šifrována, takže zůstanou v bezpečí i v případě, že proces nedokončíte.</string>
<string name="mailbox_status_unlink_success">Váš Mailbox byl odpojen</string>
<string name="mailbox_error_notification_channel_title">Problém s Briar Mailboxem</string>
<string name="mailbox_error_notification_title">Briar Mailbox je nedostupný</string>
<string name="mailbox_error_notification_text">Klepněte pro vyřešení problému.</string>
<string name="mailbox_error_wizard_button">Vyřešit problém</string>
<string name="mailbox_error_wizard_title">Průvodce řešení problémů s Mailboxem</string>
<string name="mailbox_error_wizard_question1">Máte přístup k vašemu Mailbox zařízení?</string>
<string name="mailbox_error_wizard_answer1">Ano, mám k němu nyní přístup.</string>
<string name="mailbox_error_wizard_answer2">Nyní k němu nemám přístup ale budu ho mít později.</string>
<string name="mailbox_error_wizard_answer3">Ne, již k němu nemám přístup.</string>
<string name="mailbox_error_wizard_info1_1">Zkontrolujte, že Mailbox zařízení je zapnuto a připojeno k internetu.</string>
<string name="mailbox_error_wizard_question1_1">Otevřete Mailbox aplikaci. Co vidíte?</string>
<string name="mailbox_error_wizard_answer1_1">Vidím instrukce k nastavení Mailboxu</string>
<string name="mailbox_error_wizard_answer1_2">Vidím QR kód</string>
<string name="mailbox_error_wizard_answer1_3">Vidím \"Mailbox běží\"</string>
<string name="mailbox_error_wizard_answer1_4">Vidím \"Zařízení je nedostupné\"</string>
<string name="mailbox_error_wizard_info1_1_1">Prosím odpojte váš Mailbox pomocí tlačítka níže, potom postupujte podle instrukcí na Mailbox zařízení pro opětovné spojení.</string>
<string name="mailbox_error_wizard_info_1_1_2">Prosím odpojte váš Mailbox pomocí tlačítka níže, potom oskenujte QR kód pro opětovné spojení.</string>
<string name="mailbox_error_wizard_info1_1_3">Prosím, použijte tlačítko níže pro kontrolu spojení mezi Briarem a Mailboxem.\n\n
Pokud spojení znovu selže:\n
\u2022 Zkontrolujte, že Mailbox a Briar aplikace jsou aktualizované na nejnovější verzi.\n
\u2022 Restartujte Mailbox a Briar zařízení a zkuste to znovu.</string>
<string name="mailbox_error_wizard_info1_1_4">Zkontrolujte že mailbox zařízení je správně připojeno k internetu.\n\nZkontrolujte že hodiny na Mailbox zařízení ukazují správný čas, datum a časové pásmo.\n\nZkontrolujte že Mailbox a Briar aplikace jsou aktualizované na nejnovější verzi.\n\nRestartujte Mailbox i Briar zařízení a zkuste to znovu.</string>
<string name="mailbox_error_wizard_info2">Prosím vraťte se zpět na tuto obrazovku jakmile získáte přístup k zařízení.</string>
<string name="mailbox_error_wizard_info3">Prosím odpojte váš Mailbox pomocí tlačítka níže.\n\nPo odpojení vašeho starého Mailboxu můžete kdykoliv nastavit nový Mailbox.</string>
<!--About-->
<string name="about_title">O</string>
<string name="briar_version">Briar verze: %s</string>
<string name="tor_version">Tor verze: %s</string>
<string name="links">Odkazy</string>
<string name="briar_website">\u2022 <a href="">Webová stránka</a></string>
<string name="briar_source_code">\u2022 <a href="">Zdrojový kód</a></string>
<string name="briar_changelog">\u2022 <a href="">Změny v aplikaci</a></string>
<string name="briar_privacy_policy">\u2022 <a href="">Zásady ochrany osobních údajů</a></string>
<!--Here translators can add their names or Transifex usernames(eg "Thanks to all the contributors at the Localization Lab, especially Tom, Matthew and Jerry")-->
<string name="translator_thanks">Díky všem, kdo přispěli k překladu aplikace na https://www.transifex.com/otf/briar</string>
<!--Conversation Settings-->
<string name="disappearing_messages_title">Mizející zprávy</string>
<string name="disappearing_messages_explanation_long">Zapnutím této volby znamená, že nové
zprávy v této konverzaci automaticky zmizí po 7\u00A0dnech.
\n\nOdpočítávání pro kopii zprávy odesilatele začíná po jejím doručení.
Odpočítávání začíná pro příjemce po tom, co si zprávu přečtou.
\n\nZprávy, které zmizí jsou označeny ikonou bomby.
\n\nBerte na vědomí, že odesilatelé stále mohou vytvářet kopie vámi odeslaných zpráv.
\n\nPokud změníte tuto volbu, bude použita na vaše nové zprávy okamžitě a na
zprávy vašich kontaktů jakmile obdrží vaši další zprávu.
Váš kontakt také může změnit tuto volbu pro oba z vás.</string>
<string name="learn_more">Zjistit více</string>
<string name="disappearing_messages_summary">Nastavte automatické zmizení zpráv této konverzace po 7\u00A0dnech.</string>
<!--Settings Actions-->
<string name="pref_category_actions">Akce</string>
<string name="send_feedback">Poslat zpětnou vazbu</string>
<!--Link Warning-->
<string name="link_warning_title">Odkaz varování</string>
<string name="link_warning_intro">Chystáte se otevřít následující odkaz pomocí externí eplikace.</string>
<string name="link_warning_text">Toto může být užito pro vaší identifikaci. Přemýšlejte o tom, zda věřujete osobě, která vám poslala tento odkaz, a zvažte, zda ho otevřete s aplikací Orfox.</string>
<string name="link_warning_text">Toto může být použito k vaší identifikaci. Zamyslete se, zda věříte osobě, která vám poslala tento odkaz a zvažte otevření pomocí Prohlížeče Tor.</string>
<string name="link_warning_open_link">Otevřít odkaz</string>
<!--Crash Reporter-->
<string name="crash_report_title">Hlášení o pádu Briar</string>
<string name="briar_crashed">Promiňte, Briar se zhroutil.</string>
<string name="briar_crashed">Omlouváme se, Briar se zhroutil</string>
<string name="not_your_fault">Toto není vaše chyba.</string>
<string name="please_send_report">Vaše pomoc je důležitá. Díky ní můžeme postavit lepší Briar tím, že nám pošlete zprávu o pádu aplikace.</string>
<string name="report_is_encrypted">Slibujeme, že hlášení je zašifrováno a bezpečně odesláno.</string>
@@ -390,29 +737,164 @@
<string name="describe_crash">Popište, co se stalo (nepovinné)</string>
<string name="enter_feedback">Vložte svou zpětnou vazbu</string>
<string name="optional_contact_email">Vaše emailová adresa (nepovinné)</string>
<string name="privacy_policy">Tím, že nám odešlete data, souhlasíte s našimi <a href="">zásadami ochrany osobních údajů</a></string>
<string name="include_debug_report_crash">Zahrnout anonymní data o tomto selhání</string>
<string name="include_debug_report_feedback">Zahrnout anonymní data o tomto zařízení</string>
<string name="could_not_load_report_data">Data hlášení nemohla být načtena.</string>
<string name="dev_report_user_info">Informace o uživateli</string>
<string name="dev_report_basic_info">Základní údaje</string>
<string name="dev_report_device_info">Informace o zařízení</string>
<string name="dev_report_stacktrace">Stacktrace</string>
<string name="dev_report_time_info">Informace o času</string>
<string name="dev_report_memory">Paměť</string>
<string name="dev_report_storage">Úložiště</string>
<string name="dev_report_connectivity">Konektivita</string>
<string name="dev_report_network_usage">Využití sítě</string>
<string name="dev_report_build_config">Konfigurace sestavení</string>
<string name="dev_report_logcat">Log aplikace</string>
<string name="dev_report_device_features">Vlastnosti zařízení</string>
<string name="send_report">Odeslat hlášení</string>
<string name="close">Zavřít</string>
<string name="dev_report_sending">Odesílání zpětné vazby...</string>
<string name="dev_report_sent">Zpětná vazba odeslána</string>
<string name="dev_report_saved">Hlášení uloženo. Odesláno bude při příštím přihlášení do Briar.</string>
<string name="dev_report_error">Chyba: Odesílání hlášení selhalo</string>
<!--Sign Out-->
<string name="progress_title_logout">Odhlásit se z Briar...</string>
<!--Screen Filters & Tapjacking-->
<string name="screen_filter_title">Bylo zjištěno překrytí obrazovky</string>
<string name="screen_filter_body">Jiná aplikace se nachází nad aplikací Briar. Kvůli ochraně vaší bezpečnosti Briar nebude odpovídat na klepnutí prstem pokud jiná aplikace je na popředí.\n\nNásledující aplikace mohou být na popředí:\n\n%1$s</string>
<string name="screen_filter_body_api_30">Jiná aplikace se nachází nad aplikací Briar. Kvůli ochraně vaší bezpečnosti Briar nebude odpovídat na klepnutí prstem pokud jiná aplikace je na popředí.\n\nZkontrolujte níže uvedené aplikace abyste našli dotyčnou aplikaci.</string>
<string name="screen_filter_allow">Povolit těmto aplikacím zůstat navrchu</string>
<string name="screen_filter_review_apps">Zkontrolujte aplikace</string>
<!--Permission Requests-->
<string name="permission_camera_title">Oprávnění pro přístup k fotoaparátu</string>
<string name="permission_camera_request_body">Pro scan QR kódu, Briar vyžaduje přístup k fotoaparátu.</string>
<string name="permission_location_title">Místní povolení</string>
<string name="permission_location_request_body">Aby mohl Briar najít zařízení Bluetooth, potřebuje Briar povolení zjistit vaše umístění.\n\nBriar neukládá vaše umístění ani ho s nikým nesdílí.</string>
<string name="permission_camera_location_title">Fotoaparát a umístění</string>
<string name="permission_camera_location_request_body">Pro oskenování QR kódu potřebuje Briar přístup k fotoaparátu.\n\nPro nalezení zařízení Bluetooth potřebuje Briar povolení zjistit vaše umístění.\n\nBriar neukládá vaše umístění ani ho s nikým nesdílí.</string>
<string name="permission_camera_bluetooth_title">Fotoaparát a zařízení v okolí</string>
<string name="permission_camera_bluetooth_request_body">Pro oskenování QR kódu Briar potřebuje přístup k vašemu fotoaparátu.\n\nPro nalezení Bluetooth zařízení potřebuje Briar povolení přístupu k zařízením v okolí.</string>
<string name="permission_camera_denied_body">Odmítli jste udělit oprávnění přístupu k fotoaparátu, avšak pro přidání kontaktů je nutné použití fotoaparátu.\n\nZvažte prosím, opětovné udělení přístupu.</string>
<string name="permission_location_denied_body">Zamítli jste přístup k umístění ale Briar tento přístup potřebuje k nalezení zařízení Bluetooth.\n\nZvažte povolení přístupu.</string>
<string name="permission_location_setting_title">Volba umístění</string>
<string name="permission_location_setting_body">Volba umístění vašeho zařízení musí být zapnuta aby byla nalezena jiná zařízení přes Bluetooth. Prosím zapněte umístění pro pokračování. Následně ho můžete zase vypnout.</string>
<string name="permission_location_setting_hotspot_body">Volba umístění vašeho zařízení musí být zapnuta aby mohl být vytvořen Wi-Fi hotspot. Prosím zapněte umístění pro pokračování. Následně ho můžete zase vypnout.</string>
<string name="permission_location_setting_button">Zapnout umístění</string>
<string name="permission_bluetooth_title">Povolení pro zařízení v okolí</string>
<string name="permission_bluetooth_body">Pro využití Bluetooth komunikace potřebuje Briar povolení hledat a spojovat se se zařízeními v okolí.</string>
<string name="permission_bluetooth_denied_body">Zamítli jste přístup k zařízením v okolí. Briar ale potřebuje tento přístup pro použití Bluetooth.\n\nProsím zvažte povolení přístupu.</string>
<string name="qr_code">QR kód</string>
<string name="show_qr_code_fullscreen">Zobrazit QR kód na celou obrazovku</string>
<!--App Locking-->
<string name="lock_unlock">Odemknout Briar</string>
<string name="lock_unlock_verbose">K odemknutí aplikace Briar zadejte PIN, vzor nebo heslo vašeho zařízení</string>
<string name="lock_unlock_fingerprint_description">Pro pokračování se dotkněte snímače otisku prstu registrovaným prstem</string>
<string name="lock_unlock_password">Použít heslo</string>
<string name="lock_is_locked">Briar je zamčen</string>
<string name="lock_tap_to_unlock">Klepněte pro odemčení</string>
<!--Connections Screen-->
<string name="transports_help_text">Briar se může připojit k vašim kontaktům pomocí internetu, Wi-Fi nebo Bluetooth.\n\nVšechna internetová spojení jsou kvůli soukromí přenášena sítí Tor.\n\nPokud kontakt může být dosažen pomocí několika metod, Briar je využije zároveň.</string>
<!--Share app offline-->
<string name="hotspot_title">Sdílet tuto aplikaci offline</string>
<string name="hotspot_intro">Sdílejte tuto aplikaci s někým, kdo je v okolí a to bez použití internetu, jen pomocí místní Wi-Fi sítě.
\n\nVáš telefon vytvoří Wi-Fi hotspot. Lidé v okolí se budou moci připojit k hotspotu a stáhnout aplikaci Briar z vašeho telefonu.</string>
<string name="hotspot_button_start_sharing">Spustit hotspot</string>
<string name="hotspot_button_stop_sharing">Zastavit hotspot</string>
<string name="hotspot_progress_text_start">Nastavování hotspotu...</string>
<string name="hotspot_notification_channel_title">Wi-Fi hotspot</string>
<string name="hotspot_notification_title">Sdílení Briaru offline</string>
<string name="hotspot_button_connected">Další</string>
<string name="permission_hotspot_location_request_body">Pro vytvoření Wi-Fi hotspotu potřebuje Briar povolení zjistit vaše umístění.\n\nBriar neukládá vaše umístění ani ho s nikým nesdílí.</string>
<string name="permission_hotspot_location_request_precise_body">Pro vytvoření Wi-Fi hotspotu potřebuje Briar povolení zjistit vaše přesné umístění.\n\nBriar neukládá vaše umístění ani ho s nikým nesdílí.</string>
<string name="permission_hotspot_location_denied_body">Zamítli jste přístup k vašemu umístění. Briar přístup potřebuje, aby mohl vytvořit Wi-Fi hotspot.\n\nProsím zvažte povolení přístupu.</string>
<string name="permission_hotspot_location_denied_precise_body">Zamítli jste přístup k vašemu přesnému umístění. Briar přístup potřebuje, aby mohl vytvořit Wi-Fi hotspot.\n\nProsím zvažte povolení přístupu.</string>
<string name="wifi_settings_title">Wi-Fi volba</string>
<string name="wifi_settings_request_enable_body">Pro vytvoření Wi-Fi hotspotu potřebuje Briar využít Wi-Fi. Prosím zapněte ji.</string>
<string name="hotspot_tab_manual">Manuálně</string>
<!--The placeholder to be inserted into the string 'hotspot_manual_wifi': People can connect by %s-->
<string name="hotspot_scanning_a_qr_code">oskenováním QR kódu</string>
<!--Wi-Fi setup-->
<!--The %s placeholder will be replaced with the translation of 'hotspot_scanning_a_qr_code'-->
<string name="hotspot_manual_wifi">Váš telefon poskytuje Wi-Fi hotspot. Lidé, kteří si chtějí stáhnout Briar se mohou k hotspotu připojit tak, že ho přidají ve Wi-Fi nastavení svého zařízení, za použití údajů uvedených níže a nebo %s. Jakmile se připojí k hotspotu, klikněte na \'Další\'.</string>
<string name="hotspot_manual_wifi_ssid">Název sítě</string>
<string name="hotspot_qr_wifi">Váš telefon poskytuje Wi-Fi hotspot. Lidé, kteří si chtějí stáhnout Briar se mohou k hotspotu připojit tak, že oskenují tento QR kód. Jakmile se připojí k hotspotu, klikněte na \'Další\'.</string>
<string name="hotspot_no_peers_connected">Nejsou připojena žádná zařízení</string>
<plurals name="hotspot_peers_connected">
<item quantity="one">%s zařízení připojeno</item>
<item quantity="few">%s zařízení připojena</item>
<item quantity="many">%s zařízení připojeno</item>
<item quantity="other">%s zařízení připojeno</item>
</plurals>
<!--Download link-->
<!--The %s placeholder will be replaced with the translation of 'hotspot_scanning_a_qr_code'-->
<string name="hotspot_manual_site">Váš telefon poskytuje Wi-Fi hotspot. Lidé, kteří jsou připojeni k hotspotu si mohou stáhnout Briar tak, že zadají následující odkaz do internetového prohlížeče nebo %s.</string>
<string name="hotspot_manual_site_address">Adresa (URL)</string>
<string name="hotspot_qr_site">Váš telefon poskytuje Wi-Fi hotspot. Lidé, kteří jsou připojeni k hotspotu si mohou stáhnout Briar po oskenování tohoto QR kódu.</string>
<!--e.g. Download Briar 1.2.20-->
<string name="website_download_title_1">Stáhnout Briar %s</string>
<string name="website_download_intro_1">Někdo v okolí s vámi sdílel Briar.</string>
<string name="website_download_button">Stáhnout Briar</string>
<string name="website_download_outro">Po tom, co stahování skončí, otevřete stažený soubor a nainstalujte ho.</string>
<string name="website_troubleshooting_title">Odstraňování problémů</string>
<string name="website_troubleshooting_1">Pokud nemůžete aplikaci stáhnout, zkuste použít jiný internetový prohlížeč.</string>
<string name="website_troubleshooting_2_old">Pro instalaci stažené aplikace možná bude nutné v nastavení systému povolit instalaci aplikací z neznámých zdrojů. Následně může být potřeba aplikaci znovu stáhnout. Po instalaci aplikace doporučujeme vypnout zmíněnou volbu neznámých zdrojů.</string>
<string name="website_troubleshooting_2_new">Pro instalaci stažené aplikace možná bude nutné v nastavení internetového prohlížeče povolit instalaci aplikací z neznámých zdrojů. Po instalaci aplikace doporučujeme vypnout zmíněnou volbu instalace neznámých aplikací.</string>
<string name="hotspot_help_wifi_title">Potíže s připojením k Wi-Fi:</string>
<string name="hotspot_help_wifi_1">Zkuste vypnout a zapnout Wi-Fi na obou telefonech a zkusit to znovu.</string>
<string name="hotspot_help_wifi_2">Pokud si váš telefon stěžuje, že Wi-Fi není připojena k internetu, vyberte i tak volbu zachování připojení k Wi-Fi.</string>
<string name="hotspot_help_wifi_3">Restartujte telefon, který provozuje Wi-Fi hotspot. Spusťte Briar a akci opakujte.</string>
<string name="hotspot_help_site_title">Potíže při navštívení místní webové stránky:</string>
<string name="hotspot_help_site_1">Dobře zkontrolujte, že jste zadali adresu přesně tak, jak je zobrazena. Malá chyba může způsobit selhání.</string>
<string name="hotspot_help_site_2">Ujistěte se, že váš telefon je stále připojen ke správně síti Wi-Fi (viz. výše) ve chvíli, kdy se pokoušíte přistoupit na stránku.</string>
<string name="hotspot_help_site_3">Pokud používáte firewall aplikaci, zkontrolujte že neblokuje přístup.</string>
<string name="hotspot_help_site_4">Pokud můžete navštívit stránku, ale stahování aplikace Briar nefunguje, zkuste to s jiným internetovým prohlížečem.</string>
<string name="hotspot_help_fallback_title">Nic nefunguje?</string>
<string name="hotspot_help_fallback_intro">Můžete zkusit uložit aplikaci jako .apk soubor a sdílet i jinými způsoby. Po přenesení souboru na jiné zařízení je možné ho využít k instalaci Briaru.
\n\nTip: Pro sdílení přes Bluetooth může být potřeba nejprve soubor přejmenovat aby končil příponou .zip.</string>
<string name="hotspot_help_fallback_button">Uložit aplikaci</string>
<!--error handling-->
<string name="hotspot_error_intro">Něco se pokazilo při pokusu o sdílení aplikace přes Wi-Fi:</string>
<string name="hotspot_error_no_wifi_direct">Zařízení nepodporuje Wi-Fi Direct</string>
<string name="hotspot_error_start_callback_failed">Hotspot se nespustil: chyba %s</string>
<string name="hotspot_error_start_callback_failed_unknown">Hotspot se nespustil kvůli neznámé chybě, důvod %d</string>
<string name="hotspot_error_start_callback_no_group_info">Spuštění hotspotu selhalo: žádné info skupiny</string>
<string name="hotspot_error_web_server_start">Chyba spuštění web serveru</string>
<string name="hotspot_error_web_server_serve">Chyba představení webové stránky.\n\nPokud problém přetrvává, prosím odešlete zpětnou vazbu (s anonymizovanými daty) pomocí aplikace Briar.</string>
<string name="hotspot_flag_test">Varování: Tato aplikace byla instalována pomocí Android Studia a NEMŮŽE být instalována na jiném zařízení.</string>
<string name="hotspot_error_framework_busy">Nebylo možné spustit hotspot.\n\nPokud máte spuštěný jiný hotspot a nebo sdílíte své internetové připojení pomocí Wi-Fi, zkuste to vypnout a pak akci opakovat.</string>
<!--Transfer Data via Removable Drives-->
<string name="removable_drive_menu_title">Připojit se přes vyměnitelný disk</string>
<string name="removable_drive_intro">Pokud se nemůžete připojit k vašemu kontaktu pomocí internetu, Wi-Fi nebo Bluetooth, Briar může také přenést zprávy na vyměnitelný disk, kterým je například USB klíčenka a nebo SD karta.</string>
<string name="removable_drive_explanation">Pokud se nemůžete připojit k vašemu kontaktu pomocí internetu, Wi-Fi nebo Bluetooth, Briar může také přenést zprávy na vyměnitelný disk, kterým je například USB klíčenka a nebo SD karta.\n\nKdyž použijete tlačítko \"Poslat data\", budou data čekající na odeslání kontaktům, zapsána na vyměnitelný disk. Tato data zahrnují soukromé zprávy, přílohy, blogy, fóra a soukromé skupiny.\n\nVše bude zašifrováno před zapsáním na vyměnitelný disk.\n\nJakmile kontakt obdrží vyměnitelný disk, může použít tlačítko \"Přijmout data\" a tím importovat zprávy do Briaru.</string>
<string name="removable_drive_title_send">Poslat data</string>
<string name="removable_drive_title_receive">Přijmout data</string>
<string name="removable_drive_send_intro">Klepněte na tlačítko níže pro vytvoření nového souboru obsahujícího šifrované zprávy. Můžete si zvolit kam bude soubor uložen.\n\nPokud chcete uložit soubor na vyměnitelný disk, tak ho nyní připojte.</string>
<string name="removable_drive_send_no_data">Nyní zde nejsou žádné zprávy čekající na odeslání tomuto kontaktu.</string>
<string name="removable_drive_send_not_supported">Tento kontakt používá starou verzi Briar a nebo staré zařízení, které nepodporuje tuto funkci.</string>
<string name="removable_drive_send_button">Vyberte soubor k exportu</string>
<string name="removable_drive_ongoing">Prosím čekejte až bude probíhající úloha dokončena</string>
<string name="removable_drive_receive_intro">Klepněte na tlačítko níže pro výběr souboru, který vám zaslal kontakt.\n\nPokud je soubor na vyměnitelném disku, tak disk nyní připojte.</string>
<string name="removable_drive_receive_button">Vyberte soubor k importu</string>
<string name="removable_drive_success_send_title">Export úspěšný</string>
<string name="removable_drive_success_send_text">Data byla úspěšně exportována. Nyní máte 28 dnů na přenos souboru vašemu kontaktu.\n\nPokud je soubor na vyměnitelném disku, použijte oznamovací oblast ve stavovém řádku pro bezpečné odebrání disku před odpojením.</string>
<string name="removable_drive_success_receive_title">Import byl úspěšný</string>
<string name="removable_drive_success_receive_text">Všechny šifrované zprávy obsažené v tomto souboru byly přijaty.</string>
<string name="removable_drive_error_send_title">Chyba při exportu dat</string>
<string name="removable_drive_error_send_text">Došlo k chybě při zápisu dat do souboru.\n\nPokud používáte vyměnitelný disk, ujistěte se že je správně vložen a akci opakujte.\n\nPokud chyba přetrvává, prosím informujte o problému Briar team odesláním zpětné vazby.</string>
<string name="removable_drive_error_receive_title">Chyba importu dat</string>
<string name="removable_drive_error_receive_text">Vybraný soubor neobsahoval nic co by Briar rozpoznal.\n\nProsím zkontrolujte, že jste vybrali správný soubor.\n\nPokud váš kontakt vytvořil soubor před více než 28 dny, Briar ho nebude moci rozpoznat.</string>
<!--Screenshots-->
<!--This is a name to be used in screenshots. Feel free to change it to a local name.-->
<string name="screenshot_alice">Alice</string>
<!--This is a name to be used in screenshots. Feel free to change it to a local name.-->
<string name="screenshot_bob">Tomáš</string>
<!--This is a name to be used in screenshots. Feel free to change it to a local name.-->
<string name="screenshot_carol">Karolína</string>
<!--This is a message to be used in screenshots. Please use the same translation for Bob!-->
<string name="screenshot_message_1">Ahoj Tomáši!</string>
<!--This is a message to be used in screenshots. Please use the same translation for Alice!-->
<string name="screenshot_message_2">Ahoj Alice! Díky, že jsi mi dala vědět o Briaru!</string>
<!--This is a message to be used in screenshots.-->
<string name="screenshot_message_3">V pořádku, doufám že se ti líbí 😀</string>
</resources>

View File

@@ -234,6 +234,7 @@
<string name="exchanging_contact_details">Kontaktdetails werden ausgetauscht\u2026</string>
<string name="contact_added_toast">Kontakt hinzugefügt: %s</string>
<string name="contact_already_exists">Kontakt %s existiert bereits</string>
<string name="contact_already_exists_general">Kontakt existiert bereits</string>
<string name="qr_code_invalid">Der QR-Code ist ungültig</string>
<string name="qr_code_too_old_1">Der QR-Code, den du gescannt hast, kommt von einer älteren Version von Briar.\n\nBitte deinen Kontakt, zur neuesten Version upzudaten, und versuche es erneut.</string>
<string name="qr_code_too_new_1">Der QR-Code, den du gescannt hast, kommt von einer neueren Version.\n\nBitte aktualisiere Briar auf die neueste Version und versuche es erneut.</string>

View File

@@ -443,6 +443,7 @@
<string name="forum_declined_toast">La invitación ha sido rechazada</string>
<string name="shared_by_format">Compartido por %s</string>
<string name="forum_invitation_already_sharing">Ya se está compartiendo</string>
<string name="forum_invitation_already_invited">Invitación ya enviada</string>
<string name="forum_invitation_response_accepted_sent">Aceptaste la invitación al foro de %s.</string>
<string name="forum_invitation_response_declined_sent">Rechazaste la invitación al foro de %s.</string>
<string name="forum_invitation_response_declined_auto">La invitación al foro de %s fue automáticamente rechazada.</string>

View File

@@ -244,6 +244,7 @@
<string name="exchanging_contact_details">تبادیل جزییات مخاطبu2026\</string>
<string name="contact_added_toast">مخاطب اضافه شد: %s</string>
<string name="contact_already_exists">مخاطب %s از قبل وجود دارد</string>
<string name="contact_already_exists_general">مخاطب از قبل وجود دارد</string>
<string name="qr_code_invalid">کد کیوآر نامعتبر می باشد</string>
<string name="qr_code_too_old_1">کد QR که اسکن کرده‌اید مربوط به نسخه قدیمی Briar است.\n\nلطفا از مخاطب خود بخواهید به آخرین نسخه ارتقا دهد و سپس دوباره امتحان کنید.</string>
<string name="qr_code_too_new_1">کد QR که اسکن کرده‌اید مربوط به نسخه جدیدتری از Briar است.\n\nلطفا به آخرین نسخه ارتقا دهید و سپس دوباره امتحان کنید.</string>
@@ -453,6 +454,10 @@
<string name="forum_declined_toast">دعوت نامه رد شد</string>
<string name="shared_by_format">به اشتراک گذاشته شده توسط %s</string>
<string name="forum_invitation_already_sharing">در حال به اشتراک گذاری</string>
<string name="forum_invitation_already_invited">دعوتنامه قبلا ارسال شده است</string>
<string name="forum_invitation_invite_received">دعوتنامه قبلا دریافت شده است</string>
<string name="forum_invitation_not_supported">توسط این مخاطب پشتیبانی نمی‌شود</string>
<string name="forum_invitation_error">خطا. این یک اشکال است و تقصیر شما نیست</string>
<string name="forum_invitation_response_accepted_sent">شما دعوت نامه فروم از %s را پذیرفتید.</string>
<string name="forum_invitation_response_declined_sent">شما دعوت نامه فروم از %s را رد کردید.</string>
<string name="forum_invitation_response_declined_auto">دعوت به تالار از %s به صورت خودکار رد شد.</string>
@@ -509,7 +514,9 @@
<string name="blogs_rss_feeds_import">وارد کردن خوراک RSS</string>
<string name="blogs_rss_feeds_import_button">وارد کردن</string>
<string name="blogs_rss_feeds_import_hint">آدرس خوراک RSS را وارد کنید</string>
<string name="blogs_rss_feeds_import_progress">در حال وارد کردن خوراک RSS…</string>
<string name="blogs_rss_feeds_import_error">متاسفیم! وارد کردن خوراک شما با خطا مواجه شده است.</string>
<string name="blogs_rss_feeds_import_title">وارد کردن خوراک از پرونده</string>
<string name="blogs_rss_feeds">خوراک های RSS</string>
<string name="blogs_rss_feeds_manage_imported">وارد شده:</string>
<string name="blogs_rss_feeds_manage_author">نویسنده:</string>

View File

@@ -243,6 +243,7 @@
<string name="exchanging_contact_details">Scambio dettagli contatto\u2026</string>
<string name="contact_added_toast">Contatto aggiunto: %s</string>
<string name="contact_already_exists">Il contatto %s esiste già</string>
<string name="contact_already_exists_general">Il contatto esiste già</string>
<string name="qr_code_invalid">Il codice QR non è valido</string>
<string name="qr_code_too_old_1">Il codice QR che hai scansionato proviene da una versione più vecchia di Briar.\n\nChiedi al tuo contatto di aggiornare all\'ultima versione e poi riprova.</string>
<string name="qr_code_too_new_1">Il codice QR che hai scansionato proviene da una versione più recente di Briar.\n\nAggiorna all\'ultima versione e poi riprova.</string>

View File

@@ -5,9 +5,9 @@
<string name="setup_name_explanation">あなたのニックネームは、常に、あなたが投稿するコンテンツとともに表示されます。プロフィール作成後、編集はできません。</string>
<string name="setup_next">次へ</string>
<string name="setup_password_intro">パスワードを選択</string>
<string name="setup_password_explanation">Briarのアカウント情報はクラウドではなく、暗号化された端末に保存されます。アプリのアンインストールやパスワードを紛失した場合、アカウントへのアクセスとデータを回復する手段はありません。\n\n推測するのが難しい、長いパスワードを設定してください。ランダムな4単語やランダムな10文字と数字と記号を組み合わせたものなどです。</string>
<string name="setup_password_explanation">Briarのアカウント情報はクラウドではなく、暗号化された端末に保存されます。アプリのアンインストールやパスワードを紛失した場合、アカウントへのアクセスとデータを回復する手段はありません。\n\n推測するのが難しい、長いパスワードを設定してください。無作為な4単語や無作為な10文字と数字と記号を組み合わせたものなどです。</string>
<string name="dnkm_doze_intro">メッセージを受信するために、Briarはバックグラウンドで接続を維持する必要があります。</string>
<string name="dnkm_doze_explanation">メッセージを受信するために、Briarはバックグラウンドで接続を維持する必要があります。 Briarが接続を維持できるように、バッテリーの最適化を無効にしてください。</string>
<string name="dnkm_doze_explanation">メッセージを受信するために、Briarはバックグラウンドで接続を維持する必要があります。 Briarが接続を維持できるように、電池の最適化を無効にしてください。</string>
<string name="choose_nickname">ニックネームを入力</string>
<string name="choose_password">パスワードを入力</string>
<string name="confirm_password">確認のため再度パスワードを入力</string>
@@ -19,13 +19,14 @@
<string name="don_t_ask_again">次からは尋ねない</string>
<string name="dnkm_huawei_protected_text">下のボタンをタップして、「保護されたアプリ」画面で Briarが保護されていることを確認してください。</string>
<string name="dnkm_huawei_protected_button">Briarを保護する</string>
<string name="dnkm_huawei_protected_help">Briarが保護されたアプリのリストに追加されていないと、Briarはバックグラウンドで実行することができません。</string>
<string name="dnkm_huawei_protected_help">Briarが保護されたアプリの一覧に追加されていないと、Briarはバックグラウンドで実行することができません。</string>
<string name="dnkm_huawei_app_launch_text">下のボタンをタップして「アプリの起動」画面を開き、Briarが「手動で管理する」に設定されていることを確認してください。</string>
<string name="dnkm_huawei_app_launch_help">「アプリ起動」画面で Briarを「手動で管理する」に設定していないと、バックグラウンドで動作させることができません。</string>
<string name="dnkm_xiaomi_text">バックグラウンドで実行するには、Briarを最近のアプリのリストにロックする必要があります。</string>
<string name="dnkm_xiaomi_text">バックグラウンドで実行するには、Briarを最近のアプリの一覧にロックする必要があります。</string>
<string name="dnkm_xiaomi_button">Briarを保護する</string>
<string name="dnkm_xiaomi_help">Briarが最近アプリのリストにロックされていないと、バックグラウンドで実行することができません。</string>
<string name="dnkm_xiaomi_dialog_body_old">1. 最近使ったアプリのリスト(アプリスイッチャーともいう)を開いて下さい。\n\n2. Briarの画像を下にスワイプすると、南京錠のアイコンが表示されます。\n\n3. ロックされていない場合は、タップしてロックします。</string>
<string name="dnkm_xiaomi_help">Briarが最近使ったアプリの一覧にロックされていないと、バックグラウンドで実行することができません。</string>
<string name="dnkm_xiaomi_dialog_body_old">1. 最近使ったアプリの一覧(アプリスイッチャーともいう)を開いて下さい。\n\n2. Briarの画像を下にスワイプすると、南京錠のアイコンが表示されます。\n\n3. 南京錠がロックされていない場合は、タップしてロックします。</string>
<string name="dnkm_xiaomi_dialog_body_new">1. 最近使ったアプリの一覧(アプリスイッチャーともいう)を開いて下さい。\n\n2. Briarの名前の隣に南京錠の小さな画像があれば、何もする必要がありません。\n\n3. そこに南京錠がなければ、南京錠ボタンが現れるまでBriarの画像を押し続け、そしてBriarをタップしてください。</string>
<string name="dnkm_warning_dozed_1">Briarはバックグラウンドで実行できませんでした</string>
<!--Login-->
<string name="enter_password">パスワード</string>
@@ -38,31 +39,31 @@
<string name="dialog_message_lost_password">Briarアカウントはクラウド上ではなく、暗号化さた上であなたの端末に保存さています。したがって、Briarはパスワードをリセットできません。アカウントを削除して、はじめからやり直しますか\n\n注意あなたのID、連絡先、メッセージは永久に失われます。</string>
<string name="startup_failed_activity_title">Briarの起動に失敗</string>
<string name="startup_failed_clock_error">お使いの端末の時計が正しくないため、Briarは起動できませんでした。\n\n端末の時計を正しい時刻に設定してから、もう一度試してください。</string>
<string name="startup_failed_db_error">Briarは、あなたのアカウント、連絡先、メッセージを含むデータベースを開くことができませんでした。\n\nアプリを最新版にアップグレードしてもう一度お試しいただくか、パスワード入力画面で「パスワードを忘れました」を選択して新しいアカウントを設定してください。</string>
<string name="startup_failed_data_too_old_error">あなたのアカウントは古いバージョンのアプリで作成されたもので、このバージョンでは開くことができません。\n\n古いバージョンを再インストールするか、パスワード入力画面で\'パスワードを忘れました\'を選択して新しいアカウントを設定する必要があります。</string>
<string name="startup_failed_db_error">Briarは、あなたのアカウント、連絡先、メッセージを含むデータベースを開くことができませんでした。\n\nアプリを最新版にアップグレードしてもう一度お試しいただくか、パスワード入力画面で「パスワードを忘れました」を選択して新アカウントを設定してください。</string>
<string name="startup_failed_data_too_old_error">あなたのアカウントは古いバージョンのアプリで作成されたもので、このバージョンでは開くことができません。\n\n古いバージョンを再インストールするか、パスワード入力画面でパスワードを忘れましたを選択して新アカウントを設定する必要があります。</string>
<string name="startup_failed_data_too_new_error">あなたのアカウントは、このアプリの新しいバージョンで作成されたもので、このバージョンでは開くことができません。\n\n最新版にアップグレードしてから、もう一度試してください。</string>
<string name="startup_failed_service_error">Briarは要求されたコンポーネントを起動できませんでした。\n\nアプリの最新版にアップグレードしてから、もう一度試してください。</string>
<string name="startup_failed_service_error">Briarは必要なコンポーネントを起動できませんでした。\n\nアプリの最新版にアップグレードしてから、もう一度試してください。</string>
<plurals name="expiry_warning">
<item quantity="other">これは、Briarのテストバージョンです。 アカウントはあと%d日で期限切れになり、更新できません。</item>
<item quantity="other">これは、Briarの試験バージョンです。 アカウントはあと%d日で期限切れになり、更新できません。</item>
</plurals>
<plurals name="old_android_expiry_warning">
<item quantity="other">Android 4はサポートされなくなりました。Briarは(%d日後に)%s上での動作を停止します。新しい端末に Briarをインストールして、新しいアカウントを作成してください。</item>
<item quantity="other">Android 4はサポートされなくなりました。Briarは(%d日後に)%s上での動作を停止します。新しい端末に Briarをインストールして、新アカウントを作成してください。</item>
</plurals>
<string name="expiry_date_reached">このソフトウェアの有効期限が切れました。テストに参加してくださりありがとうございます!</string>
<string name="download_briar">Briar使用続けるには、最新のリリースをダウンロードしてください。</string>
<string name="create_new_account">しいアカウントを作成する必要があります。同じニックネームも使用できます。</string>
<string name="expiry_date_reached">このソフトウェアの有効期限が切れました。試験に参加してくださりありがとうございます!</string>
<string name="download_briar">Briar使用続けるには、最新のリリースをダウンロードしてください。</string>
<string name="create_new_account">アカウントを作成する必要があります。同じニックネームも使用できます。</string>
<string name="download_briar_button">最新リリースをダウンロード</string>
<string name="old_android_expiry_date_reached">BriarはAndroid 4では動作しなくなりました。\n新しい端末にBriarをインストールしてください。</string>
<string name="old_android_delete_account">下のボタンをタップして、この端末からあなたのアカウントを削除できます。</string>
<string name="delete_account_button">アカウントを削除</string>
<string name="startup_open_database">データベース復号中…</string>
<string name="startup_open_database">データベース復号中…</string>
<string name="startup_migrate_database">データベースをアップグレード中…</string>
<string name="startup_compact_database">データベース圧縮中…</string>
<string name="startup_compact_database">データベース圧縮中…</string>
<!--Navigation Drawer-->
<string name="nav_drawer_open_description">ナビゲーションを開く</string>
<string name="nav_drawer_close_description">ナビゲーションを閉じる</string>
<string name="nav_drawer_open_description">ナビゲーションドロワーを開く</string>
<string name="nav_drawer_close_description">ナビゲーションドロワーを閉じる</string>
<string name="contact_list_button">連絡先</string>
<string name="groups_button">プライベートグループ</string>
<string name="groups_button">非公開グループ</string>
<string name="forums_button">フォーラム</string>
<string name="blogs_button">ブログ</string>
<!--This is part of the main menu. The app will be locked when this is tapped.-->
@@ -73,41 +74,41 @@
<!--Transports: Tor-->
<string name="transport_tor">インターネット</string>
<string name="tor_device_status_online_wifi">電話機はWi-Fiでインターネットにアクセスできます</string>
<string name="tor_device_status_online_mobile">電話機はモバイル データでインターネットにアクセスできます</string>
<string name="tor_device_status_offline">電話機インターネットに接続できません</string>
<string name="tor_plugin_status_enabling">Briarはインターネットに接続中です</string>
<string name="tor_device_status_online_mobile">電話機はモバイルデータでインターネットにアクセスできます</string>
<string name="tor_device_status_offline">電話機インターネットに接続していません</string>
<string name="tor_plugin_status_enabling">Briarはインターネットに接続中です</string>
<string name="tor_plugin_status_active">Briarはインターネットに接続されました</string>
<string name="tor_plugin_status_inactive">Briarはインターネットに接続できません</string>
<string name="tor_plugin_status_disabled">Briarはインターネットを使用しないように設定されています</string>
<string name="tor_plugin_status_disabled_mobile_data">Briarはモバイルデータを使用しないように設定されています</string>
<string name="tor_plugin_status_disabled_battery">Briarはバッテリー駆動時にインターネットを使用しないように設定されています</string>
<string name="tor_plugin_status_disabled_battery">Briarは電池で動作する時にインターネットを使用しないように設定されています</string>
<string name="tor_plugin_status_disabled_country_blocked">Briarはこの国でインターネットを使わないように設定されています</string>
<!--Transports: Wi-Fi-->
<string name="transport_lan">Wi-Fi</string>
<string name="transport_lan_long">同じ Wi-Fi ネットワーク</string>
<string name="lan_device_status_on">電話機は Wi-Fi に接続されました</string>
<string name="transport_lan_long">同じWi-Fiネットワーク</string>
<string name="lan_device_status_on">電話機はWi-Fiに接続されました</string>
<string name="lan_device_status_off">電話機はWi-Fiに接続されていません</string>
<string name="lan_plugin_status_enabling">BriarはWi-Fiネットワークに接続中です</string>
<string name="lan_plugin_status_enabling">BriarはWi-Fiネットワークに接続中です</string>
<string name="lan_plugin_status_active">BriarはWi-Fiネットワークに接続されました</string>
<string name="lan_plugin_status_inactive">BriarはWi-Fiネットワークに接続できません</string>
<string name="lan_plugin_status_disabled">BriarはWi-Fiネットワークを使用しないように設定されています</string>
<!--Transports: Bluetooth-->
<string name="transport_bt">Bluetooth</string>
<string name="bt_device_status_on">携帯電話の Bluetooth はオンになっています</string>
<string name="bt_device_status_off">携帯電話の Bluetooth はオフにされました</string>
<string name="bt_plugin_status_enabling">BriarはBluetoothに接続中です</string>
<string name="bt_plugin_status_active">BriarはBluetoothに接続ました</string>
<string name="bt_device_status_on">電話機のBluetoothはオンにされました</string>
<string name="bt_device_status_off">電話機のBluetoothはオフにされました</string>
<string name="bt_plugin_status_enabling">BriarはBluetoothに接続中です</string>
<string name="bt_plugin_status_active">BriarはBluetoothに接続されました</string>
<string name="bt_plugin_status_inactive">BriarはBluetoothに接続できません</string>
<string name="bt_plugin_status_disabled">BriarはBluetoothを使用しないように設定されています</string>
<!--Notifications-->
<string name="reminder_notification_title">Briarからサインアウト</string>
<string name="reminder_notification_text">タップして再ログインします。</string>
<string name="reminder_notification_channel_title">Briarサインインリマインダー</string>
<string name="reminder_notification_dismiss"></string>
<string name="reminder_notification_dismiss">退かせ</string>
<string name="ongoing_notification_title">Briarにサインイン</string>
<string name="ongoing_notification_text">Briarを開く</string>
<string name="ongoing_notification_text">触れてBriarを開く</string>
<plurals name="private_message_notification_text">
<item quantity="other">%d件の新規プライベートメッセージ</item>
<item quantity="other">%d件の新規非公開メッセージ</item>
</plurals>
<plurals name="group_message_notification_text">
<item quantity="other">%d件の新規グループメッセージ</item>
@@ -126,8 +127,8 @@
<string name="cancel">キャンセル</string>
<string name="got_it">了解</string>
<string name="delete">削除</string>
<string name="accept">承認</string>
<string name="decline">却下</string>
<string name="accept">受諾</string>
<string name="decline">辞退</string>
<string name="online">オンライン</string>
<string name="offline">オフライン</string>
<string name="send">送信</string>
@@ -137,14 +138,14 @@
<string name="start">開始</string>
<string name="finish">終了</string>
<string name="no_data">データなし</string>
<string name="ellipsis">...</string>
<string name="text_too_long">入力された文章が長すぎます</string>
<string name="ellipsis"></string>
<string name="text_too_long">入力された文章が長すぎます</string>
<string name="show_onboarding">ヘルプダイアログを表示</string>
<string name="fix">修復する</string>
<string name="help">ヘルプ</string>
<string name="sorry">申し訳ありません</string>
<string name="error_start_activity">あなたのシステム上で利用できません</string>
<string name="status_heading">状態</string>
<string name="error_start_activity">あなたのシステム上で利用できません</string>
<string name="status_heading">状態: </string>
<string name="error">エラー</string>
<string name="info">情報</string>
<!--Contacts and Private Conversations-->
@@ -153,14 +154,14 @@
<string name="date_no_private_messages">メッセージがありません。</string>
<string name="no_private_messages">表示するメッセージがありません</string>
<string name="message_hint">新しいメッセージ</string>
<string name="message_hint_auto_delete">しい消えるメッセージ</string>
<string name="message_hint_auto_delete">規の消えるメッセージ</string>
<string name="message_error">メッセージ送信エラー</string>
<string name="image_caption_hint">説明文を追加する(任意)</string>
<string name="image_attach">画像を添付</string>
<string name="image_attach_error">画像を添付できませんでした</string>
<string name="image_attach_error_too_big">画像が大きすぎます。 %dMBが制限です。</string>
<string name="image_attach_error_too_big">画像が大きすぎます。上限は%dMBです。</string>
<string name="image_attach_error_invalid_mime_type">サポートされていない画像形式:%s</string>
<string name="set_contact_alias">連絡先を変更</string>
<string name="set_contact_alias">連絡先を変更</string>
<string name="set_contact_alias_hint">連絡先名</string>
<string name="menu_item_disappearing_messages">消えるメッセージ</string>
<!--The first placeholder will show a duration like "7 days". The second placeholder at the end will add "Tap to learn more."-->
@@ -180,14 +181,14 @@
</plurals>
<!--The first placeholder will show a contact's name. The second placeholder at the end will add "Tap to learn more."-->
<string name="auto_delete_msg_contact_disabled">%1$sのメッセージは消えません。%2$s</string>
<string name="tap_to_learn_more">タップすると詳細が表示されます</string>
<string name="auto_delete_changed_warning_title">消えるメッセージ変更されました</string>
<string name="tap_to_learn_more">タップして詳しく</string>
<string name="auto_delete_changed_warning_title">消えるメッセージ変更ました</string>
<string name="auto_delete_changed_warning_message_enabled">メッセージの作成を開始してから、消えるメッセージが有効になりました。</string>
<string name="auto_delete_changed_warning_message_disabled">メッセージの作成を開始してから、消えるメッセージは無効になりました。</string>
<string name="auto_delete_changed_warning_send">とりあえず送る</string>
<string name="auto_delete_changed_warning_send">それでも送る</string>
<string name="delete_all_messages">全てのメッセージを削除</string>
<string name="dialog_title_delete_all_messages">メッセージの削除時に確認</string>
<string name="dialog_message_delete_all_messages">本当に全てのメッセージを削除してもよろしいですか?</string>
<string name="dialog_message_delete_all_messages">全てのメッセージを削除してもよろしいですか?</string>
<string name="dialog_title_not_all_messages_deleted">全てのメッセージを削除不可能</string>
<string name="dialog_message_not_deleted_ongoing_both">継続中の招待と紹介に関わるメッセージは、終了するまで削除できません。</string>
<string name="dialog_message_not_deleted_ongoing_introductions">継続中の紹介に関わるメッセージは、終了するまで削除できません。</string>
@@ -195,9 +196,9 @@
<string name="dialog_message_not_deleted_not_all_selected_both">招待と紹介を削除するには、要求と応答を選択する必要があります。</string>
<string name="dialog_message_not_deleted_not_all_selected_introductions">紹介を削除するには、要求と応答を選択する必要があります。</string>
<string name="dialog_message_not_deleted_not_all_selected_invitations">招待を削除するには、要求と応答を選択する必要があります。</string>
<string name="delete_contact">この連絡先を削除</string>
<string name="delete_contact">連絡先を削除</string>
<string name="dialog_title_delete_contact">連絡先の削除時に確認</string>
<string name="dialog_message_delete_contact">この連絡先と、この連絡先とのすべてのメッセージを削除してもよろしいですか?</string>
<string name="dialog_message_delete_contact">この連絡先と、この連絡先と交わした全てのメッセージを削除してもよろしいですか?</string>
<string name="contact_deleted_toast">連絡先を削除しました</string>
<!--This is shown in the action bar when opening an image in fullscreen that the user sent-->
<string name="you">あなた</string>
@@ -206,9 +207,9 @@
<string name="dialog_message_save_image">画像を保存すると、他のアプリがその画像にアクセスできるようになります。\n\n保存してもよろしいですか</string>
<string name="save_image_success">画像を保存しました</string>
<string name="save_image_error">画像を保存できませんでした</string>
<string name="dialog_title_no_image_support">利用できない画像です</string>
<string name="dialog_message_no_image_support">あなたのこの連絡先のBriarは画像の添付をまだサポートしていません。連絡先がアップグレードすると、別のアイコンが表示されます。</string>
<string name="dialog_title_image_support">この連絡先に画像を送信できるようになりました</string>
<string name="dialog_title_no_image_support">画像は利用できません</string>
<string name="dialog_message_no_image_support">あなたの連絡先のBriarは画像の添付をまだサポートしていません。連絡先がアップグレードすると、別のアイコンが表示されます。</string>
<string name="dialog_title_image_support">今はこの連絡先に画像を送信できます</string>
<string name="dialog_message_image_support">このアイコンをタップして画像を添付します。</string>
<string name="messaging_too_many_attachments_toast">最初の%d個の画像のみが送信されます。</string>
<string name="menu_contact">連絡先</string>
@@ -216,64 +217,65 @@
<string name="add_contact_title">近くの人を連絡先に追加する</string>
<string name="add_contact_error_two_way">お互いのQRコードを読み取りましたか</string>
<string name="face_to_face">連絡先として追加したい人と会う必要があります。\n\nこれにより、だれかがあなたになりすましたり、メッセージを読んだりするのを防ぐことができます。</string>
<string name="continue_button">ける</string>
<string name="try_again_button">もう一度やり直してください</string>
<string name="waiting_for_contact_to_scan">連絡先がスキャンして接続するのを待っています\u2026</string>
<string name="continue_button"></string>
<string name="try_again_button">再試行</string>
<string name="waiting_for_contact_to_scan">連絡先が読み取って接続するのを待っています\u2026</string>
<string name="exchanging_contact_details">連絡先の詳細を交換しています\ u2026</string>
<string name="contact_added_toast">追加された連絡先:%s</string>
<string name="contact_added_toast">連絡先を追加しました%s</string>
<string name="contact_already_exists">連絡先%sは既に存在しています </string>
<string name="contact_already_exists_general">連絡先は既に存在します </string>
<string name="qr_code_invalid">QRコードが無効です</string>
<string name="qr_code_too_old_1">読み取ったQRコードは、Briarの古いバージョンから生じました。\n\n最新版へアップグレードしてもらって、もう一度お試しください。</string>
<string name="qr_code_too_new_1">読み取ったQRコードは、新しいバージョンのBriarから生じました。\n\n最新版にアップグレードしてから、もう一度お試しください。</string>
<string name="mailbox_qr_code_for_contact">読み取ったQRコードは、Briarメールボックスから生じるものです。\n\nメールボックスに関連付けたいならば、設定を選択してください&gt; Briarメニューからメールボックス</string>
<string name="mailbox_qr_code_for_contact">読み取ったQRコードは、Briarメールボックスから生じました。\n\nメールボックスに関連付けたいならば、設定を選択してください&gt; Briarメニューからメールボックス</string>
<string name="qr_code_format_unknown">読み取ったQRコードは、Briarの連絡先を追加するために示されたものではありません。\n\nあなたの連絡先の画面上に表示されたQRコードを読み取ってください。</string>
<string name="camera_error">カメラエラー</string>
<string name="connecting_to_device">端末に接続中\u2026</string>
<string name="authenticating_with_device">端末同士での認証中\u2026</string>
<string name="connection_error_title">連絡先に接続できませんでした</string>
<string name="connection_error_feedback">この問題が解決しない場合、アプリを改善するために<a href="feedback">フィードバック</a>を送信してください。</string>
<string name="connection_error_feedback">この問題が解決しない場合、アプリを改善するために<a href="feedback">フィードバックを送信</a>してください。</string>
<string name="info_both_must_scan">お互いのQRコードを読み取る必要があります</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">離れた場所にいる相手を連絡先に追加</string>
<string name="add_contact_nearby_title">近くにいる相手を連絡先に追加</string>
<string name="add_contact_remotely_title">離れた場所にいる相手を連絡先に追加</string>
<string name="contact_link_intro">連絡相手のリンクをここに入力してください</string>
<string name="contact_link_hint">連絡相手のリンク</string>
<string name="add_contact_remotely_title_case">離れた場所にいるを連絡先に追加</string>
<string name="add_contact_nearby_title">近くにいるを連絡先に追加</string>
<string name="add_contact_remotely_title">離れた場所にいるを連絡先に追加</string>
<string name="contact_link_intro">連絡のリンクをここに入力してください</string>
<string name="contact_link_hint">連絡のリンク</string>
<string name="paste_button">貼り付け</string>
<string name="add_contact_button">連絡相手を追加</string>
<string name="add_contact_button">連絡を追加</string>
<string name="copy_button">コピー</string>
<string name="share_button">共有</string>
<string name="send_link_title">リンク交換</string>
<string name="send_link_title">リンク交換</string>
<string name="add_contact_choose_nickname">ニックネームを選んでください</string>
<string name="add_contact_choose_a_nickname">ニックネームを入力してください</string>
<string name="nickname_intro">この連絡相手にニックネームを付けます。 あなただけがそれを見ることができます。</string>
<string name="your_link">リンクを共有する連絡相手を追加する</string>
<string name="nickname_intro">この連絡にニックネームを付けます。 あなただけがそれを見ることができます。</string>
<string name="your_link">追加したい連絡先にこのリンクを渡す</string>
<string name="link_clip_label">Briarリンク</string>
<string name="link_copied_toast">リンクをコピーしました</string>
<string name="adding_contact_error">連絡先への追加中にエラーが発生しました。</string>
<string name="adding_contact_error">連絡先追加中にエラーが発生しました。</string>
<string name="pending_contact_requests_snackbar">保留中の連絡先への追加要求があります</string>
<string name="pending_contact_requests">連絡先追加要求</string>
<string name="no_pending_contacts">保留中の連絡先追加リクエストはありません</string>
<string name="waiting_for_contact_to_come_online">連絡相手がオンラインになるのを待っています…</string>
<string name="no_pending_contacts">保留中の連絡先追加要求はありません</string>
<string name="waiting_for_contact_to_come_online">連絡がオンラインになるのを待っています…</string>
<string name="connecting">接続中…</string>
<string name="adding_contact">連絡先を追加しています…</string>
<string name="adding_contact_failed">連絡先の追加に失敗しました</string>
<string name="dialog_title_remove_pending_contact">削除の確認</string>
<string name="dialog_message_remove_pending_contact">この連絡先はまだ追加中です。 今削除すると、追加されません。</string>
<string name="own_link_error">あなたのリンクではなく連絡先のリンクを入力してください</string>
<string name="own_link_error">あなたのリンクではなく連絡先のリンクを入力してください</string>
<string name="nickname_missing">ニックネームを入力してください</string>
<string name="invalid_link">無効なリンク</string>
<string name="unsupported_link">このリンクはBriarの新しいバージョンからのものです。 最新版にアップグレードしてから、もう一度試してください。</string>
<string name="intent_own_link">あなたのBriar自身を指すリンクを開きました。 別の追加したい連絡先を使用してください!</string>
<string name="unsupported_link">このリンクはBriarの新しいバージョンからのものです。 最新版にアップグレードしてから、もう一度試してください。</string>
<string name="intent_own_link">あなた自身のリンクを開きました。追加したい連絡先のリンクを使用してください!</string>
<string name="missing_link">リンクを入力してください</string>
<!--This is a numeral indicating the first step in a series of screens-->
<string name="step_1">1</string>
<!--This is a numeral indicating the second step in a series of screens-->
<string name="step_2">2</string>
<plurals name="contact_added_notification_text">
<item quantity="other">%d 新しい連絡先が追加されました。</item>
<item quantity="other">%d件の新規連絡先が追加されました。</item>
</plurals>
<string name="offline_state">インターネット接続されていません</string>
<string name="offline_state">インターネット接続なし</string>
<string name="duplicate_link_dialog_title">重複リンク</string>
<string name="duplicate_link_dialog_text_1">既に保留中の連絡先があります。リンク:%s</string>
<string name="duplicate_link_dialog_text_1_contact">既に連絡先があります。リンク:%s</string>
@@ -286,8 +288,8 @@
<!--This is a button for answering that two nicknames refer to different people. This string
will be used in a dialog button, so if the translation of this string longer than 20 characters,
please use "No" instead, and use "Yes" for the "Same Person" button-->
<string name="different_person_button"></string>
<string name="duplicate_link_dialog_text_3">%1$sと%2$sから同じリンクを信しました。\n\nどちらかがあなたの連絡先の内容を知ろうとしている可能性があります。\n\n他の人から同じリンクを受け取ったことを伝えないでください。</string>
<string name="different_person_button">別人</string>
<string name="duplicate_link_dialog_text_3">%1$sと%2$sがあなたに同じリンクを信しました。\n\nどちらかがあなたの連絡先が誰であるかを探ろうとしている可能性があります。\n\n同じリンクを他の人から受信したとは言わないでください。</string>
<string name="pending_contact_updated_toast">保留中の連絡先が更新されました</string>
<string name="info_both_must_enter_links">お互いのリンクを追加する必要があります</string>
<!--Peer trust levels-->
@@ -298,53 +300,53 @@
<!--Introductions-->
<string name="introduction_onboarding_title">連絡先を紹介</string>
<string name="introduction_onboarding_text">連絡先をお互いに紹介することで、Briarで繋がることができます。</string>
<string name="introduction_menu_item">はじめに</string>
<string name="introduction_menu_item">紹介する</string>
<string name="introduction_activity_title">連絡先を選択</string>
<string name="introduction_not_possible">これらの連絡先については、すでに1つの紹介が進行中です。 これが最初に完了するようにしてください。 あなたやあなたの連絡相手がめったにオンラインにならない場合、これには時間がかかることがあります。</string>
<string name="introduction_not_possible">これらの連絡先、すでに1つの紹介が進行中です。最初にこれを終了するため、これを許可してください。 あなたやあなたの連絡相手が滅多にオンラインにならない場合、時間がかかることがあります。</string>
<string name="introduction_message_title">連絡相手を紹介する</string>
<string name="introduction_message_hint">メッセージを追加する(任意)</string>
<string name="introduction_button">はじめに</string>
<string name="introduction_sent">こちらの構成情報を送信しました。</string>
<string name="introduction_error">構成情報の作成中にエラーが発生しました。</string>
<string name="introduction_button">紹介する</string>
<string name="introduction_sent">紹介は送信されました。</string>
<string name="introduction_error">紹介中にエラーが発生しました。</string>
<string name="introduction_request_sent">%1$sを%2$sに追加するように要求しました。</string>
<string name="introduction_request_received">%1$sから%2$sへの紹介を求められました。 連絡先リストに%2$sを追加しますか</string>
<string name="introduction_request_exists_received">%1$sから%2$sの紹介を求められましたが、%2$sは既に連絡先リストにあります。%1$sはそれを知らない可能性があるため、引き続き応じれます</string>
<string name="introduction_request_received">%1$sから%2$sへの紹介を求められました。 連絡先一覧に%2$sを追加しますか</string>
<string name="introduction_request_exists_received">%1$sから%2$sの紹介を求められましたが、%2$sは既に連絡先一覧にあります。%1$sはそれを知らない可能性があるため、引き続き応じれます</string>
<string name="introduction_request_answered_received">%1$sから%2$sへの紹介を求められました。</string>
<string name="introduction_response_accepted_sent">%1$sの紹介を受け入れました。</string>
<string name="introduction_response_accepted_sent_info">%1$sを連絡先に追加する前に、紹介を受け入れる必要があります。 これには時間がかかる場合があります。</string>
<string name="introduction_response_accepted_sent">%1$sの紹介を受諾しました。</string>
<string name="introduction_response_accepted_sent_info">%1$sを連絡先に追加する前に、紹介を受諾する必要があります。 これには時間がかかる場合があります。</string>
<string name="introduction_response_declined_sent">%1$sへの紹介を辞退しました。</string>
<string name="introduction_response_declined_auto">%1$sへの紹介は自動的に辞退されました。</string>
<string name="introduction_response_accepted_received">%1$sは%2$sの紹介を受け入れました。</string>
<string name="introduction_response_accepted_received">%1$sは%2$sの紹介を受諾しました。</string>
<string name="introduction_response_declined_received">%1$sは%2$sへの紹介を辞退しました。</string>
<string name="introduction_response_declined_received_by_introducee">%1$sによると、%2$sが紹介を辞退しました。</string>
<!--Connect via Bluetooth-->
<string name="menu_item_connect_via_bluetooth">Bluetooth経由で接続する</string>
<string name="connect_via_bluetooth_title">Bluetooth経由で接続する</string>
<string name="connect_via_bluetooth_intro">Bluetooth接続が自動的に行われない場合は、この画面を使って手動で接続することができます。\n\nこの機能を利用するには、あなたの連絡先が近くにある必要があります。\n\nあなたと連絡先が同時に\"開始\"を押してください。</string>
<string name="connect_via_bluetooth_intro">Bluetooth接続が自動的に行われない場合は、この画面を使って手動で接続することができます。\n\nこの機能を利用するには、あなたの連絡先が近くにある必要があります。\n\nあなたと連絡先が同時に「開始」を押してください。</string>
<string name="connect_via_bluetooth_already_discovering">既にBluetooth経由での接続を試行中です。すぐに再試行してください。</string>
<string name="connect_via_bluetooth_no_location_permission">位置情報の権限なくして続行不可能</string>
<string name="connect_via_bluetooth_no_bluetooth_permission">付近の端末の権限なくして続行不可能</string>
<string name="connect_via_bluetooth_start">Bluetooth経由で接続中…</string>
<string name="connect_via_bluetooth_success">Bluetooth経由で接続に成功</string>
<string name="connect_via_bluetooth_error">Bluetooth経由で接続不可能。</string>
<string name="connect_via_bluetooth_success">Bluetooth経由で接続に成功</string>
<string name="connect_via_bluetooth_error">Bluetooth経由で接続不可能。</string>
<string name="connect_via_bluetooth_error_not_supported">Bluetoothは端末によってサポートされていません。</string>
<!--Private Groups-->
<string name="groups_list_empty">表示するグループがありません</string>
<string name="groups_list_empty_action">「+」アイコンをタップしてグループを作成するか、連絡先に登録している誰かにグループを共有してもらう</string>
<string name="groups_created_by">%sによって作成されました。</string>
<string name="groups_created_by">%sが作成</string>
<plurals name="messages">
<item quantity="other">%dのメッセージ</item>
<item quantity="other">%dのメッセージ</item>
</plurals>
<string name="groups_group_is_empty">このグループは空です</string>
<string name="groups_group_is_dissolved">このグループは解散しました</string>
<string name="groups_remove">削除</string>
<string name="groups_create_group_title">プライベートグループ作成</string>
<string name="groups_create_group_title">非公開グループ作成</string>
<string name="groups_create_group_button">グループ作成</string>
<string name="groups_create_group_invitation_button">招待を送信</string>
<string name="groups_create_group_hint">プライベートグループに名前をつける</string>
<string name="groups_create_group_hint">非公開グループに名前をつける</string>
<string name="groups_invitation_sent">グループ招待状が送信されました</string>
<string name="groups_member_list">メンバー一覧</string>
<string name="groups_invite_members">メンバーを招待</string>
<string name="groups_member_list">人員一覧</string>
<string name="groups_invite_members">一員を招待</string>
<string name="groups_member_created_you">グループを作成しました</string>
<string name="groups_member_created">%sがグループを作成しました</string>
<string name="groups_member_joined_you">グループに参加しました</string>
@@ -352,14 +354,14 @@
<string name="groups_leave">グループを脱退</string>
<string name="groups_leave_dialog_title">グループをやめる確認</string>
<string name="groups_leave_dialog_message">このグループを脱退してもよろしいですか?</string>
<string name="groups_dissolve">グループを削除</string>
<string name="groups_dissolve_dialog_title">グループの削除の確認</string>
<string name="groups_dissolve_dialog_message">このグループを削除してもよろしいですか?\n\nグループを削除すると、他のすべてのメンバーは会話を続けることができなくなり、最新のメッセージは受信できなくなります。</string>
<string name="groups_dissolve_button">削除</string>
<string name="groups_dissolved_dialog_title">グループを削除しました</string>
<string name="groups_dissolved_dialog_message">このグループの作成者はこのグループを削除しました。\n\nそのため、書き込まれたすべてのメンバーは会話を続けることができなくなり、最新のメッセージも受信できなくなりました</string>
<string name="groups_dissolve">グループを解散</string>
<string name="groups_dissolve_dialog_title">グループ解散の確認</string>
<string name="groups_dissolve_dialog_message">このグループを解散してもよろしいですか?\n\n他の全人員は会話を続けることができなくなり、最新のメッセージは受信できなくなります。</string>
<string name="groups_dissolve_button">解散</string>
<string name="groups_dissolved_dialog_title">グループは解散されました</string>
<string name="groups_dissolved_dialog_message">このグループの作成者はグループを解散しました。\n\nもうグループにはメッセージを書けなくなり、過去に書かれた全ての投稿は受信できなくなる可能があります</string>
<!--Private Group Invitations-->
<string name="groups_invitations_title">グループ招待</string>
<string name="groups_invitations_title">グループ招待</string>
<string name="groups_invitations_invitation_sent">%1$sをグループ\"%2$s\"に招待しています。</string>
<string name="groups_invitations_invitation_received">%1$sがあなたをグループ\"%2$s\"に招待しています。</string>
<string name="groups_invitations_joined">グループに参加しました</string>
@@ -367,39 +369,39 @@
<plurals name="groups_invitations_open">
<item quantity="other">%d個のオープングループへの招待</item>
</plurals>
<string name="groups_invitations_response_accepted_sent">%sからのグループ招待を受け入れました。</string>
<string name="groups_invitations_response_accepted_sent">%sからのグループ招待を受諾しました。</string>
<string name="groups_invitations_response_declined_sent">%sからのグループへの招待を辞退しました。</string>
<string name="groups_invitations_response_declined_auto">%sからのグループへの招待は自動的に辞退されました。</string>
<string name="groups_invitations_response_accepted_received">%sはグループへの招待を受け入れました。</string>
<string name="groups_invitations_response_accepted_received">%sはグループへの招待を受諾しました。</string>
<string name="groups_invitations_response_declined_received">%sはグループへの招待を辞退しました。</string>
<string name="sharing_status_groups">グループに新しいメンバーを招待できるのは作成者のみです。 以下は、グループの現在の全員のメンバーです。</string>
<string name="sharing_status_groups">グループに新規人員を招待できるのは作成者のみです。 以下は、グループの現在の全員です。</string>
<!--Private Groups Revealing Contacts-->
<string name="groups_reveal_contacts">連絡先を公開する</string>
<string name="groups_reveal_dialog_message">このグループの現在および将来のすべてのメンバーに連絡先を公開するかどうかを選択できます。\n\n連絡先を公開すると、グループの作成者がオフラインの場合でも公開された連絡先と通信できるため、グループへの接続がより高速で信頼性が高くなります。</string>
<string name="groups_reveal_visible">連絡先関係はグループに表示されます</string>
<string name="groups_reveal_visible_revealed_by_us">連絡先の関係はグループに表示されます(あなたによって公開されました)</string>
<string name="groups_reveal_visible_revealed_by_contact">連絡先の関係はグループに表示されます(%sによって公開されました)</string>
<string name="groups_reveal_contacts">連絡先を明かす</string>
<string name="groups_reveal_dialog_message">このグループの現在および将来の全人員に連絡先を明かすかどうかを選択できます。\n\n連絡先を明かすと、グループの作成者がオフラインの場合でも明かされた連絡先と通信できるため、グループへの接続がより高速で信頼性が高くなります。</string>
<string name="groups_reveal_visible">連絡先関係はグループに表示されます</string>
<string name="groups_reveal_visible_revealed_by_us">連絡先の関係はグループに表示されます(あなたによって明かされました)</string>
<string name="groups_reveal_visible_revealed_by_contact">連絡先の関係はグループに表示されます(%sによって明かされました)</string>
<string name="groups_reveal_invisible">連絡先の関係はグループには表示されません</string>
<!--Forums-->
<string name="no_forums">表示するフォーラムがありません</string>
<string name="no_forums_action">「+」アイコンをタップしてフォーラムを作成するか、連絡先に登録している誰かにフォーラムを共有してもらいます</string>
<string name="create_forum_title">フォーラム作成</string>
<string name="create_forum_title">フォーラム作成</string>
<string name="choose_forum_hint">フォーラムの名前を選択してください</string>
<string name="create_forum_button">フォーラムを作成</string>
<string name="forum_created_toast">フォーラムが作成されました</string>
<string name="no_forum_posts">表示する投稿がありません</string>
<string name="no_posts">投稿なし</string>
<plurals name="posts">
<item quantity="other">%dの投稿</item>
<item quantity="other">%dの投稿</item>
</plurals>
<string name="forum_new_message_hint">新しい投稿</string>
<string name="forum_message_reply_hint">新しい返信</string>
<string name="btn_reply">返信</string>
<string name="forum_leave">フォーラムを脱退</string>
<string name="dialog_title_leave_forum">フォーラムをやめる確認</string>
<string name="dialog_message_leave_forum">このフォーラムを脱退してもよろしいですか?\n\nこのフォーラムで共有した連絡先は更新の受信を停止します。</string>
<string name="dialog_title_leave_forum">フォーラム脱退の確認</string>
<string name="dialog_message_leave_forum">このフォーラムを脱退してもよろしいですか?\n\nこのフォーラムで共有した連絡先は更新の受信を停止します。</string>
<string name="dialog_button_leave">脱退</string>
<string name="forum_left_toast">フォーラムをやめました</string>
<string name="forum_left_toast">フォーラムを脱退しました</string>
<!--Forum Sharing-->
<string name="forum_share_button">フォーラムを共有</string>
<string name="contacts_selected">選択した連絡先</string>
@@ -411,8 +413,8 @@
<string name="forum_share_error">このフォーラムの共有中にエラーが発生しました。</string>
<string name="forum_invitation_received">%1$sがフォーラム\"%2$s\"をあなたと共有しました。</string>
<string name="forum_invitation_sent">フォーラム\"%1$s\"を%2$sと共有しました。</string>
<string name="forum_invitations_title">フォーラムへの招待</string>
<string name="forum_invitation_exists">既にこのフォーラムへの招待を受け入れています。\n\n招待をさらに受け入れると、フォーラムへの接続がより速く、より信頼できるものになります。</string>
<string name="forum_invitations_title">フォーラム招待</string>
<string name="forum_invitation_exists">既にこのフォーラムへの招待を受諾しています。\n\n招待をさらに受け入れると、フォーラムへの接続がより速く、より信頼できるものになります。</string>
<string name="forum_joined_toast">フォーラムに参加しました</string>
<string name="forum_declined_toast">招待を辞退しました</string>
<string name="shared_by_format">%sによって共有されました。</string>
@@ -421,13 +423,13 @@
<string name="forum_invitation_invite_received">招待は既に受信されました</string>
<string name="forum_invitation_not_supported">この連絡先によってサポートされていません</string>
<string name="forum_invitation_error">エラー。これはバグか、そうでなければ、あなたの誤りです</string>
<string name="forum_invitation_response_accepted_sent">%sからのフォーラムへの招待を受け入れました。</string>
<string name="forum_invitation_response_accepted_sent">%sからのフォーラムへの招待を受諾しました。</string>
<string name="forum_invitation_response_declined_sent">%sからのフォーラムへの招待を辞退しました。</string>
<string name="forum_invitation_response_declined_auto">%sからのフォーラムへの招待は自動的に辞退されました。</string>
<string name="forum_invitation_response_accepted_received">%sはフォーラムへの招待を受け入れました。</string>
<string name="forum_invitation_response_accepted_received">%sはフォーラムへの招待を受諾しました。</string>
<string name="forum_invitation_response_declined_received">%sはフォーラムへの招待を辞退しました。</string>
<string name="sharing_status">共有ステータス</string>
<string name="sharing_status_forum">フォーラムのメンバーは誰でも連絡先と共有できます。 このフォーラムを次の連絡先と共有しています。 他のメンバーが表示されない場合もあります。</string>
<string name="sharing_status">共有状況</string>
<string name="sharing_status_forum">フォーラムは誰でも連絡先と共有できます。 このフォーラムを次の連絡先と共有しています。 他の人員が表示されない場合もあります。</string>
<string name="shared_with">%1$dと共有%2$d オンライン)</string>
<plurals name="forums_shared">
<item quantity="other">連絡先に登録している人が共有している%dフォーラム</item>
@@ -440,30 +442,30 @@
<string name="blogs_write_blog_post_body_hint">ブログの投稿内容を入力してください</string>
<string name="blogs_publish_blog_post">公開</string>
<string name="blogs_blog_post_created">ブログ投稿が作成されました</string>
<string name="blogs_blog_post_received">しいブログ投稿を受け取りました</string>
<string name="blogs_blog_post_received">ブログ投稿を受信しました</string>
<string name="blogs_blog_post_scroll_to">スクロール:</string>
<string name="blogs_feed_empty_state">表示する投稿がありません</string>
<string name="blogs_feed_empty_state_action">登録している連絡先やブログからの投稿がここに表示されます\n\nペンアイコンをタップして投稿を書き込みます</string>
<string name="blogs_remove_blog">ブログを削除</string>
<string name="blogs_remove_blog_dialog_message">このブログを削除してもよろしいですか?\n\n投稿は端末から削除されますが、他の人の端末からは削除されません。\n\nこのブログを共有した人に更新の受信を停止します。</string>
<string name="blogs_remove_blog_ok"></string>
<string name="blogs_remove_blog_ok"></string>
<string name="blogs_blog_removed">ブログを削除しました</string>
<string name="blogs_reblog_comment_hint">コメントを追加する(任意)</string>
<string name="blogs_reblog_button">ブログ</string>
<string name="blogs_reblog_button">ブログ再掲</string>
<!--Blog Sharing-->
<string name="blogs_sharing_share">ブログを共有</string>
<string name="blogs_sharing_error">このブログ共有中にエラーが発生しました。</string>
<string name="blogs_sharing_error">このブログ共有中にエラーが発生しました。</string>
<string name="blogs_sharing_button">ブログを共有</string>
<string name="blogs_sharing_snackbar">選択した連絡先と共有するブログ</string>
<string name="blogs_sharing_response_accepted_sent">%sからのブログへの招待を受け入れました。</string>
<string name="blogs_sharing_response_accepted_sent">%sからのブログへの招待を受諾しました。</string>
<string name="blogs_sharing_response_declined_sent">%sからのブログへの招待を辞退しました。</string>
<string name="blogs_sharing_response_declined_auto">%sからのブログへの招待は自動的に辞退されました。</string>
<string name="blogs_sharing_response_accepted_received">%sはブログへの招待を受け入れました。</string>
<string name="blogs_sharing_response_accepted_received">%sはブログへの招待を受諾しました。</string>
<string name="blogs_sharing_response_declined_received">%sはブログへの招待を辞退しました。</string>
<string name="blogs_sharing_invitation_received">%1$sがブログ\"%2$s\"をあなたと共有しました。</string>
<string name="blogs_sharing_invitation_sent">ブログ\"%1$s\"を%2$sと共有しました。</string>
<string name="blogs_sharing_invitations_title">ブログへの招待</string>
<string name="blogs_sharing_joined_toast">ブログ購読</string>
<string name="blogs_sharing_invitations_title">ブログ招待</string>
<string name="blogs_sharing_joined_toast">ブログ購読</string>
<string name="blogs_sharing_declined_toast">招待を辞退しました</string>
<string name="sharing_status_blog">ブログを購読している人は誰でも、ブログを連絡先と共有できます。 このブログを次の連絡先と共有しています。 表示できない他の購読者もいる可能性があります。</string>
<!--RSS Feeds-->
@@ -479,7 +481,7 @@
<string name="blogs_rss_feeds_manage_updated">最終更新:</string>
<string name="blogs_rss_remove_feed">フィードを削除</string>
<string name="blogs_rss_remove_feed_dialog_message">このフィードを削除してもよろしいですか?\n\n投稿は端末から削除されますが、他の人の端末からは削除されません。\n\nこのフィードを共有した人は更新の受信を停止されます。</string>
<string name="blogs_rss_remove_feed_ok"></string>
<string name="blogs_rss_remove_feed_ok"></string>
<string name="blogs_rss_feeds_manage_empty_state">表示するRSSフィードはありません\n\n「」アイコンをタップしてフィードをインポートします</string>
<string name="blogs_rss_feeds_manage_error">フィードの読み込み中に問題が発生しました。 後でもう一度やり直してください。</string>
<!--Settings Profile Picture-->
@@ -493,14 +495,14 @@
<string name="pref_language_default">システムのデフォルト</string>
<string name="display_settings_title">表示</string>
<string name="pref_theme_title">テーマ</string>
<string name="pref_theme_light">ライト</string>
<string name="pref_theme_dark">ダーク</string>
<string name="pref_theme_light"></string>
<string name="pref_theme_dark"></string>
<string name="pref_theme_auto">自動(昼間)</string>
<string name="pref_theme_system">システムのデフォルト</string>
<!--Settings Connections-->
<string name="network_settings_title">接続</string>
<string name="bluetooth_setting">Bluetooth経由で連絡先に接続</string>
<string name="wifi_setting">同じ Wi-Fi ネットワークで連絡先に接続</string>
<string name="wifi_setting">同じWi-Fiネットワークで連絡先に接続</string>
<string name="tor_enable_title">インターネット経由で連絡先に接続</string>
<string name="tor_enable_summary">全接続をプライバシーのためにTorネットワークを通す</string>
<string name="tor_network_setting">Torネットワークの接続方法</string>
@@ -512,7 +514,7 @@
<string name="tor_network_setting_summary">自動:%1$s%2$s内</string>
<string name="tor_mobile_data_title">モバイルデータを使用する</string>
<string name="tor_only_when_charging_title">充電時にのみインターネットに接続する</string>
<string name="tor_only_when_charging_summary">端末がバッテリーを使用している場合、インターネット接続を無効にする</string>
<string name="tor_only_when_charging_summary">端末が電池で動作する時に、インターネット接続を無効にする</string>
<!--Settings Security and Panic-->
<string name="security_settings_title">セキュリティ</string>
<string name="pref_lock_title">アプリロック</string>
@@ -522,25 +524,25 @@
<!--The %s placeholder is replaced with the following time spans, e.g. 5 Minutes, 1 Hour-->
<string name="pref_lock_timeout_summary">Briarを使用しない場合、%s後に自動的にロックします</string>
<!--Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s"-->
<string name="pref_lock_timeout_1">1 </string>
<string name="pref_lock_timeout_1">1分</string>
<!--Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s"-->
<string name="pref_lock_timeout_5">5 </string>
<string name="pref_lock_timeout_5">5分</string>
<!--Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s"-->
<string name="pref_lock_timeout_15">15分</string>
<!--Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s"-->
<string name="pref_lock_timeout_30">30分</string>
<!--Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s"-->
<string name="pref_lock_timeout_60">1時間</string>
<string name="pref_lock_timeout_never">ない</string>
<string name="pref_lock_timeout_never">行わない</string>
<string name="pref_lock_timeout_never_summary">Briarを自動的にロックしない</string>
<string name="change_password">パスワード変更</string>
<string name="change_password">パスワード変更</string>
<string name="current_password">現在のパスワード</string>
<string name="choose_new_password">しいパスワード</string>
<string name="confirm_new_password">しいパスワード確認</string>
<string name="choose_new_password">パスワード</string>
<string name="confirm_new_password">パスワード確認</string>
<string name="password_changed">パスワードが変更されました。</string>
<string name="panic_setting">パニックボタンセットアップ</string>
<string name="panic_setting">パニックボタンセットアップ</string>
<string name="panic_setting_title">パニックボタン</string>
<string name="panic_setting_hint">パニックボタンアプリを使用したときのBriarの反応を構成する</string>
<string name="panic_setting_hint">パニックボタンアプリを使用したときのBriarの反応を設定する</string>
<string name="panic_app_setting_title">パニックボタンアプリ</string>
<string name="unknown_app">未知のアプリ</string>
<string name="panic_app_setting_summary">アプリが設定されていません</string>
@@ -556,9 +558,9 @@
<string name="notification_settings_title">通知</string>
<string name="notify_sign_in_title">サインインするように通知する</string>
<string name="notify_sign_in_summary">電話機の起動時またはアプリの更新時にリマインダーを表示する</string>
<string name="notify_private_messages_setting_title">プライベート・メッセージ</string>
<string name="notify_private_messages_setting_summary">プライベートメッセージのアラートを表示する</string>
<string name="notify_private_messages_setting_summary_26">プライベートメッセージのアラートを設定する</string>
<string name="notify_private_messages_setting_title">非公開メッセージ</string>
<string name="notify_private_messages_setting_summary">非公開メッセージのアラートを表示する</string>
<string name="notify_private_messages_setting_summary_26">非公開メッセージのアラートを設定する</string>
<string name="notify_group_messages_setting_title">グループメッセージ</string>
<string name="notify_group_messages_setting_summary">グループメッセージのアラートを表示する</string>
<string name="notify_group_messages_setting_summary_26">グループメッセージのアラートを設定する</string>
@@ -568,7 +570,7 @@
<string name="notify_blog_posts_setting_title">ブログ投稿</string>
<string name="notify_blog_posts_setting_summary">ブログ投稿のアラートを表示する</string>
<string name="notify_blog_posts_setting_summary_26">ブログ投稿のアラートを設定する</string>
<string name="notify_vibration_setting">バイブレーション</string>
<string name="notify_vibration_setting">振動</string>
<string name="notify_sound_setting"></string>
<string name="notify_sound_setting_default">デフォルト着信音</string>
<string name="notify_sound_setting_disabled">なし</string>
@@ -576,11 +578,11 @@
<string name="cannot_load_ringtone">着信音を読み込めません</string>
<!--Mailbox-->
<string name="mailbox_settings_title">メールボックス</string>
<string name="mailbox_setup_title">メールボックスセットアップ</string>
<string name="mailbox_setup_title">メールボックスセットアップ</string>
<string name="mailbox_setup_intro">メールボックスはあなたがオフラインの間、連絡先があなたにメッセージを送信することを有効にします。メールボックスはあなたがオンラインになるまで、メッセージを受信し保管します。\n
\n予備端末上にBriarのメールボックスアプリをインストールできます。それを電源とWi-Fiに接続し、常時オンラインにしてください。</string>
<string name="mailbox_setup_download">最初に、Google PlayまたはBriarをダウンロードしたどこかで\"BriarMailbox\"を検索して、他の端末上にメールボックスアプリをインストールします。\n
\nそして、メールボックスアプリによって表示されるQRコードを読み取って、Briarとあなたのメールボックス結びつけます。</string>
<string name="mailbox_setup_download">最初に、Google PlayまたはBriarをダウンロードしたどこかでBriarMailboxを検索して、他の端末上にメールボックスアプリをインストールします。\n
\nそして、メールボックスアプリによって表示されるQRコードを読み取って、Briarとあなたのメールボックスをリンクします。</string>
<string name="mailbox_setup_download_link">ダウンロードリンクを共有</string>
<string name="mailbox_setup_button_scan">メールボックスのQRコードを読み取る</string>
<string name="permission_camera_qr_denied_body">あなたはカメラにアクセスすることを拒否しましたが、QRコードを読み取るには、カメラを使用する必要があります。\n\nアクセス権を付与することを考慮願います。</string>
@@ -595,7 +597,7 @@
<string name="mailbox_setup_already_paired_description">あなたの端末上のメールボックスのリンクを解き、再試行してください。</string>
<string name="mailbox_setup_io_error_title">接続できません</string>
<string name="mailbox_setup_io_error_description">双方の端末がインターネットに接続されていることを確かにして、再試行してください。</string>
<string name="mailbox_setup_assertion_error_title">メールボックスエラー</string>
<string name="mailbox_setup_assertion_error_title">メールボックスエラー</string>
<string name="mailbox_setup_assertion_error_description">もし問題が続くのであれば、Briarアプリ経由で匿名データ付きのフィードバックを送信してください。</string>
<string name="mailbox_setup_camera_error_description">カメラにアクセスできません。端末を再起動してから、もう一度試してみてください。</string>
<string name="mailbox_setup_paired_title">接続済み</string>
@@ -617,11 +619,11 @@
<!--Example for string substitution: Last connection: 3min ago-->
<string name="mailbox_status_connected_info">最終接続: %s</string>
<!--Indicates that there never was a connection to the mailbox. Last connection: Never-->
<string name="mailbox_status_connected_never">ない</string>
<string name="mailbox_status_connected_never">一度もない</string>
<string name="mailbox_status_unlink_button">リンク解除</string>
<string name="mailbox_status_unlink_dialog_title">メールボックスをリンク解除しますか?</string>
<string name="mailbox_status_unlink_dialog_question">本当にあなたのメールボックスをリンク解除してもよろしいですか?</string>
<string name="mailbox_status_unlink_dialog_warning">メールボックスをリンク解除すると、Briarがオフライン中にメッセージを受け取れません。</string>
<string name="mailbox_status_unlink_dialog_warning">メールボックスをリンク解除すると、Briarがオフライン中にメッセージを受信できません。</string>
<string name="mailbox_status_unlink_no_wipe_title">メールボックスはリンク解除されました</string>
<string name="mailbox_status_unlink_no_wipe_message">次回、メールボックス端末にアクセスした際に、メールボックスアプリを起動し、「リンク解除」ボタンをタップして処理を完了してください。\n\nメールボックス端末にアクセスできなくなった場合でも、ご安心ください。データは暗号化されているので、処理を完了しなくても安全なままです。</string>
<string name="mailbox_status_unlink_success">メールボックスはリンク解除されました</string>
@@ -650,9 +652,9 @@
<string name="mailbox_error_wizard_info2">端末にアクセスしたら、この画面に戻って来てください。</string>
<string name="mailbox_error_wizard_info3">以下のボタンを使用してメールボックスをリンク解除してください。\n\n古いメールボックスをリンク解除した後、いつでも新しいメールボックスをセットアップできます。</string>
<!--About-->
<string name="about_title">Tor Project について</string>
<string name="about_title">バージョン情報</string>
<string name="briar_version">Briarバージョン: %s</string>
<string name="tor_version">Tor バージョン: %s</string>
<string name="tor_version">Torバージョン: %s</string>
<string name="links">リンク</string>
<string name="briar_website">\u2022 <a href="">ウェブサイト</a></string>
<string name="briar_source_code">\u2022 <a href="">ソースコード</a></string>
@@ -663,12 +665,12 @@
<!--Conversation Settings-->
<string name="disappearing_messages_title">消えるメッセージ</string>
<string name="disappearing_messages_explanation_long">この設定を有効にすると、
この会話内での新しいメッセージは、自動的に7\u00A0日後に消えます。
この会話内での新メッセージは、自動的に7\u00A0日後に消えます。
\n\nメッセージの送信者の複製用のカウントダウンは、メッセージが到着した後に始まります。
受取人用のカウントダウンは、メッセージを読んでから始まります。
\n\n消えるメッセージには、爆弾アイコンで印が付けられます。
\n\n受取人は、あなたが送ったメッセージの複製を取れることに留意してください。
\n\nこの設定を変更すると、すぐにあなたの新メッセージで反映され、
\n\nこの設定を変更すると、すぐにあなたの新メッセージで反映され、
連絡先があなたの次のメッセージを受信した時点で、その連絡先のメッセージに適用されます。
連絡先もあなたと二人に、この設定を変更できます。</string>
<string name="learn_more">詳細情報</string>
@@ -715,20 +717,20 @@
<!--Sign Out-->
<string name="progress_title_logout">Briarからサインアウト中…</string>
<!--Screen Filters & Tapjacking-->
<string name="screen_filter_title">スクリーンオーバーレイが検出されました</string>
<string name="screen_filter_body">のアプリがBriarの画面上に描画ています。 セキュリティ保護するために、Briarは、別のアプリがBriarの画面上に描画している場合、タッチに応答しません。\n\nのアプリが上に描画されている可能性があります\n\n%1$s</string>
<string name="screen_filter_title">画面オーバーレイが検出されました</string>
<string name="screen_filter_body">のアプリがBriarの上に描画されています。セキュリティ保護のため、他のアプリが上に描画しているときは、Briarに触れても反応しません。\n\n以下のアプリが上に描画されている可能性があります:\n\n%1$s</string>
<string name="screen_filter_body_api_30">他のアプリがBriarの上に描画されています。セキュリティ保護のため、他のアプリが上に描画しているときは、Briarに触れても反応しません。\n\n以下のアプリを確認して、原因のアプリを見つけてください。</string>
<string name="screen_filter_allow">これらのアプリがBriarの画面上に描画できるようにする</string>
<string name="screen_filter_review_apps">アプリを確認</string>
<!--Permission Requests-->
<string name="permission_camera_title">カメラへのアクセス許可</string>
<string name="permission_camera_title">カメラの権限</string>
<string name="permission_camera_request_body">QRコードを読み取るには、Briarはカメラにアクセスする必要があります。</string>
<string name="permission_location_title">位置情報へのアクセスの許可</string>
<string name="permission_location_request_body">Bluetooth端末を検出するには、Briarがあなたの位置情報へアクセスを必要とします。\n\nBriarはあなたの場所を保存したり、誰とも共有したりしません。</string>
<string name="permission_location_title">位置情報の権限</string>
<string name="permission_location_request_body">Bluetooth端末を検出するには、Briarがあなたの位置情報へアクセスする権限を必要とします。\n\nBriarはあなたの場所を保存したり、誰とも共有したりしません。</string>
<string name="permission_camera_location_title">カメラと位置情報</string>
<string name="permission_camera_location_request_body">QRコードを読み取るには、Briarはカメラにアクセスする必要があります。\n\nBluetooth端末を検出するには、Briarは現在地情報にアクセスする許可が必要です。\n\nBriarは現在地を保存したり、誰とも共有したりしません。</string>
<string name="permission_camera_location_request_body">QRコードを読み取るには、Briarはカメラにアクセスする権限を必要とします。\n\nBluetooth端末を検出するには、Briarは現在地情報にアクセスする許可が必要です。\n\nBriarは現在地を保存したり、誰とも共有したりしません。</string>
<string name="permission_camera_bluetooth_title">カメラと付近の端末</string>
<string name="permission_camera_bluetooth_request_body">QRコードを読み取るには、Briarはカメラにアクセスする必要があります。\n\nBluetooth端末を検出するには、Briarは付近の端末を探し接続する許可が必要です。</string>
<string name="permission_camera_bluetooth_request_body">QRコードを読み取るには、Briarはカメラにアクセスする権限を必要とします。\n\nBluetooth端末を検出するには、Briarは付近の端末を探し接続する許可が必要です。</string>
<string name="permission_camera_denied_body">あなたはカメラにアクセスすることを拒否しましたが、連絡先を追加するには、カメラを使用する必要があります。\n\nアクセス権を付与することを考慮願います。</string>
<string name="permission_location_denied_body">あなたは位置情報にアクセスすることを拒否しましたが、BriarはBluetooth端末を発見するのに、この権限が必要です。\n\nアクセス権を付与することを考慮願います。</string>
<string name="permission_location_setting_title">位置情報設定</string>
@@ -748,7 +750,7 @@
<string name="lock_is_locked">Briarはロックされています</string>
<string name="lock_tap_to_unlock">タップしてロック解除</string>
<!--Connections Screen-->
<string name="transports_help_text">Briarは、インターネット、Wi-Fi、Bluetoothを介して連絡先に接続することができます。\n\nすべてのインターネット接続は、プライバシー保護のためにTorネットワークを経由します。\n\n複数の方法で連絡が取れる場合、Briarはそれらを並行して使用します。</string>
<string name="transports_help_text">Briarは、インターネット、Wi-Fi、Bluetoothを介して連絡先に接続することができます。\n\nてのインターネット接続は、プライバシー保護のためにTorネットワークを経由します。\n\n複数の方法で連絡が取れる場合、Briarはそれらを並行して使用します。</string>
<!--Share app offline-->
<string name="hotspot_title">このアプリをオフラインで共有</string>
<string name="hotspot_intro">あなたの電話機のWi-Fiを使用して、インターネット接続なしで、近くの誰かとこのアプリを共有します。
@@ -817,10 +819,10 @@
<!--Transfer Data via Removable Drives-->
<string name="removable_drive_menu_title">リムーバブルドライブ経由で接続する</string>
<string name="removable_drive_intro">インターネット、Wi-FiまたはBluetooth経由であなたの連絡先と接続できない場合、Briarは例えばUSBメモリーまたはSDカードのような、リムーバルドライブ上でメッセージを転送することもできます。</string>
<string name="removable_drive_explanation">インターネット、Wi-FiまたはBluetooth経由であなたの連絡先と接続できない場合、Briarは例えばUSBメモリーまたはSDカードのような、リムーバルドライブ上でメッセージを転送することもできます。\n\n\"データ送信\"ボタンを使用したとき、連絡先への送信を待っているデータは、リムーバブルドライブに書き込まれます。これはプライベートメッセージ、添付、ブログ、フォーラムとプライベートグループを含みます。\n\n連絡先はリムーバルドライブを受け取ったときに、Briar内にメッセージをインポートするため、\"データ受信\"ボタンを使用できます。</string>
<string name="removable_drive_explanation">インターネット、Wi-FiまたはBluetooth経由であなたの連絡先と接続できない場合、Briarは例えばUSBメモリーまたはSDカードのような、リムーバルドライブ上でメッセージを転送することもできます。\n\n\"データ送信\"ボタンを使用したとき、連絡先への送信を待っているデータは、リムーバブルドライブに書き込まれます。これは非公開メッセージ、添付、ブログ、フォーラムと非公開グループを含みます。\n\n連絡先はリムーバルドライブを受け取ったときに、Briar内にメッセージをインポートするため、データ受信ボタンを使用できます。</string>
<string name="removable_drive_title_send">データ送信</string>
<string name="removable_drive_title_receive">データ受信</string>
<string name="removable_drive_send_intro">暗号化されたメッセージを含む新しいファイルを作成するには、下のボタンをタップしてください。ファイルの保存先を選択できます。\n\nリムーバブルドライブ上にファイルを保存したければ、ドライブを今挿れてください。</string>
<string name="removable_drive_send_intro">暗号化されたメッセージを含む新ファイルを作成するには、下のボタンをタップしてください。ファイルの保存先を選択できます。\n\nリムーバブルドライブ上にファイルを保存したければ、ドライブを今挿れてください。</string>
<string name="removable_drive_send_no_data">現在、この連絡先に送信待ちのメッセージはありません。</string>
<string name="removable_drive_send_not_supported">この連絡先はBriarの古いバージョン、またはこの機能をサポートしない古い端末を使用中です。</string>
<string name="removable_drive_send_button">エクスポート用ファイルを選択してください</string>
@@ -830,10 +832,10 @@
<string name="removable_drive_success_send_title">エクスポート成功</string>
<string name="removable_drive_success_send_text">データのエクスポートが成功しました。28日以内に連絡先へファイルを転送することができます。\n\nファイルがリムーバブルドライブ上にある場合、それを着脱する前に、ステータスバー内の通知を利用してイジェクトしてください。</string>
<string name="removable_drive_success_receive_title">インポート成功</string>
<string name="removable_drive_success_receive_text">全ての暗号化されたメッセージは、受け取っているこのファイル内に含まれました。</string>
<string name="removable_drive_success_receive_text">全ての暗号化されたメッセージは、受信しているこのファイル内に含まれました。</string>
<string name="removable_drive_error_send_title">データエクスポートでエラー</string>
<string name="removable_drive_error_send_text">ファイルへデータを書き込み中にエラーが発生しました。\n\nリムーバブルドライブを使用している場合、適切に挿入されていることを確かにして、再度お試しください。\n\nエラーが持続する場合、経験している問題について、Briarチームにフィードバックを送信してください。</string>
<string name="removable_drive_error_receive_title">データインポートエラー</string>
<string name="removable_drive_error_receive_title">データインポート中にエラー</string>
<string name="removable_drive_error_receive_text">選択されたファイルは、Briarが正しく認識するものが含まれていません。\n\n正しいファイルが選択されていることを確認してください。\n\n連絡先が28日より前にファイルを作成した場合、Briarは正しく認識することができません。</string>
<!--Screenshots-->
<!--This is a name to be used in screenshots. Feel free to change it to a local name.-->

View File

@@ -247,12 +247,14 @@
<string name="exchanging_contact_details">Apsikeičiama adresato informacija\u2026</string>
<string name="contact_added_toast">Adresatas pridėtas: %s</string>
<string name="contact_already_exists">Adresatas %s jau yra</string>
<string name="contact_already_exists_general">Adresatas jau yra</string>
<string name="qr_code_invalid">QR kodas yra neteisingas</string>
<string name="camera_error">Kameros klaida</string>
<string name="connecting_to_device">Jungiamasi prie įrenginio\u2026</string>
<string name="authenticating_with_device">Tapatybės nustatymas su įrenginiu\u2026</string>
<string name="connection_error_title">Nepavyko prisijungti prie jūsų adresato</string>
<string name="connection_error_feedback">Jei ši problema išlieka, <a href="feedback">atsiųskite mums atsiliepimą</a>, kad padėtumėte mums patobulinti programėlę.</string>
<string name="info_both_must_scan">Jūs abu privalote nuskenuoti vienas kito QR kodus</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Pridėti adresatą per atstumą</string>
<string name="add_contact_nearby_title">Pridėti šalia esantį adresatą</string>
@@ -266,7 +268,7 @@
<string name="send_link_title">Apsikeiskite nuorodomis</string>
<string name="add_contact_choose_nickname">Pasirinkite slapyvardį</string>
<string name="add_contact_choose_a_nickname">Įveskite slapyvardį</string>
<string name="nickname_intro">Suteikite savo adresatui slapyvardį. Slapyvardį matysite tik jūs.</string>
<string name="nickname_intro">Suteikite adresatui slapyvardį. Slapyvardį matysite tik jūs.</string>
<string name="your_link">Perduokite šią nuorodą adresatui, kurį norite pridėti</string>
<string name="link_clip_label">Briar nuoroda</string>
<string name="link_copied_toast">Nuoroda nukopijuota</string>
@@ -312,7 +314,10 @@
<string name="different_person_button">Kitas asmuo</string>
<string name="duplicate_link_dialog_text_3">%1$s ir %2$s išsiuntė jums tą pačią nuorodą.\n\nGali būti, kad vienas iš šių asmenų bando sužinoti kas yra jūsų adresatų sąraše.\n\nNesakykite šiems asmenims, kad gavote tokią pačią nuorodą iš kito asmens.</string>
<string name="pending_contact_updated_toast">Laukiantis adresatas atnaujintas</string>
<string name="info_both_must_enter_links">Jūs abu privalote pridėti vienas kito nuorodas</string>
<!--Peer trust levels-->
<string name="peer_trust_level_unverified">Nepatvirtintas adresatas</string>
<string name="peer_trust_level_verified">Patvirtintas adresatas</string>
<string name="peer_trust_level_ourselves"></string>
<string name="peer_trust_level_stranger">Nepažįstamasis</string>
<!--Introductions-->
@@ -610,9 +615,11 @@
\nGalite įsidiegti Briar pašto dėžutę laisvame atsarginiame įrenginyje. Palikite įrenginį prijungtą prie maitinimo šaltinio ir belaidžio (Wi-Fi) ryšio, kad jis būtų pastoviai prijungtas prie interneto.</string>
<string name="mailbox_setup_download_link">Bendrinti atsisiuntimo nuorodą</string>
<string name="mailbox_setup_button_scan">Skenuoti pašto dėžutės QR kodą</string>
<string name="mailbox_setup_connecting">Jungiamasi prie pašto dėžutės…</string>
<!--This string is shown when connecting to a Mailbox for the first time. The placeholder will be replaced with a duration, e.g. "2 minutes".-->
<string name="mailbox_setup_connecting_info">Tai gali užtrukti iki %1s</string>
<string name="mailbox_setup_already_paired_title">Pašto dėžutė jau susieta</string>
<string name="mailbox_setup_already_paired_description">Atsiekite pašto dėžutę kitame įrenginyje ir bandykite dar kartą.</string>
<string name="mailbox_setup_io_error_title">Nepavyko prisijungti</string>
<string name="mailbox_setup_io_error_description">Įsitikinkite, kad abu įrenginiai yra prisijungę prie interneto ir bandykite dar kartą.</string>
<string name="mailbox_setup_assertion_error_title">Pašto dėžutės klaida</string>
@@ -623,6 +630,7 @@
<string name="tor_offline_button_check">Tikrinti ryšio nustatymus</string>
<string name="mailbox_status_title">Pašto dėžutės būsena</string>
<string name="mailbox_status_connected_title">Pašto dėžutė veikia</string>
<string name="mailbox_status_problem_title">Briar kyla nesklandumų jungiantis prie pašto dėžutės</string>
<string name="mailbox_status_failure_title">Pašto dėžutė yra neprieinama</string>
<string name="mailbox_status_app_too_old_title">Briar yra per sena</string>
<string name="mailbox_status_app_too_old_message">Atnaujinkite Briar programėlę iki naujausios versijos ir bandykite dar kartą.</string>
@@ -637,6 +645,10 @@
<string name="mailbox_status_unlink_dialog_question">Ar tikrai norite atsieti pašto dėžutę?</string>
<string name="mailbox_status_unlink_no_wipe_title">Jūsų pašto dėžutė atsieta</string>
<string name="mailbox_status_unlink_success">Jūsų pašto dėžutė atsieta</string>
<string name="mailbox_error_notification_channel_title">Problemos su Briar pašto dėžute</string>
<string name="mailbox_error_notification_title">Briar pašto dėžutė yra neprieinama</string>
<string name="mailbox_error_notification_text">Bakstelėkite norėdami išspręsti problemą.</string>
<string name="mailbox_error_wizard_button">Išspręsti problemą</string>
<string name="mailbox_error_wizard_title">Pašto dėžutės nesklandumų šalinimo vediklis</string>
<!--About-->
<string name="about_title">Apie</string>

View File

@@ -252,9 +252,12 @@
<string name="exchanging_contact_details">Wymienianie szczegółów dotyczących kontatku\u2026</string>
<string name="contact_added_toast">Kontakt dodany: %s</string>
<string name="contact_already_exists">Kontakt %s już istnieje</string>
<string name="contact_already_exists_general">Kontakt już istnieje</string>
<string name="qr_code_invalid">Kod QR jest nieprawidłowy</string>
<string name="qr_code_too_old_1">Zeskanowany kod QR pochodzi ze starszej wersji Briar.\n\nProszę poprosić Twój kontakt o aktualizację do najnowszej wersji, a następnie spróbować ponownie.</string>
<string name="qr_code_too_new_1">Zeskanowany kod QR pochodzi z nowszej wersji programu Briar.\n\nProszę zaktualizować go do najnowszej wersji, a następnie spróbować ponownie.</string>
<string name="mailbox_qr_code_for_contact">Zeskanowany kod QR pochodzi ze skrzynki odbiorczej Briar.\n\nJeśli chcesz połączyć skrzynkę odbiorczą, wybierz Ustawienia i Skrzynka odbiorcza z menu Briar.</string>
<string name="qr_code_format_unknown">Zeskanowany kod QR nie jest przeznaczony do dodawania kontaktu z Briar.\n\nZeskanuj kod QR wyświetlany na ekranie kontaktu.</string>
<string name="camera_error">Błąd aparatu</string>
<string name="connecting_to_device">Łączenie z urządzeniem\u2026</string>
<string name="authenticating_with_device">Autoryzowanie z urządzeniem\u2026</string>
@@ -630,6 +633,10 @@
<string name="mailbox_setup_connecting">Łączenie się ze Skrzynką odbiorczą…</string>
<!--This string is shown when connecting to a Mailbox for the first time. The placeholder will be replaced with a duration, e.g. "2 minutes".-->
<string name="mailbox_setup_connecting_info">Może to potrwać do %1s</string>
<string name="mailbox_qr_code_too_old">Zeskanowany kod QR pochodzi ze starszej wersji skrzynki odbiorczej Briar.\n\nProszę zaktualizować ją do najnowszej wersji, a następnie spróbować ponownie.</string>
<string name="mailbox_qr_code_too_new">Zeskanowany kod QR pochodzi z nowszej wersji skrzynki odbiorczej Briar.\n\nProszę zaktualizować ją do najnowszej wersji, a następnie spróbować ponownie.</string>
<string name="contact_qr_code_for_mailbox">Zeskanowany kod QR służy do dodawania kontaktu Briar.\n\nJeśli chcesz dodać kontakt, przejdź do listy kontaktów i naciśnij ikonę +.</string>
<string name="mailbox_setup_qr_code_wrong_description">Zeskanowany kod QR nie pochodzi ze skrzynki odbiorczej Briar. Otwórz skrzynkę odbiorczą Briar na urządzeniu z Twoją skrzynką i zeskanuj wyświetlany kod QR. </string>
<string name="mailbox_setup_already_paired_title">Mailbox już podłączony</string>
<string name="mailbox_setup_already_paired_description">Odłącz Mailbox na drugim urządzeniu i spróbuj ponownie.</string>
<string name="mailbox_setup_io_error_title">Nie udało się połączyć</string>
@@ -768,10 +775,12 @@ Brak dostępu do aparatu. Spróbuj ponownie, może po ponownym uruchomieniu urz
<string name="permission_camera_location_title">Kamera i lokalizacja</string>
<string name="permission_camera_location_request_body">Aby zeskanować kod QR, Briar potrzebuje dostępu do kamery.\n\nAby odkryć urządzenia Bluetooth, Briar potrzebuje zezwolenia na dostęp do Twojej lokalizacji.\n\nBriar nie przechowuje Twojej lokalizacji ani nie udostępnia jej nikomu.</string>
<string name="permission_camera_bluetooth_title">Aparat i urządzenia w pobliżu</string>
<string name="permission_camera_bluetooth_request_body">Aby zeskanować kod QR, Briar potrzebuje dostępu do aparatu.\n\nAby wykryć urządzenia Bluetooth, Briar potrzebuje uprawnień do znajdowania i łączenia się z urządzeniami w pobliżu.</string>
<string name="permission_camera_denied_body">Odmówiłeś dostępu do aparatu, lecz dodawanie kontaktów wymaga jego użycia.\n\nProszę rozważyć udzielenie dostępu do aparatu</string>
<string name="permission_location_denied_body">Zabroniłeś dostępu do Twojej lokalizacji, ale Briar potrzebuje tego uprawnienia do wykrywania urządzeń Bluetooth.\n\nRozważ przyznanie tego dostępu.</string>
<string name="permission_location_setting_title">Ustawienia lokalizacji</string>
<string name="permission_location_setting_body">Ustawienie lokalizacji urządzenia musi być włączone, aby można było znaleźć inne urządzenia przez Bluetooth. Włącz lokalizację, aby kontynuować. Później możesz ją ponownie wyłączyć.</string>
<string name="permission_location_setting_hotspot_body">Aby utworzyć hotspot Wi-Fi, musisz włączyć ustawienie lokalizacji urządzenia. Włącz lokalizację, aby kontynuować. Możesz ją później wyłączyć ponownie.</string>
<string name="permission_location_setting_button">Włącz lokalizację</string>
<string name="permission_bluetooth_title">Pozwolenie do urządzeń w pobliżu</string>
<string name="permission_bluetooth_body">Aby korzystać z komunikacji Bluetooth, Briar potrzebuje uprawnień do znajdowania i łączenia się z pobliskimi urządzeniami.</string>
@@ -798,7 +807,9 @@ Brak dostępu do aparatu. Spróbuj ponownie, może po ponownym uruchomieniu urz
<string name="hotspot_notification_title">Udostępnianie Briar offline</string>
<string name="hotspot_button_connected">Następny</string>
<string name="permission_hotspot_location_request_body">Aby utworzyć hotspot Wi-Fi, Briar potrzebuje uprawnienia do dostępu do Twojej lokalizacji.\n\nBriar nie przechowuje Twojej lokalizacji ani nie udostępnia jej nikomu.</string>
<string name="permission_hotspot_location_request_precise_body">Aby utworzyć hotspot Wi-Fi, Briar potrzebuje uprawnienia do dostępu do Twojej dokładnej lokalizacji.\n\nBriar nie przechowuje Twojej lokalizacji ani nie udostępnia jej nikomu.</string>
<string name="permission_hotspot_location_denied_body">Zabroniłeś dostępu do Twojej lokalizacji, ale Briar potrzebuje tego uprawnienia do tworzenia hotspotu Wi-Fi.\n\nRozważ przyznanie tego dostępu.</string>
<string name="permission_hotspot_location_denied_precise_body">Zabroniono dostępu do dokładnej lokalizacji. Briar potrzebuje tego uprawnienia do tworzenia hotspotu Wi-Fi.\n\nRozważ przyznanie tego dostępu.</string>
<string name="wifi_settings_title">Ustawienia Wi-Fi</string>
<string name="wifi_settings_request_enable_body">Aby utworzyć hotspot Wi-Fi, Briar potrzebuje użyć Wi-Fi. Włącz Wi-Fi.</string>
<string name="hotspot_tab_manual">Manualne</string>

View File

@@ -243,6 +243,7 @@
<string name="exchanging_contact_details">Se face schimbul de date de contact\u2026</string>
<string name="contact_added_toast">Contact adăugat: %s</string>
<string name="contact_already_exists">Contactul %s există deja</string>
<string name="contact_already_exists_general">Contactul există deja</string>
<string name="qr_code_invalid">Codul QR este nevalid!</string>
<string name="qr_code_too_old_1">Codul QR pe care l-ați scanat provine de la o versiune Briar mai veche.\n\nSolicitați contactului să actualizeze aplicația la cea mai recentă versiune, după care încercați din nou.</string>
<string name="qr_code_too_new_1">Codul QR pe care l-ați scanat provine de la o versiune Briar mai nouă.\n\nActualizați aplicația la cea mai recentă versiune, după care încercați din nou.</string>

View File

@@ -252,6 +252,7 @@
<string name="exchanging_contact_details">Обмен контактными данными\u2026</string>
<string name="contact_added_toast">Контакт добавлен: %s</string>
<string name="contact_already_exists">Контакт %s уже существует</string>
<string name="contact_already_exists_general">Контакт уже существует</string>
<string name="qr_code_invalid">Неверный QR-код</string>
<string name="qr_code_too_old_1">QR-код, который вы сосканировали, сгенерирован в старой версии Briar.\n\nПопросите вашего собеседника обновиться до последней версии и повторите попытку.</string>
<string name="qr_code_too_new_1">QR-код, который вы сосканировали, сгенерирован в новой версии Briar.\n\nОбновите приложение до последней версии и повторите попытку.</string>

View File

@@ -0,0 +1,901 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources xmlns:tools="http://schemas.android.com/tools">
<!--Setup-->
<string name="setup_title">Vitajte v Briar</string>
<string name="setup_name_explanation">Vaša prezývka sa bude zobrazovať pri každom obsahu, ktorý zverejníte. Po vytvorení účtu ju už nemôžete zmeniť.</string>
<string name="setup_next">Ďalej</string>
<string name="setup_password_intro">Zvoľte si heslo</string>
<string name="setup_password_explanation">Vaše konto Briar je uložené šifrovane vo vašom zariadení, nie v cloude. Ak zabudnete heslo alebo odinštalujete aplikáciu Briar, konto sa nedá obnoviť.\n\nVyberte si dlhé heslo, ktoré je ťažké uhádnuť, napríklad štyri náhodné slová alebo desať náhodných písmen, číslic a symbolov.</string>
<string name="dnkm_doze_intro">Aby ste mohli prijímať správy, musí byť Briar pripojený na pozadí.</string>
<string name="dnkm_doze_explanation">Aby ste mohli prijímať správy, musí byť Briar pripojený na pozadí. Vypnite optimalizáciu batérie, aby Briar mohol zostať pripojený.</string>
<string name="choose_nickname">Vyberte si svoju prezývku</string>
<string name="choose_password">Zvoľte si heslo</string>
<string name="confirm_password">Potvrďte svoje heslo</string>
<string name="name_too_long">Meno je príliš dlhé</string>
<string name="password_too_weak">Heslo je príliš slabé</string>
<string name="passwords_do_not_match">Hesla sa nezhodujú</string>
<string name="create_account_button">Vytvoriť účet</string>
<string name="more_info">Viac informácií</string>
<string name="don_t_ask_again">Nepýtať sa znova</string>
<string name="dnkm_huawei_protected_text">Ťuknite na tlačidlo nižšie a na obrazovke \"Chránené aplikácie\" skontrolujte, či je aplikácia Briar chránená.</string>
<string name="dnkm_huawei_protected_button">Ochrániť Briar</string>
<string name="dnkm_huawei_protected_help">Ak Briar nie je pridaný do zoznamu chránených aplikácií, nebude môcť byť spustený na pozadí.</string>
<string name="dnkm_huawei_app_launch_text">Ťuknite na tlačidlo nižšie, otvorte obrazovku \"Spustenie aplikácie\" a uistite sa, že je Briar nastavený na \"Spravovať ručne\".</string>
<string name="dnkm_huawei_app_launch_help">Ak Briar nie je na obrazovke \"Spustenie aplikácie\" nastavený na možnosť \"Spravovať ručne\", nebude môcť byť spustený na pozadí.</string>
<string name="dnkm_xiaomi_text">Ak má byť aplikácia Briar spustená na pozadí, musí byť uzamknutá v zozname posledných aplikácií.</string>
<string name="dnkm_xiaomi_button">Ochrániť Briar</string>
<string name="dnkm_xiaomi_help">Ak Briar nie je uzamknutý v zozname posledných aplikácií, nebude môcť byť spustený na pozadí.</string>
<string name="dnkm_xiaomi_dialog_body_old">1. Otvorte zoznam posledných aplikácií (nazývaný aj prepínač aplikácií)\n\n2. Potiahnite prstom nadol na obrázok Briar, aby sa zobrazila ikona visiaceho zámku\n\n3. Ak visiaci zámok nie je zamknutý, ťuknutím naň ho zamknite</string>
<string name="dnkm_xiaomi_dialog_body_new">1. Otvorte zoznam posledných aplikácií (nazývaný aj prepínač aplikácií)\n\n2. Ak má Briar vedľa svojho názvu malý obrázok visiaceho zámku, nemusíte robiť nič\n\n3. Ak tam visiaci zámok nie je, stlačte a podržte obrázok Briar, kým sa nezobrazí tlačidlo visiaceho zámku, a potom naň ťuknite</string>
<string name="dnkm_xiaomi_lock_apps_text">Ťuknutím na tlačidlo nižšie otvorte nastavenia zabezpečenia. Klepnite na položku \"Zvýšenie rýchlosti\", potom klepnite na položku \"Uzamknúť aplikácie\" a uistite sa, že je Briar nastavený na možnosť \"Uzamknuté\".</string>
<string name="dnkm_xiaomi_lock_apps_help">Ak Briar nie je na obrazovke \"Uzamknuté aplikácie\" nastavený na možnosť \"Uzamknuté\", nebude môcť byť spustený na pozadí.</string>
<string name="dnkm_warning_dozed_1">Aplikáciu Briar sa nepodarilo spustiť na pozadí</string>
<!--Login-->
<string name="enter_password">Heslo</string>
<string name="try_again">Nesprávne heslo, skúste to znova</string>
<string name="dialog_title_cannot_check_password">Nie je možné skontrolovať heslo</string>
<string name="dialog_message_cannot_check_password">Briar nemôže skontrolovať vaše heslo. Skúste tento problém vyriešiť reštartovaním zariadenia.</string>
<string name="sign_in_button">Prihlásiť sa</string>
<string name="forgotten_password">Zabudol som svoje heslo</string>
<string name="dialog_title_lost_password">Zabudnuté heslo</string>
<string name="dialog_message_lost_password">Vaše konto Briar je uložené šifrovane vo vašom zariadení, nie v cloude, takže vaše heslo nemôžeme resetovať. Chcete odstrániť svoj účet a začať znova?\n\nPozor: Vaše identity, kontakty a správy budú natrvalo stratené.</string>
<string name="startup_failed_activity_title">Zlyhanie spustenia aplikácie Briar</string>
<string name="startup_failed_clock_error">Briar sa nepodarilo spustiť, pretože hodiny vášho zariadenia sú nesprávne.\n\nProsím, nastavte hodiny vášho zariadenia na správny čas a skúste to znova.</string>
<string name="startup_failed_db_error">Aplikácii Briar sa nepodarilo otvoriť databázu, ktorá obsahuje vaše konto, kontakty a správy.\n\nProsím, aktualizujte na najnovšiu verziu aplikácie a skúste to znova, alebo si nastavte nové konto výberom možnosti \"Zabudol som heslo\" vo výzve na zadanie hesla.</string>
<string name="startup_failed_data_too_old_error">Vaše konto bolo vytvorené v starej verzii tejto aplikácie a v tejto verzii sa nedá otvoriť.\n\nMusíte buď nainštalovať starú verziu, alebo nastaviť nové konto výberom možnosti \"Zabudol som heslo\" vo výzve na zadanie hesla.</string>
<string name="startup_failed_data_too_new_error">Vaše konto bolo vytvorené s novšou verziou tejto aplikácie a s touto verziou ho nemožno otvoriť.\n\nProsím, aktualizujte na najnovšiu verziu a skúste to znova.</string>
<string name="startup_failed_service_error">Briar nedokázal spustiť požadovaný komponent.\n\nProsím, aktualizujte na najnovšiu verziu aplikácie a skúste to znova.</string>
<plurals name="expiry_warning">
<item quantity="one">Toto je testovacia verzia aplikácie Briar. Platnosť vášho účtu vyprší o %d deň a nie je možné ho obnoviť.</item>
<item quantity="few">Toto je testovacia verzia aplikácie Briar. Platnosť vášho účtu vyprší o %d dni a nie je možné ho obnoviť.</item>
<item quantity="many">Toto je testovacia verzia aplikácie Briar. Platnosť vášho účtu vyprší o %d dní a nie je možné ho obnoviť.</item>
<item quantity="other">Toto je testovacia verzia aplikácie Briar. Platnosť vášho účtu vyprší o %d dní a nie je možné ho obnoviť.</item>
</plurals>
<plurals name="old_android_expiry_warning">
<item quantity="one">Systém Android 4 už nie je podporovaný. Briar prestane fungovať na %s (za %d deň). Nainštalujte si Briar na novšie zariadenie a vytvorte si nový účet.</item>
<item quantity="few">Systém Android 4 už nie je podporovaný. Briar prestane fungovať na %s (za %d dni). Nainštalujte si Briar na novšie zariadenie a vytvorte si nový účet.</item>
<item quantity="many">Systém Android 4 už nie je podporovaný. Briar prestane fungovať na %s (za %d dní). Nainštalujte si Briar na novšie zariadenie a vytvorte si nový účet.</item>
<item quantity="other">Systém Android 4 už nie je podporovaný. Briar prestane fungovať na %s (za %d dní). Nainštalujte si Briar na novšie zariadenie a vytvorte si nový účet.</item>
</plurals>
<string name="expiry_date_reached">Platnosť tohto softvéru vypršala.\nĎakujeme za testovanie!</string>
<string name="download_briar">Ak chcete pokračovať v používaní aplikácie Briar, stiahnite si najnovšiu verziu.</string>
<string name="create_new_account">Budete si musieť vytvoriť nový účet, ale môžete použiť rovnakú prezývku.</string>
<string name="download_briar_button">Stiahnite si najnovšiu verziu</string>
<string name="old_android_expiry_date_reached">Briar už nefunguje na systéme Android 4.\nProsím, nainštalujte Briar na novšie zariadenie.</string>
<string name="old_android_delete_account">Ťuknutím na tlačidlo nižšie môžete odstrániť svoje konto z tohto zariadenia.</string>
<string name="delete_account_button">Vymazať účet</string>
<string name="startup_open_database">Dešifrovanie databázy...</string>
<string name="startup_migrate_database">Aktualizácia databázy...</string>
<string name="startup_compact_database">Komprimovanie databázy...</string>
<!--Navigation Drawer-->
<string name="nav_drawer_open_description">Otvoriť navigačnú lištu</string>
<string name="nav_drawer_close_description">Zavrieť navigačnú lištu</string>
<string name="contact_list_button">Kontakty</string>
<string name="groups_button">Súkromné skupiny</string>
<string name="forums_button">Fóra</string>
<string name="blogs_button">Blogy</string>
<!--This is part of the main menu. The app will be locked when this is tapped.-->
<string name="lock_button">Zamknúť aplikáciu</string>
<string name="settings_button">Nastavenia</string>
<string name="sign_out_button">Odhlásiť sa</string>
<string name="transports_onboarding_text">Ťuknutím sem môžete ovládať, ako sa Briar pripája k vašim kontaktom.</string>
<!--Transports: Tor-->
<string name="transport_tor">Internet</string>
<string name="tor_device_status_online_wifi">Váš telefón má prístup na internet cez Wi-Fi</string>
<string name="tor_device_status_online_mobile">Váš telefón má prístup na internet cez mobilné dáta</string>
<string name="tor_device_status_offline">Váš telefón nemá prístup na internet</string>
<string name="tor_plugin_status_enabling">Briar sa pripája na internet</string>
<string name="tor_plugin_status_active">Briar sa pripojený na internet</string>
<string name="tor_plugin_status_inactive">Briar sa nemôže pripojiť na internet</string>
<string name="tor_plugin_status_disabled">Briar je nastavený tak, aby nepoužíval internet</string>
<string name="tor_plugin_status_disabled_mobile_data">Briar je nastavený tak, aby nepoužíval mobilné dáta</string>
<string name="tor_plugin_status_disabled_battery">Briar je nastavený tak, aby nepoužíval internet, keď ide na batériu</string>
<string name="tor_plugin_status_disabled_country_blocked">Briar je nastavený tak, aby v tejto krajine nepoužíval internet</string>
<!--Transports: Wi-Fi-->
<string name="transport_lan">Wi-Fi</string>
<string name="transport_lan_long">Rovnaká sieť Wi-Fi</string>
<string name="lan_device_status_on">Váš telefón je pripojený k sieti Wi-Fi</string>
<string name="lan_device_status_off">Váš telefón nie je pripojený k sieti Wi-Fi</string>
<string name="lan_plugin_status_enabling">Briar sa pripája k sieti Wi-Fi</string>
<string name="lan_plugin_status_active">Briar je pripojený k sieti Wi-Fi</string>
<string name="lan_plugin_status_inactive">Briar sa nemôže pripojiť k sieti Wi-Fi</string>
<string name="lan_plugin_status_disabled">Briar je nastavený tak, aby nepoužíval sieť Wi-Fi</string>
<!--Transports: Bluetooth-->
<string name="transport_bt">Bluetooth</string>
<string name="bt_device_status_on">Váš telefón má zapnuté Bluetooth</string>
<string name="bt_device_status_off">Váš telefón má vypnuté Bluetooth</string>
<string name="bt_plugin_status_enabling">Briar sa pripája cez Bluetooth</string>
<string name="bt_plugin_status_active">Briar je pripojený cez Bluetooth</string>
<string name="bt_plugin_status_inactive">Briar sa nedokáže pripojiť k Bluetooth</string>
<string name="bt_plugin_status_disabled">Briar je nastavený tak, aby nepoužíval Bluetooth</string>
<!--Notifications-->
<string name="reminder_notification_title">Odhlásený z aplikácie Briar</string>
<string name="reminder_notification_text">Ťuknutím sa prihláste späť.</string>
<string name="reminder_notification_channel_title">Pripomienka prihlásenia do aplikácie Briar</string>
<string name="reminder_notification_dismiss">Odmietnuť</string>
<string name="ongoing_notification_title">Prihlásený do Briar</string>
<string name="ongoing_notification_text">Dotknutím sa otvorte Briar.</string>
<plurals name="private_message_notification_text">
<item quantity="one">Nová súkromná správa</item>
<item quantity="few">%d nové súkromné správy</item>
<item quantity="many">%d nových súkromných správ</item>
<item quantity="other">%d nových súkromných správ</item>
</plurals>
<plurals name="group_message_notification_text">
<item quantity="one">Nová skupinová správa.</item>
<item quantity="few">%d nové skupinové správy.</item>
<item quantity="many">%d nových skupinových správ.</item>
<item quantity="other">%d nových skupinových správ.</item>
</plurals>
<plurals name="forum_post_notification_text">
<item quantity="one">Nový príspevok na fóre.</item>
<item quantity="few">%d nové príspevky na fóre.</item>
<item quantity="many">%d nových príspevkov na fóre.</item>
<item quantity="other">%d nových príspevkov na fóre.</item>
</plurals>
<plurals name="blog_post_notification_text">
<item quantity="one">Nový príspevok na blogu.</item>
<item quantity="few">%d nové príspevky na blogu.</item>
<item quantity="many">%d nových príspevkov na blogu.</item>
<item quantity="other">%d nových príspevkov na blogu.</item>
</plurals>
<!--Misc-->
<string name="now">teraz</string>
<string name="show">Zobraziť</string>
<string name="hide">Skryť</string>
<string name="ok">OK</string>
<string name="cancel">Zrušiť</string>
<string name="got_it">Rozumiem</string>
<string name="delete">Odstrániť</string>
<string name="accept">Prijať</string>
<string name="decline">Odmietnuť</string>
<string name="online">Pripojený</string>
<string name="offline">Odpojený</string>
<string name="send">Odoslať</string>
<string name="allow">Povoliť</string>
<string name="open">Otvoriť</string>
<string name="change">Zmeniť</string>
<string name="start">Spustiť</string>
<string name="finish">Dokončiť</string>
<string name="no_data">Žiadne údaje</string>
<string name="ellipsis"></string>
<string name="text_too_long">Zadaný text je príliš dlhý</string>
<string name="show_onboarding">Zobraziť dialógové okno pomocníka</string>
<string name="fix">Opraviť</string>
<string name="help">Pomoc</string>
<string name="sorry">Prepáčte</string>
<string name="error_start_activity">Vo vašom systéme nie je dostupné</string>
<string name="status_heading">Stav:</string>
<string name="error">Chyba</string>
<string name="info">Informácie</string>
<!--Contacts and Private Conversations-->
<string name="no_contacts">Žiadne kontakty na zobrazenie</string>
<string name="no_contacts_action">Ťuknutím na ikonu + pridáte kontakt</string>
<string name="date_no_private_messages">Žiadne správy.</string>
<string name="no_private_messages">Žiadne správy na zobrazenie</string>
<string name="message_hint">Nová správa</string>
<string name="message_hint_auto_delete">Nová miznúca správa</string>
<string name="message_error">Chyba pri odosielaní správy</string>
<string name="image_caption_hint">Pridať popis (nepovinné)</string>
<string name="image_attach">Priložiť obrázok</string>
<string name="image_attach_error">Nepodarilo sa pripojiť obrázok(ky)</string>
<string name="image_attach_error_too_big">Príliš veľký obrázok. Limit je %d MB.</string>
<string name="image_attach_error_invalid_mime_type">Formát obrázka nie je podporovaný: %s</string>
<string name="set_contact_alias">Zmeniť meno kontaktu</string>
<string name="set_contact_alias_hint">Meno kontaktu</string>
<string name="menu_item_disappearing_messages">Miznúce správy</string>
<!--The first placeholder will show a duration like "7 days". The second placeholder at the end will add "Tap to learn more."-->
<string name="auto_delete_msg_you_enabled">Vaše správy zmiznú po %1$s. %2$s </string>
<!--The placeholder at the end will add "Tap to learn more."-->
<string name="auto_delete_msg_you_disabled">Vaše správy nezmiznú. %1$s</string>
<!--The first placeholder will show a contact's name. The second placeholder will show a duration like "7 days". The third placeholder at the end will add "Tap to learn more."-->
<string name="auto_delete_msg_contact_enabled">Správy používateľa %1$szmiznú po %2$s. %3$s</string>
<plurals name="duration_minutes">
<item quantity="one">%d minúta</item>
<item quantity="few">%d minúty</item>
<item quantity="many">%d minút</item>
<item quantity="other">%d minút</item>
</plurals>
<plurals name="duration_hours">
<item quantity="one">%d hodina</item>
<item quantity="few">%d hodiny</item>
<item quantity="many">%d hodín</item>
<item quantity="other">%d hodín</item>
</plurals>
<plurals name="duration_days">
<item quantity="one">%d deň</item>
<item quantity="few">%d dni</item>
<item quantity="many">%d dní</item>
<item quantity="other">%d dní</item>
</plurals>
<!--The first placeholder will show a contact's name. The second placeholder at the end will add "Tap to learn more."-->
<string name="auto_delete_msg_contact_disabled">Správy používateľa %1$snezmiznú. %2$s</string>
<string name="tap_to_learn_more">Ťuknutím sa dozviete viac.</string>
<string name="auto_delete_changed_warning_title">Miznúce správy sa zmenili</string>
<string name="auto_delete_changed_warning_message_enabled">Odkedy ste začali písať správu, miznúce správy boli zapnuté.</string>
<string name="auto_delete_changed_warning_message_disabled">Odkedy ste začali písať správu, miznúce správy boli vypnuté.</string>
<string name="auto_delete_changed_warning_send">Odoslať aj tak</string>
<string name="delete_all_messages">Odstrániť všetky správy</string>
<string name="dialog_title_delete_all_messages">Potvrdiť odstránenie správy</string>
<string name="dialog_message_delete_all_messages">Ste si istí, že chcete odstrániť všetky správy?</string>
<string name="dialog_title_not_all_messages_deleted">Nepodarilo sa vymazať všetky správy</string>
<string name="dialog_message_not_deleted_ongoing_both">Správy týkajúce sa prebiehajúcich pozvaní a zoznámení nie je možné vymazať až do ich ukončenia.</string>
<string name="dialog_message_not_deleted_ongoing_introductions">Správy súvisiace s prebiehajúcimi zoznámeniami nie je možné vymazať, kým sa neukončia.</string>
<string name="dialog_message_not_deleted_ongoing_invitations">Správy súvisiace s prebiehajúcimi pozvaniami nie je možné vymazať, kým sa neukončia.</string>
<string name="dialog_message_not_deleted_not_all_selected_both">Ak chcete odstrániť pozvanie alebo zoznámenie, musíte vybrať žiadosť a odpoveď.</string>
<string name="dialog_message_not_deleted_not_all_selected_introductions">Ak chcete odstrániť zoznámenie, musíte vybrať žiadosť a odpoveď.</string>
<string name="dialog_message_not_deleted_not_all_selected_invitations">Ak chcete odstrániť pozvanie, musíte vybrať žiadosť a odpoveď.</string>
<string name="delete_contact">Odstrániť kontakt</string>
<string name="dialog_title_delete_contact">Potvrdiť odstránenie kontaktu</string>
<string name="dialog_message_delete_contact">Ste si istí, že chcete odstrániť tento kontakt a všetky správy vymenené s týmto kontaktom?</string>
<string name="contact_deleted_toast">Kontakt bol odstránený</string>
<!--This is shown in the action bar when opening an image in fullscreen that the user sent-->
<string name="you">Vy</string>
<string name="save_image">Uložiť obrázok</string>
<string name="dialog_title_save_image">Uložiť obrázok?</string>
<string name="dialog_message_save_image">Uloženie tohto obrázka umožní ostatným aplikáciám k jeho prístupu.\n\nSte si istí, že ho chcete uložiť?</string>
<string name="save_image_success">Obrázok bol uložený</string>
<string name="save_image_error">Obrázok sa nepodarilo uložiť</string>
<string name="dialog_title_no_image_support">Obrázky nie sú dostupné</string>
<string name="dialog_message_no_image_support">Aplikácia Briar vášho kontaktu zatiaľ nepodporuje obrázkové prílohy. Po ich aktualizácii sa vám zobrazí iná ikona.</string>
<string name="dialog_title_image_support">Tomuto kontaktu môžete teraz posielať obrázky</string>
<string name="dialog_message_image_support">Ťuknutím na túto ikonu pripojíte obrázky.</string>
<string name="messaging_too_many_attachments_toast">Odošle sa len prvých %d obrázkov</string>
<string name="menu_contact">Kontakt</string>
<!--Adding Contacts-->
<string name="add_contact_title">Pridať kontakt v blízkosti</string>
<string name="add_contact_error_two_way">Naskenovali ste si navzájom QR kódy?</string>
<string name="face_to_face">S osobou, ktorú chcete pridať ako kontakt sa musíte sa stretnúť osobne.\n\nTým sa zabráni tomu, aby sa niekto za vás vydával alebo čítal vaše správy v budúcnosti.</string>
<string name="continue_button">Pokračovať</string>
<string name="try_again_button">Skúsiť znova</string>
<string name="waiting_for_contact_to_scan">Čaká sa, kým kontakt naskenuje a pripojí sa\u2026</string>
<string name="exchanging_contact_details">Výmena kontaktných údajov\u2026</string>
<string name="contact_added_toast">Kontakt pridaný: %s</string>
<string name="contact_already_exists">Kontakt %s už existuje</string>
<string name="contact_already_exists_general">Kontakt už existuje</string>
<string name="qr_code_invalid">QR kód nie je platný</string>
<string name="qr_code_too_old_1">QR kód, ktorý ste naskenovali, pochádza zo staršej verzie aplikácie Briar.\n\nProsím, požiadajte svoj kontakt o aktualizáciu na najnovšiu verziu a potom to skúste znova.</string>
<string name="qr_code_too_new_1">QR kód, ktorý ste naskenovali, pochádza z novšej verzie aplikácie Briar.\n\nProsím, aktualizujte prosím na najnovšiu verziu a potom to skúste znova.</string>
<string name="mailbox_qr_code_for_contact">QR kód, ktorý ste naskenovali, pochádza z Briar Mailbox.\n\nAk chcete prepojiť Mailbox, vyberte prosím Nastavenia &gt; Mailbox z ponuky Briar.</string>
<string name="qr_code_format_unknown">QR kód, ktorý ste naskenovali, nie je určený na pridanie kontaktu Briar.\n\nNaskenujte QR kód zobrazený na obrazovke kontaktu.</string>
<string name="camera_error">Chyba kamery</string>
<string name="connecting_to_device">Pripájanie k zariadeniu\u2026</string>
<string name="authenticating_with_device">Overovanie so zariadením\u2026</string>
<string name="connection_error_title">Nepodarilo sa pripojiť k vášmu kontaktu</string>
<string name="connection_error_feedback">Ak tento problém pretrváva, pošlite nám prosím <a href="feedback">spätnú väzbu</a>, ktorá nám pomôže aplikáciu vylepšiť.</string>
<string name="info_both_must_scan">Obaja si musíte navzájom naskenovať QR kódy.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Pridať vzdialený kontakt</string>
<string name="add_contact_nearby_title">Pridať kontakt v blízkosti</string>
<string name="add_contact_remotely_title">Pridať vzdialený kontakt </string>
<string name="contact_link_intro">Sem zadajte odkaz od vášho kontaktu</string>
<string name="contact_link_hint">Odkaz kontaktu</string>
<string name="paste_button">Vložiť</string>
<string name="add_contact_button">Pridať kontakt</string>
<string name="copy_button">Kopírovať</string>
<string name="share_button">Zdieľať</string>
<string name="send_link_title">Vymeniť odkazy</string>
<string name="add_contact_choose_nickname">Vybrať prezývku</string>
<string name="add_contact_choose_a_nickname">Zadajte prezývku</string>
<string name="nickname_intro">Dajte svojmu kontaktu prezývku. Len vy ju môžete vidieť.</string>
<string name="your_link">Poskytnite tento odkaz kontaktu, ktorý chcete pridať</string>
<string name="link_clip_label">Odkaz Briar</string>
<string name="link_copied_toast">Odkaz skopírovaný</string>
<string name="adding_contact_error">Pri pridávaní kontaktu došlo k chybe.</string>
<string name="pending_contact_requests_snackbar">Existujú čakajúce žiadosti o kontakt</string>
<string name="pending_contact_requests">Čakajúce žiadosti o kontakt</string>
<string name="no_pending_contacts">Žiadne čakajúce kontakty</string>
<string name="waiting_for_contact_to_come_online">Čaká sa na kontakt, kým sa pripojí online...</string>
<string name="connecting">Pripája sa…</string>
<string name="adding_contact">Pridávanie kontaktu...</string>
<string name="adding_contact_failed">Pridávanie kontaktu zlyhalo</string>
<string name="dialog_title_remove_pending_contact">Potvrdiť odstránenie</string>
<string name="dialog_message_remove_pending_contact">Tento kontakt sa stále pridáva. Ak ho teraz odstránite, nebude pridaný.</string>
<string name="own_link_error">Zadajte odkaz vášho kontaktu, nie svoj vlastný</string>
<string name="nickname_missing">Zadajte prosím prezývku</string>
<string name="invalid_link">Neplatný odkaz</string>
<string name="unsupported_link">Tento odkaz pochádza z novšej verzie aplikácie Briar. Prejdite na najnovšiu verziu a skúste to znova.</string>
<string name="intent_own_link">Otvorili ste svoj vlastný odkaz. Použite ten odkaz na kontakt, ktorý chcete pridať!</string>
<string name="missing_link">Prosím, zadajte odkaz</string>
<!--This is a numeral indicating the first step in a series of screens-->
<string name="step_1">1</string>
<!--This is a numeral indicating the second step in a series of screens-->
<string name="step_2">2</string>
<plurals name="contact_added_notification_text">
<item quantity="one">Nový kontakt pridaný.</item>
<item quantity="few">%dnové kontakty pridané.</item>
<item quantity="many">%dnových pridaných kontaktov.</item>
<item quantity="other">%dnových pridaných kontaktov.</item>
</plurals>
<string name="offline_state">Žiadne internetové pripojenie</string>
<string name="duplicate_link_dialog_title">Duplicitný odkaz</string>
<string name="duplicate_link_dialog_text_1">Už máte jeden čakajúci kontakt s týmto odkazom:: %s</string>
<string name="duplicate_link_dialog_text_1_contact">Už máte kontakt s týmto odkazom: %s</string>
<!--This is a question asking whether two nicknames refer to the same person-->
<string name="duplicate_link_dialog_text_2">Je %1$s a %2$stá istá osoba?</string>
<!--This is a button for answering that two nicknames do indeed refer to the same person. This
string will be used in a dialog button, so if the translation of this string is longer than 20
characters, please use "Yes" instead, and use "No" for the "Different Person" button-->
<string name="same_person_button">Tá istá osoba</string>
<!--This is a button for answering that two nicknames refer to different people. This string
will be used in a dialog button, so if the translation of this string longer than 20 characters,
please use "No" instead, and use "Yes" for the "Same Person" button-->
<string name="different_person_button">Iná osoba</string>
<string name="duplicate_link_dialog_text_3">%1$s a %2$s vám poslali rovnaký odkaz.\n\nJeden z nich sa možno snaží zistiť, kto sú vaše kontakty.\n\nNehovorte im, že ste dostali rovnaký odkaz od niekoho iného.</string>
<string name="pending_contact_updated_toast">Čakajúci kontakt bol aktualizovaný</string>
<string name="info_both_must_enter_links">Obaja si musíte navzájom pridať odkazy</string>
<!--Peer trust levels-->
<string name="peer_trust_level_unverified">Neoverený kontakt</string>
<string name="peer_trust_level_verified">Overený kontakt</string>
<string name="peer_trust_level_ourselves">Ja</string>
<string name="peer_trust_level_stranger">Cudzinec</string>
<!--Introductions-->
<string name="introduction_onboarding_title">Zoznámte svoje kontakty</string>
<string name="introduction_onboarding_text">Zoznámte svoje kontakty navzájom, aby sa mohli spojiť v aplikácii Briar.</string>
<string name="introduction_menu_item">Zoznámiť</string>
<string name="introduction_activity_title">Vybrať kontakt</string>
<string name="introduction_not_possible">S týmito kontaktmi už máte jedno zoznámenie za sebou. Prosím, umožnite, aby sa najskôr toto zoznámenie dokončilo. Ak ste vy alebo vaše kontakty zriedkakedy online, môže to chvíľu trvať.</string>
<string name="introduction_message_title">Zoznámiť kontakty</string>
<string name="introduction_message_hint">Pridať správu (nepovinné)</string>
<string name="introduction_button">Zoznámenie</string>
<string name="introduction_sent">Vaše zoznámenie bolo odoslané.</string>
<string name="introduction_error">Pri zoznamovaní došlo k chybe.</string>
<string name="introduction_request_sent">Požiadali ste o zoznámenie používateľa%1$s s%2$s.</string>
<string name="introduction_request_received">%1$s vás požiadal, aby ste sa zoznámili s %2$s. Chcete si pridať používateľa %2$sdo vášho zoznamu kontaktov?</string>
<string name="introduction_request_exists_received">%1$s vás požiadal, aby vás zoznámil s používateľom %2$s, ale %2$s je už vo vašom zozname kontaktov. Keďže %1$s o tom nemusí vedieť, stále môžete odpovedať:</string>
<string name="introduction_request_answered_received">%1$svás požiadal, aby ste zoznámili s %2$s.</string>
<string name="introduction_response_accepted_sent">Prijali ste zoznámenie s %1$s.</string>
<string name="introduction_response_accepted_sent_info">Predtým, ako bude %1$s pridaný do vašich kontaktov, musí zoznámenie prijať aj on. To môže nejaký čas trvať.</string>
<string name="introduction_response_declined_sent">Odmietli ste zoznámenie s %1$s.</string>
<string name="introduction_response_declined_auto">Zoznámenie s %1$s bolo automaticky odmietnuté.</string>
<string name="introduction_response_accepted_received">%1$sprijal/a zoznámenie s %2$s.</string>
<string name="introduction_response_declined_received">%1$sodmietol/a zoznámenie s %2$s.</string>
<string name="introduction_response_declined_received_by_introducee">%1$shovorí, že %2$sodmietol zoznámenie.</string>
<!--Connect via Bluetooth-->
<string name="menu_item_connect_via_bluetooth">Pripojiť cez Bluetooth</string>
<string name="connect_via_bluetooth_title">Pripojiť cez Bluetooth</string>
<string name="connect_via_bluetooth_intro">V prípade, že pripojenie Bluetooth nefunguje automaticky, môžete sa pomocou tejto obrazovky pripojiť manuálne.\n\nAby to fungovalo, váš kontakt musí byť nablízku.\n\nVy a váš kontakt by ste mali stlačiť \"Štart\" súčasne.</string>
<string name="connect_via_bluetooth_already_discovering">Už sa pokúšate pripojiť cez Bluetooth. Skús to prosím čoskoro znova.</string>
<string name="connect_via_bluetooth_no_location_permission">Nie je možné pokračovať bez povolenia určenia polohy</string>
<string name="connect_via_bluetooth_no_bluetooth_permission">Nie je možné pokračovať bez povolenia blízkych zariadení</string>
<string name="connect_via_bluetooth_start">Pripájanie cez Bluetooth…</string>
<string name="connect_via_bluetooth_success">Úspešne pripojené cez Bluetooth</string>
<string name="connect_via_bluetooth_error">Nepodarilo sa pripojiť cez Bluetooth.</string>
<string name="connect_via_bluetooth_error_not_supported">Bluetooth nie je podporovaný na tomto zariadením.</string>
<!--Private Groups-->
<string name="groups_list_empty">Žiadne skupiny na zobrazenie</string>
<string name="groups_list_empty_action">Ťuknutím na ikonu + vytvorte skupinu alebo požiadajte svoje kontakty, aby s vami zdieľali skupiny</string>
<string name="groups_created_by">Vytvoril používateľ %s</string>
<plurals name="messages">
<item quantity="one">%d správa</item>
<item quantity="few">%d správy</item>
<item quantity="many">%d správ</item>
<item quantity="other">%d správ</item>
</plurals>
<string name="groups_group_is_empty">Táto skupina je prázdna</string>
<string name="groups_group_is_dissolved">Táto skupina bola zrušená</string>
<string name="groups_remove">Odstrániť</string>
<string name="groups_create_group_title">Vytvoriť súkromnú skupinu</string>
<string name="groups_create_group_button">Vytvoriť skupinu</string>
<string name="groups_create_group_invitation_button">Poslať pozvánku</string>
<string name="groups_create_group_hint">Vyberte názov vašej súkromnej skupiny</string>
<string name="groups_invitation_sent">Skupinová pozvánka bola odoslaná</string>
<string name="groups_member_list">Zoznam členov</string>
<string name="groups_invite_members">Pozvať členov</string>
<string name="groups_member_created_you">Vytvorili ste skupinu</string>
<string name="groups_member_created">%s vytvoril/a skupinu</string>
<string name="groups_member_joined_you">Pripojili ste sa k skupine</string>
<string name="groups_member_joined">%s sa pripojil ku skupine</string>
<string name="groups_leave">Opustiť skupinu</string>
<string name="groups_leave_dialog_title">Potvrdiť opustenie skupiny</string>
<string name="groups_leave_dialog_message">Ste si istí, že chcete opustiť túto skupinu?</string>
<string name="groups_dissolve">Zrušiť skupinu</string>
<string name="groups_dissolve_dialog_title">Potvrdiť zrušenie skupiny</string>
<string name="groups_dissolve_dialog_message">Ste si istí, že chcete túto skupinu zrušiť?\n\nVšetci ostatní členovia nebudú môcť pokračovať v konverzácii a nemusia dostávať najnovšie správy.</string>
<string name="groups_dissolve_button">Zrušiť skupinu</string>
<string name="groups_dissolved_dialog_title">Skupina bola zrušená</string>
<string name="groups_dissolved_dialog_message">Zakladateľ tejto skupiny ju zrušil.\n\nUž nemôžete písať správy do skupiny a nemusíte dostávať všetky príspevky, ktoré boli napísané.</string>
<!--Private Group Invitations-->
<string name="groups_invitations_title">Skupinové pozvánky</string>
<string name="groups_invitations_invitation_sent">Pozvali ste používateľa %1$s skupiny \"%2$s\".</string>
<string name="groups_invitations_invitation_received">%1$svás pozval do skupiny \"%2$s\".</string>
<string name="groups_invitations_joined">Pripojený do skupiny</string>
<string name="groups_invitations_declined">Skupinové pozvanie odmietnuté</string>
<plurals name="groups_invitations_open">
<item quantity="one">%d otvorená pozvánka do skupiny</item>
<item quantity="few">%d otvorené pozvánky do skupiny</item>
<item quantity="many">%d otvorených pozvánok do skupiny</item>
<item quantity="other">%d otvorených pozvánok do skupiny</item>
</plurals>
<string name="groups_invitations_response_accepted_sent">Prijali ste pozvánku do skupiny od používateľa %s.</string>
<string name="groups_invitations_response_declined_sent">Odmietli ste pozvánku do skupiny od používateľa %s.</string>
<string name="groups_invitations_response_declined_auto">Pozvánka do skupiny od používateľa %sbola automaticky odmietnutá.</string>
<string name="groups_invitations_response_accepted_received">%sprijal/a pozvanie do skupiny.</string>
<string name="groups_invitations_response_declined_received">%s odmietol pozvanie do skupiny.</string>
<string name="sharing_status_groups">Do skupiny môže pozývať nových členov len jej zakladateľ. Nižšie sú uvedení všetci súčasní členovia skupiny.</string>
<!--Private Groups Revealing Contacts-->
<string name="groups_reveal_contacts">Odhaliť kontakty</string>
<string name="groups_reveal_dialog_message">Môžete si vybrať, či chcete odhaliť kontakty všetkým súčasným a budúcim členom tejto skupiny.\n\nOdhalenie kontaktov urýchľuje a zvyšuje spoľahlivosť vášho pripojenia k skupine, pretože s odhalenými kontaktmi môžete komunikovať, aj keď je tvorca skupiny offline.</string>
<string name="groups_reveal_visible">Vzťah s kontaktom je viditeľný pre skupinu</string>
<string name="groups_reveal_visible_revealed_by_us">Vzťah s kontaktom je viditeľný pre skupinu (odhalený vami)</string>
<string name="groups_reveal_visible_revealed_by_contact">Vzťah s kontaktom je viditeľný pre skupinu (odhalený používateľom %s )</string>
<string name="groups_reveal_invisible">Vzťah s kontaktom nie je viditeľný pre skupinu</string>
<!--Forums-->
<string name="no_forums">Žiadne fóra na zobrazenie</string>
<string name="no_forums_action">Ťuknutím na ikonu + vytvoríte fórum alebo požiadajte svoje kontakty, aby s vami zdieľali fóra</string>
<string name="create_forum_title">Vytvoriť fórum</string>
<string name="choose_forum_hint">Vyberte si názov pre vaše fórum</string>
<string name="create_forum_button">Vytvoriť fórum</string>
<string name="forum_created_toast">Fórum bolo vytvorené</string>
<string name="no_forum_posts">Žiadne články na zobrazenie</string>
<string name="no_posts">Žiadne príspevky</string>
<plurals name="posts">
<item quantity="one">%dpríspevok</item>
<item quantity="few">%dpríspevky</item>
<item quantity="many">%dpríspevkov</item>
<item quantity="other">%d príspevkov</item>
</plurals>
<string name="forum_new_message_hint">Nový príspevok</string>
<string name="forum_message_reply_hint">Nová odpoveď</string>
<string name="btn_reply">Odpovedať</string>
<string name="forum_leave">Opustiť fórum</string>
<string name="dialog_title_leave_forum">Potvrdiť opustenie fóra</string>
<string name="dialog_message_leave_forum">Ste si istí, že chcete opustiť toto fórum?\n\nVšetkým kontaktom, s ktorými ste zdieľali toto fórum, môžu prestať chodiť aktualizácie.</string>
<string name="dialog_button_leave">Odísť</string>
<string name="forum_left_toast">Opustené fórum</string>
<!--Forum Sharing-->
<string name="forum_share_button">Zdieľať fórum</string>
<string name="contacts_selected">Vybraté kontakty</string>
<string name="activity_share_toolbar_header">Vyberte kontakty</string>
<string name="no_contacts_selector">Žiadne kontakty na zobrazenie</string>
<string name="no_contacts_selector_action">Po pridaní kontaktu sa sem prosím vráťte</string>
<string name="forum_shared_snackbar">Fórum je zdieľané s vybranými kontaktmi</string>
<string name="forum_share_message">Pridať správu (nepovinné)</string>
<string name="forum_share_error">Pri zdieľaní tohto fóra došlo k chybe.</string>
<string name="forum_invitation_received">%1$s s vami zdieľa fórum \"%2$s\".</string>
<string name="forum_invitation_sent">Zdieľali ste fórum \"%1$s\" s používateľom %2$s.</string>
<string name="forum_invitations_title">Pozvánky na fórum</string>
<string name="forum_invitation_exists">Už ste prijali pozvánku do tohto fóra.\n\nPrijatím ďalších pozvánok sa vaše pripojenie k fóru zrýchli a bude spoľahlivejšie.</string>
<string name="forum_joined_toast">Pripojený do fóra</string>
<string name="forum_declined_toast">Pozvánka odmietnutá</string>
<string name="shared_by_format">Zdieľal používateľ %s</string>
<string name="forum_invitation_already_sharing">Už zdieľate</string>
<string name="forum_invitation_already_invited">Pozvánka už bola odoslaná</string>
<string name="forum_invitation_invite_received">Pozvánka už bola doručená</string>
<string name="forum_invitation_not_supported">Nie je podporované týmto kontaktom</string>
<string name="forum_invitation_error">Chyba. Toto je chyba a nie je to vaša chyba</string>
<string name="forum_invitation_response_accepted_sent">Prijali ste pozvanie do fóra od %s.</string>
<string name="forum_invitation_response_declined_sent">Odmietli ste pozvanie do fóra od %s.</string>
<string name="forum_invitation_response_declined_auto">Pozvánka do fóra od používateľa %s bola automaticky odmietnutá.</string>
<string name="forum_invitation_response_accepted_received">Používateľ %sprijal pozvanie do fóra.</string>
<string name="forum_invitation_response_declined_received">Používateľ %s odmietol pozvanie do fóra.</string>
<string name="sharing_status">Stav zdieľania</string>
<string name="sharing_status_forum">Každý člen fóra ho môže zdieľať so svojimi kontaktmi. Toto fórum zdieľate s nasledujúcimi kontaktmi. Môžu tam byť aj ďalší členovia, ktorých nevidíte.</string>
<string name="shared_with">Zdieľané s %1$d (%2$donline)</string>
<plurals name="forums_shared">
<item quantity="one">%d fórum zdieľané prostredníctvom kontaktov</item>
<item quantity="few">%d fóra zdieľané prostredníctvom kontaktov</item>
<item quantity="many">%d fór zdieľaných prostredníctvom kontaktov</item>
<item quantity="other">%d fór zdieľaných prostredníctvom kontaktov</item>
</plurals>
<string name="nobody">Nikto</string>
<!--Blogs-->
<string name="blogs_other_blog_empty_state">Žiadne články na zobrazenie</string>
<string name="read_more">čítať viac</string>
<string name="blogs_write_blog_post">Napísať príspevok do blogu</string>
<string name="blogs_write_blog_post_body_hint">Napíšte svoj príspevok na blog</string>
<string name="blogs_publish_blog_post">Zverejniť</string>
<string name="blogs_blog_post_created">Príspevok na blogu bol vytvorený</string>
<string name="blogs_blog_post_received">Prijatý nový príspevok na blogu</string>
<string name="blogs_blog_post_scroll_to">Prejsť na</string>
<string name="blogs_feed_empty_state">Žiadne články na zobrazenie</string>
<string name="blogs_feed_empty_state_action">Zobrazia sa tu príspevky od vašich kontaktov a blogov, ktoré odoberáte\n\nŤuknutím na ikonu pera napíšete príspevok.</string>
<string name="blogs_remove_blog">Odstrániť blog</string>
<string name="blogs_remove_blog_dialog_message">Ste si istí, že chcete odstrániť tento blog?\n\nPríspevky budú odstránené z vášho zariadenia, ale nie zo zariadení iných ľudí.\n\nVšetky kontakty, s ktorými ste zdieľali tento blog, môžu prestať dostávať aktualizácie.</string>
<string name="blogs_remove_blog_ok">Odstrániť</string>
<string name="blogs_blog_removed">Blog odstránený</string>
<string name="blogs_reblog_comment_hint">Pridať komentár (nepovinné)</string>
<string name="blogs_reblog_button">Zdieľať blog</string>
<!--Blog Sharing-->
<string name="blogs_sharing_share">Zdieľať blog</string>
<string name="blogs_sharing_error">Pri zdieľaní tohto blogu došlo k chybe.</string>
<string name="blogs_sharing_button">Zdieľať blog</string>
<string name="blogs_sharing_snackbar">Blog zdieľaný s vybranými kontaktmi</string>
<string name="blogs_sharing_response_accepted_sent">Prijali ste pozvanie na blog od %s.</string>
<string name="blogs_sharing_response_declined_sent">Odmietli ste pozvanie na blog od %s.</string>
<string name="blogs_sharing_response_declined_auto">Pozvánka na blog od používateľa %s bola automaticky odmietnutá.</string>
<string name="blogs_sharing_response_accepted_received">%s prijal pozvanie na blog.</string>
<string name="blogs_sharing_response_declined_received">%s odmietol pozvanie na blog.</string>
<string name="blogs_sharing_invitation_received">%1$szdieľal s vami blog \"%2$s\".</string>
<string name="blogs_sharing_invitation_sent">Zdieľali ste blog \"%1$s\" s používateľom%2$s.</string>
<string name="blogs_sharing_invitations_title">Pozvánky na blog</string>
<string name="blogs_sharing_joined_toast">Prihlásený na blog</string>
<string name="blogs_sharing_declined_toast">Pozvánka odmietnutá</string>
<string name="sharing_status_blog">Ktokoľvek, kto sa prihlási na odber blogu, ho môže zdieľať so svojimi kontaktmi. Tento blog zdieľate s nasledujúcimi kontaktmi. Môžu existovať aj ďalší odberatelia, ktorých nevidíte.</string>
<!--RSS Feeds-->
<string name="blogs_rss_feeds_import">Importovať RSS kanál</string>
<string name="blogs_rss_feeds_import_button">Importovať</string>
<string name="blogs_rss_feeds_import_hint">Zadajte adresu URL RSS kanálu</string>
<string name="blogs_rss_feeds_import_progress">Importovanie RSS kanála...</string>
<string name="blogs_rss_feeds_import_error">Je nám to ľúto! Pri importovaní vášho kanála došlo k chybe.</string>
<string name="blogs_rss_feeds_import_title">Importovať kanál zo súboru</string>
<string name="blogs_rss_feeds">Kanály RSS</string>
<string name="blogs_rss_feeds_manage_imported">Importované:</string>
<string name="blogs_rss_feeds_manage_author">Autor:</string>
<string name="blogs_rss_feeds_manage_updated">Naposledy aktualizované:</string>
<string name="blogs_rss_remove_feed">Odstrániť kanál</string>
<string name="blogs_rss_remove_feed_dialog_message">Ste si istí, že chcete odstrániť tento kanál?\n\nPríspevky budú odstránené z vášho zariadenia, ale nie zo zariadení iných ľudí.\n\nVšetky kontakty, s ktorými ste zdieľali tento kanál, môžu prestať dostávať aktualizácie.</string>
<string name="blogs_rss_remove_feed_ok">Odstrániť</string>
<string name="blogs_rss_feeds_manage_empty_state">Žiadne RSS kanály na zobrazenie\n\nŤuknutím na ikonu + naimportujte kanál</string>
<string name="blogs_rss_feeds_manage_error">Vyskytol sa problém s načítaním vašich kanálov. Skúste to prosím neskôr.</string>
<!--Settings Profile Picture-->
<string name="change_profile_picture">Ťuknutím zmeníte svoj profilový obrázok</string>
<string name="dialog_confirm_profile_picture_title">Zmeniť profilový obrázok</string>
<string name="dialog_confirm_profile_picture_remark">Iba vaše kontakty môžu vidieť tento obrázok </string>
<string name="change_profile_picture_failed_message">Je nám ľúto, ale pri aktualizácii vašej profilovej fotografie sa niečo pokazilo</string>
<!--Settings Display-->
<string name="pref_language_title">Jazyk a región</string>
<string name="pref_language_changed">Toto nastavenie sa prejaví po reštartovaní aplikácie Briar. Odhláste sa a reštartujte Briar.</string>
<string name="pref_language_default">Predvolené systémom</string>
<string name="display_settings_title">Zobrazenie</string>
<string name="pref_theme_title">Téma</string>
<string name="pref_theme_light">Svetlá</string>
<string name="pref_theme_dark">Tmavá</string>
<string name="pref_theme_auto">Automatická (podľa denného času)</string>
<string name="pref_theme_system">Predvolené systémom</string>
<!--Settings Connections-->
<string name="network_settings_title">Pripojenia</string>
<string name="bluetooth_setting">Prepojiť sa s kontaktmi cez Bluetooth</string>
<string name="wifi_setting">Prepojiť sa s kontaktmi v rovnakej sieti Wi-Fi</string>
<string name="tor_enable_title">Prepojiť sa s kontaktmi cez internet</string>
<string name="tor_enable_summary">Všetky pripojenia prechádzajú cez sieť Tor kvôli ochrane súkromia</string>
<string name="tor_network_setting">Spôsob pripojenia pre sieť Tor</string>
<string name="tor_network_setting_automatic">Automaticky podľa polohy</string>
<string name="tor_network_setting_without_bridges">Použiť sieť Tor bez premostenia</string>
<string name="tor_network_setting_with_bridges">Použiť sieť Tor s premostením</string>
<string name="tor_network_setting_never">Nepripájať sa k internetu</string>
<!--How and when Briar will connect to Tor: E.g. "Don't connect to the Internet (in China)" or "Use Tor network with bridges (in Belarus)"-->
<string name="tor_network_setting_summary">Automaticky: %1$s (v %2$s)</string>
<string name="tor_mobile_data_title">Použiť mobilné dáta</string>
<string name="tor_only_when_charging_title">Pripojiť sa k internetu len počas nabíjania</string>
<string name="tor_only_when_charging_summary">Zakáže pripojenie k internetu, keď zariadenie beží na batériu</string>
<!--Settings Security and Panic-->
<string name="security_settings_title">Bezpečnosť</string>
<string name="pref_lock_title">Zámok aplikácie</string>
<string name="pref_lock_summary">Použite zámok obrazovky zariadenia na ochranu aplikácie Briar, keď ste prihlásení</string>
<string name="pref_lock_disabled_summary">Ak chcete používať túto funkciu, nastavte pre svoje zariadenie zámok obrazovky.</string>
<string name="pref_lock_timeout_title">Časový limit nečinnosti zámku aplikácie</string>
<!--The %s placeholder is replaced with the following time spans, e.g. 5 Minutes, 1 Hour-->
<string name="pref_lock_timeout_summary">Ak nepoužívate program Briar, automaticky sa uzamkne po %s</string>
<!--Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s"-->
<string name="pref_lock_timeout_1">1 minúte</string>
<!--Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s"-->
<string name="pref_lock_timeout_5">5 minútach</string>
<!--Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s"-->
<string name="pref_lock_timeout_15">15 minútach</string>
<!--Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s"-->
<string name="pref_lock_timeout_30">30 minútach</string>
<!--Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s"-->
<string name="pref_lock_timeout_60">1 hodina</string>
<string name="pref_lock_timeout_never">Nikdy</string>
<string name="pref_lock_timeout_never_summary">Nikdy automaticky nezamykať Briar</string>
<string name="change_password">Zmeniť heslo</string>
<string name="current_password">Aktuálne heslo</string>
<string name="choose_new_password">Nové heslo</string>
<string name="confirm_new_password">Potvrdiť nové heslo</string>
<string name="password_changed">Heslo bolo zmenené.</string>
<string name="panic_setting">Nastavenie tlačidla paniky</string>
<string name="panic_setting_title">Tlačidlo Paniky</string>
<string name="panic_setting_hint">Nastavte, ako bude aplikácia Briar reagovať, keď použijete aplikáciu tlačidla paniky</string>
<string name="panic_app_setting_title">Aplikácia tlačidla paniky</string>
<string name="unknown_app">neznáma aplikácia</string>
<string name="panic_app_setting_summary">Žiadna aplikácia nebola nastavená</string>
<string name="panic_app_setting_none">Žiadne</string>
<string name="dialog_title_connect_panic_app">Potvrdiť aplikáciu paniky</string>
<string name="dialog_message_connect_panic_app">Ste si istí, že chcete povoliť aplikácii %1$sspustenie deštruktívnych akcií tlačidla paniky?</string>
<string name="panic_setting_destructive_action">Deštruktívne akcie</string>
<string name="panic_setting_signout_title">Odhlásiť sa</string>
<string name="panic_setting_signout_summary">Odhlásiť sa z Briaru, ak je stlačené tlačidlo pre paniku</string>
<string name="purge_setting_title">Vymazať účet</string>
<string name="purge_setting_summary">Vymazať svoje konto Briar pri stlačení tlačidla paniky. Pozor: Týmto sa natrvalo vymažú vaše identity, kontakty a správy</string>
<!--Settings Notifications-->
<string name="notification_settings_title">Oznámenia</string>
<string name="notify_sign_in_title">Pripomenúť mi, aby som sa prihlásil</string>
<string name="notify_sign_in_summary">Zobraziť pripomienku pri spustení telefónu alebo aktualizácii aplikácie</string>
<string name="notify_private_messages_setting_title">Súkromné správy</string>
<string name="notify_private_messages_setting_summary">Zobraziť upozornenia pre súkromné správy</string>
<string name="notify_private_messages_setting_summary_26">Nastaviť upozornenia pre súkromné správy</string>
<string name="notify_group_messages_setting_title">Skupinové správy</string>
<string name="notify_group_messages_setting_summary">Zobraziť upozornenia pre skupinové správy</string>
<string name="notify_group_messages_setting_summary_26">Nastaviť upozornenia pre skupinové správy</string>
<string name="notify_forum_posts_setting_title">Príspevky vo fóre</string>
<string name="notify_forum_posts_setting_summary">Zobraziť upozornenia na príspevky vo fóre</string>
<string name="notify_forum_posts_setting_summary_26">Nastaviť upozornenia na príspevky vo fóre</string>
<string name="notify_blog_posts_setting_title">Príspevky na blogu</string>
<string name="notify_blog_posts_setting_summary">Zobraziť upozornenia pre príspevky v blogu</string>
<string name="notify_blog_posts_setting_summary_26">Nastaviť upozornenia pre príspevky v blogu</string>
<string name="notify_vibration_setting">Vibrovať</string>
<string name="notify_sound_setting">Zvuk</string>
<string name="notify_sound_setting_default">Predvolené zvonenie</string>
<string name="notify_sound_setting_disabled">Žiadne</string>
<string name="choose_ringtone_title">Vybrať zvonenie</string>
<string name="cannot_load_ringtone">Nie je možné načítať zvonenie</string>
<!--Mailbox-->
<string name="mailbox_settings_title">Mailbox</string>
<string name="mailbox_setup_title">Nastavenie Mailbox</string>
<string name="mailbox_setup_intro">Aplikácia Mailbox umožňuje vašim kontaktom posielať správy, aj keď ste v režime offline. Schránka bude prijímať vaše správy a uchovávať ich, kým sa neobjavíte online.
\nAplikáciu Briar Mailbox môžete nainštalovať do náhradného zariadenia. Udržujte ho pripojené k napájaniu a Wi-Fi, aby bolo vždy online.</string>
<string name="mailbox_setup_download">Najprv nainštalujte aplikáciu Mailbox do iného zariadenia vyhľadaním \"Briar Mailbox\" v službe Google Play alebo kdekoľvek kde ste si stiahli Briar.\n
\nPotom prepojte svoj Mailbox s aplikáciou Briar naskenovaním QR kódu, ktorý zobrazí aplikácia Mailbox.</string>
<string name="mailbox_setup_download_link">Zdieľať odkaz na stiahnutie</string>
<string name="mailbox_setup_button_scan">Naskenovať kód QR aplikácie Mailbox</string>
<string name="permission_camera_qr_denied_body">Odmietli ste prístup ku kamere, ale skenovanie QR kódu vyžaduje použitie kamery.\n\nProsím, zvážte udelenie prístupu.</string>
<string name="mailbox_setup_connecting">Pripájanie na Mailbox...</string>
<!--This string is shown when connecting to a Mailbox for the first time. The placeholder will be replaced with a duration, e.g. "2 minutes".-->
<string name="mailbox_setup_connecting_info">Toto môže trvať až %1s</string>
<string name="mailbox_qr_code_too_old">QR kód, ktorý ste naskenovali, pochádza zo staršej verzie aplikácie Briar Mailbox.\n\nProsím, aktualizujte Briar Mailbox na najnovšiu verziu a potom to skúste znova.</string>
<string name="mailbox_qr_code_too_new">QR kód, ktorý ste naskenovali, pochádza z novšej verzie aplikácie Briar Mailbox.\n\nProsím, aktualizujte Briar na najnovšiu verziu a potom to skúste znova.</string>
<string name="contact_qr_code_for_mailbox">Naskenovaný QR kód slúži na pridanie kontaktu Briar.\n\nAk chcete pridať kontakt, prejdite do zoznamu kontaktov a ťuknite na ikonu +.</string>
<string name="mailbox_setup_qr_code_wrong_description">QR kód, ktorý ste naskenovali, nepochádza z aplikácie Briar Mailbox.\n\nProsím, otvorte aplikáciu Briar Mailbox na svojom Mailbox zariadení a naskenujte QR kód, ktorý sa v nej nachádza.</string>
<string name="mailbox_setup_already_paired_title">Mailbox je už prepojený</string>
<string name="mailbox_setup_already_paired_description">Odpojte Mailbox na vašom druhom zariadení a skúste to znova.</string>
<string name="mailbox_setup_io_error_title">Nepodarilo sa pripojiť</string>
<string name="mailbox_setup_io_error_description">Skontrolujte, či sú obe zariadenia pripojené k internetu, a skúste to znova.</string>
<string name="mailbox_setup_assertion_error_title">Chyba aplikácie Mailbox</string>
<string name="mailbox_setup_assertion_error_description">Ak problém pretrváva, pošlite prosím spätnú väzbu (s anonymnými údajmi) prostredníctvom aplikácie Briar.</string>
<string name="mailbox_setup_camera_error_description">Nepodarilo sa získať prístup ku kamere. Skúste to znova, možno po reštartovaní zariadenia.</string>
<string name="mailbox_setup_paired_title">Pripojené</string>
<string name="mailbox_setup_paired_description">Vaša aplikácia Mailbox bola úspešne prepojená s Briar.\n
\nUdržujte svoju aplikáciu Mailbox pripojenú k napájaniu a Wi-Fi, aby bola vždy online.</string>
<string name="tor_offline_title">Odpojený</string>
<string name="tor_offline_description">Skontrolujte, či je toto zariadenie online a či je povolené pripojenie na internet.\n
\nPotom počkajte, kým sa ikona zemegule na obrazovke nastavení pripojenia zmení na zelenú.</string>
<string name="tor_offline_button_check">Skontrolovať nastavenia pripojenia</string>
<string name="mailbox_status_title">Stav aplikácie Mailbox</string>
<string name="mailbox_status_connected_title">Mailbox je spustený</string>
<string name="mailbox_status_problem_title">Briar má problémy s pripojením k Mailbox</string>
<string name="mailbox_status_failure_title">Mailbox nie je dostupný</string>
<string name="mailbox_status_app_too_old_title">Briar je príliš starý</string>
<string name="mailbox_status_app_too_old_message">Aktualizujte aplikáciu Briar na najnovšiu verziu a skúste to znova.</string>
<string name="mailbox_status_mailbox_too_old_title">Mailbox je príliš starý</string>
<string name="mailbox_status_mailbox_too_old_message">Aktualizujte aplikáciu Mailbox na najnovšiu verziu a skúste to znova.</string>
<string name="mailbox_status_check_button">Skontrolovať pripojenie</string>
<!--Example for string substitution: Last connection: 3min ago-->
<string name="mailbox_status_connected_info">Posledné pripojenie: %s</string>
<!--Indicates that there never was a connection to the mailbox. Last connection: Never-->
<string name="mailbox_status_connected_never">Nikdy</string>
<string name="mailbox_status_unlink_button">Odpojiť</string>
<string name="mailbox_status_unlink_dialog_title">Odpojiť Mailbox?</string>
<string name="mailbox_status_unlink_dialog_question">Ste si istí, že chcete zrušiť prepojenie s Mailbox?</string>
<string name="mailbox_status_unlink_dialog_warning">Ak zrušíte prepojenie s Mailbox, nebudete môcť prijímať správy, keď je Briar v režime offline.</string>
<string name="mailbox_status_unlink_no_wipe_title">Váš Mailbox bol odpojený</string>
<string name="mailbox_status_unlink_no_wipe_message">Keď budete mať nabudúce prístup k zariadeniu Mailbox, otvorte aplikáciu Mailbox a ťuknutím na tlačidlo \"Odpojiť\" dokončite proces.\n\nAk už nemáte prístup k zariadeniu Mailbox, neznepokojujte sa. Vaše údaje sú zašifrované, takže zostanú v bezpečí, aj keď proces nedokončíte.</string>
<string name="mailbox_status_unlink_success">Váš Mailbox bol odpojený</string>
<string name="mailbox_error_notification_channel_title">Briar Mailbox problém</string>
<string name="mailbox_error_notification_title">Briar Mailbox nie je dostupný</string>
<string name="mailbox_error_notification_text">Ťuknutím na položku opravte problém.</string>
<string name="mailbox_error_wizard_button">Opraviť problém</string>
<string name="mailbox_error_wizard_title">Sprievodca riešením problémov Mailbox</string>
<string name="mailbox_error_wizard_question1">Máte prístup k vášmu zariadeniu Mailbox?</string>
<string name="mailbox_error_wizard_answer1">Áno, mám k nemu prístup práve teraz.</string>
<string name="mailbox_error_wizard_answer2">Teraz nie, ale môžem k nemu získať prístup neskôr.</string>
<string name="mailbox_error_wizard_answer3">Nie, už k nemu nemám prístup.</string>
<string name="mailbox_error_wizard_info1_1">Skontrolujte, či je zariadenie Mailbox zapnuté a pripojené k internetu.</string>
<string name="mailbox_error_wizard_question1_1">Otvorte aplikáciu Mailbox. Čo vidíte?</string>
<string name="mailbox_error_wizard_answer1_1">Vidím pokyny na nastavenie aplikácie Mailbox</string>
<string name="mailbox_error_wizard_answer1_2">Vidím QR kód</string>
<string name="mailbox_error_wizard_answer1_3">Vidím \" Mailbox je spustený\"</string>
<string name="mailbox_error_wizard_answer1_4">Vidím \"Zariadenie je v režime offline\"</string>
<string name="mailbox_error_wizard_info1_1_1">Zrušte prosím prepojenie aplikácie Mailbox pomocou nižšie uvedeného tlačidla a potom postupujte podľa pokynov na zariadení Mailbox, aby ste ju opäť prepojili.</string>
<string name="mailbox_error_wizard_info_1_1_2">Zrušte prosím prepojenie aplikácie Mailbox pomocou tlačidla nižšie a potom naskenujte QR kód, aby ste ju opäť prepojili.</string>
<string name="mailbox_error_wizard_info1_1_3">Pomocou nasledujúceho tlačidla skontrolujte prosím pripojenie medzi aplikáciami Briar a Mailbox.\n\n
Ak spojenie opäť zlyhá:\n
\u2022 Skontrolujte, či sú aplikácie Mailbox a Briar aktualizované na najnovšiu verziu.\n
\u2022 Reštartujte svoje zariadenia Mailbox a Briar a skúste to znova.</string>
<string name="mailbox_error_wizard_info1_1_4">Skontrolujte, či je zariadenie Mailbox správne pripojené k internetu.\n\nPrekontrolujte, či hodiny na zariadení Mailbox ukazujú správny čas, dátum a časové pásmo.\n\nPrekontrolujte, či sú aplikácie Mailbox a Briar aktualizované na najnovšiu verziu.\n\nReštartujte zariadenia Mailbox a Briar a skúste to znova.</string>
<string name="mailbox_error_wizard_info2">Vráťte sa prosím späť na túto obrazovku, keď budete mať prístup k zariadeniu.</string>
<string name="mailbox_error_wizard_info3">Zrušte prosím prepojenie svojej aplikácie Mailbox pomocou tlačidla nižšie.\n\nPo zrušení prepojenia vašej starej aplikácie Mailbox môžete kedykoľvek nastaviť novú aplikáciu Mailbox.</string>
<!--About-->
<string name="about_title">O programe</string>
<string name="briar_version">Briar verzia: %s</string>
<string name="tor_version">Tor verzia: %s</string>
<string name="links">Odkazy</string>
<string name="briar_website">\u2022 <a href="">Webová stránka</a></string>
<string name="briar_source_code">\u2022 <a href="">Zdrojový kód</a></string>
<string name="briar_changelog">\u2022 <a href="">Zoznam zmien</a></string>
<string name="briar_privacy_policy">\u2022 <a href="">Zásady ochrany súkromia</a></string>
<!--Here translators can add their names or Transifex usernames(eg "Thanks to all the contributors at the Localization Lab, especially Tom, Matthew and Jerry")-->
<string name="translator_thanks">Ďakujeme všetkým prispievateľom z Localization Lab, hlavne prekladateľom: Jozef Gaál</string>
<!--Conversation Settings-->
<string name="disappearing_messages_title">Miznúce správy</string>
<string name="disappearing_messages_explanation_long">Zapnutím tohto nastavenia nové
správy v tejto konverzácii automaticky zmiznú po 7\u00A0dňoch.
\n\nOdpočet pre kópiu správy odosielateľa sa začne po jej doručení.
Odpočítavanie pre príjemcu sa začne po prečítaní správy.
\n\nSprávy, ktoré zmiznú sú označené ikonou bomby.
\n\nMajte na pamäti, že príjemcovia môžu stále vytvárať kópie správ, ktoré ste odoslali.
\n\nAk toto nastavenie zmeníte, bude sa okamžite vzťahovať na nové správy a na
správy kontaktov, keď dostanú vašu ďalšiu správu.
Váš kontakt môže toto nastavenie zmeniť aj pre vás oboch.</string>
<string name="learn_more">Zisti viac</string>
<string name="disappearing_messages_summary">Nastaviť, aby budúce správy v tejto konverzácii automaticky zmizli po 7\u00A0dňoch.</string>
<!--Settings Actions-->
<string name="pref_category_actions">Akcie</string>
<string name="send_feedback">Odoslať spätnú väzbu</string>
<!--Link Warning-->
<string name="link_warning_title">Varovanie o odkaze</string>
<string name="link_warning_intro">Chystáte sa otvoriť nasledujúci odkaz pomocou externej aplikácie.</string>
<string name="link_warning_text">Toto môže byť použité na vašu identifikáciu. Premyslite si, či dôverujete osobe, ktorá vám poslala tento odkaz, a zvážte jeho otvorenie pomocou prehliadača Tor.</string>
<string name="link_warning_open_link">Otvoriť odkaz</string>
<!--Crash Reporter-->
<string name="crash_report_title">Briar Hlásenie o chybe</string>
<string name="briar_crashed">Prepáčte, aplikácia Briar spadla</string>
<string name="not_your_fault">Toto nie je vaša chyba.</string>
<string name="please_send_report">Pomôžte nám prosím vytvoriť lepší Briar tým, že nám pošlete hlásenie o chybe.</string>
<string name="report_is_encrypted">Sľubujeme, že hlásenie bude zašifrované a odoslané bezpečne.</string>
<string name="feedback_title">Spätná väzba</string>
<string name="describe_crash">Opíšte, čo sa stalo (nepovinné)</string>
<string name="enter_feedback">Zadajte svoju spätnú väzbu</string>
<string name="optional_contact_email">Vaša e-mailová adresa (nepovinné)</string>
<string name="privacy_policy">Odoslaním údajov súhlasíte s našimi <a href="">zásadami ochrany osobných údajov</a></string>
<string name="include_debug_report_crash">Zahrnúť anonymné údaje o chybe</string>
<string name="include_debug_report_feedback">Zahrnúť anonymné údaje o tomto zariadení</string>
<string name="dev_report_user_info">Informácie o používateľovi</string>
<string name="dev_report_basic_info">Základné informácie</string>
<string name="dev_report_device_info">Informácie o zariadení</string>
<string name="dev_report_stacktrace">Trasovanie zásobníka</string>
<string name="dev_report_time_info">Informácie o čase</string>
<string name="dev_report_memory">Pamäť</string>
<string name="dev_report_storage">Úložný priestor</string>
<string name="dev_report_connectivity">Konektivita</string>
<string name="dev_report_network_usage">Využitie siete</string>
<string name="dev_report_build_config">Konfigurácia zostavy</string>
<string name="dev_report_logcat">Záznam aplikácie</string>
<string name="dev_report_device_features">Funkcie zariadenia</string>
<string name="send_report">Odoslať hlásenie</string>
<string name="close">Zavrieť</string>
<string name="dev_report_sending">Odosielanie spätnej väzby...</string>
<string name="dev_report_sent">Spätná väzba odoslaná</string>
<string name="dev_report_saved">Hlásenie bolo uložené. Odošle sa pri ďalšom prihlásení do aplikácie Briar.</string>
<string name="dev_report_error">Chyba: Odoslanie hlásenia zlyhalo</string>
<!--Sign Out-->
<string name="progress_title_logout">Odhlasovanie z Briar...</string>
<!--Screen Filters & Tapjacking-->
<string name="screen_filter_title">Rozpoznané prekrytie obrazovky</string>
<string name="screen_filter_body">Ďalšia aplikácia vykresľuje nad aplikáciou Briar. Na ochranu vašej bezpečnosti nebude Briar reagovať na dotyky, keď naň vykresľuje iná aplikácia.\n\nNasledujúce aplikácie môžu vykresľovať nad ňou:\n\n%1$s</string>
<string name="screen_filter_body_api_30">Iná aplikácia vykresľuje údaje nad aplikáciou Briar. Na ochranu vašej bezpečnosti nebude Briar reagovať na dotyky, keď naň vykresľuje iná aplikácia.\n\nPreskúmajte aplikácie nižšie uvedené a nájdite zodpovednú aplikáciu.</string>
<string name="screen_filter_allow">Povoliť týmto aplikáciám vykresľovanie nad aplikáciou</string>
<string name="screen_filter_review_apps">Preskúmať aplikácie</string>
<!--Permission Requests-->
<string name="permission_camera_title">Povolenie na používanie kamery</string>
<string name="permission_camera_request_body">Na naskenovanie QR kódu potrebuje Briar prístup ku kamere.</string>
<string name="permission_location_title">Povolenie na určenie polohy</string>
<string name="permission_location_request_body">Na zistenie zariadení Bluetooth potrebuje Briar povolenie na prístup k vašej polohe.\n\nBriar neukladá vašu polohu ani ju s nikým nezdieľa.</string>
<string name="permission_camera_location_title">Kamera a poloha</string>
<string name="permission_camera_location_request_body">Na skenovanie QR kódu potrebuje Briar prístup ku kamere.\n\nNa zistenie zariadení Bluetooth potrebuje Briar povolenie na prístup k vašej polohe.\n\nBriar neukladá vašu polohu ani ju s nikým nezdieľa.</string>
<string name="permission_camera_bluetooth_title">Kamera a blízke zariadenia</string>
<string name="permission_camera_bluetooth_request_body">Na skenovanie QR kódu potrebuje Briar prístup ku kamere.\n\nNa zisťovanie zariadení Bluetooth potrebuje Briar povolenie na vyhľadanie a pripojenie k blízkym zariadeniam.</string>
<string name="permission_camera_denied_body">Odmietli ste prístup k fotoaparátu, ale pridávanie kontaktov vyžaduje používanie fotoaparátu.\n\nProsím, zvážte udelenie prístupu.</string>
<string name="permission_location_denied_body">Odmietli ste prístup k vašej polohe, ale Briar potrebuje toto povolenie na zistenie zariadení Bluetooth.\n\nProsím, zvážte udelenie prístupu.</string>
<string name="permission_location_setting_title">Nastavenie polohy</string>
<string name="permission_location_setting_body">Nastavenie polohy vášho zariadenia musí byť zapnuté, aby ste mohli nájsť iné zariadenia prostredníctvom Bluetooth. Ak chcete pokračovať, povoľte určovanie polohy. Neskôr ho môžete opäť vypnúť.</string>
<string name="permission_location_setting_hotspot_body">Ak chcete vytvoriť prístupový bod Wi-Fi, musí byť v zariadení zapnuté nastavenie polohy. Ak chcete pokračovať, povoľte určovanie polohy. Neskôr ho môžete opäť zakázať.</string>
<string name="permission_location_setting_button">Zapnúť polohu</string>
<string name="permission_bluetooth_title">Povolenie pre blízke zariadenia</string>
<string name="permission_bluetooth_body">Na používanie komunikácie Bluetooth potrebuje zariadenie Briar povolenie na vyhľadávanie a pripojenie k blízkym zariadeniam.</string>
<string name="permission_bluetooth_denied_body">Odmietli ste prístup k blízkym zariadeniam, ale Briar potrebuje toto povolenie na používanie Bluetooth.\n\nProsím, zvážte udelenie prístupu.</string>
<string name="qr_code">QR kód</string>
<string name="show_qr_code_fullscreen">Zobraziť QR kód na celú obrazovku</string>
<!--App Locking-->
<string name="lock_unlock">Odomknúť Briar</string>
<string name="lock_unlock_verbose">Na odomknutie zariadenia Briar zadajte PIN, vzor alebo heslo.</string>
<string name="lock_unlock_fingerprint_description">Dotknite sa snímača odtlačkov prstov registrovaným prstom a pokračujte</string>
<string name="lock_unlock_password">Použiť heslo</string>
<string name="lock_is_locked">Briar je zamknutý</string>
<string name="lock_tap_to_unlock">Ťuknutím odomknite</string>
<!--Connections Screen-->
<string name="transports_help_text">Briar sa môže pripojiť ku kontaktom cez internet, Wi-Fi alebo Bluetooth.\n\nVšetky internetové pripojenia prechádzajú cez sieť Tor kvôli ochrane súkromia.\n\nAk sa kontakt dá dosiahnuť viacerými spôsobmi, Briar ich bude používať paralelne.</string>
<!--Share app offline-->
<string name="hotspot_title">Zdieľať túto aplikáciu v režime offline</string>
<string name="hotspot_intro">Zdieľajte túto aplikáciu s niekým v okolí bez pripojenia na internet pomocou Wi-Fi v telefóne.
\n\nVáš telefón spustí prístupový bod Wi-Fi. Ľudia v blízkosti sa budú môcť pripojiť k prístupovému bodu a stiahnuť si aplikáciu Briar z vášho telefónu.</string>
<string name="hotspot_button_start_sharing">Spustiť prístupový bod</string>
<string name="hotspot_button_stop_sharing">Zastaviť prístupový bod</string>
<string name="hotspot_progress_text_start">Nastavovanie prístupového bodu...</string>
<string name="hotspot_notification_channel_title">Prístupový bod Wi-Fi</string>
<string name="hotspot_notification_title">Zdieľanie aplikácie Briar v režime offline</string>
<string name="hotspot_button_connected">Ďalej</string>
<string name="permission_hotspot_location_request_body">Na vytvorenie prístupového bodu Wi-Fi potrebuje Briar povolenie na prístup k vašej polohe.\n\nBriar neukladá vašu polohu ani ju s nikým nezdieľa.</string>
<string name="permission_hotspot_location_request_precise_body">Na vytvorenie prístupového bodu Wi-Fi potrebuje Briar povolenie na prístup k vašej presnej polohe.\n\nBriar neukladá vašu polohu ani ju s nikým nezdieľa.</string>
<string name="permission_hotspot_location_denied_body">Odmietli ste prístup k svojej polohe, ale Briar potrebuje toto povolenie na vytvorenie prístupového bodu Wi-Fi.\n\nProsím, zvážte udelenie prístupu.</string>
<string name="permission_hotspot_location_denied_precise_body">Odmietli ste prístup k presnej polohe, ale Briar potrebuje toto povolenie na vytvorenie prístupového bodu Wi-Fi.\n\nProsím, zvážte udelenie prístupu.</string>
<string name="wifi_settings_title">Nastavenie Wi-Fi</string>
<string name="wifi_settings_request_enable_body">Ak chcete vytvoriť prístupový bod Wi-Fi, zariadenie Briar musí používať Wi-Fi. Povoľte ho.</string>
<string name="hotspot_tab_manual">Manuálne</string>
<!--The placeholder to be inserted into the string 'hotspot_manual_wifi': People can connect by %s-->
<string name="hotspot_scanning_a_qr_code">naskenovaním QR kódu</string>
<!--Wi-Fi setup-->
<!--The %s placeholder will be replaced with the translation of 'hotspot_scanning_a_qr_code'-->
<string name="hotspot_manual_wifi">Váš telefón poskytuje prístupový bod Wi-Fi. Ľudia, ktorí si chcú stiahnuť Briar, sa môžu pripojiť k vášmu prístupovému bodu pridaním nižšie uvedených údajov do nastavení Wi-Fi svojho zariadenia alebo pomocou %s. Po ich pripojení k prístupovému bodu stlačte tlačidlo \"Ďalej\".</string>
<string name="hotspot_manual_wifi_ssid">Názov siete</string>
<string name="hotspot_qr_wifi">Váš telefón poskytuje prístupový bod Wi-Fi. Ľudia, ktorí si chcú stiahnuť program Briar, sa môžu pripojiť k prístupovému bodu naskenovaním tohto QR kódu. Po ich pripojení k prístupovému bodu stlačte tlačidlo \'Ďalej\'.</string>
<string name="hotspot_no_peers_connected">Žiadne pripojené zariadenia</string>
<plurals name="hotspot_peers_connected">
<item quantity="one">%spripojené zariadenie</item>
<item quantity="few">%spripojené zariadenia</item>
<item quantity="many">%spripojených zariadení</item>
<item quantity="other">%spripojených zariadení</item>
</plurals>
<!--Download link-->
<!--The %s placeholder will be replaced with the translation of 'hotspot_scanning_a_qr_code'-->
<string name="hotspot_manual_site">Váš telefón poskytuje prístupový bod Wi-Fi. Ľudia, ktorí sú pripojení k prístupovému bodu, si môžu stiahnuť aplikáciu Briar zadaním nasledujúceho odkazu do webového prehliadača alebo %s.</string>
<string name="hotspot_manual_site_address">Adresa (URL)</string>
<string name="hotspot_qr_site">Váš telefón poskytuje prístupový bod Wi-Fi. Ľudia, ktorí sú pripojení k prístupovému bodu, si môžu stiahnuť Briar naskenovaním tohto QR kódu.</string>
<!--e.g. Download Briar 1.2.20-->
<string name="website_download_title_1">Stiahnuť Briar %s</string>
<string name="website_download_intro_1">Niekto v okolí s vami zdieľa Briar.</string>
<string name="website_download_button">Stiahnuť Briar</string>
<string name="website_download_outro">Po dokončení sťahovania otvorte stiahnutý súbor a nainštalujte ho.</string>
<string name="website_troubleshooting_title">Riešenie problémov</string>
<string name="website_troubleshooting_1">Ak sa vám aplikáciu nepodarí stiahnuť, skúste to pomocou inej aplikácie webového prehliadača.</string>
<string name="website_troubleshooting_2_old">Ak chcete nainštalovať prevzatú aplikáciu, možno budete musieť v nastaveniach systému povoliť inštaláciu aplikácií z \"Neznámych zdrojov\". Potom bude možno potrebné aplikáciu znova stiahnuť. Po nainštalovaní aplikácie odporúčame vypnúť nastavenie \"Neznáme zdroje\".</string>
<string name="website_troubleshooting_2_new">Ak chcete nainštalovať prevzatú aplikáciu, možno budete musieť prehliadaču povoliť inštaláciu neznámych aplikácií. Po nainštalovaní aplikácie odporúčame odstrániť povolenie prehliadača inštalovať neznáme aplikácie.</string>
<string name="hotspot_help_wifi_title">Problémy s pripojením k sieti Wi-Fi:</string>
<string name="hotspot_help_wifi_1">Skúste vypnúť a znova povoliť Wi-Fi na oboch telefónoch a skúste to znova.</string>
<string name="hotspot_help_wifi_2">Ak sa telefón sťažuje, že v sieti Wi-Fi nie je internet, povedzte mu, že aj tak chcete zostať pripojení.</string>
<string name="hotspot_help_wifi_3">Reštartujte telefón, v ktorom je spustený prístupový bod Wi-Fi, potom spustite aplikáciu Briar a skúste zdieľanie znova.</string>
<string name="hotspot_help_site_title">Problémy s návštevou miestnej webovej stránky:</string>
<string name="hotspot_help_site_1">Skontrolujte, či ste adresu zadali presne tak, ako je zobrazená. Aj malá chyba môže spôsobiť zlyhanie.</string>
<string name="hotspot_help_site_2">Pri pokuse o prístup na stránku sa uistite, že je telefón stále pripojený k správnej sieti Wi-Fi (pozrite vyššie).</string>
<string name="hotspot_help_site_3">Ak máte aplikáciu firewall, skontrolujte, či neblokuje prístup.</string>
<string name="hotspot_help_site_4">Ak môžete navštíviť stránku, ale nemôžete si stiahnuť aplikáciu Briar, skúste to pomocou inej aplikácie webového prehliadača.</string>
<string name="hotspot_help_fallback_title">Nič nefunguje?</string>
<string name="hotspot_help_fallback_intro">Môžete sa pokúsiť uložiť aplikáciu ako súbor .apk a zdieľať ju iným spôsobom. Po prenesení súboru do druhého zariadenia ho môžete použiť na inštaláciu aplikácie Briar.
\n\nTip: Pri zdieľaní cez Bluetooth bude možno potrebné najprv premenovať súbor tak, aby končil na .zip.</string>
<string name="hotspot_help_fallback_button">Uložiť aplikáciu</string>
<!--error handling-->
<string name="hotspot_error_intro">Pri pokuse o zdieľanie aplikácie cez Wi-Fi sa niečo pokazilo:</string>
<string name="hotspot_error_no_wifi_direct">Zariadenie nepodporuje funkciu Wi-Fi Direct</string>
<string name="hotspot_error_start_callback_failed">Prístupový bod sa nepodarilo spustiť: chyba %s</string>
<string name="hotspot_error_start_callback_failed_unknown">Prístupový bod sa nepodarilo spustiť s neznámej príčiny, dôvod %d</string>
<string name="hotspot_error_start_callback_no_group_info">Prístupový bod sa nepodarilo spustiť: žiadne informácie o skupine</string>
<string name="hotspot_error_web_server_start">Chyba pri spustení webového servera</string>
<string name="hotspot_error_web_server_serve">Chyba pri zobrazovaní webovej stránky.\n\nProsím, pošlite spätnú väzbu (s anonymnými údajmi) prostredníctvom aplikácie Briar, ak problém pretrváva.</string>
<string name="hotspot_flag_test">Varovanie: Táto aplikácia bola nainštalovaná pomocou aplikácie Android Studio a NIE je možné ju nainštalovať do iného zariadenia.</string>
<string name="hotspot_error_framework_busy">Prístupový bod sa nedá spustiť.\n\nAk máte spustený iný prístupový bod alebo zdieľate internetové pripojenie cez Wi-Fi, skúste ho zastaviť a potom to skúste znova.</string>
<!--Transfer Data via Removable Drives-->
<string name="removable_drive_menu_title">Pripojiť cez vymeniteľný disk</string>
<string name="removable_drive_intro">Ak sa nemôžete pripojiť ku kontaktu cez internet, Wi-Fi alebo Bluetooth, Briar dokáže prenášať správy aj na vymeniteľnom disku, ako je USB kľúč alebo SD karta.</string>
<string name="removable_drive_explanation">Ak sa nemôžete pripojiť ku kontaktu cez internet, Wi-Fi alebo Bluetooth, Briar dokáže prenášať správy aj na vymeniteľnom disku, ako je napríklad USB kľúč alebo SD karta.\n\nPri použití tlačidla \"Odoslať údaje\" sa všetky údaje, ktoré čakajú na odoslanie kontaktu, zapíšu na vymeniteľný disk. Patria sem súkromné správy, prílohy, blogy, fóra a súkromné skupiny.\n\nVšetko bude zašifrované pred zápisom na vymeniteľný disk.\n\nKeď váš kontakt dostane vymeniteľný disk, môže použiť tlačidlo \"Prijať údaje\" na import správ do aplikácie Briar.</string>
<string name="removable_drive_title_send">Odoslať údaje</string>
<string name="removable_drive_title_receive">Prijať údaje</string>
<string name="removable_drive_send_intro">Ťuknutím na tlačidlo nižšie vytvoríte nový súbor obsahujúci zašifrované správy. Môžete si vybrať, kam sa súbor uloží.\n\nAk chcete súbor uložiť na vymeniteľný disk, vložte ho teraz.</string>
<string name="removable_drive_send_no_data">V súčasnosti nie sú žiadne správy čakajúce na odoslanie tomuto kontaktu.</string>
<string name="removable_drive_send_not_supported">Tento kontakt používa starú verziu aplikácie Briar alebo staré zariadenie, ktoré túto funkciu nepodporuje.</string>
<string name="removable_drive_send_button">Výber súboru na exportovanie</string>
<string name="removable_drive_ongoing">Počkajte na dokončenie prebiehajúcej úlohy</string>
<string name="removable_drive_receive_intro">Ťuknite na tlačidlo nižšie a vyberte súbor, ktorý vám poslal váš kontakt.\n\nAk je súbor na vymeniteľnom disku, vložte ho teraz.</string>
<string name="removable_drive_receive_button">Vyberte súbor na importovanie</string>
<string name="removable_drive_success_send_title">Exportovanie bolo úspešné</string>
<string name="removable_drive_success_send_text">Údaje boli úspešne exportované. Teraz máte 28 dní na prenos súboru ku kontaktu.\n\nAk je súbor na vymeniteľnom disku, použite upozornenie v stavovom riadku, aby ste disk vysunuli pred jeho odpojením.</string>
<string name="removable_drive_success_receive_title">Nahrávanie bolo úspešné</string>
<string name="removable_drive_success_receive_text">Všetky zašifrované správy obsiahnuté v tomto súbore boli prijaté.</string>
<string name="removable_drive_error_send_title">Chyba pri exportovaní údajov</string>
<string name="removable_drive_error_send_text">Došlo k chybe pri zápise údajov do súboru.\n\nAk používate vymeniteľný disk, uistite sa, že je správne vložený a skúste to znova.\n\nAk chyba pretrváva, pošlite spätnú väzbu a informujte o probléme tím Briar.</string>
<string name="removable_drive_error_receive_title">Chyba pri importovaní údajov</string>
<string name="removable_drive_error_receive_text">Vybraný súbor neobsahoval nič, čo by Briar mohol rozpoznať.\n\nProsím, skontrolujte, či ste vybrali správny súbor.\n\nAk váš kontakt vytvoril súbor pred viac ako 28 dňami, Briar ho nebude môcť rozpoznať.</string>
<!--Screenshots-->
<!--This is a name to be used in screenshots. Feel free to change it to a local name.-->
<string name="screenshot_alice">Alica</string>
<!--This is a name to be used in screenshots. Feel free to change it to a local name.-->
<string name="screenshot_bob">Robo</string>
<!--This is a name to be used in screenshots. Feel free to change it to a local name.-->
<string name="screenshot_carol">Karolína</string>
<!--This is a message to be used in screenshots. Please use the same translation for Bob!-->
<string name="screenshot_message_1">Ahoj, Robo!</string>
<!--This is a message to be used in screenshots. Please use the same translation for Alice!-->
<string name="screenshot_message_2">Ahoj Alica! Vďaka, že si mi povedala o Briar!</string>
<!--This is a message to be used in screenshots.-->
<string name="screenshot_message_3">Žiadny problém, dúfam, že sa ti páči 😀</string>
</resources>

View File

@@ -235,6 +235,7 @@ dhe smund të hapet me këtë version.\n\nJu lutemi, përmirësojeni me versi
<string name="exchanging_contact_details">Po shkëmbehen hollësi kontaktesh\u2026</string>
<string name="contact_added_toast">Kontakti u shtua: %s</string>
<string name="contact_already_exists">Kontakti %s ekziston tashmë</string>
<string name="contact_already_exists_general">Kontakti ekziston tashmë</string>
<string name="qr_code_invalid">Kodi QR është i pavlefshëm</string>
<string name="qr_code_too_old_1">Kodi QR që keni skanuar vjen prej një versioni të vjetër të Briar-it.\n\nJu lutemi, kërkojini kontaktit tuaj ta përmirësojë me versionin më të ri dhe mandej riprovoni.</string>
<string name="qr_code_too_new_1">Kodi QR që keni skanuar vjen prej një versioni më të ri të Briar-it.\n\nJu lutemi, përmirësojeni me versionin më të ri dhe mandej riprovoni.</string>

View File

@@ -20,7 +20,7 @@
<string name="dnkm_huawei_protected_text">Будь ласка, натисніть кнопку, що знаходиться нижче і впевніться у тому, що Briar захищено на екрані \"Захищені додатки\".</string>
<string name="dnkm_huawei_protected_button">Захистити Briar</string>
<string name="dnkm_huawei_protected_help">Якщо Briar немає у списку захищених додатків, він не зможе працювати у фоновому режимі.</string>
<string name="dnkm_huawei_app_launch_text">Будь ласка, торкніть кнопку внизу, відкрийте екран «Запуск програми» й переконайтесь, що Briar має налаштування «Керувати вручну».</string>
<string name="dnkm_huawei_app_launch_text">Будь ласка, торкніться кнопки внизу, відкрийте екран «Запуск програми» й переконайтесь, що Briar має налаштування «Керувати вручну».</string>
<string name="dnkm_huawei_app_launch_help">Якщо не вказати «Керувати вручну» для Briar на екрані «Запуск програми», він не зможе працювати в фоновому режимі.</string>
<string name="dnkm_xiaomi_text">Щоб Briar працював у фоновому режимі, закріпіть його в переліку недавніх застосунків.</string>
<string name="dnkm_xiaomi_button">Захистити Briar</string>
@@ -515,7 +515,7 @@
<string name="blogs_rss_feeds_manage_empty_state">Немає RSS-стрічок до відображення\n\nНатисніть на символ \"+\", щоб імпортувати стрічку</string>
<string name="blogs_rss_feeds_manage_error">Під час завантаження ваших стрічок виникла проблема. Будь ласка, спробуйте пізніше.</string>
<!--Settings Profile Picture-->
<string name="change_profile_picture">Торкніть, щоб змінити зображення профілю</string>
<string name="change_profile_picture">Торкніться, щоб змінити зображення профілю</string>
<string name="dialog_confirm_profile_picture_title">Змінити зображення профілю</string>
<string name="dialog_confirm_profile_picture_remark">Лише ваші контакти можуть бачити це зображення</string>
<string name="change_profile_picture_failed_message">Перепрошуємо, щось пішло не так при оновленні вашого зображення профілю</string>
@@ -826,12 +826,12 @@
<string name="removable_drive_explanation">Якщо не вдається з\'єднатися з контактом через інтернет, Wi-Fi та Bluetooth, Briar ще може передавати повідомлення за допомогою флешки чи SD-картки.\n\nКоли ви натиснете кнопку «Надіслати дані», будь-які дані в очікуванні надсилання контактові буде записано на флешку. Зокрема дані особистих повідомлень, прикріплень, блогів, форумів і приватних груп.\n\nПеред записом на флешку все буде зашифровано.\n\nОтримавши флешку, ваш контакт зможе імпортувати повідомлення в свій Briar кнопкою «Отримати дані».</string>
<string name="removable_drive_title_send">Надіслати дані</string>
<string name="removable_drive_title_receive">Отримати дані</string>
<string name="removable_drive_send_intro">Торкніть кнопку внизу, щоб створити файл зашифрованих повідомлень. Ви зможете обрати, куди зберегти файл.\n\nЯкщо бажаєте зберегти файл на флешку, під\'єднайте її зараз.</string>
<string name="removable_drive_send_intro">Торкніться кнопки внизу, щоб створити файл із зашифрованими повідомленнями. Ви зможете обрати, куди зберегти файл.\n\nЯкщо бажаєте зберегти файл на флешку, під\'єднайте її зараз.</string>
<string name="removable_drive_send_no_data">Жодне повідомлення не очікує на надсилання цьому контактові.</string>
<string name="removable_drive_send_not_supported">Контакт використовує стару версію Briar чи старий пристрій, що не підтримує цієї можливості.</string>
<string name="removable_drive_send_button">Оберіть файл експорту</string>
<string name="removable_drive_ongoing">Дочекайтесь завершення поточного завдання</string>
<string name="removable_drive_receive_intro">Торкніть кнопку внизу, щоб обрати файл, надісланий вам контактом.\n\nЯкщо файл на флешці, під\'єднайте її зараз.</string>
<string name="removable_drive_receive_intro">Торкніться кнопки внизу, щоб обрати файл, надісланий вам контактом.\n\nЯкщо файл на флешці, під\'єднайте її зараз.</string>
<string name="removable_drive_receive_button">Оберіть файл імпорту</string>
<string name="removable_drive_success_send_title">Експорт успішний</string>
<string name="removable_drive_success_send_text">Дані успішно експортовано. Маєте 28 днів, щоб передати файл контактові.\n\nЯкщо файл на флешці, перед від\'єднанням вимкніть її за допомогою сповіщення в рядку стану.</string>

View File

@@ -225,6 +225,7 @@
<string name="exchanging_contact_details">正在交换联系人详细信息\u2026</string>
<string name="contact_added_toast">联系人已添加:%s</string>
<string name="contact_already_exists">联系人 %s 已存在</string>
<string name="contact_already_exists_general">联系人已存在</string>
<string name="qr_code_invalid">二维码无效</string>
<string name="qr_code_too_old_1">您扫描的二维码来自旧版本的 Briar。\n\n请让您的联系人升级到最新版本然后重试。</string>
<string name="qr_code_too_new_1">您扫描的二维码来自新版本的 Briar。\n\n请升级到最新版本然后重试。</string>

View File

@@ -476,7 +476,9 @@
<string name="blogs_rss_feeds_import">導入 RSS 訂閱源</string>
<string name="blogs_rss_feeds_import_button">導入</string>
<string name="blogs_rss_feeds_import_hint">輸入 RSS 訂閱源鏈接</string>
<string name="blogs_rss_feeds_import_progress">滙入 RSS 消息來源</string>
<string name="blogs_rss_feeds_import_error">抱歉!導入訂閱源時發生錯誤。</string>
<string name="blogs_rss_feeds_import_title">透過檔案滙入消息源</string>
<string name="blogs_rss_feeds">RSS 消息源</string>
<string name="blogs_rss_feeds_manage_imported">已導入:</string>
<string name="blogs_rss_feeds_manage_author">作者:</string>

View File

@@ -48,6 +48,7 @@
<item>pt-BR</item>
<item>ro</item>
<item>ru</item>
<item>sk</item>
<item>sq</item>
<item>sr</item>
<item>sv</item>

View File

@@ -249,6 +249,7 @@
<string name="exchanging_contact_details">Exchanging contact details\u2026</string>
<string name="contact_added_toast">Contact added: %s</string>
<string name="contact_already_exists">Contact %s already exists</string>
<string name="contact_already_exists_general">Contact already exists</string>
<string name="qr_code_invalid">The QR code is invalid</string>
<string name="qr_code_too_old_1">The QR code you have scanned comes from an older version of Briar.\n\nPlease ask your contact to upgrade to the latest version and then try again.</string>
<string name="qr_code_too_new_1">The QR code you have scanned comes from a newer version of Briar.\n\nPlease upgrade to the latest version and then try again.</string>

View File

@@ -120,7 +120,6 @@ dependencyVerification {
'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd',
'org.apache-extras.beanshell:bsh:2.0b6:bsh-2.0b6.jar:a17955976070c0573235ee662f2794a78082758b61accffce8d3f8aedcd91047',
'org.bouncycastle:bcprov-jdk15on:1.65:bcprov-jdk15on-1.65.jar:e78f96eb59066c94c94fb2d6b5eb80f52feac6f5f9776898634f8addec6e2137',
'org.briarproject:dont-kill-me-lib:0.2.5:dont-kill-me-lib-0.2.5.aar:55cd9d511b7016ab573905d64bc54e222e2633144d36389192b8b34485b31b9d',
'org.checkerframework:checker-compat-qual:2.5.5:checker-compat-qual-2.5.5.jar:11d134b245e9cacc474514d2d66b5b8618f8039a1465cdc55bbc0b34e0008b7a',
'org.checkerframework:checker-qual:2.5.2:checker-qual-2.5.2.jar:64b02691c8b9d4e7700f8ee2e742dce7ea2c6e81e662b7522c9ee3bf568c040a',
'org.checkerframework:checker-qual:3.12.0:checker-qual-3.12.0.jar:ff10785ac2a357ec5de9c293cb982a2cbb605c0309ea4cc1cb9b9bc6dbe7f3cb',
@@ -136,12 +135,11 @@ dependencyVerification {
'org.jacoco:org.jacoco.core:0.8.7:org.jacoco.core-0.8.7.jar:ad7739b5fb5969aa1a8aead3d74ed54dc82ed012f1f10f336bd1b96e71c1a13c',
'org.jacoco:org.jacoco.report:0.8.7:org.jacoco.report-0.8.7.jar:cc89258623700a6c932592153cb528785876b6da183d5431f97efbba6f020e5b',
'org.jetbrains.kotlin:kotlin-stdlib-common:1.7.0:kotlin-stdlib-common-1.7.0.jar:59c6ff64fe9a6604afce03e8aaa75f83586c6030ac71fb0b34ee7cdefed3618f',
'org.jetbrains.kotlin:kotlin-stdlib-common:1.7.10:kotlin-stdlib-common-1.7.10.jar:19f102efe9629f8eabc63853ad15c533e47c47f91fca09285c5bde86e59f91d4',
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.6.20:kotlin-stdlib-jdk7-1.6.20.jar:aa2fa2e81355c4d98dd97da2169bf401f842261378f5b1cbea1aa11855d67620',
'org.jetbrains.kotlin:kotlin-stdlib-common:1.8.0:kotlin-stdlib-common-1.8.0.jar:78ef93b59e603cc0fe51def9bd4c037b07cbace3b3b7806d1a490a42bc1f4cb2',
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.0:kotlin-stdlib-jdk7-1.7.0.jar:07e91be9b2ca20672d2bdb7e181b766e73453a2da13492b5ddaee8fa47aea239',
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.0:kotlin-stdlib-jdk8-1.7.0.jar:cf058e11db1dfc9944680c8c61b95ac689aaaa8a3eb30bced028100f038f030b',
'org.jetbrains.kotlin:kotlin-stdlib:1.7.0:kotlin-stdlib-1.7.0.jar:aa88e9625577957f3249a46cb6e166ee09b369e600f7a11d148d16b0a6d87f05',
'org.jetbrains.kotlin:kotlin-stdlib:1.7.10:kotlin-stdlib-1.7.10.jar:e771fe74250a943e8f6346713201ff1d8cb95c3a5d1a91a22b65a9e04f6a8901',
'org.jetbrains.kotlin:kotlin-stdlib:1.8.0:kotlin-stdlib-1.8.0.jar:c77bef8774640b9fb9d6e217459ff220dae59878beb7d2e4b430506feffc654e',
'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1:kotlinx-coroutines-android-1.4.1.jar:d4cadb673b2101f1ee5fbc147956ac78b1cfd9cc255fb53d3aeb88dff11d99ca',
'org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.4.1:kotlinx-coroutines-core-jvm-1.4.1.jar:6d2f87764b6638f27aff12ed380db4b63c9d46ba55dc32683a650598fa5a3e22',
'org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.5.0:kotlinx-metadata-jvm-0.5.0.jar:ca063a96639b08b9eaa0de4d65e899480740a6efbe28ab9a8681a2ced03055a4',

View File

@@ -29,6 +29,12 @@ public interface IntroductionManager extends ConversationClient {
*/
boolean canIntroduce(Contact c1, Contact c2) throws DbException;
/**
* Returns true if both contacts can be introduced at this moment.
*/
boolean canIntroduce(Transaction txn, Contact c1, Contact c2)
throws DbException;
/**
* The current minor version of the introduction client.
*/
@@ -40,6 +46,12 @@ public interface IntroductionManager extends ConversationClient {
void makeIntroduction(Contact c1, Contact c2, @Nullable String text)
throws DbException;
/**
* Sends two initial introduction messages.
*/
void makeIntroduction(Transaction txn, Contact c1, Contact c2,
@Nullable String text) throws DbException;
/**
* Responds to an introduction.
*/

View File

@@ -52,11 +52,21 @@ public interface PrivateGroupManager {
void addPrivateGroup(Transaction txn, PrivateGroup group,
GroupMessage joinMsg, boolean creator) throws DbException;
/**
* Removes a dissolved private group.
*/
void removePrivateGroup(Transaction txn, GroupId g) throws DbException;
/**
* Removes a dissolved private group.
*/
void removePrivateGroup(GroupId g) throws DbException;
/**
* Returns the ID of the user's previous message sent to the group
*/
MessageId getPreviousMsgId(Transaction txn, GroupId g) throws DbException;
/**
* Returns the ID of the user's previous message sent to the group
*/
@@ -112,7 +122,8 @@ public interface PrivateGroupManager {
/**
* Returns true if the given private group was created by us.
*/
boolean isOurPrivateGroup(Transaction txn, PrivateGroup g) throws DbException;
boolean isOurPrivateGroup(Transaction txn, PrivateGroup g)
throws DbException;
/**
* Returns the text of the private group message with the given ID.
@@ -161,6 +172,12 @@ public interface PrivateGroupManager {
*/
GroupCount getGroupCount(GroupId g) throws DbException;
/**
* Marks a message as read or unread and updates the group count.
*/
void setReadFlag(Transaction txn, GroupId g, MessageId m, boolean read)
throws DbException;
/**
* Marks a message as read or unread and updates the group count.
*/

View File

@@ -3,6 +3,7 @@ package org.briarproject.briar.api.privategroup.invitation;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.sync.ClientId;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.briar.api.client.ProtocolStateException;
@@ -47,6 +48,18 @@ public interface GroupInvitationManager extends ConversationClient {
long timestamp, byte[] signature, long autoDeleteTimer)
throws DbException;
/**
* Sends an invitation to share the given private group with the given
* contact, including an optional message.
*
* @throws ProtocolStateException if the group is no longer eligible to be
* shared with the contact, for example because an invitation is already
* pending.
*/
void sendInvitation(Transaction txn, GroupId g, ContactId c,
@Nullable String text, long timestamp, byte[] signature,
long autoDeleteTimer) throws DbException;
/**
* Responds to a pending private group invitation from the given contact.
*
@@ -56,6 +69,15 @@ public interface GroupInvitationManager extends ConversationClient {
void respondToInvitation(ContactId c, PrivateGroup g, boolean accept)
throws DbException;
/**
* Responds to a pending private group invitation from the given contact.
*
* @throws ProtocolStateException if the invitation is no longer pending,
* for example because the group has been dissolved.
*/
void respondToInvitation(Transaction txn, ContactId c, PrivateGroup g,
boolean accept) throws DbException;
/**
* Responds to a pending private group invitation from the given contact.
*
@@ -65,6 +87,15 @@ public interface GroupInvitationManager extends ConversationClient {
void respondToInvitation(ContactId c, SessionId s, boolean accept)
throws DbException;
/**
* Responds to a pending private group invitation from the given contact.
*
* @throws ProtocolStateException if the invitation is no longer pending,
* for example because the group has been dissolved.
*/
void respondToInvitation(Transaction txn, ContactId c, SessionId s,
boolean accept) throws DbException;
/**
* Makes the user's relationship with the given contact visible to the
* given private group.
@@ -74,11 +105,27 @@ public interface GroupInvitationManager extends ConversationClient {
*/
void revealRelationship(ContactId c, GroupId g) throws DbException;
/**
* Makes the user's relationship with the given contact visible to the
* given private group.
*
* @throws ProtocolStateException if the relationship is no longer eligible
* to be revealed, for example because the contact has revealed it.
*/
void revealRelationship(Transaction txn, ContactId c, GroupId g)
throws DbException;
/**
* Returns all private groups to which the user has been invited.
*/
Collection<GroupInvitationItem> getInvitations() throws DbException;
/**
* Returns all private groups to which the user has been invited.
*/
Collection<GroupInvitationItem> getInvitations(Transaction txn)
throws DbException;
/**
* Returns the current {@link SharingStatus} for the given {@link Contact}
* and {@link PrivateGroup} identified by the given {@link GroupId}.
@@ -89,4 +136,16 @@ public interface GroupInvitationManager extends ConversationClient {
* was already dissolved.
*/
SharingStatus getSharingStatus(Contact c, GroupId g) throws DbException;
/**
* Returns the current {@link SharingStatus} for the given {@link Contact}
* and {@link PrivateGroup} identified by the given {@link GroupId}.
* This indicates whether the {@link PrivateGroup} can be shared
* with the contact.
*
* @throws ProtocolStateException if {@link PrivateGroup}
* was already dissolved.
*/
SharingStatus getSharingStatus(Transaction txn, Contact c, GroupId g)
throws DbException;
}

View File

@@ -300,36 +300,37 @@ class IntroductionManagerImpl extends ConversationClientImpl
@Override
public boolean canIntroduce(Contact c1, Contact c2) throws DbException {
Transaction txn = db.startTransaction(true);
return db.transactionWithResult(true,
txn -> canIntroduce(txn, c1, c2));
}
public boolean canIntroduce(Transaction txn, Contact c1, Contact c2)
throws DbException {
try {
boolean can = canIntroduce(txn, c1, c2);
db.commitTransaction(txn);
return can;
// Look up the session, if there is one
Author introducer = identityManager.getLocalAuthor(txn);
SessionId sessionId =
crypto.getSessionId(introducer, c1.getAuthor(),
c2.getAuthor());
StoredSession ss = getSession(txn, sessionId);
if (ss == null) return true;
IntroducerSession session =
sessionParser.parseIntroducerSession(ss.bdfSession);
return session.getState().isComplete();
} catch (FormatException e) {
throw new DbException(e);
} finally {
db.endTransaction(txn);
}
}
private boolean canIntroduce(Transaction txn, Contact c1, Contact c2)
throws DbException, FormatException {
// Look up the session, if there is one
Author introducer = identityManager.getLocalAuthor(txn);
SessionId sessionId =
crypto.getSessionId(introducer, c1.getAuthor(),
c2.getAuthor());
StoredSession ss = getSession(txn, sessionId);
if (ss == null) return true;
IntroducerSession session =
sessionParser.parseIntroducerSession(ss.bdfSession);
return session.getState().isComplete();
public void makeIntroduction(Contact c1, Contact c2, @Nullable String text)
throws DbException {
db.transaction(false,
txn -> makeIntroduction(txn, c1, c2, text));
}
@Override
public void makeIntroduction(Contact c1, Contact c2, @Nullable String text)
throws DbException {
Transaction txn = db.startTransaction(false);
public void makeIntroduction(Transaction txn, Contact c1, Contact c2,
@Nullable String text) throws DbException {
try {
// Look up the session, if there is one
Author introducer = identityManager.getLocalAuthor(txn);
@@ -363,11 +364,8 @@ class IntroductionManagerImpl extends ConversationClientImpl
session = introducerEngine.onRequestAction(txn, session, text);
// Store the updated session
storeSession(txn, storageId, session);
db.commitTransaction(txn);
} catch (FormatException e) {
throw new DbException(e);
} finally {
db.endTransaction(txn);
}
}

View File

@@ -150,40 +150,35 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
}
@Override
public void removePrivateGroup(GroupId g) throws DbException {
Transaction txn = db.startTransaction(false);
try {
for (PrivateGroupHook hook : hooks) {
hook.removingGroup(txn, g);
}
Group group = db.getGroup(txn, g);
db.removeGroup(txn, group);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
public void removePrivateGroup(Transaction txn, GroupId g)
throws DbException {
for (PrivateGroupHook hook : hooks) {
hook.removingGroup(txn, g);
}
Group group = db.getGroup(txn, g);
db.removeGroup(txn, group);
}
@Override
public void removePrivateGroup(GroupId g) throws DbException {
db.transaction(false, txn -> removePrivateGroup(txn, g));
}
@Override
public MessageId getPreviousMsgId(GroupId g) throws DbException {
MessageId previousMsgId;
Transaction txn = db.startTransaction(true);
try {
previousMsgId = getPreviousMsgId(txn, g);
db.commitTransaction(txn);
} catch (FormatException e) {
throw new DbException(e);
} finally {
db.endTransaction(txn);
}
return previousMsgId;
return db.transactionWithResult(true,
txn -> getPreviousMsgId(txn, g));
}
private MessageId getPreviousMsgId(Transaction txn, GroupId g)
throws DbException, FormatException {
BdfDictionary d = clientHelper.getGroupMetadataAsDictionary(txn, g);
byte[] previousMsgIdBytes = d.getRaw(KEY_PREVIOUS_MSG_ID);
return new MessageId(previousMsgIdBytes);
public MessageId getPreviousMsgId(Transaction txn, GroupId g)
throws DbException {
try {
BdfDictionary d = clientHelper.getGroupMetadataAsDictionary(txn, g);
byte[] previousMsgIdBytes = d.getRaw(KEY_PREVIOUS_MSG_ID);
return new MessageId(previousMsgIdBytes);
} catch (FormatException e) {
throw new DbException(e);
}
}
private void setPreviousMsgId(Transaction txn, GroupId g,
@@ -483,11 +478,16 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
return messageTracker.getGroupCount(g);
}
@Override
public void setReadFlag(Transaction txn, GroupId g, MessageId m,
boolean read) throws DbException {
messageTracker.setReadFlag(txn, g, m, read);
}
@Override
public void setReadFlag(GroupId g, MessageId m, boolean read)
throws DbException {
db.transaction(false, txn ->
messageTracker.setReadFlag(txn, g, m, read));
db.transaction(false, txn -> setReadFlag(txn, g, m, read));
}
@Override

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