Merge branch 'develop' into feature/restore-vaultconfig

This commit is contained in:
Jan-Peter Klein
2025-02-19 19:49:35 +01:00
155 changed files with 1942 additions and 1351 deletions

View File

@@ -1,4 +1,5 @@
import ch.qos.logback.classic.spi.Configurator;
import org.cryptomator.networking.SSLContextWithPKCS12TrustStore;
import org.cryptomator.common.locationpresets.DropboxLinuxLocationPresetsProvider;
import org.cryptomator.common.locationpresets.DropboxMacLocationPresetsProvider;
import org.cryptomator.common.locationpresets.DropboxWindowsLocationPresetsProvider;
@@ -13,6 +14,9 @@ import org.cryptomator.common.locationpresets.OneDriveLinuxLocationPresetsProvid
import org.cryptomator.common.locationpresets.OneDriveMacLocationPresetsProvider;
import org.cryptomator.common.locationpresets.OneDriveWindowsLocationPresetsProvider;
import org.cryptomator.common.locationpresets.PCloudLocationPresetsProvider;
import org.cryptomator.networking.SSLContextWithMacKeychain;
import org.cryptomator.networking.SSLContextProvider;
import org.cryptomator.networking.SSLContextWithWindowsCertStore;
import org.cryptomator.integrations.tray.TrayMenuController;
import org.cryptomator.logging.LogbackConfiguratorFactory;
import org.cryptomator.ui.traymenu.AwtTrayMenuController;
@@ -51,11 +55,14 @@ open module org.cryptomator.desktop {
requires jakarta.inject;
requires static javax.inject;
requires java.compiler;
requires com.github.benmanes.caffeine;
uses org.cryptomator.common.locationpresets.LocationPresetsProvider;
uses SSLContextProvider;
provides TrayMenuController with AwtTrayMenuController;
provides Configurator with LogbackConfiguratorFactory;
provides SSLContextProvider with SSLContextWithWindowsCertStore, SSLContextWithMacKeychain, SSLContextWithPKCS12TrustStore;
provides LocationPresetsProvider with //
DropboxWindowsLocationPresetsProvider, DropboxMacLocationPresetsProvider, DropboxLinuxLocationPresetsProvider, //
GoogleDriveMacLocationPresetsProvider, GoogleDriveWindowsLocationPresetsProvider, //

View File

@@ -1,8 +1,7 @@
package org.cryptomator.common.keychain;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import org.cryptomator.integrations.keychain.KeychainAccessException;
import org.cryptomator.integrations.keychain.KeychainAccessProvider;
@@ -24,9 +23,9 @@ public class KeychainManager implements KeychainAccessProvider {
@Inject
KeychainManager(ObjectExpression<KeychainAccessProvider> selectedKeychain) {
this.keychain = selectedKeychain;
this.passphraseStoredProperties = CacheBuilder.newBuilder() //
this.passphraseStoredProperties = Caffeine.newBuilder() //
.weakValues() //
.build(CacheLoader.from(this::createStoredPassphraseProperty));
.build(this::createStoredPassphraseProperty);
keychain.addListener(ignored -> passphraseStoredProperties.invalidateAll());
}
@@ -124,7 +123,7 @@ public class KeychainManager implements KeychainAccessProvider {
* @see #isPassphraseStored(String)
*/
public ReadOnlyBooleanProperty getPassphraseStoredProperty(String key) {
return passphraseStoredProperties.getUnchecked(key);
return passphraseStoredProperties.get(key);
}
private BooleanProperty createStoredPassphraseProperty(String key) {

View File

@@ -67,7 +67,7 @@ public final class GoogleDriveMacLocationPresetsProvider implements LocationPres
*/
private String getDriveLocationString(Path accountPath) {
String accountName = accountPath.getFileName().toString().replace("GoogleDrive-", "");
return STR."Google Drive - \{accountName}";
return "Google Drive - " + accountName;
}
/**

View File

@@ -160,7 +160,7 @@ public class Mounter {
var mountService = mountProviders.stream().filter(s -> s.getClass().getName().equals(vaultSettings.mountService.getValue())).findFirst().orElse(defaultMountService.getValue());
if (isConflictingMountService(mountService)) {
var msg = STR."\{mountService.getClass()} unavailable due to conflict with either of \{CONFLICTING_MOUNT_SERVICES.get(mountService.getClass().getName())}";
var msg = mountService.getClass() + " unavailable due to conflict with either of " + CONFLICTING_MOUNT_SERVICES.get(mountService.getClass().getName());
throw new ConflictingMountServiceException(msg);
}

View File

@@ -58,6 +58,7 @@ public class VaultSettings {
public final StringExpression mountName;
public final StringProperty mountService;
public final IntegerProperty port;
public final StringProperty lastKnownKeyLoader;
VaultSettings(VaultSettingsJson json) {
this.id = json.id;
@@ -74,6 +75,7 @@ public class VaultSettings {
this.mountPoint = new SimpleObjectProperty<>(this, "mountPoint", json.mountPoint == null ? null : Path.of(json.mountPoint));
this.mountService = new SimpleStringProperty(this, "mountService", json.mountService);
this.port = new SimpleIntegerProperty(this, "port", json.port);
this.lastKnownKeyLoader = new SimpleStringProperty(this, "lastKnownKeyLoader", json.lastKnownKeyLoader);
// mount name is no longer an explicit setting, see https://github.com/cryptomator/cryptomator/pull/1318
this.mountName = StringExpression.stringExpression(Bindings.createStringBinding(() -> {
final String name;
@@ -99,7 +101,7 @@ public class VaultSettings {
}
Observable[] observables() {
return new Observable[]{actionAfterUnlock, autoLockIdleSeconds, autoLockWhenIdle, displayName, maxCleartextFilenameLength, mountFlags, mountPoint, path, revealAfterMount, unlockAfterStartup, usesReadOnlyMode, port, mountService};
return new Observable[]{actionAfterUnlock, autoLockIdleSeconds, autoLockWhenIdle, displayName, maxCleartextFilenameLength, mountFlags, mountPoint, path, revealAfterMount, unlockAfterStartup, usesReadOnlyMode, port, mountService, lastKnownKeyLoader};
}
public static VaultSettings withRandomId() {
@@ -130,6 +132,7 @@ public class VaultSettings {
json.mountPoint = mountPoint.map(Path::toString).getValue();
json.mountService = mountService.get();
json.port = port.get();
json.lastKnownKeyLoader = lastKnownKeyLoader.get();
return json;
}

View File

@@ -48,6 +48,9 @@ class VaultSettingsJson {
@JsonProperty("mountService")
String mountService;
@JsonProperty("lastKnownKeyLoader")
String lastKnownKeyLoader;
@JsonProperty("port")
int port = VaultSettings.DEFAULT_PORT;

View File

@@ -44,6 +44,7 @@ import javafx.beans.property.SimpleBooleanProperty;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.ReadOnlyFileSystemException;
import java.util.EnumSet;
import java.util.Objects;
import java.util.Set;
@@ -115,15 +116,22 @@ public class Vault {
private CryptoFileSystem createCryptoFileSystem(MasterkeyLoader keyLoader) throws IOException, MasterkeyLoadingFailedException {
Set<FileSystemFlags> flags = EnumSet.noneOf(FileSystemFlags.class);
if (vaultSettings.usesReadOnlyMode.get()) {
var createReadOnly = vaultSettings.usesReadOnlyMode.get();
try {
FileSystemCapabilityChecker.assertWriteAccess(getPath());
} catch (FileSystemCapabilityChecker.MissingCapabilityException e) {
if (!createReadOnly) {
throw new ReadOnlyFileSystemException();
}
}
if (createReadOnly) {
flags.add(FileSystemFlags.READONLY);
} else if (vaultSettings.maxCleartextFilenameLength.get() == -1) {
LOG.debug("Determining cleartext filename length limitations...");
var checker = new FileSystemCapabilityChecker();
int shorteningThreshold = configCache.get().allegedShorteningThreshold();
int ciphertextLimit = checker.determineSupportedCiphertextFileNameLength(getPath());
int ciphertextLimit = FileSystemCapabilityChecker.determineSupportedCiphertextFileNameLength(getPath());
if (ciphertextLimit < shorteningThreshold) {
int cleartextLimit = checker.determineSupportedCleartextFileNameLength(getPath());
int cleartextLimit = FileSystemCapabilityChecker.determineSupportedCleartextFileNameLength(getPath());
vaultSettings.maxCleartextFilenameLength.set(cleartextLimit);
} else {
vaultSettings.maxCleartextFilenameLength.setValue(UNLIMITED_FILENAME_LENGTH);

View File

@@ -29,6 +29,7 @@ import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.ResourceBundle;
import java.util.stream.Stream;
@@ -54,9 +55,9 @@ public class VaultListManager {
@Inject
public VaultListManager(ObservableList<Vault> vaultList, //
AutoLocker autoLocker, //
List<MountService> mountServices,
VaultComponent.Factory vaultComponentFactory,
ResourceBundle resourceBundle,
List<MountService> mountServices, //
VaultComponent.Factory vaultComponentFactory, //
ResourceBundle resourceBundle, //
Settings settings) {
this.vaultList = vaultList;
this.autoLocker = autoLocker;
@@ -123,6 +124,10 @@ public class VaultListManager {
private Vault create(VaultSettings vaultSettings) {
var wrapper = new VaultConfigCache(vaultSettings);
try {
if (Objects.isNull(vaultSettings.lastKnownKeyLoader.get())) {
var keyIdScheme = wrapper.get().getKeyId().getScheme();
vaultSettings.lastKnownKeyLoader.set(keyIdScheme);
}
var vaultState = determineVaultState(vaultSettings.path.get());
if (vaultState == LOCKED) { //for legacy reasons: pre v8 vault do not have a config, but they are in the NEEDS_MIGRATION state
wrapper.reloadConfig();

View File

@@ -9,8 +9,9 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder;
import dagger.Lazy;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.common.Environment;
import org.cryptomator.common.SubstitutingProperties;
import org.cryptomator.common.ShutdownHook;
import org.cryptomator.common.SubstitutingProperties;
import org.cryptomator.networking.SSLContextProvider;
import org.cryptomator.ipc.IpcCommunicator;
import org.cryptomator.logging.DebugMode;
import org.cryptomator.ui.fxapp.FxApplicationComponent;
@@ -19,8 +20,10 @@ import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.net.ssl.SSLContext;
import javafx.application.Application;
import javafx.stage.Stage;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
@@ -48,14 +51,16 @@ public class Cryptomator {
private final Environment env;
private final Lazy<IpcMessageHandler> ipcMessageHandler;
private final ShutdownHook shutdownHook;
private final SecureRandom csprng;
@Inject
Cryptomator(DebugMode debugMode, SupportedLanguages supportedLanguages, Environment env, Lazy<IpcMessageHandler> ipcMessageHandler, ShutdownHook shutdownHook) {
Cryptomator(DebugMode debugMode, SupportedLanguages supportedLanguages, Environment env, Lazy<IpcMessageHandler> ipcMessageHandler, ShutdownHook shutdownHook, SecureRandom csprng) {
this.debugMode = debugMode;
this.supportedLanguages = supportedLanguages;
this.env = env;
this.ipcMessageHandler = ipcMessageHandler;
this.shutdownHook = shutdownHook;
this.csprng = csprng;
}
public static void main(String[] args) {
@@ -89,7 +94,7 @@ public class Cryptomator {
LOG.info("Starting Cryptomator {} on {} {} ({})", env.getAppVersion(), SystemUtils.OS_NAME, SystemUtils.OS_VERSION, SystemUtils.OS_ARCH);
debugMode.initialize();
supportedLanguages.applyPreferred();
changeDefaultSSLContext();
/*
* Attempts to create an IPC connection to a running Cryptomator instance and sends it the given args.
* If no external process could be reached, the args will be handled by the loopback IPC endpoint.
@@ -115,6 +120,17 @@ public class Cryptomator {
}
}
private void changeDefaultSSLContext() {
SSLContextProvider.loadAll().findFirst().ifPresent(p -> {
try {
var context = p.getContext(csprng);
SSLContext.setDefault(context);
} catch (SSLContextProvider.SSLContextBuildException e) {
LOG.warn("Failed to change default SSL context with provider {}", p.getClass().getName(), e);
}
});
}
/**
* Launches the JavaFX application, blocking the main thread until shuts down.
*

View File

@@ -0,0 +1,33 @@
package org.cryptomator.networking;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
abstract class SSLContextDifferentTrustStoreBase implements SSLContextProvider {
abstract KeyStore getTruststore() throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException;
@Override
public SSLContext getContext(SecureRandom csprng) throws SSLContextBuildException {
try {
KeyStore truststore = getTruststore();
truststore.load(null, null);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(truststore);
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), csprng);
return context;
} catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | KeyManagementException | IOException e) {
throw new SSLContextBuildException(e);
}
}
}

View File

@@ -0,0 +1,24 @@
package org.cryptomator.networking;
import org.cryptomator.integrations.common.IntegrationsLoader;
import javax.net.ssl.SSLContext;
import java.security.SecureRandom;
import java.util.ServiceLoader;
import java.util.stream.Stream;
public interface SSLContextProvider {
SSLContext getContext(SecureRandom csprng) throws SSLContextBuildException;
class SSLContextBuildException extends Exception {
SSLContextBuildException(Throwable t) {
super(t);
}
}
static Stream<SSLContextProvider> loadAll() {
return IntegrationsLoader.loadAll(ServiceLoader.load(SSLContextProvider.class), SSLContextProvider.class);
}
}

View File

@@ -0,0 +1,21 @@
package org.cryptomator.networking;
import org.cryptomator.integrations.common.OperatingSystem;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
/**
* SSLContextProvider for macOS using the macOS Keychain as truststore
*/
@OperatingSystem(OperatingSystem.Value.MAC)
public class SSLContextWithMacKeychain extends SSLContextDifferentTrustStoreBase implements SSLContextProvider {
@Override
KeyStore getTruststore() throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException {
return KeyStore.getInstance("KeychainStore-ROOT");
}
}

View File

@@ -0,0 +1,42 @@
package org.cryptomator.networking;
import org.cryptomator.integrations.common.CheckAvailability;
import org.cryptomator.integrations.common.OperatingSystem;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.Optional;
/**
* SSLContextProvider for Linux using a PKCS#12 file as trust store
*/
@OperatingSystem(OperatingSystem.Value.LINUX)
@CheckAvailability
public class SSLContextWithPKCS12TrustStore extends SSLContextDifferentTrustStoreBase implements SSLContextProvider {
private static final String CERT_FILE_LOCATION_PROPERTY = "cryptomator.networking.truststore.p12Path";
@Override
KeyStore getTruststore() throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException {
var pkcs12FilePath = Path.of(System.getProperty(CERT_FILE_LOCATION_PROPERTY));
try {
return KeyStore.getInstance(pkcs12FilePath.toFile(), new char[]{});
} catch (IllegalArgumentException e) {
throw new NoSuchFileException(pkcs12FilePath.toString());
}
}
@CheckAvailability
public static boolean isSupported() {
var pkcs12Path = System.getProperty(CERT_FILE_LOCATION_PROPERTY);
return Optional.ofNullable(pkcs12Path) //
.map(Path::of) //
.map(Files::exists).orElse(false);
}
}

View File

@@ -0,0 +1,21 @@
package org.cryptomator.networking;
import org.cryptomator.integrations.common.OperatingSystem;
import java.security.KeyStore;
import java.security.KeyStoreException;
/**
* SSLContextProvider for Windows using the Windows certificate store as trust store
* <p>
* In order to work, the jdk.crypto.mscapi jmod is needed
*/
@OperatingSystem(OperatingSystem.Value.WINDOWS)
public class SSLContextWithWindowsCertStore extends SSLContextDifferentTrustStoreBase implements SSLContextProvider {
@Override
KeyStore getTruststore() throws KeyStoreException {
return KeyStore.getInstance("WINDOWS-ROOT");
}
}

View File

@@ -26,7 +26,7 @@ public class CreateNewVaultExpertSettingsController implements FxController {
public static final int MAX_SHORTENING_THRESHOLD = 220;
public static final int MIN_SHORTENING_THRESHOLD = 36;
private static final String DOCS_NAME_SHORTENING_URL = "https://docs.cryptomator.org/en/1.7/security/architecture/#name-shortening";
private static final String DOCS_NAME_SHORTENING_URL = "https://docs.cryptomator.org/security/architecture/#name-shortening";
private final Stage window;
private final Lazy<Application> application;

View File

@@ -40,7 +40,6 @@ import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Optional;
import java.util.ResourceBundle;
import java.util.concurrent.ExecutorService;
@@ -50,7 +49,7 @@ public class CreateNewVaultLocationController implements FxController {
private static final Logger LOG = LoggerFactory.getLogger(CreateNewVaultLocationController.class);
private static final Path DEFAULT_CUSTOM_VAULT_PATH = Paths.get(System.getProperty("user.home"));
private static final String TEMP_FILE_FORMAT = ".locationTest.cryptomator.tmp";
private static final String TEMP_FILE_PREFIX = ".locationTest.cryptomator";
private final Stage window;
private final Lazy<Scene> chooseNameScene;
@@ -126,16 +125,19 @@ public class CreateNewVaultLocationController implements FxController {
private boolean isActuallyWritable(Path p) {
Path tmpFile = p.resolve(TEMP_FILE_FORMAT);
try (var chan = Files.newByteChannel(tmpFile, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE, StandardOpenOption.DELETE_ON_CLOSE)) {
Path tmpDir = null;
try {
tmpDir = Files.createTempDirectory(p, TEMP_FILE_PREFIX );
return true;
} catch (IOException e) {
return false;
} finally {
try {
Files.deleteIfExists(tmpFile);
} catch (IOException e) {
LOG.warn("Unable to delete temporary file {}. Needs to be deleted manually.", tmpFile);
if (tmpDir != null) {
try {
Files.deleteIfExists(tmpDir);
} catch (IOException e) {
LOG.warn("Unable to delete temporary directory {}. Needs to be deleted manually.", tmpDir);
}
}
}
}

View File

@@ -12,7 +12,6 @@ public enum FxmlFile {
CONVERTVAULT_HUBTOPASSWORD_START("/fxml/convertvault_hubtopassword_start.fxml"), //
CONVERTVAULT_HUBTOPASSWORD_CONVERT("/fxml/convertvault_hubtopassword_convert.fxml"), //
CONVERTVAULT_HUBTOPASSWORD_SUCCESS("/fxml/convertvault_hubtopassword_success.fxml"), //
DOKANY_SUPPORT_END("/fxml/dokany_support_end.fxml"), //
ERROR("/fxml/error.fxml"), //
FORGET_PASSWORD("/fxml/forget_password.fxml"), //
HEALTH_START("/fxml/health_start.fxml"), //
@@ -47,9 +46,8 @@ public enum FxmlFile {
RECOVERYKEY_RESET_PASSWORD_SUCCESS("/fxml/recoverykey_reset_password_success.fxml"), //
RECOVERYKEY_RESET_VAULT_CONFIG_SUCCESS("/fxml/recoverykey_reset_vault_config_success.fxml"), //
RECOVERYKEY_SUCCESS("/fxml/recoverykey_success.fxml"), //
REMOVE_CERT("/fxml/remove_cert.fxml"), //
REMOVE_VAULT("/fxml/remove_vault.fxml"), //
SHARE_VAULT("/fxml/share_vault.fxml"), //
SIMPLE_DIALOG("/fxml/simple_dialog.fxml"), //
UPDATE_REMINDER("/fxml/update_reminder.fxml"), //
UNLOCK_ENTER_PASSWORD("/fxml/unlock_enter_password.fxml"),
UNLOCK_REQUIRES_RESTART("/fxml/unlock_requires_restart.fxml"), //

View File

@@ -15,6 +15,7 @@ import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.fxapp.FxApplicationWindows;
import org.cryptomator.ui.keyloading.masterkeyfile.MasterkeyFileLoadingStrategy;
import org.cryptomator.ui.recoverykey.RecoveryKeyFactory;
import org.jetbrains.annotations.VisibleForTesting;
import org.slf4j.Logger;
@@ -108,6 +109,7 @@ public class HubToPasswordConvertController implements FxController {
.thenRunAsync(this::convertInternal, backgroundExecutorService) //
.whenCompleteAsync((result, exception) -> {
if (exception == null) {
vault.getVaultSettings().lastKnownKeyLoader.set(MasterkeyFileLoadingStrategy.SCHEME);
LOG.info("Conversion of vault {} succeeded.", vault.getPath());
window.setScene(successScene.get());
} else {

View File

@@ -0,0 +1,90 @@
package org.cryptomator.ui.dialogs;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.common.StageFactory;
import org.cryptomator.ui.controls.FontAwesome5Icon;
import org.cryptomator.ui.fxapp.FxApplicationScoped;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javafx.collections.ObservableList;
import javafx.stage.Stage;
import java.util.ResourceBundle;
import java.util.function.Consumer;
@FxApplicationScoped
public class Dialogs {
private final ResourceBundle resourceBundle;
private final StageFactory stageFactory;
@Inject
public Dialogs(ResourceBundle resourceBundle, StageFactory stageFactory) {
this.resourceBundle = resourceBundle;
this.stageFactory = stageFactory;
}
private static final Logger LOG = LoggerFactory.getLogger(Dialogs.class);
private SimpleDialog.Builder createDialogBuilder() {
return new SimpleDialog.Builder(resourceBundle, stageFactory);
}
public SimpleDialog.Builder prepareRemoveVaultDialog(Stage window, Vault vault, ObservableList<Vault> vaults) {
return createDialogBuilder().setOwner(window) //
.setTitleKey("removeVault.title", vault.getDisplayName()) //
.setMessageKey("removeVault.message") //
.setDescriptionKey("removeVault.description") //
.setIcon(FontAwesome5Icon.QUESTION) //
.setOkButtonKey("removeVault.confirmBtn") //
.setCancelButtonKey("generic.button.cancel") //
.setOkAction(stage -> {
LOG.debug("Removing vault {}.", vault.getDisplayName());
vaults.remove(vault);
stage.close();
});
}
public SimpleDialog.Builder prepareRemoveCertDialog(Stage window, Settings settings) {
return createDialogBuilder() //
.setOwner(window) //
.setTitleKey("removeCert.title") //
.setMessageKey("removeCert.message") //
.setDescriptionKey("removeCert.description") //
.setIcon(FontAwesome5Icon.QUESTION) //
.setOkButtonKey("removeCert.confirmBtn") //
.setCancelButtonKey("generic.button.cancel") //
.setOkAction(stage -> {
settings.licenseKey.set(null);
stage.close();
});
}
public SimpleDialog.Builder prepareDokanySupportEndDialog(Stage window, Consumer<Stage> cancelAction) {
return createDialogBuilder() //
.setOwner(window) //
.setTitleKey("dokanySupportEnd.title") //
.setMessageKey("dokanySupportEnd.message") //
.setDescriptionKey("dokanySupportEnd.description") //
.setIcon(FontAwesome5Icon.EXCLAMATION) //
.setOkButtonKey("generic.button.close") //
.setCancelButtonKey("dokanySupportEnd.preferencesBtn") //
.setOkAction(Stage::close) //
.setCancelAction(cancelAction);
}
public SimpleDialog.Builder prepareRetryIfReadonlyDialog(Stage window, Consumer<Stage> okAction) {
return createDialogBuilder() //
.setOwner(window) //
.setTitleKey("retryIfReadonly.title") //
.setMessageKey("retryIfReadonly.message") //
.setDescriptionKey("retryIfReadonly.description") //
.setIcon(FontAwesome5Icon.EXCLAMATION) //
.setOkButtonKey("retryIfReadonly.retry") //
.setCancelButtonKey("generic.button.close") //
.setOkAction(okAction) //
.setCancelAction(Stage::close);
}
}

View File

@@ -0,0 +1,140 @@
package org.cryptomator.ui.dialogs;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlLoaderFactory;
import org.cryptomator.ui.common.StageFactory;
import org.cryptomator.ui.controls.FontAwesome5Icon;
import javafx.scene.Scene;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.IllegalFormatException;
import java.util.Objects;
import java.util.ResourceBundle;
import java.util.function.Consumer;
public class SimpleDialog {
private final ResourceBundle resourceBundle;
private final Stage dialogStage;
SimpleDialog(Builder builder) throws IOException {
this.resourceBundle = builder.resourceBundle;
dialogStage = builder.stageFactory.create();
dialogStage.initOwner(builder.owner);
dialogStage.initModality(Modality.WINDOW_MODAL);
dialogStage.setTitle(resolveText(builder.titleKey, builder.titleArgs));
dialogStage.setResizable(false);
FxmlLoaderFactory loaderFactory = FxmlLoaderFactory.forController( //
new SimpleDialogController(resolveText(builder.messageKey, null), //
resolveText(builder.descriptionKey, null), //
builder.icon, resolveText(builder.okButtonKey, null), //
resolveText(builder.cancelButtonKey, null), //
() -> builder.okAction.accept(dialogStage), //
() -> builder.cancelAction.accept(dialogStage)), //
Scene::new, builder.resourceBundle);
dialogStage.setScene(new Scene(loaderFactory.load(FxmlFile.SIMPLE_DIALOG.getRessourcePathString()).getRoot()));
}
public void showAndWait() {
dialogStage.showAndWait();
}
private String resolveText(String key, String[] args) {
if (key == null || key.isEmpty() || !resourceBundle.containsKey(key)) {
throw new IllegalArgumentException(String.format("Invalid key: '%s'. Key not found in ResourceBundle.", key));
}
String text = resourceBundle.getString(key);
try {
return args != null && args.length > 0 ? String.format(text, (Object[]) args) : text;
} catch (IllegalFormatException e) {
throw new IllegalArgumentException("Formatting error: Check if arguments match placeholders in the text.", e);
}
}
public static class Builder {
private Stage owner;
private final ResourceBundle resourceBundle;
private final StageFactory stageFactory;
private String titleKey;
private String[] titleArgs;
private String messageKey;
private String descriptionKey;
private String okButtonKey;
private String cancelButtonKey;
private FontAwesome5Icon icon;
private Consumer<Stage> okAction = Stage::close;
private Consumer<Stage> cancelAction = Stage::close;
public Builder(ResourceBundle resourceBundle, StageFactory stageFactory) {
this.resourceBundle = resourceBundle;
this.stageFactory = stageFactory;
}
public Builder setOwner(Stage owner) {
this.owner = owner;
return this;
}
public Builder setTitleKey(String titleKey, String... args) {
this.titleKey = titleKey;
this.titleArgs = args;
return this;
}
public Builder setMessageKey(String messageKey) {
this.messageKey = messageKey;
return this;
}
public Builder setDescriptionKey(String descriptionKey) {
this.descriptionKey = descriptionKey;
return this;
}
public Builder setIcon(FontAwesome5Icon icon) {
this.icon = icon;
return this;
}
public Builder setOkButtonKey(String okButtonKey) {
this.okButtonKey = okButtonKey;
return this;
}
public Builder setCancelButtonKey(String cancelButtonKey) {
this.cancelButtonKey = cancelButtonKey;
return this;
}
public Builder setOkAction(Consumer<Stage> okAction) {
this.okAction = okAction;
return this;
}
public Builder setCancelAction(Consumer<Stage> cancelAction) {
this.cancelAction = cancelAction;
return this;
}
public SimpleDialog build() {
Objects.requireNonNull(titleKey, "SimpleDialog titleKey must be set.");
Objects.requireNonNull(messageKey, "SimpleDialog messageKey must be set.");
Objects.requireNonNull(descriptionKey, "SimpleDialog descriptionKey must be set.");
Objects.requireNonNull(okButtonKey, "SimpleDialog okButtonKey must be set.");
Objects.requireNonNull(cancelButtonKey, "SimpleDialog cancelButtonKey must be set.");
try {
return new SimpleDialog(this);
} catch (IOException e) {
throw new UncheckedIOException("Failed to create SimpleDialog.", e);
}
}
}
}

View File

@@ -0,0 +1,61 @@
package org.cryptomator.ui.dialogs;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.controls.FontAwesome5Icon;
import javafx.fxml.FXML;
public class SimpleDialogController implements FxController {
private final String message;
private final String description;
private final FontAwesome5Icon icon;
private final String okButtonText;
private final String cancelButtonText;
private final Runnable okAction;
private final Runnable cancelAction;
public SimpleDialogController(String message, String description, FontAwesome5Icon icon, String okButtonText, String cancelButtonText, Runnable okAction, Runnable cancelAction) {
this.message = message;
this.description = description;
this.icon = icon;
this.okButtonText = okButtonText;
this.cancelButtonText = cancelButtonText;
this.okAction = okAction;
this.cancelAction = cancelAction;
}
public String getMessage() {
return message;
}
public String getDescription() {
return description;
}
public FontAwesome5Icon getIcon() {
return icon;
}
public String getOkButtonText() {
return okButtonText;
}
public String getCancelButtonText() {
return cancelButtonText;
}
@FXML
private void handleOk() {
if (okAction != null) {
okAction.run();
}
}
@FXML
private void handleCancel() {
if (cancelAction != null) {
cancelAction.run();
}
}
}

View File

@@ -1,34 +0,0 @@
package org.cryptomator.ui.dokanysupportend;
import dagger.Lazy;
import dagger.Subcomponent;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import javafx.scene.Scene;
import javafx.stage.Stage;
@DokanySupportEndScoped
@Subcomponent(modules = {DokanySupportEndModule.class})
public interface DokanySupportEndComponent {
@DokanySupportEndWindow
Stage window();
@FxmlScene(FxmlFile.DOKANY_SUPPORT_END)
Lazy<Scene> dokanySupportEndScene();
default void showDokanySupportEndWindow() {
Stage stage = window();
stage.setScene(dokanySupportEndScene().get());
stage.sizeToScene();
stage.show();
}
@Subcomponent.Factory
interface Factory {
DokanySupportEndComponent create();
}
}

View File

@@ -1,34 +0,0 @@
package org.cryptomator.ui.dokanysupportend;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.fxapp.FxApplicationWindows;
import org.cryptomator.ui.preferences.SelectedPreferencesTab;
import javax.inject.Inject;
import javafx.fxml.FXML;
import javafx.stage.Stage;
@DokanySupportEndScoped
public class DokanySupportEndController implements FxController {
private final Stage window;
private final FxApplicationWindows applicationWindows;
@Inject
DokanySupportEndController(@DokanySupportEndWindow Stage window, FxApplicationWindows applicationWindows) {
this.window = window;
this.applicationWindows = applicationWindows;
}
@FXML
public void close() {
window.close();
}
public void openVolumePreferences() {
applicationWindows.showPreferencesWindow(SelectedPreferencesTab.VOLUME);
window.close();
}
}

View File

@@ -1,57 +0,0 @@
package org.cryptomator.ui.dokanysupportend;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
import org.cryptomator.ui.common.DefaultSceneFactory;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxControllerKey;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlLoaderFactory;
import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.common.StageFactory;
import javax.inject.Provider;
import javafx.scene.Scene;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.util.Map;
import java.util.ResourceBundle;
@Module
abstract class DokanySupportEndModule {
@Provides
@DokanySupportEndWindow
@DokanySupportEndScoped
static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
}
@Provides
@DokanySupportEndWindow
@DokanySupportEndScoped
static Stage provideStage(StageFactory factory, ResourceBundle resourceBundle) {
Stage stage = factory.create();
stage.setTitle(resourceBundle.getString("dokanySupportEnd.title"));
stage.setMinWidth(500);
stage.setMinHeight(100);
stage.initModality(Modality.APPLICATION_MODAL);
return stage;
}
@Provides
@FxmlScene(FxmlFile.DOKANY_SUPPORT_END)
@DokanySupportEndScoped
static Scene provideDokanySupportEndScene(@DokanySupportEndWindow FxmlLoaderFactory fxmlLoaders) {
return fxmlLoaders.createScene(FxmlFile.DOKANY_SUPPORT_END);
}
@Binds
@IntoMap
@FxControllerKey(DokanySupportEndController.class)
abstract FxController bindDokanySupportEndController(DokanySupportEndController controller);
}

View File

@@ -1,13 +0,0 @@
package org.cryptomator.ui.dokanysupportend;
import javax.inject.Scope;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
@interface DokanySupportEndScoped {
}

View File

@@ -1,14 +0,0 @@
package org.cryptomator.ui.dokanysupportend;
import javax.inject.Qualifier;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Qualifier
@Documented
@Retention(RUNTIME)
@interface DokanySupportEndWindow {
}

View File

@@ -43,8 +43,8 @@ public class AutoUnlocker {
private CompletionStage<Void> unlockSequentially(Stream<Vault> vaultStream) {
// this is an attempt to run all the unlock workflows sequentially, i.e. start the next workflow only after completing/failing the previous workflow.
return vaultStream.filter(Vault::isLocked).reduce(CompletableFuture.completedFuture(null),
(prevUnlock, nextVault) -> prevUnlock.thenCompose(unused -> appWindows.startUnlockWorkflow(nextVault, null)),
(prevUnlock, nextUnlock) -> nextUnlock.exceptionally(e -> null) // we don't care here about the exception, logged elsewhere
(prevUnlock, nextVault) -> prevUnlock.thenCompose(_ -> appWindows.startUnlockWorkflow(nextVault, null)),
(_, nextUnlock) -> nextUnlock.exceptionally(_ -> null) // we don't care here about the exception, logged elsewhere
);
}

View File

@@ -7,14 +7,12 @@ package org.cryptomator.ui.fxapp;
import dagger.Module;
import dagger.Provides;
import org.cryptomator.ui.dokanysupportend.DokanySupportEndComponent;
import org.cryptomator.ui.error.ErrorComponent;
import org.cryptomator.ui.health.HealthCheckComponent;
import org.cryptomator.ui.lock.LockComponent;
import org.cryptomator.ui.mainwindow.MainWindowComponent;
import org.cryptomator.ui.preferences.PreferencesComponent;
import org.cryptomator.ui.quit.QuitComponent;
import org.cryptomator.ui.removecert.RemoveCertComponent;
import org.cryptomator.ui.sharevault.ShareVaultComponent;
import org.cryptomator.ui.traymenu.TrayMenuComponent;
import org.cryptomator.ui.unlock.UnlockComponent;
@@ -35,8 +33,6 @@ import java.io.InputStream;
ErrorComponent.class, //
HealthCheckComponent.class, //
UpdateReminderComponent.class, //
DokanySupportEndComponent.class, //
RemoveCertComponent.class, //
ShareVaultComponent.class})
abstract class FxApplicationModule {

View File

@@ -5,7 +5,8 @@ import dagger.Lazy;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.integrations.tray.TrayIntegrationProvider;
import org.cryptomator.ui.dokanysupportend.DokanySupportEndComponent;
import org.cryptomator.ui.dialogs.Dialogs;
import org.cryptomator.ui.dialogs.SimpleDialog;
import org.cryptomator.ui.error.ErrorComponent;
import org.cryptomator.ui.lock.LockComponent;
import org.cryptomator.ui.mainwindow.MainWindowComponent;
@@ -49,13 +50,13 @@ public class FxApplicationWindows {
private final QuitComponent.Builder quitWindowBuilder;
private final UnlockComponent.Factory unlockWorkflowFactory;
private final UpdateReminderComponent.Factory updateReminderWindowFactory;
private final DokanySupportEndComponent.Factory dokanySupportEndWindowBuilder;
private final LockComponent.Factory lockWorkflowFactory;
private final ErrorComponent.Factory errorWindowFactory;
private final ExecutorService executor;
private final VaultOptionsComponent.Factory vaultOptionsWindow;
private final ShareVaultComponent.Factory shareVaultWindow;
private final FilteredList<Window> visibleWindows;
private final Dialogs dialogs;
@Inject
public FxApplicationWindows(@PrimaryStage Stage primaryStage, //
@@ -65,12 +66,12 @@ public class FxApplicationWindows {
QuitComponent.Builder quitWindowBuilder, //
UnlockComponent.Factory unlockWorkflowFactory, //
UpdateReminderComponent.Factory updateReminderWindowFactory, //
DokanySupportEndComponent.Factory dokanySupportEndWindowBuilder, //
LockComponent.Factory lockWorkflowFactory, //
ErrorComponent.Factory errorWindowFactory, //
VaultOptionsComponent.Factory vaultOptionsWindow, //
ShareVaultComponent.Factory shareVaultWindow, //
ExecutorService executor) {
ExecutorService executor, //
Dialogs dialogs) {
this.primaryStage = primaryStage;
this.trayIntegration = trayIntegration;
this.mainWindow = mainWindow;
@@ -78,13 +79,13 @@ public class FxApplicationWindows {
this.quitWindowBuilder = quitWindowBuilder;
this.unlockWorkflowFactory = unlockWorkflowFactory;
this.updateReminderWindowFactory = updateReminderWindowFactory;
this.dokanySupportEndWindowBuilder = dokanySupportEndWindowBuilder;
this.lockWorkflowFactory = lockWorkflowFactory;
this.errorWindowFactory = errorWindowFactory;
this.executor = executor;
this.vaultOptionsWindow = vaultOptionsWindow;
this.shareVaultWindow = shareVaultWindow;
this.visibleWindows = Window.getWindows().filtered(Window::isShowing);
this.dialogs = dialogs;
}
public void initialize() {
@@ -93,17 +94,17 @@ public class FxApplicationWindows {
// register preferences shortcut
if (desktop.isSupported(Desktop.Action.APP_PREFERENCES)) {
desktop.setPreferencesHandler(evt -> showPreferencesWindow(SelectedPreferencesTab.ANY));
desktop.setPreferencesHandler(_ -> showPreferencesWindow(SelectedPreferencesTab.ANY));
}
// register preferences shortcut
if (desktop.isSupported(Desktop.Action.APP_ABOUT)) {
desktop.setAboutHandler(evt -> showPreferencesWindow(SelectedPreferencesTab.ABOUT));
desktop.setAboutHandler(_ -> showPreferencesWindow(SelectedPreferencesTab.ABOUT));
}
// register app reopen listener
if (desktop.isSupported(Desktop.Action.APP_EVENT_REOPENED)) {
desktop.addAppEventListener((AppReopenedListener) e -> showMainWindow());
desktop.addAppEventListener((AppReopenedListener) _ -> showMainWindow());
}
// observe visible windows
@@ -135,11 +136,12 @@ public class FxApplicationWindows {
}
public CompletionStage<Stage> showVaultOptionsWindow(Vault vault, SelectedVaultOptionsTab tab) {
return showMainWindow().thenApplyAsync((window) -> vaultOptionsWindow.create(vault).showVaultOptionsWindow(tab), Platform::runLater).whenComplete(this::reportErrors);
return showMainWindow().thenApplyAsync(_ -> vaultOptionsWindow.create(vault).showVaultOptionsWindow(tab), Platform::runLater) //
.whenComplete(this::reportErrors);
}
public void showQuitWindow(QuitResponse response, boolean forced) {
CompletableFuture.runAsync(() -> quitWindowBuilder.build().showQuitWindow(response,forced), Platform::runLater);
CompletableFuture.runAsync(() -> quitWindowBuilder.build().showQuitWindow(response, forced), Platform::runLater);
}
public void showUpdateReminderWindow() {
@@ -147,9 +149,15 @@ public class FxApplicationWindows {
}
public void showDokanySupportEndWindow() {
CompletableFuture.runAsync(() -> dokanySupportEndWindowBuilder.create().showDokanySupportEndWindow(), Platform::runLater);
CompletableFuture.runAsync(() -> createDokanySupportEndDialog().showAndWait(), Platform::runLater);
}
private SimpleDialog createDokanySupportEndDialog() {
return dialogs.prepareDokanySupportEndDialog(mainWindow.get().window(), stage -> {
showPreferencesWindow(SelectedPreferencesTab.VOLUME);
stage.close();
}).build();
}
public CompletionStage<Void> startUnlockWorkflow(Vault vault, @Nullable Stage owner) {
return CompletableFuture.supplyAsync(() -> {
@@ -157,8 +165,7 @@ public class FxApplicationWindows {
LOG.debug("Start unlock workflow for {}", vault.getDisplayName());
return unlockWorkflowFactory.create(vault, owner).unlockWorkflow();
}, Platform::runLater) //
.thenAcceptAsync(UnlockWorkflow::run, executor)
.exceptionally(e -> {
.thenAcceptAsync(UnlockWorkflow::run, executor).exceptionally(e -> {
showErrorWindow(e, owner == null ? primaryStage : owner, null);
return null;
});

View File

@@ -3,6 +3,8 @@ package org.cryptomator.ui.keyloading;
import org.cryptomator.cryptolib.api.Masterkey;
import org.cryptomator.cryptolib.api.MasterkeyLoader;
import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
import org.cryptomator.ui.keyloading.hub.HubKeyLoadingStrategy;
import org.cryptomator.ui.keyloading.masterkeyfile.MasterkeyFileLoadingStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -28,6 +30,33 @@ public interface KeyLoadingStrategy extends MasterkeyLoader {
@Override
Masterkey loadKey(URI keyId) throws MasterkeyLoadingFailedException;
/**
* Determines whether the provided key loader scheme corresponds to a Hub Vault.
* <p>
* This method compares the {@code keyLoader} parameter with the known Hub Vault schemes
* {@link HubKeyLoadingStrategy#SCHEME_HUB_HTTP} and {@link HubKeyLoadingStrategy#SCHEME_HUB_HTTPS}.
*
* @param keyLoader A string representing the key loader scheme to be checked.
* @return {@code true} if the given key loader scheme represents a Hub Vault; {@code false} otherwise.
*/
static boolean isHubVault(String keyLoader) {
return HubKeyLoadingStrategy.SCHEME_HUB_HTTP.equals(keyLoader) || HubKeyLoadingStrategy.SCHEME_HUB_HTTPS.equals(keyLoader);
}
/**
* Determines whether the provided key loader scheme corresponds to a Masterkey File Vault.
* <p>
* This method checks if the {@code keyLoader} parameter matches the known Masterkey File Vault scheme
* {@link MasterkeyFileLoadingStrategy#SCHEME}.
* </p>
*
* @param keyLoader A string representing the key loader scheme to be checked.
* @return {@code true} if the given key loader scheme represents a Masterkey File Vault; {@code false} otherwise.
*/
static boolean isMasterkeyFileVault(String keyLoader) {
return MasterkeyFileLoadingStrategy.SCHEME.equals(keyLoader);
}
/**
* Allows the loader to try and recover from an exception thrown during the last attempt.
*

View File

@@ -20,7 +20,7 @@ public class HubConfig {
public String devicesResourceUrl;
/**
* A collection of String template processors to construct URIs related to this Hub instance.
* A collection of functions to construct URIs related to this Hub instance.
*/
@JsonIgnore
public final URIProcessors URIs = new URIProcessors();
@@ -49,14 +49,20 @@ public class HubConfig {
public class URIProcessors {
public final URIProcessor API = this::fromApiEndpoint;
/**
* Resolves paths relative to the <code>/api/</code> endpoint of this Hub instance.
*/
public final StringTemplate.Processor<URI, RuntimeException> API = template -> {
var path = template.interpolate();
public URI fromApiEndpoint(String path) {
var relPath = path.startsWith("/") ? path.substring(1) : path;
return getApiBaseUrl().resolve(relPath);
};
}
}
@FunctionalInterface
public interface URIProcessor {
URI resolve(String path);
}
}

View File

@@ -88,7 +88,7 @@ public class ReceiveKeyController implements FxController {
* STEP 0 (Request): GET /api/config
*/
private void requestApiConfig() {
var configUri = hubConfig.URIs.API."config";
var configUri = hubConfig.URIs.API.resolve("config");
var request = HttpRequest.newBuilder(configUri) //
.GET() //
.timeout(REQ_TIMEOUT) //
@@ -122,7 +122,7 @@ public class ReceiveKeyController implements FxController {
* STEP 1 (Request): GET user key for this device
*/
private void requestDeviceData() {
var deviceUri = hubConfig.URIs.API."devices/\{deviceId}";
var deviceUri = hubConfig.URIs.API.resolve("devices/" + deviceId);
var request = HttpRequest.newBuilder(deviceUri) //
.header("Authorization", "Bearer " + bearerToken) //
.GET() //
@@ -162,9 +162,10 @@ public class ReceiveKeyController implements FxController {
* STEP 2 (Request): GET vault key for this user
*/
private void requestVaultMasterkey(String encryptedUserKey) {
var vaultKeyUri = hubConfig.URIs.API."vaults/\{vaultId}/access-token";
var vaultKeyUri = hubConfig.URIs.API.resolve("vaults/" + vaultId + "/access-token");
var request = HttpRequest.newBuilder(vaultKeyUri) //
.header("Authorization", "Bearer " + bearerToken) //
.header("Hub-Device-ID", deviceId) //
.GET() //
.timeout(REQ_TIMEOUT) //
.build();
@@ -205,7 +206,7 @@ public class ReceiveKeyController implements FxController {
*/
@Deprecated
private void requestLegacyAccessToken() {
var legacyAccessTokenUri = hubConfig.URIs.API."vaults/\{vaultId}/keys/\{deviceId}";
var legacyAccessTokenUri = hubConfig.URIs.API.resolve("vaults/" + vaultId + "/keys/" + deviceId);
var request = HttpRequest.newBuilder(legacyAccessTokenUri) //
.header("Authorization", "Bearer " + bearerToken) //
.GET() //

View File

@@ -115,7 +115,7 @@ public class RegisterDeviceController implements FxController {
workInProgress.set(true);
var userReq = HttpRequest.newBuilder(hubConfig.URIs.API."users/me") //
var userReq = HttpRequest.newBuilder(hubConfig.URIs.API.resolve("users/me")) //
.GET() //
.timeout(REQ_TIMEOUT) //
.header("Authorization", "Bearer " + bearerToken) //
@@ -143,7 +143,7 @@ public class RegisterDeviceController implements FxController {
var now = Instant.now().toString();
var dto = new CreateDeviceDto(deviceId, deviceNameField.getText(), BaseEncoding.base64().encode(deviceKeyPair.getPublic().getEncoded()), "DESKTOP", jwe.serialize(), now);
var json = toJson(dto);
var deviceUri = hubConfig.URIs.API."devices/\{deviceId}";
var deviceUri = hubConfig.URIs.fromApiEndpoint("devices/" + deviceId);
var putDeviceReq = HttpRequest.newBuilder(deviceUri) //
.PUT(HttpRequest.BodyPublishers.ofString(json, StandardCharsets.UTF_8)) //
.timeout(REQ_TIMEOUT) //
@@ -164,7 +164,7 @@ public class RegisterDeviceController implements FxController {
private void migrateLegacyDevices(ECPublicKey userPublicKey) {
try {
// GET legacy access tokens
var getUri = hubConfig.URIs.API."devices/\{deviceId}/legacy-access-tokens";
var getUri = hubConfig.URIs.API.resolve("devices/" + deviceId + "/legacy-access-tokens");
var getReq = HttpRequest.newBuilder(getUri).GET().timeout(REQ_TIMEOUT).header("Authorization", "Bearer " + bearerToken).build();
var getRes = httpClient.send(getReq, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
if (getRes.statusCode() != 200) {
@@ -185,12 +185,12 @@ public class RegisterDeviceController implements FxController {
LOG.warn("Failed to decrypt legacy access token for vault {}. Skipping migration.", entry.getKey());
}
}).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
var postUri = hubConfig.URIs.API."users/me/access-tokens";
var postUri = hubConfig.URIs.fromApiEndpoint("users/me/access-tokens");
var postBody = JSON.writer().writeValueAsString(newAccessTokens);
var postReq = HttpRequest.newBuilder(postUri).POST(HttpRequest.BodyPublishers.ofString(postBody)).timeout(REQ_TIMEOUT).header("Authorization", "Bearer " + bearerToken).build();
var postRes = httpClient.send(postReq, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
if (postRes.statusCode() != 200) {
throw new IOException(STR."Unexpected response from POST \{postUri}: \{postRes.statusCode()}");
throw new IOException("Unexpected response from POST " + postUri + ": " + postRes.statusCode());
}
} catch (IOException e) {
// log and ignore: this is merely a best-effort attempt of migrating legacy devices. Failure is uncritical as this is merely a convenience feature.

View File

@@ -1,13 +1,5 @@
package org.cryptomator.ui.mainwindow;
import javafx.beans.Observable;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.fxml.FXML;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.common.LicenseHolder;
import org.cryptomator.common.settings.Settings;
@@ -21,6 +13,15 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javafx.beans.Observable;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.fxml.FXML;
import javafx.scene.layout.StackPane;
import javafx.stage.Screen;
import javafx.stage.Stage;
@MainWindowScoped
public class MainWindowController implements FxController {
@@ -63,27 +64,46 @@ public class MainWindowController implements FxController {
}
window.focusedProperty().addListener(this::mainWindowFocusChanged);
if (!neverTouched()) {
window.setHeight(settings.windowHeight.get() > window.getMinHeight() ? settings.windowHeight.get() : window.getMinHeight());
window.setWidth(settings.windowWidth.get() > window.getMinWidth() ? settings.windowWidth.get() : window.getMinWidth());
window.setX(settings.windowXPosition.get());
window.setY(settings.windowYPosition.get());
int x = settings.windowXPosition.get();
int y = settings.windowYPosition.get();
int width = settings.windowWidth.get();
int height = settings.windowHeight.get();
if (windowPositionSaved(x, y, width, height) ) {
if(isWithinDisplayBounds(x, y, width, height)) { //use stored window position
window.setX(x);
window.setY(y);
window.setWidth(Math.clamp(width, window.getMinWidth(), window.getMaxWidth()));
window.setHeight(Math.clamp(height, window.getMinHeight(), window.getMaxHeight()));
} else if(isWithinDisplayBounds((int) window.getX(), (int) window.getY(), width, height)) { //just reset position of upper left corner, keep window size
window.setWidth(Math.clamp(width, window.getMinWidth(), window.getMaxWidth()));
window.setHeight(Math.clamp(height, window.getMinHeight(), window.getMaxHeight()));
} //else reset window completely
}
window.widthProperty().addListener((_, _, _) -> savePositionalSettings());
window.heightProperty().addListener((_, _, _) -> savePositionalSettings());
window.xProperty().addListener((_, _, _) -> savePositionalSettings());
window.yProperty().addListener((_, _, _) -> savePositionalSettings());
settings.windowXPosition.bind(window.xProperty());
settings.windowYPosition.bind(window.yProperty());
settings.windowWidth.bind(window.widthProperty());
settings.windowHeight.bind(window.heightProperty());
}
private boolean neverTouched() {
return (settings.windowHeight.get() == 0) && (settings.windowWidth.get() == 0) && (settings.windowXPosition.get() == 0) && (settings.windowYPosition.get() == 0);
private boolean windowPositionSaved(int x, int y, int width, int height) {
return x != 0 || y != 0 || width != 0 || height != 0;
}
public void savePositionalSettings() {
settings.windowWidth.setValue(window.getWidth());
settings.windowHeight.setValue(window.getHeight());
settings.windowXPosition.setValue(window.getX());
settings.windowYPosition.setValue(window.getY());
private boolean isWithinDisplayBounds(int x, int y, int width, int height) {
// define a rect which is inset on all sides from the window's rect:
final int shrinkedX = x + 20; // 20px left
final int shrinkedY = y + 5; // 5px top
final int shrinkedWidth = width - 40; // 20px left + 20px right
final int shrinkedHeigth = height - 25; // 5px top + 20px bottom
return isRectangleWithinBounds(shrinkedX, shrinkedY, 0, shrinkedHeigth) // Left pixel column
&& isRectangleWithinBounds(shrinkedX + shrinkedWidth, shrinkedY, 0, shrinkedHeigth) // Right pixel column
&& isRectangleWithinBounds(shrinkedX, shrinkedY, shrinkedWidth, 0) // Top pixel row
&& isRectangleWithinBounds(shrinkedX, shrinkedY + shrinkedHeigth, shrinkedWidth, 0); // Bottom pixel row
}
private boolean isRectangleWithinBounds(int x, int y, int width, int height) {
return !Screen.getScreensForRectangle(x, y, width, height).isEmpty();
}
private void mainWindowFocusChanged(Observable observable) {

View File

@@ -1,6 +1,7 @@
package org.cryptomator.ui.mainwindow;
import dagger.Binds;
import dagger.Lazy;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
@@ -14,11 +15,12 @@ import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.common.StageFactory;
import org.cryptomator.ui.common.StageInitializer;
import org.cryptomator.ui.error.ErrorComponent;
import org.cryptomator.ui.fxapp.FxApplicationTerminator;
import org.cryptomator.ui.fxapp.PrimaryStage;
import org.cryptomator.ui.migration.MigrationComponent;
import org.cryptomator.ui.recoverykey.RecoveryKeyComponent;
import org.cryptomator.ui.removevault.RemoveVaultComponent;
import org.cryptomator.ui.stats.VaultStatisticsComponent;
import org.cryptomator.ui.traymenu.TrayMenuComponent;
import org.cryptomator.ui.wrongfilealert.WrongFileAlertComponent;
import javax.inject.Named;
@@ -31,17 +33,25 @@ import javafx.stage.Stage;
import java.util.Map;
import java.util.ResourceBundle;
@Module(subcomponents = {AddVaultWizardComponent.class, MigrationComponent.class, RemoveVaultComponent.class, VaultStatisticsComponent.class, WrongFileAlertComponent.class, ErrorComponent.class, RecoveryKeyComponent.class})
@Module(subcomponents = {AddVaultWizardComponent.class, MigrationComponent.class, VaultStatisticsComponent.class, WrongFileAlertComponent.class, ErrorComponent.class, RecoveryKeyComponent.class})
abstract class MainWindowModule {
@Provides
@MainWindow
@MainWindowScoped
static Stage provideMainWindow(@PrimaryStage Stage stage, StageInitializer initializer) {
static Stage provideMainWindow(@PrimaryStage Stage stage, StageInitializer initializer, FxApplicationTerminator terminator, Lazy<TrayMenuComponent> trayMenu) {
initializer.accept(stage);
stage.setTitle("Cryptomator");
stage.setMinWidth(650);
stage.setMinHeight(498);
stage.setOnCloseRequest(e -> {
if (!trayMenu.get().isInitialized()) {
terminator.terminate();
e.consume();
} else {
stage.close();
}
});
return stage;
}

View File

@@ -3,11 +3,12 @@ package org.cryptomator.ui.mainwindow;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultListManager;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.dialogs.Dialogs;
import org.cryptomator.ui.recoverykey.RecoveryKeyComponent;
import org.cryptomator.ui.removevault.RemoveVaultComponent;
import javax.inject.Inject;
import javafx.beans.property.ObjectProperty;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
@@ -20,20 +21,25 @@ import static org.cryptomator.common.Constants.CRYPTOMATOR_FILENAME_GLOB;
public class VaultDetailMissingVaultController implements FxController {
private final ObjectProperty<Vault> vault;
private final RemoveVaultComponent.Builder removeVault;
private final ObservableList<Vault> vaults;
private final ResourceBundle resourceBundle;
private final Stage window;
private final RecoveryKeyComponent.Factory recoveryKeyWindow;
private final Dialogs dialogs;
@Inject
public VaultDetailMissingVaultController(ObjectProperty<Vault> vault, RemoveVaultComponent.Builder removeVault, ResourceBundle resourceBundle, @MainWindow Stage window, RecoveryKeyComponent.Factory recoveryKeyWindow) {
public VaultDetailMissingVaultController(ObjectProperty<Vault> vault, //
ObservableList<Vault> vaults, //
ResourceBundle resourceBundle, //
@MainWindow Stage window, //
Dialogs dialogs, //
RecoveryKeyComponent.Factory recoveryKeyWindow) {
this.vault = vault;
this.removeVault = removeVault;
this.vaults = vaults;
this.resourceBundle = resourceBundle;
this.window = window;
this.recoveryKeyWindow = recoveryKeyWindow;
this.dialogs = dialogs;
}
@FXML
@@ -43,16 +49,16 @@ public class VaultDetailMissingVaultController implements FxController {
@FXML
void didClickRemoveVault() {
removeVault.vault(vault.get()).build().showRemoveVault();
dialogs.prepareRemoveVaultDialog(window, vault.get(), vaults).build().showAndWait();
}
@FXML
void restoreVaultConfig(){
void restoreVaultConfig() {
recoveryKeyWindow.create(vault.get(), window).showIsHubVaultDialogWindow();
}
@FXML
void restoreMasterkey(){
void restoreMasterkey() {
recoveryKeyWindow.create(vault.get(), window).showRecoveryKeyRecoverWindow("Recover Masterkey");
}

View File

@@ -3,12 +3,13 @@ package org.cryptomator.ui.mainwindow;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultListManager;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.dialogs.Dialogs;
import org.cryptomator.ui.fxapp.FxApplicationWindows;
import org.cryptomator.ui.removevault.RemoveVaultComponent;
import javax.inject.Inject;
import javax.inject.Named;
import javafx.beans.property.ObjectProperty;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.stage.Stage;
@@ -18,14 +19,23 @@ public class VaultDetailUnknownErrorController implements FxController {
private final ObjectProperty<Vault> vault;
private final FxApplicationWindows appWindows;
private final Stage errorWindow;
private final RemoveVaultComponent.Builder removeVault;
private final ObservableList<Vault> vaults;
private final Stage mainWindow;
private final Dialogs dialogs;
@Inject
public VaultDetailUnknownErrorController(ObjectProperty<Vault> vault, FxApplicationWindows appWindows, @Named("errorWindow") Stage errorWindow, RemoveVaultComponent.Builder removeVault) {
public VaultDetailUnknownErrorController(@MainWindow Stage mainWindow, //
ObjectProperty<Vault> vault, //
ObservableList<Vault> vaults, //
FxApplicationWindows appWindows, //
@Named("errorWindow") Stage errorWindow, //
Dialogs dialogs) {
this.mainWindow = mainWindow;
this.vault = vault;
this.vaults = vaults;
this.appWindows = appWindows;
this.errorWindow = errorWindow;
this.removeVault = removeVault;
this.dialogs = dialogs;
}
@FXML
@@ -40,6 +50,6 @@ public class VaultDetailUnknownErrorController implements FxController {
@FXML
void didClickRemoveVault() {
removeVault.vault(vault.get()).build().showRemoveVault();
dialogs.prepareRemoveVaultDialog(mainWindow, vault.get(), vaults).build().showAndWait();
}
}

View File

@@ -13,10 +13,16 @@ import javax.inject.Inject;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.geometry.Insets;
import javafx.scene.layout.HBox;
// unscoped because each cell needs its own controller
public class VaultListCellController implements FxController {
private static final Insets COMPACT_INSETS = new Insets(6, 12, 6, 12);
private static final Insets DEFAULT_INSETS = new Insets(12);
private final ObjectProperty<Vault> vault = new SimpleObjectProperty<>();
private final ObservableValue<FontAwesome5Icon> glyph;
private final ObservableValue<Boolean> compactMode;
@@ -25,6 +31,8 @@ public class VaultListCellController implements FxController {
/* FXML */
public FontAwesome5IconView vaultStateView;
@FXML
public HBox vaultListCell;
@Inject
VaultListCellController(Settings settings) {
@@ -37,6 +45,7 @@ public class VaultListCellController implements FxController {
.onCondition(vault.flatMap(Vault::stateProperty).map(VaultState.Value.PROCESSING::equals).orElse(false)) //
.afterStop(() -> vaultStateView.setRotate(0)) //
.build();
this.vaultListCell.paddingProperty().bind(compactMode.map(c -> c ? COMPACT_INSETS : DEFAULT_INSETS));
}
// TODO deduplicate w/ VaultDetailController

View File

@@ -5,8 +5,8 @@ import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.VaultService;
import org.cryptomator.ui.dialogs.Dialogs;
import org.cryptomator.ui.fxapp.FxApplicationWindows;
import org.cryptomator.ui.removevault.RemoveVaultComponent;
import org.cryptomator.ui.vaultoptions.SelectedVaultOptionsTab;
import org.cryptomator.ui.vaultoptions.VaultOptionsComponent;
@@ -14,6 +14,7 @@ import javax.inject.Inject;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.stage.Stage;
import java.util.EnumSet;
@@ -35,23 +36,32 @@ public class VaultListContextMenuController implements FxController {
private final FxApplicationWindows appWindows;
private final VaultService vaultService;
private final KeychainManager keychain;
private final RemoveVaultComponent.Builder removeVault;
private final VaultOptionsComponent.Factory vaultOptionsWindow;
private final ObservableValue<VaultState.Value> selectedVaultState;
private final ObservableValue<Boolean> selectedVaultPassphraseStored;
private final ObservableValue<Boolean> selectedVaultRemovable;
private final ObservableValue<Boolean> selectedVaultUnlockable;
private final ObservableValue<Boolean> selectedVaultLockable;
private final ObservableList<Vault> vaults;
private final Dialogs dialogs;
@Inject
VaultListContextMenuController(ObjectProperty<Vault> selectedVault, @MainWindow Stage mainWindow, FxApplicationWindows appWindows, VaultService vaultService, KeychainManager keychain, RemoveVaultComponent.Builder removeVault, VaultOptionsComponent.Factory vaultOptionsWindow) {
VaultListContextMenuController(ObjectProperty<Vault> selectedVault, //
ObservableList<Vault> vaults, //
@MainWindow Stage mainWindow, //
FxApplicationWindows appWindows, //
VaultService vaultService, //
KeychainManager keychain, //
VaultOptionsComponent.Factory vaultOptionsWindow, //
Dialogs dialogs) {
this.selectedVault = selectedVault;
this.vaults = vaults;
this.mainWindow = mainWindow;
this.appWindows = appWindows;
this.vaultService = vaultService;
this.keychain = keychain;
this.removeVault = removeVault;
this.vaultOptionsWindow = vaultOptionsWindow;
this.dialogs = dialogs;
this.selectedVaultState = selectedVault.flatMap(Vault::stateProperty).orElse(null);
this.selectedVaultPassphraseStored = selectedVault.map(this::isPasswordStored).orElse(false);
@@ -67,7 +77,7 @@ public class VaultListContextMenuController implements FxController {
@FXML
public void didClickRemoveVault() {
var vault = Objects.requireNonNull(selectedVault.get());
removeVault.vault(vault).build().showRemoveVault();
dialogs.prepareRemoveVaultDialog(mainWindow, vault, vaults).build().showAndWait();
}
@FXML

View File

@@ -9,9 +9,9 @@ import org.cryptomator.cryptofs.DirStructure;
import org.cryptomator.ui.addvaultwizard.AddVaultWizardComponent;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.VaultService;
import org.cryptomator.ui.dialogs.Dialogs;
import org.cryptomator.ui.fxapp.FxApplicationWindows;
import org.cryptomator.ui.preferences.SelectedPreferencesTab;
import org.cryptomator.ui.removevault.RemoveVaultComponent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -26,6 +26,7 @@ import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.geometry.Side;
import javafx.scene.control.Button;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.ListView;
import javafx.scene.input.ContextMenuEvent;
@@ -66,16 +67,17 @@ public class VaultListController implements FxController {
private final VaultListCellFactory cellFactory;
private final AddVaultWizardComponent.Builder addVaultWizard;
private final BooleanBinding emptyVaultList;
private final RemoveVaultComponent.Builder removeVaultDialogue;
private final VaultListManager vaultListManager;
private final BooleanProperty draggingVaultOver = new SimpleBooleanProperty();
private final ResourceBundle resourceBundle;
private final FxApplicationWindows appWindows;
private final ObservableValue<Double> cellSize;
private final Dialogs dialogs;
public ListView<Vault> vaultList;
public StackPane root;
@FXML
private HBox addVaultButton;
private Button addVaultButton;
@FXML
private ContextMenu addVaultContextMenu;
@@ -86,21 +88,21 @@ public class VaultListController implements FxController {
VaultListCellFactory cellFactory, //
VaultService vaultService, //
AddVaultWizardComponent.Builder addVaultWizard, //
RemoveVaultComponent.Builder removeVaultDialogue, //
VaultListManager vaultListManager, //
ResourceBundle resourceBundle, //
FxApplicationWindows appWindows, //
Settings settings) {
Settings settings, //
Dialogs dialogs) {
this.mainWindow = mainWindow;
this.vaults = vaults;
this.selectedVault = selectedVault;
this.cellFactory = cellFactory;
this.vaultService = vaultService;
this.addVaultWizard = addVaultWizard;
this.removeVaultDialogue = removeVaultDialogue;
this.vaultListManager = vaultListManager;
this.resourceBundle = resourceBundle;
this.appWindows = appWindows;
this.dialogs = dialogs;
this.emptyVaultList = Bindings.isEmpty(vaults);
@@ -212,7 +214,7 @@ public class VaultListController implements FxController {
private void pressedShortcutToRemoveVault() {
final var vault = selectedVault.get();
if (vault != null && EnumSet.of(LOCKED, MISSING, ERROR, NEEDS_MIGRATION).contains(vault.getState())) {
removeVaultDialogue.vault(vault).build().showRemoveVault();
dialogs.prepareRemoveVaultDialog(mainWindow, vault, vaults).build().showAndWait();
}
}

View File

@@ -16,7 +16,7 @@ import javafx.fxml.FXML;
public class WelcomeController implements FxController {
private static final Logger LOG = LoggerFactory.getLogger(WelcomeController.class);
private static final String GETTING_STARTED_URI = "https://docs.cryptomator.org/en/1.7/desktop/getting-started/";
private static final String GETTING_STARTED_URI = "https://docs.cryptomator.org/desktop/getting-started/";
private final Application application;
private final BooleanBinding noVaultPresent;

View File

@@ -10,7 +10,7 @@ import javafx.stage.Stage;
public class MigrationImpossibleController implements FxController {
private static final String HELP_URI = "https://docs.cryptomator.org/en/1.7/help/manual-migration/";
private static final String HELP_URI = "https://docs.cryptomator.org/help/manual-migration/";
private final Application application;
private final Stage window;

View File

@@ -5,7 +5,7 @@ import org.cryptomator.common.LicenseHolder;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.common.settings.UiTheme;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.removecert.RemoveCertComponent;
import org.cryptomator.ui.dialogs.Dialogs;
import javax.inject.Inject;
import javafx.application.Application;
@@ -15,6 +15,7 @@ import javafx.scene.control.TextArea;
import javafx.scene.control.TextFormatter;
import javafx.stage.Stage;
@PreferencesScoped
public class SupporterCertificateController implements FxController {
@@ -26,18 +27,22 @@ public class SupporterCertificateController implements FxController {
private final Stage window;
private final LicenseHolder licenseHolder;
private final Settings settings;
private final RemoveCertComponent.Builder removeCert;
private final Dialogs dialogs;
@FXML
private TextArea supporterCertificateField;
@Inject
SupporterCertificateController(Application application, @PreferencesWindow Stage window, LicenseHolder licenseHolder, Settings settings, RemoveCertComponent.Builder removeCert) {
SupporterCertificateController(Application application, //
@PreferencesWindow Stage window, //
LicenseHolder licenseHolder, //
Settings settings, //
Dialogs dialogs) {
this.application = application;
this.window = window;
this.licenseHolder = licenseHolder;
this.settings = settings;
this.removeCert = removeCert;
this.dialogs = dialogs;
}
@FXML
@@ -84,10 +89,11 @@ public class SupporterCertificateController implements FxController {
@FXML
void didClickRemoveCert() {
removeCert.build().showRemoveCert(window);
dialogs.prepareRemoveCertDialog(window, settings).build().showAndWait();
}
public LicenseHolder getLicenseHolder() {
return licenseHolder;
}
}

View File

@@ -19,6 +19,8 @@ import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ContentDisplay;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
@@ -32,7 +34,10 @@ import java.util.ResourceBundle;
@PreferencesScoped
public class UpdatesPreferencesController implements FxController {
private static final String DOWNLOADS_URI = "https://cryptomator.org/downloads";
private static final String DOWNLOADS_URI_TEMPLATE = "https://cryptomator.org/downloads/" //
+ "?utm_source=cryptomator-desktop" //
+ "&utm_medium=update-notification&" //
+ "utm_campaign=app-update-%s";
private final Application application;
private final Environment environment;
@@ -50,6 +55,7 @@ public class UpdatesPreferencesController implements FxController {
private final BooleanProperty upToDateLabelVisible = new SimpleBooleanProperty(false);
private final DateTimeFormatter formatter;
private final BooleanBinding upToDate;
private final String downloadsUri;
/* FXML */
public CheckBox checkForUpdatesCheckbox;
@@ -65,12 +71,13 @@ public class UpdatesPreferencesController implements FxController {
this.latestVersion = updateChecker.latestVersionProperty();
this.lastSuccessfulUpdateCheck = updateChecker.lastSuccessfulUpdateCheckProperty();
this.timeDifferenceMessage = Bindings.createStringBinding(this::getTimeDifferenceMessage, lastSuccessfulUpdateCheck);
this.currentVersion = updateChecker.getCurrentVersion();
this.currentVersion = environment.getAppVersion();
this.updateAvailable = updateChecker.updateAvailableProperty();
this.formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withLocale(Locale.getDefault());
this.upToDate = updateChecker.updateCheckStateProperty().isEqualTo(UpdateChecker.UpdateCheckState.CHECK_SUCCESSFUL).and(latestVersion.isEqualTo(currentVersion));
this.checkFailed = updateChecker.checkFailedProperty();
this.lastUpdateCheckMessage = Bindings.createStringBinding(this::getLastUpdateCheckMessage, lastSuccessfulUpdateCheck);
this.downloadsUri = DOWNLOADS_URI_TEMPLATE.formatted(URLEncoder.encode(currentVersion, StandardCharsets.US_ASCII));
}
public void initialize() {
@@ -93,7 +100,7 @@ public class UpdatesPreferencesController implements FxController {
@FXML
public void visitDownloadsPage() {
application.getHostServices().showDocument(DOWNLOADS_URI);
application.getHostServices().showDocument(downloadsUri);
}
@FXML

View File

@@ -22,7 +22,7 @@ import java.util.ResourceBundle;
@PreferencesScoped
public class VolumePreferencesController implements FxController {
public static final String DOCS_MOUNTING_URL = "https://docs.cryptomator.org/en/1.7/desktop/volume-type/";
public static final String DOCS_MOUNTING_URL = "https://docs.cryptomator.org/desktop/volume-type/";
public static final int MIN_PORT = 1024;
public static final int MAX_PORT = 65535;

View File

@@ -1,34 +0,0 @@
package org.cryptomator.ui.removecert;
import dagger.Lazy;
import dagger.Subcomponent;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import javafx.scene.Scene;
import javafx.stage.Stage;
@RemoveCertScoped
@Subcomponent(modules = {RemoveCertModule.class})
public interface RemoveCertComponent {
@RemoveCertWindow
Stage window();
@FxmlScene(FxmlFile.REMOVE_CERT)
Lazy<Scene> scene();
default void showRemoveCert(Stage owner) {
Stage stage = window();
stage.setScene(scene().get());
stage.sizeToScene();
stage.initOwner(owner);
stage.show();
}
@Subcomponent.Builder
interface Builder {
RemoveCertComponent build();
}
}

View File

@@ -1,32 +0,0 @@
package org.cryptomator.ui.removecert;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.ui.common.FxController;
import javax.inject.Inject;
import javafx.fxml.FXML;
import javafx.stage.Stage;
@RemoveCertScoped
public class RemoveCertController implements FxController {
private final Stage window;
private final Settings settings;
@Inject
public RemoveCertController(@RemoveCertWindow Stage window, Settings settings) {
this.window = window;
this.settings = settings;
}
@FXML
public void close() {
window.close();
}
@FXML
public void remove() {
settings.licenseKey.set(null);
window.close();
}
}

View File

@@ -1,56 +0,0 @@
package org.cryptomator.ui.removecert;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
import org.cryptomator.ui.common.DefaultSceneFactory;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxControllerKey;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlLoaderFactory;
import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.common.StageFactory;
import javax.inject.Provider;
import javafx.scene.Scene;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.util.Map;
import java.util.ResourceBundle;
@Module
abstract class RemoveCertModule {
@Provides
@RemoveCertWindow
@RemoveCertScoped
static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
}
@Provides
@RemoveCertWindow
@RemoveCertScoped
static Stage provideStage(StageFactory factory, ResourceBundle resourceBundle) {
Stage stage = factory.create();
stage.setTitle(resourceBundle.getString("removeCert.title"));
stage.setResizable(false);
stage.initModality(Modality.WINDOW_MODAL);
return stage;
}
@Provides
@FxmlScene(FxmlFile.REMOVE_CERT)
@RemoveCertScoped
static Scene provideRemoveCertScene(@RemoveCertWindow FxmlLoaderFactory fxmlLoaders) {
return fxmlLoaders.createScene(FxmlFile.REMOVE_CERT);
}
// ------------------
@Binds
@IntoMap
@FxControllerKey(RemoveCertController.class)
abstract FxController bindRemoveCertController(RemoveCertController controller);
}

View File

@@ -1,13 +0,0 @@
package org.cryptomator.ui.removecert;
import javax.inject.Scope;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface RemoveCertScoped {
}

View File

@@ -1,14 +0,0 @@
package org.cryptomator.ui.removecert;
import javax.inject.Qualifier;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Qualifier
@Documented
@Retention(RUNTIME)
@interface RemoveCertWindow {
}

View File

@@ -1,39 +0,0 @@
package org.cryptomator.ui.removevault;
import dagger.BindsInstance;
import dagger.Lazy;
import dagger.Subcomponent;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import javafx.scene.Scene;
import javafx.stage.Stage;
@RemoveVaultScoped
@Subcomponent(modules = {RemoveVaultModule.class})
public interface RemoveVaultComponent {
@RemoveVaultWindow
Stage window();
@FxmlScene(FxmlFile.REMOVE_VAULT)
Lazy<Scene> scene();
default void showRemoveVault() {
Stage stage = window();
stage.setScene(scene().get());
stage.sizeToScene();
stage.show();
}
@Subcomponent.Builder
interface Builder {
@BindsInstance
Builder vault(@RemoveVaultWindow Vault vault);
RemoveVaultComponent build();
}
}

View File

@@ -1,40 +0,0 @@
package org.cryptomator.ui.removevault;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.common.FxController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.stage.Stage;
@RemoveVaultScoped
public class RemoveVaultController implements FxController {
private static final Logger LOG = LoggerFactory.getLogger(RemoveVaultController.class);
private final Stage window;
private final Vault vault;
private final ObservableList<Vault> vaults;
@Inject
public RemoveVaultController(@RemoveVaultWindow Stage window, @RemoveVaultWindow Vault vault, ObservableList<Vault> vaults) {
this.window = window;
this.vault = vault;
this.vaults = vaults;
}
@FXML
public void close() {
window.close();
}
@FXML
public void finish() {
vaults.remove(vault);
LOG.debug("Removing vault {}.", vault.getDisplayName());
window.close();
}
}

View File

@@ -1,59 +0,0 @@
package org.cryptomator.ui.removevault;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.common.DefaultSceneFactory;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxControllerKey;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlLoaderFactory;
import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.common.StageFactory;
import org.cryptomator.ui.fxapp.PrimaryStage;
import javax.inject.Provider;
import javafx.scene.Scene;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.util.Map;
import java.util.ResourceBundle;
@Module
abstract class RemoveVaultModule {
@Provides
@RemoveVaultWindow
@RemoveVaultScoped
static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
}
@Provides
@RemoveVaultWindow
@RemoveVaultScoped
static Stage provideStage(StageFactory factory, @PrimaryStage Stage primaryStage, @RemoveVaultWindow Vault vault, ResourceBundle resourceBundle) {
Stage stage = factory.create();
stage.setTitle(String.format(resourceBundle.getString("removeVault.title"), vault.getDisplayName()));
stage.setResizable(false);
stage.initModality(Modality.WINDOW_MODAL);
stage.initOwner(primaryStage);
return stage;
}
@Provides
@FxmlScene(FxmlFile.REMOVE_VAULT)
@RemoveVaultScoped
static Scene provideRemoveVaultScene(@RemoveVaultWindow FxmlLoaderFactory fxmlLoaders) {
return fxmlLoaders.createScene(FxmlFile.REMOVE_VAULT);
}
// ------------------
@Binds
@IntoMap
@FxControllerKey(RemoveVaultController.class)
abstract FxController bindRemoveVaultController(RemoveVaultController controller);
}

View File

@@ -1,13 +0,0 @@
package org.cryptomator.ui.removevault;
import javax.inject.Scope;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface RemoveVaultScoped {
}

View File

@@ -1,14 +0,0 @@
package org.cryptomator.ui.removevault;
import javax.inject.Qualifier;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Qualifier
@Documented
@Retention(RUNTIME)
@interface RemoveVaultWindow {
}

View File

@@ -3,7 +3,7 @@ package org.cryptomator.ui.sharevault;
import dagger.Lazy;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.keyloading.hub.HubKeyLoadingStrategy;
import org.cryptomator.ui.keyloading.KeyLoadingStrategy;
import javax.inject.Inject;
import javafx.application.Application;
@@ -33,8 +33,7 @@ public class ShareVaultController implements FxController {
this.window = window;
this.application = application;
this.vault = vault;
var vaultScheme = vault.getVaultConfigCache().getUnchecked().getKeyId().getScheme();
this.hubVault = (vaultScheme.equals(HubKeyLoadingStrategy.SCHEME_HUB_HTTP) || vaultScheme.equals(HubKeyLoadingStrategy.SCHEME_HUB_HTTPS));
this.hubVault = KeyLoadingStrategy.isHubVault(vault.getVaultSettings().lastKnownKeyLoader.get());
}
@FXML

View File

@@ -10,6 +10,7 @@ import org.cryptomator.integrations.mount.MountFailedException;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.common.VaultService;
import org.cryptomator.ui.dialogs.Dialogs;
import org.cryptomator.ui.fxapp.FxApplicationWindows;
import org.cryptomator.ui.fxapp.PrimaryStage;
import org.cryptomator.ui.keyloading.KeyLoadingStrategy;
@@ -25,6 +26,8 @@ import javafx.scene.Scene;
import javafx.stage.Screen;
import javafx.stage.Stage;
import java.io.IOException;
import java.nio.file.ReadOnlyFileSystemException;
import java.util.concurrent.TimeUnit;
/**
* A multi-step task that consists of background activities as well as user interaction.
@@ -46,6 +49,7 @@ public class UnlockWorkflow extends Task<Void> {
private final FxApplicationWindows appWindows;
private final KeyLoadingStrategy keyLoadingStrategy;
private final ObjectProperty<IllegalMountPointException> illegalMountPointException;
private final Dialogs dialogs;
@Inject
UnlockWorkflow(@PrimaryStage Stage mainWindow, //
@@ -57,7 +61,8 @@ public class UnlockWorkflow extends Task<Void> {
@FxmlScene(FxmlFile.UNLOCK_REQUIRES_RESTART) Lazy<Scene> restartRequiredScene, //
FxApplicationWindows appWindows, //
@UnlockWindow KeyLoadingStrategy keyLoadingStrategy, //
@UnlockWindow ObjectProperty<IllegalMountPointException> illegalMountPointException) {
@UnlockWindow ObjectProperty<IllegalMountPointException> illegalMountPointException, //
Dialogs dialogs) {
this.mainWindow = mainWindow;
this.window = window;
this.vault = vault;
@@ -68,6 +73,7 @@ public class UnlockWorkflow extends Task<Void> {
this.appWindows = appWindows;
this.keyLoadingStrategy = keyLoadingStrategy;
this.illegalMountPointException = illegalMountPointException;
this.dialogs = dialogs;
}
@Override
@@ -144,11 +150,36 @@ public class UnlockWorkflow extends Task<Void> {
switch (throwable) {
case IllegalMountPointException e -> handleIllegalMountPointError(e);
case ConflictingMountServiceException _ -> handleConflictingMountServiceException();
case ReadOnlyFileSystemException _ -> handleReadOnlyFileSystem();
default -> handleGenericError(throwable);
}
vault.stateProperty().transition(VaultState.Value.PROCESSING, VaultState.Value.LOCKED);
}
private void handleReadOnlyFileSystem() {
var readOnlyDialog = dialogs.prepareRetryIfReadonlyDialog(mainWindow, stage -> {
stage.close();
this.retry();
}).build();
Platform.runLater(readOnlyDialog::showAndWait);
}
private void retry() {
try {
vault.getVaultSettings().usesReadOnlyMode.set(true);
var isLocked = vault.stateProperty().awaitState(VaultState.Value.LOCKED, 5, TimeUnit.SECONDS);
if (!isLocked) {
LOG.error("Vault did not changed to LOCKED state within 5 seconds. Aborting unlock retry.");
} else {
appWindows.startUnlockWorkflow(vault, mainWindow);
}
} catch (InterruptedException e) {
LOG.error("Waiting for LOCKED vault state was interrupted. Aborting unlock retry.", e);
Thread.currentThread().interrupt();
}
}
@Override
protected void cancelled() {
LOG.debug("Unlock of '{}' canceled.", vault.getDisplayName());

View File

@@ -17,6 +17,8 @@ import org.cryptomator.ui.preferences.VolumePreferencesController;
import javax.inject.Inject;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.value.ObservableBooleanValue;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
@@ -50,7 +52,6 @@ public class MountOptionsController implements FxController {
private final ObservableValue<String> defaultMountFlags;
private final ObservableValue<Boolean> mountpointDirSupported;
private final ObservableValue<Boolean> mountpointDriveLetterSupported;
private final ObservableValue<Boolean> readOnlySupported;
private final ObservableValue<Boolean> mountFlagsSupported;
private final ObservableValue<Boolean> defaultMountServiceSelected;
private final ObservableValue<String> directoryPath;
@@ -60,6 +61,7 @@ public class MountOptionsController implements FxController {
private final ObservableValue<MountService> selectedMountService;
private final ObservableValue<Boolean> selectedMountServiceRequiresRestart;
private final ObservableValue<Boolean> loopbackPortChangeable;
private final ObservableBooleanValue readOnlyOptionAllowed;
//-- FXML objects --
@@ -108,10 +110,10 @@ public class MountOptionsController implements FxController {
});
this.mountFlagsSupported = selectedMountService.map(s -> s.hasCapability(MountCapability.MOUNT_FLAGS));
this.defaultMountServiceSelected = ObservableUtil.mapWithDefault(vaultSettings.mountService, _ -> false, true);
this.readOnlySupported = selectedMountService.map(s -> s.hasCapability(MountCapability.READ_ONLY));
this.mountpointDirSupported = selectedMountService.map(s -> s.hasCapability(MountCapability.MOUNT_TO_EXISTING_DIR) || s.hasCapability(MountCapability.MOUNT_WITHIN_EXISTING_PARENT));
this.mountpointDriveLetterSupported = selectedMountService.map(s -> s.hasCapability(MountCapability.MOUNT_AS_DRIVE_LETTER));
this.loopbackPortChangeable = selectedMountService.map(s -> s.hasCapability(MountCapability.LOOPBACK_PORT) && vaultSettings.mountService.getValue() != null);
this.readOnlyOptionAllowed = BooleanBinding.booleanExpression(selectedMountService.map(s -> s.hasCapability(MountCapability.READ_ONLY))).or(vaultSettings.usesReadOnlyMode);
}
private MountService reselectMountService() {
@@ -345,12 +347,12 @@ public class MountOptionsController implements FxController {
return mountpointDriveLetterSupported.getValue();
}
public ObservableValue<Boolean> readOnlySupportedProperty() {
return readOnlySupported;
public ObservableValue<Boolean> readOnlyOptionAllowedProperty() {
return readOnlyOptionAllowed;
}
public boolean isReadOnlySupported() {
return readOnlySupported.getValue();
public boolean isReadOnlyOptionAllowed() {
return readOnlyOptionAllowed.getValue();
}
public ObservableValue<String> directoryPathProperty() {

View File

@@ -3,6 +3,7 @@ package org.cryptomator.ui.vaultoptions;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.keyloading.KeyLoadingStrategy;
import org.cryptomator.ui.keyloading.hub.HubKeyLoadingStrategy;
import org.cryptomator.ui.keyloading.masterkeyfile.MasterkeyFileLoadingStrategy;
import org.slf4j.Logger;
@@ -42,11 +43,11 @@ public class VaultOptionsController implements FxController {
window.setOnShowing(this::windowWillAppear);
selectedTabProperty.addListener(observable -> this.selectChosenTab());
tabPane.getSelectionModel().selectedItemProperty().addListener(observable -> this.selectedTabChanged());
var vaultScheme = vault.getVaultConfigCache().getUnchecked().getKeyId().getScheme();
if(!vaultScheme.equals(MasterkeyFileLoadingStrategy.SCHEME)){
var vaultKeyLoader = vault.getVaultSettings().lastKnownKeyLoader.get();
if(!KeyLoadingStrategy.isMasterkeyFileVault(vaultKeyLoader)){
tabPane.getTabs().remove(keyTab);
}
if(!(vaultScheme.equals(HubKeyLoadingStrategy.SCHEME_HUB_HTTP) || vaultScheme.equals(HubKeyLoadingStrategy.SCHEME_HUB_HTTPS))){
if(!KeyLoadingStrategy.isHubVault(vaultKeyLoader)){
tabPane.getTabs().remove(hubTab);
}

View File

@@ -15,7 +15,7 @@ import java.io.UncheckedIOException;
@WrongFileAlertScoped
public class WrongFileAlertController implements FxController {
private static final String DOCUMENTATION_URI = "https://docs.cryptomator.org/en/1.7/desktop/accessing-vaults/";
private static final String DOCUMENTATION_URI = "https://docs.cryptomator.org/desktop/accessing-vaults/";
private final Application app;
private final Stage window;

View File

@@ -183,19 +183,37 @@
}
.main-window .button-bar {
-fx-min-height:42px;
-fx-max-height:42px;
-fx-background-color: MAIN_BG;
-fx-border-color: CONTROL_BORDER_NORMAL transparent transparent transparent;
-fx-border-width: 1px 0 0 0;
}
.main-window .button-left {
.main-window .button-bar .button-left {
-fx-border-color: CONTROL_BORDER_NORMAL;
-fx-border-width: 0 1px 0 0;
-fx-background-color: MAIN_BG;
-fx-background-radius: 0px;
-fx-min-height: 42px;
-fx-max-height: 42px;
}
.main-window .button-right {
.main-window .button-bar .button-right {
-fx-border-color: CONTROL_BORDER_NORMAL;
-fx-border-width: 0 0 0 1px;
-fx-background-color: MAIN_BG;
-fx-background-radius: 0px;
-fx-min-height: 42px;
-fx-max-height: 42px;
}
.main-window .button-bar .button-left:armed {
-fx-background-color: CONTROL_BORDER_NORMAL, CONTROL_BG_ARMED;
}
.main-window .button-bar .button-right:armed {
-fx-background-color: CONTROL_BORDER_NORMAL, CONTROL_BG_ARMED;
}
/*******************************************************************************

View File

@@ -182,6 +182,8 @@
}
.main-window .button-bar {
-fx-min-height:42px;
-fx-max-height:42px;
-fx-background-color: MAIN_BG;
-fx-border-color: CONTROL_BORDER_NORMAL transparent transparent transparent;
-fx-border-width: 1px 0 0 0;
@@ -190,11 +192,27 @@
.main-window .button-bar .button-left {
-fx-border-color: CONTROL_BORDER_NORMAL;
-fx-border-width: 0 1px 0 0;
-fx-background-color: MAIN_BG;
-fx-background-radius: 0px;
-fx-min-height: 42px;
-fx-max-height: 42px;
}
.main-window .button-bar .button-right {
-fx-border-color: CONTROL_BORDER_NORMAL;
-fx-border-width: 0 0 0 1px;
-fx-background-color: MAIN_BG;
-fx-background-radius: 0px;
-fx-min-height: 42px;
-fx-max-height: 42px;
}
.main-window .button-bar .button-left:armed {
-fx-background-color: CONTROL_BORDER_NORMAL, CONTROL_BG_ARMED;
}
.main-window .button-bar .button-right:armed {
-fx-background-color: CONTROL_BORDER_NORMAL, CONTROL_BG_ARMED;
}
/*******************************************************************************

View File

@@ -1,53 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ButtonBar?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.Group?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Region?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.Circle?>
<HBox xmlns:fx="http://javafx.com/fxml"
xmlns="http://javafx.com/javafx"
fx:controller="org.cryptomator.ui.dokanysupportend.DokanySupportEndController"
minWidth="500"
prefWidth="500"
minHeight="145"
spacing="12"
alignment="TOP_LEFT">
<padding>
<Insets topRightBottomLeft="12"/>
</padding>
<children>
<Group>
<StackPane>
<padding>
<Insets topRightBottomLeft="6"/>
</padding>
<Circle styleClass="glyph-icon-primary" radius="24"/>
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="EXCLAMATION" glyphSize="24"/>
</StackPane>
</Group>
<VBox HBox.hgrow="ALWAYS">
<Label styleClass="label-large" text="%dokanySupportEnd.message" wrapText="true">
<padding>
<Insets bottom="6" top="6"/>
</padding>
</Label>
<Label text="%dokanySupportEnd.description" wrapText="true"/>
<Region VBox.vgrow="ALWAYS" minHeight="18"/>
<ButtonBar buttonMinWidth="120" buttonOrder="+UC">
<buttons>
<Button text="%dokanySupportEnd.preferencesBtn" ButtonBar.buttonData="OTHER" cancelButton="true" onAction="#openVolumePreferences"/>
<Button text="%generic.button.close" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#close" defaultButton="true"/>
</buttons>
</ButtonBar>
</VBox>
</children>
</HBox>

View File

@@ -22,7 +22,7 @@
</ImageView>
<VBox spacing="3" HBox.hgrow="ALWAYS" alignment="CENTER_LEFT">
<FormattedLabel styleClass="label-extra-large" format="Cryptomator %s" arg1="${controller.fullApplicationVersion}"/>
<Label text="© 2016 2024 Skymatic GmbH"/>
<Label text="© 2016 2025 Skymatic GmbH"/>
</VBox>
</HBox>

View File

@@ -1,52 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ButtonBar?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.Circle?>
<?import javafx.scene.Group?>
<?import javafx.scene.layout.Region?>
<HBox xmlns:fx="http://javafx.com/fxml"
xmlns="http://javafx.com/javafx"
fx:controller="org.cryptomator.ui.removevault.RemoveVaultController"
minWidth="400"
maxWidth="400"
minHeight="145"
spacing="12"
alignment="TOP_LEFT">
<padding>
<Insets topRightBottomLeft="12"/>
</padding>
<children>
<Group>
<StackPane>
<padding>
<Insets topRightBottomLeft="6"/>
</padding>
<Circle styleClass="glyph-icon-primary" radius="24"/>
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="QUESTION" glyphSize="24"/>
</StackPane>
</Group>
<VBox HBox.hgrow="ALWAYS">
<Label styleClass="label-large" text="%removeVault.message" wrapText="true" textAlignment="LEFT">
<padding>
<Insets bottom="6" top="6"/>
</padding>
</Label>
<Label text="%removeVault.description" wrapText="true" textAlignment="LEFT" />
<Region VBox.vgrow="ALWAYS" minHeight="18"/>
<ButtonBar buttonMinWidth="120" buttonOrder="+CI">
<buttons>
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" defaultButton="true" cancelButton="true" onAction="#close"/>
<Button text="%generic.button.remove" ButtonBar.buttonData="FINISH" onAction="#finish"/>
</buttons>
</ButtonBar>
</VBox>
</children>
</HBox>

View File

@@ -1,19 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ButtonBar?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.Circle?>
<?import javafx.scene.control.Button?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.Group?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.shape.Circle?>
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.layout.Region?>
<?import javafx.scene.control.ButtonBar?>
<HBox xmlns:fx="http://javafx.com/fxml"
xmlns="http://javafx.com/javafx"
fx:controller="org.cryptomator.ui.removecert.RemoveCertController"
fx:controller="org.cryptomator.ui.dialogs.SimpleDialogController"
minWidth="400"
maxWidth="400"
minHeight="145"
@@ -28,24 +28,23 @@
<Insets topRightBottomLeft="6"/>
</padding>
<Circle styleClass="glyph-icon-primary" radius="24"/>
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="QUESTION" glyphSize="24"/>
<FontAwesome5IconView glyph="${controller.icon}" styleClass="glyph-icon-white" glyphSize="24"/>
</StackPane>
</Group>
<VBox HBox.hgrow="ALWAYS">
<Label styleClass="label-large" text="%removeCert.message" wrapText="true" >
<Label text="${controller.message}" styleClass="label-large" wrapText="true">
<padding>
<Insets bottom="6" top="6"/>
</padding>
</Label>
<Label text="%removeCert.description" wrapText="true" />
<Label text="${controller.description}" wrapText="true"/>
<Region VBox.vgrow="ALWAYS" minHeight="18"/>
<ButtonBar buttonMinWidth="120" buttonOrder="+CI">
<buttons>
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" defaultButton="true" cancelButton="true" onAction="#close"/>
<Button text="%generic.button.remove" ButtonBar.buttonData="FINISH" onAction="#remove"/>
<Button text="${controller.cancelButtonText}" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#handleCancel"/>
<Button text="${controller.okButtonText}" ButtonBar.buttonData="FINISH" defaultButton="true" onAction="#handleOk"/>
</buttons>
</ButtonBar>
</VBox>
</children>
</HBox>
</HBox>

View File

@@ -11,6 +11,7 @@
<?import javafx.scene.layout.HBox?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.shape.Arc?>
<?import javafx.scene.control.Button?>
<StackPane xmlns:fx="http://javafx.com/fxml"
xmlns="http://javafx.com/javafx"
fx:id="root"
@@ -35,19 +36,17 @@
</VBox>
</StackPane>
<HBox styleClass="button-bar">
<HBox fx:id="addVaultButton" onMouseClicked="#toggleMenu" styleClass="button-left" alignment="CENTER" minWidth="20">
<padding>
<Insets topRightBottomLeft="12"/>
</padding>
<FontAwesome5IconView glyph="PLUS" HBox.hgrow="NEVER" glyphSize="16"/>
</HBox>
<Button fx:id="addVaultButton" onMouseClicked="#toggleMenu" styleClass="button-left" alignment="CENTER" minWidth="20" contentDisplay="GRAPHIC_ONLY">
<graphic>
<FontAwesome5IconView glyph="PLUS" glyphSize="16"/>
</graphic>
</Button>
<Region HBox.hgrow="ALWAYS"/>
<HBox onMouseClicked="#showPreferences" styleClass="button-right" alignment="CENTER" minWidth="20">
<padding>
<Insets topRightBottomLeft="12"/>
</padding>
<FontAwesome5IconView glyph="COG" HBox.hgrow="NEVER" glyphSize="16"/>
</HBox>
<Button onMouseClicked="#showPreferences" styleClass="button-right" alignment="CENTER" minWidth="20" contentDisplay="GRAPHIC_ONLY">
<graphic>
<FontAwesome5IconView glyph="COG" glyphSize="16"/>
</graphic>
</Button>
</HBox>
</VBox>
<Region styleClass="drag-n-drop-border" visible="${controller.draggingVaultOver}"/>

View File

@@ -1,22 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Tooltip?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<HBox xmlns:fx="http://javafx.com/fxml"
xmlns="http://javafx.com/javafx"
fx:id="vaultListCell"
fx:controller="org.cryptomator.ui.mainwindow.VaultListCellController"
prefHeight="60"
prefWidth="200"
spacing="12"
alignment="CENTER_LEFT">
<!-- Remark Check the containing list view for a fixed cell size before editing height properties -->
<padding>
<Insets topRightBottomLeft="12"/>
</padding>
<children>
<VBox alignment="CENTER" minWidth="20">
<FontAwesome5IconView fx:id="vaultStateView" glyph="${controller.glyph}" HBox.hgrow="NEVER" glyphSize="16"/>

View File

@@ -54,7 +54,7 @@
<Button text="%generic.button.apply" fx:id="vaultLoopbackPortApplyButton" onAction="#doChangeLoopbackPort"/>
</HBox>
<CheckBox fx:id="readOnlyCheckbox" text="%vaultOptions.mount.readonly" visible="${controller.readOnlySupported}" managed="${controller.readOnlySupported}"/>
<CheckBox fx:id="readOnlyCheckbox" text="%vaultOptions.mount.readonly" visible="${controller.readOnlyOptionAllowed}" managed="${controller.readOnlyOptionAllowed}"/>
<VBox visible="${controller.mountFlagsSupported}" managed="${controller.mountFlagsSupported}">
<CheckBox fx:id="customMountFlagsCheckbox" text="%vaultOptions.mount.customMountFlags" onAction="#toggleUseCustomMountFlags"/>

View File

@@ -107,6 +107,7 @@ addvaultwizard.success.unlockNow=Unlock Now
removeVault.title=Remove "%s"
removeVault.message=Remove vault?
removeVault.description=This will only make Cryptomator forget about this vault. You can add it again. No encrypted files will be deleted from your hard drive.
removeVault.confirmBtn=Remove Vault
# Change Password
changepassword.title=Change Password
@@ -177,7 +178,7 @@ hub.registerFailed.description.generic=An error was thrown in the registration p
hub.registerFailed.description.deviceAlreadyExists=This device is already registered for a different user. Try to change the user account or use a different device.
### Unauthorized
hub.unauthorized.message=Access denied
hub.unauthorized.description=Your device has not yet been authorized to access this vault. Ask the vault owner to authorize it.
hub.unauthorized.description=You are not authorized to open this vault. Contact the vault's owner to request access.
### Requires Account Initialization
hub.requireAccountInit.message=Action required
hub.requireAccountInit.description.0=To proceed, please complete the steps required in your
@@ -562,6 +563,12 @@ dokanySupportEnd.message=Support end for Dokany
dokanySupportEnd.description=The volume type Dokany is no longer supported by Cryptomator. Your settings are adjusted to use the default volume type now. You can view the default type in the preferences.
dokanySupportEnd.preferencesBtn=Open Preferences
#Retry If Readonly
retryIfReadonly.title=Restricted Vault Access
retryIfReadonly.message=No write access to vault directory
retryIfReadonly.description=Cryptomator cannot write to the vault directory. You can change the vault to be read-only and try again. This option can be disabled in the vault options.
retryIfReadonly.retry=Change and Retry
# Share Vault
shareVault.title=Share Vault
shareVault.message=Would you like to share your vault with others?

View File

@@ -118,4 +118,6 @@
#Dokany Support End
#Retry If Readonly
# Share Vault

View File

@@ -13,6 +13,7 @@ generic.button.copied=تم النسخ!
generic.button.done=تم
generic.button.next=التالي
generic.button.print=طباعة
generic.button.remove=حذف
# Error
error.message=حدث خطأ ما
@@ -105,7 +106,6 @@ addvaultwizard.success.unlockNow=افتح الان
removeVault.title=احذف الحافظة
removeVault.message=حذف المخزن؟
removeVault.description=سيؤدي هذا إلى نسيان Cryptomator لهذا المخزن فقط. يمكنك إضافته مرة أخرى لاحقاً. لن يتم حذف أي من الملفات المشفرة من القرص الصلب الخاص بك.
removeVault.confirmBtn=احذف الحافظة
# Change Password
changepassword.title=تغيير كلمة المرور
@@ -176,7 +176,6 @@ hub.registerFailed.description.generic=حدث خطأ في عملية تسجيل
hub.registerFailed.description.deviceAlreadyExists=هذا الجهاز مسجل لمستخدم مختلف بالفعل. حاول تغيير حساب المستخدم أو استخدام جهاز مختلف.
### Unauthorized
hub.unauthorized.message=تم رفض الوصول
hub.unauthorized.description=لم يتم بعد منح الإذن لجهازك بالوصول إلى هذا المخزن. اطلب من مالك المخزن أن يأذن بذلك.
### Requires Account Initialization
hub.requireAccountInit.message=مطلوب اتخاذ إجراء
hub.requireAccountInit.description.0=للمتابعة، يرجى إكمال الخطوات المطلوبة في
@@ -287,6 +286,7 @@ preferences.general.debugLogging=تمكين سجلات التصحيح
preferences.general.debugDirectory=عرض ملفات السجل
preferences.general.autoStart=تشغيل Cryptomator عند بدء تشغيل النظام
preferences.general.keychainBackend=تخزين كلمات المرور مع
preferences.general.quickAccessService=إضافة الخزانات المفتوحة إلى منطقة الوصول السريع
## Interface
preferences.interface=الواجهة
preferences.interface.theme=الشكل والمظهر
@@ -300,6 +300,7 @@ preferences.interface.interfaceOrientation=اتجاه الواجهة
preferences.interface.interfaceOrientation.ltr=من اليسار إلى اليمين
preferences.interface.interfaceOrientation.rtl=من اليمين إلى اليسار
preferences.interface.showTrayIcon=إظهار أيقونة اللوحة (يتطلب إعادة تشغيل)
preferences.interface.compactMode=تمكين قائمة الخزنة المدمجة
## Volume
preferences.volume=القرص الإفتراضي
preferences.volume.type=نوع القرص الافتراضي
@@ -333,12 +334,14 @@ preferences.contribute.registeredFor=شهادة الداعم مسجلة لـ %s
preferences.contribute.noCertificate=ادعم Cryptomator واحصل على شهادة الداعم. إنها مثل مفتاح الترخيص لكن للأشخاص الرائعين الذين يستخدمون البرامج المجانية ؛-)
preferences.contribute.getCertificate=ليس لديك واحدة بعد؟ تعلم كيف يمكنك الحصول عليها.
preferences.contribute.promptText=قم بلصق رمز شهادة الداعم هنا
preferences.contribute.thankYou=نشكرك على دعمك لتطوير Cryptomator مفتوح المصدر!
preferences.contribute.donate=تبرع
preferences.contribute.sponsor=الراعي
### Remove License Key Dialog
removeCert.title=إزالة الشهادة
removeCert.message=إزالة شهادة الداعم؟
removeCert.confirmBtn=حذف
removeCert.description=الميزات الأساسية لـ Cryptomator غير متأثرة بهذا. لا يتم تقييد الوصول إلى خزاناتك ولا يتم تخفيض مستوى الأمان.
#<-- Add entries for donations and code/translation/documentation contribution -->
## About
@@ -388,7 +391,11 @@ main.vaultlist.contextMenu.unlock=فتح…
main.vaultlist.contextMenu.unlockNow=افتح الان
main.vaultlist.contextMenu.vaultoptions=إظهار خيارات المخزن
main.vaultlist.contextMenu.reveal=اظهار القرص
main.vaultlist.addVaultBtn.menuItemNew=إنشاء مخزن جديد...
main.vaultlist.addVaultBtn.menuItemExisting=افتح مخزن موجود...
##Notificaition
main.notification.updateAvailable=هناك تحديث متاح.
main.notification.support=دعم Cryptomator.
## Vault Detail
### Welcome
main.vaultDetail.welcomeOnboarding=شكرا لاختيار Cryptomator لحماية ملفاتك. إذا كنت بحاجة إلى أية مساعدة، تحقق من دليل وتعليمات الإستخدام:
@@ -544,6 +551,8 @@ dokanySupportEnd.message=انتهاء الدعم لـDokany
dokanySupportEnd.description=نوع وحدة التخزين Dokany لم يعد مدعوماً من قبل Cryptomator. تم تعديل إعداداتك لاستخدام نوع وحدة التخزين الافتراضي الآن. يمكنك عرض النوع الافتراضي في التفضيلات.
dokanySupportEnd.preferencesBtn=فتح التفضيلات
#Retry If Readonly
# Share Vault
shareVault.title=مشاركة الخزانة
shareVault.message=هل ترغب في مشاركة خزانتك مع الآخرين؟

View File

@@ -13,6 +13,7 @@ generic.button.copied=Күсермә алынды!
generic.button.done=Тамам
generic.button.next=Киләһе
generic.button.print=Баҫтыр
generic.button.remove=Алып ташлау
# Error
error.message=Хата килеп сыҡты
@@ -104,7 +105,6 @@ addvaultwizard.success.unlockNow=Хәҙер бикте ас
removeVault.title="%s" һаҡлағысын алып ташла
removeVault.message=Һаҡлағысты алып ташларғамы?
removeVault.description=Cryptomator был һаҡлағысты ғына онотасаҡ. Һеҙ уны яңынан өҫтәй алаһығыҙ. Ҡаты дисктан шифрланған файлдар юйылмаясаҡ.
removeVault.confirmBtn=Һаҡлағысты алып ташла
# Change Password
changepassword.title=Серһүҙҙе үҙгәртеү
@@ -164,7 +164,6 @@ hub.registerSuccess.unlockBtn=Биген ас
### Registration Failed
### Unauthorized
hub.unauthorized.message=Инеү кире ҡағылды
hub.unauthorized.description=Һеҙҙең йыһаз әлегә был һаҡлағысҡа инеү хоҡуғына эйә түгел. Һаҡлағыс хужаһынан рөхсәт һорағыҙ.
### Requires Account Initialization
hub.requireAccountInit.message=Эш-хәрәкәт кәрәкле
hub.requireAccountInit.description.0=Дауам итер өсөн, кәрәкле аҙымдар тамамланырға тейеш урын:
@@ -316,7 +315,6 @@ preferences.contribute.getCertificate=Юҡ мы әллә? Уны нисек ал
preferences.contribute.promptText=Ярҙамсы сертификатын бында йәбештерегеҙ
### Remove License Key Dialog
removeCert.confirmBtn=Алып ташлау
#<-- Add entries for donations and code/translation/documentation contribution -->
## About
@@ -517,4 +515,6 @@ updateReminder.yesAutomatically=Эйе, автоматик рәүештә
#Dokany Support End
dokanySupportEnd.preferencesBtn=Көйләүҙәрҙе ас
#Retry If Readonly
# Share Vault

View File

@@ -13,6 +13,7 @@ generic.button.copied=Скапіявана!
generic.button.done=Файна
generic.button.next=Далей
generic.button.print=Друкаваць
generic.button.remove=Выдаліць
# Error
error.message=Адбылася памылка
@@ -104,7 +105,6 @@ addvaultwizard.success.unlockNow=Разамкнуць зараз
removeVault.title=Выдаліць "%s"
removeVault.message=Ці выдаліць скарбніцу?
removeVault.description=Гэта прывядзе толькі да таго, што Cryptomator забудзецца на гэтую скрынку. Ты зможаш дадаць яе пазней ізноў. Аніякія зашыфраваныя файлы з тайго жорсткага дыску не выдаляцьмуцца.
removeVault.confirmBtn=Выдаліць скарбніцу
# Change Password
changepassword.title=Змяніць пароль
@@ -157,7 +157,6 @@ hub.registerSuccess.unlockBtn=Адамкнуць
### Registration Failed
### Unauthorized
hub.unauthorized.message=Адмова ў доступе
hub.unauthorized.description=Тваёй прыладзе ў дадзены момант не дазволена мець доступ да гэтай скрабніцы. Запытайся ўладальніка скрабніцы за дазволам.
### Requires Account Initialization
### License Exceeded
hub.invalidLicense.message=Несапраўдная ліцэнзія Hub
@@ -303,7 +302,6 @@ preferences.contribute.getCertificate=Яшчэ ня маеш такога? Да
preferences.contribute.promptText=Устаў код сэртыфікату ахвяравальніка сюды
### Remove License Key Dialog
removeCert.confirmBtn=Выдаліць
#<-- Add entries for donations and code/translation/documentation contribution -->
## About
@@ -497,4 +495,6 @@ updateReminder.yesAutomatically=Так, аўтаматычна
#Dokany Support End
dokanySupportEnd.preferencesBtn=Адчыніць налады
#Retry If Readonly
# Share Vault

View File

@@ -13,6 +13,7 @@ generic.button.copied=Копирано!
generic.button.done=Готово
generic.button.next=Напред
generic.button.print=Отпечатване
generic.button.remove=Премахване
# Error
error.message=Възникна грешка
@@ -104,7 +105,6 @@ addvaultwizard.success.unlockNow=Отключване сега
removeVault.title=Премахване на „%s“
removeVault.message=Премахване на хранилище?
removeVault.description=По този начин Криптоматор ще забрави за това хранилище. Можете да го добавите отново. Шифрованите файлове няма да бъдат премахнати от твърдия диск.
removeVault.confirmBtn=Премахване
# Change Password
changepassword.title=Промяна на парола
@@ -164,7 +164,6 @@ hub.registerSuccess.unlockBtn=Отключване
### Registration Failed
### Unauthorized
hub.unauthorized.message=Отказан достъп
hub.unauthorized.description=Устройството не е упълномощено за достъп до това хранилище. Поискайте достъп от собственика.
### Requires Account Initialization
hub.requireAccountInit.message=Необходимо е действие
hub.requireAccountInit.description.0=За да продължите завършете необходимите стъпки в
@@ -316,7 +315,6 @@ preferences.contribute.getCertificate=Все още нямате? Научете
preferences.contribute.promptText=Поставете тук кода на сертификата за дарение
### Remove License Key Dialog
removeCert.confirmBtn=Премахване
#<-- Add entries for donations and code/translation/documentation contribution -->
## About
@@ -517,4 +515,6 @@ updateReminder.yesAutomatically=Да, автоматично
#Dokany Support End
dokanySupportEnd.preferencesBtn=Към настройките
#Retry If Readonly
# Share Vault

View File

@@ -13,6 +13,7 @@ generic.button.copied=কপি হয়েছে!
generic.button.done=সম্পন্ন হয়েছে
generic.button.next=পরবর্তী
generic.button.print=প্রিন্ট
generic.button.remove=বাতিল
# Error
error.message=ত্রুটি %s
@@ -127,7 +128,6 @@ lock.forced.retryBtn=পুনরায় চেষ্টা করুন
## Contribution
### Remove License Key Dialog
removeCert.confirmBtn=বাতিল
#<-- Add entries for donations and code/translation/documentation contribution -->
## About
@@ -182,4 +182,6 @@ vaultOptions.mount.mountPoint.directoryPickerButton=নির্বাচন ক
#Dokany Support End
#Retry If Readonly
# Share Vault

View File

@@ -13,6 +13,7 @@ generic.button.copied=Kopirano!
generic.button.done=Gotovo
generic.button.next=Sljedeće
generic.button.print=Ispis
generic.button.remove=Ukloni
# Error
error.message=Došlo je do greške
@@ -78,7 +79,6 @@ addvaultwizard.success.unlockNow=Otključaj sada
# Remove Vault
removeVault.title=Ukloni Sef
removeVault.description=Ovo će samo natjerati Cryptomator da zaboravi na ovaj sef. Možete ga dodati ponovo kasnije. Nijedna enkriptovana datoteka neće se izbrisati s vašeg diska.
removeVault.confirmBtn=Ukloni Sef
# Change Password
changepassword.title=Promjeni lozinku
@@ -175,7 +175,6 @@ preferences.updates.updateAvailable=Dostupno ažuriranje na verziju %s.
## Contribution
### Remove License Key Dialog
removeCert.confirmBtn=Ukloni
#<-- Add entries for donations and code/translation/documentation contribution -->
## About
@@ -319,4 +318,6 @@ quit.lockAndQuitBtn=Zaključaj i zatvori
#Dokany Support End
#Retry If Readonly
# Share Vault

View File

@@ -13,6 +13,7 @@ generic.button.copied=Copiat!
generic.button.done=Fet
generic.button.next=Següent
generic.button.print=Imprimeix
generic.button.remove=Elimina
# Error
error.message=S'ha produït un error
@@ -105,7 +106,6 @@ addvaultwizard.success.unlockNow=Desbloqueja ara
removeVault.title=Elimina la caixa forta
removeVault.message=Voleu eliminar la caixa forta?
removeVault.description=Cryptomator simplement deixarà de mostrar la caixa forta. Podeu tornar a afegir-la més endavant. Cap fitxer xifrat serà eliminat del disc dur.
removeVault.confirmBtn=Elimina la caixa forta
# Change Password
changepassword.title=Canvia la contrasenya
@@ -176,7 +176,6 @@ hub.registerFailed.description.generic=S'ha produït un error en el procés de r
hub.registerFailed.description.deviceAlreadyExists=El dispositiu ja ha estat registrat per un altre usuari. Mireu de canviar el compte d'usuari o feu servir un dispositiu diferent.
### Unauthorized
hub.unauthorized.message=Accés denegat
hub.unauthorized.description=El vostre dispositiu no ha estat encara autoritzat a accedir a aquesta caixa forta. Demaneu autorització al propietari.
### Requires Account Initialization
hub.requireAccountInit.message=Acció necessària
hub.requireAccountInit.description.0=Per a continuar, si us plau, seguiu els passos necessaris en el vostre
@@ -287,6 +286,7 @@ preferences.general.debugLogging=Habilita el registre de depuració
preferences.general.debugDirectory=Mostra els fitxers de registres
preferences.general.autoStart=Executa Cryptomator en engegar el sistema
preferences.general.keychainBackend=Desar contrasenyes amb
preferences.general.quickAccessService=Afegeix caixes fortes desblocades a l'àrea d'accés directe
## Interface
preferences.interface=Interfície
preferences.interface.theme=Aparença
@@ -300,6 +300,7 @@ preferences.interface.interfaceOrientation=Orientació de la interfície
preferences.interface.interfaceOrientation.ltr=Esquerra a dreta
preferences.interface.interfaceOrientation.rtl=Dreta a esquerra
preferences.interface.showTrayIcon=Mostra la icona en la barra (cal reiniciar)
preferences.interface.compactMode=Activa la llista compacta de caixes fortes
## Volume
preferences.volume=Unitat virtual
preferences.volume.type=Tipus de volum per defecte
@@ -319,6 +320,13 @@ preferences.updates.currentVersion=Versió actual: %s
preferences.updates.autoUpdateCheck=Comprova automàticament si hi ha actualitzacions
preferences.updates.checkNowBtn=Comprova-ho ara
preferences.updates.updateAvailable=L'actualització a la versió %s es troba disponible.
preferences.updates.lastUpdateCheck=Darrera comprovació: %s
preferences.updates.lastUpdateCheck.never=mai
preferences.updates.lastUpdateCheck.recently=recentment
preferences.updates.lastUpdateCheck.daysAgo=Fa %s dies
preferences.updates.lastUpdateCheck.hoursAgo=fa %s hores
preferences.updates.checkFailed=Ha fallat la cerca d'actualitzacions. Si us plau, comproveu la connexió a Internet o torneu a provar-ho més tard.
preferences.updates.upToDate=Cryptomator està actualitzat.
## Contribution
preferences.contribute=Doneu-nos suport
@@ -326,9 +334,13 @@ preferences.contribute.registeredFor=Certificat de col·laborador registrat per
preferences.contribute.noCertificate=Doneu suport a Cryptomator i rebeu un certificat de col·laborador. És com una clau de llicència però per a gent meravellosa que fa servir programari lliure. ;-)
preferences.contribute.getCertificate=Encara no en teniu cap? Sapigueu com aconseguir-ne un.
preferences.contribute.promptText=Enganxeu aquí el certificat de col·laborador
preferences.contribute.thankYou=Gràcies pel vostre suport al desenvolupament open-source de Cryptomator!
preferences.contribute.donate=Feu un donatiu
preferences.contribute.sponsor=Patrocinador
### Remove License Key Dialog
removeCert.confirmBtn=Elimina
removeCert.title=Suprimeix certificat
removeCert.description=Les característiques principals de Cryptomator no es veuen afectades per això. Ni l'accés a les vostres caixes fortes s'ha restringit ni el nivell de seguretat ha estat rebaixat.
#<-- Add entries for donations and code/translation/documentation contribution -->
## About
@@ -378,7 +390,11 @@ main.vaultlist.contextMenu.unlock=Desbloca…
main.vaultlist.contextMenu.unlockNow=Desbloqueja ara
main.vaultlist.contextMenu.vaultoptions=Opcions de la caixa forta
main.vaultlist.contextMenu.reveal=Mostra la unitat
main.vaultlist.addVaultBtn.menuItemNew=Crea una nova caixa forta…
main.vaultlist.addVaultBtn.menuItemExisting=Obri una caixa forta existent...
##Notificaition
main.notification.updateAvailable=Hi ha una actualització disponible.
main.notification.support=Doneu suport a Cryptomator.
## Vault Detail
### Welcome
main.vaultDetail.welcomeOnboarding=Gràcies per escollir Cryptomator per protegir els vostres fitxers. Si vos cal ajuda, llegiu les nostres guies per donar els Primers passos:
@@ -531,6 +547,8 @@ updateReminder.yesAutomatically=Sí, automàticament
#Dokany Support End
dokanySupportEnd.preferencesBtn=Obrir les Preferències
#Retry If Readonly
# Share Vault
shareVault.title=Comparteix la caixa forta
shareVault.message=Voleu compartir la vostra caixa forta amb altres persones?

View File

@@ -13,6 +13,7 @@ generic.button.copied=Zkopírováno!
generic.button.done=Hotovo
generic.button.next=Další
generic.button.print=Tisk
generic.button.remove=Odstranit
# Error
error.message=Chyba %s
@@ -105,7 +106,6 @@ addvaultwizard.success.unlockNow=Odemknout nyní
removeVault.title=Odstranit trezor
removeVault.message=Odstranit trezor?
removeVault.description=Toto jen umožní Cryptomatoru zapomenout tento trezor. Později jej můžete opět přidat. Žádné šifrované soubory nebudou z vašeho disku smazány.
removeVault.confirmBtn=Odstranit trezor
# Change Password
changepassword.title=Změnit heslo
@@ -137,6 +137,7 @@ unlock.success.revealBtn=Zobrazit jednotku
unlock.error.customPath.message=Nelze připojit trezor k vlastní cestě
unlock.error.customPath.description.notSupported=Pokud chcete pokračovat v používání vlastní cesty, přejděte do nastavení a vyberte typ hlasitosti, který ji podporuje. V opačném případě přejděte do možností trezoru a vyberte podporovaný přípojný bod.
unlock.error.customPath.description.notExists=Cesta k připojení neexistuje. Buď ji vytvořte ve vašem lokálním souborovém systému, nebo ji změňte v možnostech trezoru.
unlock.error.customPath.description.inUse=Označení úložiště nebo vlastní cesta "%s" se již používá.
unlock.error.restartRequired.message=Nelze odemknout trezor
unlock.error.restartRequired.description=Změňte typ svazku v možnostech trezoru nebo restartujte Cryptomator.
unlock.error.title=Odemknutí "%s" selhalo
@@ -171,7 +172,6 @@ hub.registerFailed.description.generic=Došlo k chybě v registračním procesu.
hub.registerFailed.description.deviceAlreadyExists=Toto zařízení je již registrováno pro jiného uživatele. Zkuste změnit uživatelský účet nebo použijte jiné zařízení.
### Unauthorized
hub.unauthorized.message=Přístup odepřen
hub.unauthorized.description=Vaše zařízení dosud nebylo oprávněno k přístupu k tomuto trezoru. Požádejte vlastníka trezoru, aby jej autorizoval.
### Requires Account Initialization
hub.requireAccountInit.message=Požadována akce
hub.requireAccountInit.description.0=Chcete-li pokračovat, vyplňte prosím požadované kroky ve vašem
@@ -315,7 +315,6 @@ preferences.contribute.getCertificate=Ještě žádný nemáte? Naučte se, jak
preferences.contribute.promptText=Sem vložte kód certifikátu podporovatele
### Remove License Key Dialog
removeCert.confirmBtn=Odstranit
#<-- Add entries for donations and code/translation/documentation contribution -->
## About
@@ -516,6 +515,8 @@ dokanySupportEnd.title=Oznámení o zastaralosti
dokanySupportEnd.message=Konec podpory pro Dokany
dokanySupportEnd.preferencesBtn=Otevřít předvolby
#Retry If Readonly
# Share Vault
shareVault.title=Sdílet trezor
shareVault.message=Chcete sdílet svůj trezor s ostatními?

View File

@@ -13,6 +13,7 @@ generic.button.copied=Kopieret!
generic.button.done=Færdig
generic.button.next=Næste
generic.button.print=Print
generic.button.remove=Fjern
# Error
error.message=Der opstod en fejl
@@ -105,7 +106,6 @@ addvaultwizard.success.unlockNow=Lås op nu
removeVault.title=Fjern "%s"
removeVault.message=Fjern boks?
removeVault.description=Dette får blot Cryptomator til at glemme boksen. Du kan tilføje den igen senere. Ingen krypterede filer bliver slettet fra harddisken.
removeVault.confirmBtn=Fjern boks
# Change Password
changepassword.title=Skift adgangskode
@@ -176,7 +176,7 @@ hub.registerFailed.description.generic=Der opstod en fejl i registreringsprocess
hub.registerFailed.description.deviceAlreadyExists=Denne enhed er allerede registreret af en anden bruger. Prøv at ændre brugerkontoen eller brug en anden enhed.
### Unauthorized
hub.unauthorized.message=Adgang nægtet
hub.unauthorized.description=Din enhed er endnu ikke blevet godkendt til at få adgang til denne boks. Spørg boks-ejeren om godkendelse.
hub.unauthorized.description=Du har ikke tilladelse til at åbne denne boks. Kontant ejeren af boksen for at anmode om adgang.
### Requires Account Initialization
hub.requireAccountInit.message=Handling påkrævet
hub.requireAccountInit.description.0=For at fortsætte, skal du fuldføre de nødvendige trin i din
@@ -287,6 +287,7 @@ preferences.general.debugLogging=Aktivér fejllogning
preferences.general.debugDirectory=Vis logfiler
preferences.general.autoStart=Start Cryptomator automatisk ved opstart
preferences.general.keychainBackend=Gem adgangskoder med
preferences.general.quickAccessService=Tilføj oplåste bokse til området hurtig adgang
## Interface
preferences.interface=Brugerflade
preferences.interface.theme=Udseende
@@ -319,6 +320,7 @@ preferences.updates.currentVersion=Nuværende version: %s
preferences.updates.autoUpdateCheck=Søg automatisk efter opdateringer
preferences.updates.checkNowBtn=Kontrollér nu
preferences.updates.updateAvailable=Opdatering til version %s er tilgængelig.
preferences.updates.checkFailed=Søgning efter opdateringer fejlede. Tjek din internetforbindelse eller forsøg igen senere.
## Contribution
preferences.contribute=Støt os
@@ -328,7 +330,6 @@ preferences.contribute.getCertificate=Har du ikke et allerede? Se her hvordan du
preferences.contribute.promptText=Indsæt koden for supporter-certifikatet her
### Remove License Key Dialog
removeCert.confirmBtn=Fjern
#<-- Add entries for donations and code/translation/documentation contribution -->
## About
@@ -379,6 +380,8 @@ main.vaultlist.contextMenu.unlockNow=Lås op nu
main.vaultlist.contextMenu.vaultoptions=Vis boksindstillinger
main.vaultlist.contextMenu.reveal=Vis drev
##Notificaition
main.notification.updateAvailable=Opdatering er tilgængelig.
main.notification.support=Støt Cryptomator.
## Vault Detail
### Welcome
main.vaultDetail.welcomeOnboarding=Tak fordi du valgte Cryptomator til at beskytte dine filer. Hvis du har brug for hjælp, så tjek vores guider for at komme i gang:
@@ -531,6 +534,8 @@ updateReminder.yesAutomatically=Ja, automatisk
#Dokany Support End
dokanySupportEnd.preferencesBtn=Åbn Indstillinger
#Retry If Readonly
# Share Vault
shareVault.title=Del Boks
shareVault.message=Vil du dele din boks med andre?

View File

@@ -13,6 +13,7 @@ generic.button.copied=Kopiert!
generic.button.done=Fertig
generic.button.next=Weiter
generic.button.print=Drucken
generic.button.remove=Entfernen
# Error
error.message=Ein Fehler ist aufgetreten
@@ -105,7 +106,6 @@ addvaultwizard.success.unlockNow=Jetzt entsperren
removeVault.title=„%s“ entfernen
removeVault.message=Tresor entfernen?
removeVault.description=Dieser Tresor wird nur aus der Tresorliste entfernt; du kannst ihn später jederzeit wieder hinzufügen. Es werden keine verschlüsselten Daten gelöscht.
removeVault.confirmBtn=Tresor entfernen
# Change Password
changepassword.title=Passwort ändern
@@ -176,7 +176,6 @@ hub.registerFailed.description.generic=Im Registrierungsprozess ist ein Fehler a
hub.registerFailed.description.deviceAlreadyExists=Dieses Gerät ist bereits für einen anderen Benutzer registriert. Ändere das Benutzerkonto oder verwende ein anderes Gerät.
### Unauthorized
hub.unauthorized.message=Zugriff verweigert
hub.unauthorized.description=Dein Gerät wurde noch nicht für den Zugriff auf diesen Tresor autorisiert. Bitte den Tresorbesitzer, dein Gerät zu autorisieren.
### Requires Account Initialization
hub.requireAccountInit.message=Aktion erforderlich
hub.requireAccountInit.description.0=Um fortzufahren, führe bitte die erforderlichen Schritte in deinem
@@ -245,7 +244,7 @@ health.checkList.selectAllButton=Alle Prüfungen auswählen
health.checkList.deselectAllButton=Alle Prüfungen abwählen
health.check.runBatchBtn=Ausgewählte Prüfungen ausführen
## Detail view
health.check.detail.noSelectedCheck=Wähle für die Ergebnisse eine abgeschlossene Intregritätsprüfung in der Liste links aus.
health.check.detail.noSelectedCheck=Wähle für die Ergebnisse eine abgeschlossene Integritätsprüfung in der Liste links aus.
health.check.detail.checkScheduled=Die Prüfung ist geplant.
health.check.detail.checkRunning=Die Prüfung läuft derzeit …
health.check.detail.checkSkipped=Die Prüfung wurde nicht zur Ausführung ausgewählt.
@@ -287,7 +286,7 @@ preferences.general.debugLogging=Diagnoseprotokoll aktivieren
preferences.general.debugDirectory=Protokolldateien anzeigen
preferences.general.autoStart=Cryptomator beim Systemstart starten
preferences.general.keychainBackend=Passwörter speichern mit
preferences.general.quickAccessService=Die entsperrten Tresore zum Schnellzugriff hinzufügen
preferences.general.quickAccessService=Entsperrte Tresore zum Schnellzugriff hinzufügen
## Interface
preferences.interface=Benutzeroberfläche
preferences.interface.theme=Erscheinungsbild
@@ -301,7 +300,7 @@ preferences.interface.interfaceOrientation=Oberflächenausrichtung
preferences.interface.interfaceOrientation.ltr=Von links nach rechts
preferences.interface.interfaceOrientation.rtl=Von rechts nach links
preferences.interface.showTrayIcon=Symbol im Infobereich anzeigen (Neustart erforderlich)
preferences.interface.compactMode=Kompakte Tresoransicht einschalten
preferences.interface.compactMode=Kompakte Tresorliste
## Volume
preferences.volume=Virtuelles Laufwerk
preferences.volume.type=Standard-Laufwerkstyp
@@ -343,7 +342,6 @@ preferences.contribute.sponsor=Sponsern
removeCert.title=Zertifikat entfernen
removeCert.message=Supporter-Zertifikat entfernen?
removeCert.description=Die Kernfunktionen von Cryptomator sind davon nicht betroffen. Weder der Zugriff auf deine Tresore ist eingeschränkt, noch wird das Sicherheitsniveau verringert.
removeCert.confirmBtn=Entfernen
#<-- Add entries for donations and code/translation/documentation contribution -->
## About
@@ -548,11 +546,13 @@ updateReminder.yesOnce=Ja, einmalig
updateReminder.yesAutomatically=Ja, automatisch
#Dokany Support End
dokanySupportEnd.title=Hinweis: nicht mehr verwendet
dokanySupportEnd.message=Ende der Unterstützung für Dokany
dokanySupportEnd.title=Hinweis zur Ausmusterung
dokanySupportEnd.message=Supportende für Dokany
dokanySupportEnd.description=Der Laufwerkstyp Dokany wird von Cryptomator nicht weiter unterstützt. Deine Einstellungen wurden angepasst, dass der Standard-Laufwerkstyp verwendet wird. Du kannst den Standardtyp in den Einstellungen anzeigen lassen.
dokanySupportEnd.preferencesBtn=Einstellungen öffnen
#Retry If Readonly
# Share Vault
shareVault.title=Tresor teilen
shareVault.message=Möchtest du deinen Tresor mit anderen teilen?

View File

@@ -13,6 +13,7 @@ generic.button.copied=Αντιγράφηκε!
generic.button.done=Κλείσιμο
generic.button.next=Επόμενο
generic.button.print=Εκτύπωση
generic.button.remove=Αφαίρεση
# Error
error.message=Παρουσιάστηκε σφάλμα
@@ -105,7 +106,6 @@ addvaultwizard.success.unlockNow=Ξεκλείδωμα τώρα
removeVault.title=Διαγραφή "%s"
removeVault.message=Διαγραφή κρύπτης;
removeVault.description=Αυτό θα κάνει το Cryptomator να ξεχάσει αυτή την κρύπτη. Μπορείτε να την προσθέσετε ξανά. Κανένα κρυπτογραφημένο αρχείο δε θα διαγραφεί από τον σκληρό σας δίσκο.
removeVault.confirmBtn=Διαγραφή Κρύπτης
# Change Password
changepassword.title=Αλλαγή κωδικού πρόσβασης
@@ -176,7 +176,7 @@ hub.registerFailed.description.generic=Παρουσιάστηκε σφάλμα
hub.registerFailed.description.deviceAlreadyExists=Αυτή η συσκευή είναι ήδη εγγεγραμμένη για διαφορετικό χρήστη. Προσπαθήστε να αλλάξετε τον λογαριασμό χρήστη ή να χρησιμοποιήσετε διαφορετική συσκευή.
### Unauthorized
hub.unauthorized.message=Δεν επιτρέπεται η πρόσβαση
hub.unauthorized.description=Η συσκευή σας δεν έχει ακόμη εξουσιοδοτηθεί να έχει πρόσβαση σε αυτή την κρύπτη. Ζητήστε από τον κάτοχο της κρύπτης να την εξουσιοδοτήσει.
hub.unauthorized.description=Δεν είστε εξουσιοδοτημένοι να ανοίξετε αυτή την κρύπτη. Επικοινωνήστε με τον ιδιοκτήτη τς κρύπτης για να ζητήσετε πρόσβαση.
### Requires Account Initialization
hub.requireAccountInit.message=Απαιτείται ενέργεια
hub.requireAccountInit.description.0=Για να συνεχίσετε, παρακαλούμε ολοκληρώστε τα βήματα που απαιτούνται στο δικό σας
@@ -343,7 +343,6 @@ preferences.contribute.sponsor=Χορηγός
removeCert.title=Αφαίρεση Πιστοποιητικού
removeCert.message=Αφαίρεση πιστοποιητικού υποστηρικτή;
removeCert.description=Οι βασικές λειτουργίες του Cryptomator δεν επηρεάζονται από αυτό. Ούτε η πρόσβαση στις κρύπτες σας είναι περιορισμένη ούτε το επίπεδο ασφάλειας μειώνεται.
removeCert.confirmBtn=Αφαίρεση
#<-- Add entries for donations and code/translation/documentation contribution -->
## About
@@ -553,6 +552,12 @@ dokanySupportEnd.message=Τέλος υποστήριξης για Dokany
dokanySupportEnd.description=Ο τύπος τόμου Dokany δεν υποστηρίζεται πλέον από το Cryptomator. Οι ρυθμίσεις σας έχουν προσαρμοστεί για να χρησιμοποιούν τον προεπιλεγμένο τύπο τόμου. Μπορείτε να δείτε τον προεπιλεγμένο τύπο στις προτιμήσεις.
dokanySupportEnd.preferencesBtn=Άνοιγμα Προτιμήσεων
#Retry If Readonly
retryIfReadonly.title=Περιορισμένη Πρόσβαση Κρύπτης
retryIfReadonly.message=Δεν υπάρχει πρόσβαση εγγραφής στον κατάλογο κρύπτης
retryIfReadonly.description=Το Cryptomator δεν μπορεί να γράψει στον κατάλογο κρύπτης. Μπορείτε να αλλάξετε την κρύπτη ώστε να είναι μόνο για ανάγνωση και να προσπαθήσετε ξανά. Αυτή η επιλογή μπορεί να απενεργοποιηθεί στις επιλογές κρύπτης.
retryIfReadonly.retry=Αλλαγή και Επανάληψη
# Share Vault
shareVault.title=Κοινή χρήση Κρύπτης
shareVault.message=Θα θέλατε να μοιραστείτε την κρύπτη σας με άλλους;

View File

@@ -1,198 +0,0 @@
# Locale Specific CSS files such as CJK, RTL,...
# Generics
## Button
generic.button.apply=Apply
generic.button.back=Back
generic.button.cancel=Cancel
generic.button.change=Change
generic.button.choose=Choose…
generic.button.close=Close
generic.button.done=Done
generic.button.next=Next
# Error
# Defaults
# Tray Menu
traymenu.showMainWindow=Show
traymenu.showPreferencesWindow=Preferences
traymenu.quitApplication=Quit
traymenu.vault.unlock=Unlock
traymenu.vault.lock=Lock
traymenu.vault.reveal=Reveal
# Add Vault Wizard
addvaultwizard.title=Add Vault
## New
### Name
addvaultwizard.new.nameInstruction=Choose a name for the vault
addvaultwizard.new.namePrompt=Vault Name
### Location
addvaultwizard.new.locationInstruction=Where should Cryptomator store the encrypted files of your vault?
addvaultwizard.new.locationLabel=Storage location
addvaultwizard.new.locationPrompt=
addvaultwizard.new.directoryPickerButton=Choose…
addvaultwizard.new.directoryPickerTitle=Select Directory
### Expert Settings
### Password
addvaultwizard.new.createVaultBtn=Create Vault
### Information
## Existing
addvaultwizard.existing.chooseBtn=Choose…
## Success
addvaultwizard.success.nextStepsInstructions=Added vault "%s".\nYou need to unlock this vault to access or add contents. Alternatively you can unlock it at any later point in time.
addvaultwizard.success.unlockNow=Unlock Now
# Remove Vault
removeVault.confirmBtn=Remove Vault
# Change Password
changepassword.title=Change Password
changepassword.enterOldPassword=Enter the current password for "%s"
# Forget Password
forgetPassword.title=Forget Password
forgetPassword.confirmBtn=Forget Password
# Unlock
unlock.passwordPrompt=Enter password for "%s":
unlock.unlockBtn=Unlock
## Select
unlock.chooseMasterkey.filePickerTitle=Select Masterkey File
## Success
unlock.success.revealBtn=Reveal Drive
## Failure
## Hub
### Waiting
### Receive Key
### Register Device
### Register Device Legacy
### Registration Success
hub.registerSuccess.unlockBtn=Unlock
### Registration Failed
### Unauthorized
### Requires Account Initialization
### License Exceeded
# Lock
## Force
## Failure
# Migration
migration.title=Upgrade Vault
## Start
migration.start.header=Upgrade Vault
## Run
migration.run.enterPassword=Enter the password for "%s"
migration.run.startMigrationBtn=Migrate Vault
## Success
migration.success.nextStepsInstructions=Migrated "%s" successfully.\nYou can now unlock your vault.
migration.success.unlockNow=Unlock Now
## Missing file system capabilities
## Impossible
# Health Check
## Start
## Start Failure
## Check Selection
## Detail view
## Result view
## Fix Application
# Preferences
preferences.title=Preferences
## General
preferences.general=General
preferences.general.startHidden=Hide window when starting Cryptomator
preferences.general.debugLogging=Enable debug logging
## Interface
## Volume
preferences.volume=Virtual Drive
## Updates
preferences.updates=Updates
preferences.updates.currentVersion=Current Version: %s
preferences.updates.autoUpdateCheck=Check for updates automatically
preferences.updates.checkNowBtn=Check Now
preferences.updates.updateAvailable=Update to version %s available.
## Contribution
### Remove License Key Dialog
#<-- Add entries for donations and code/translation/documentation contribution -->
## About
# Vault Statistics
## Read
## Write
## Accesses
# Main Window
## Vault List
main.vaultlist.emptyList.onboardingInstruction=Click here to add a vault
main.vaultlist.contextMenu.lock=Lock
main.vaultlist.contextMenu.unlockNow=Unlock Now
main.vaultlist.contextMenu.reveal=Reveal Drive
##Notificaition
## Vault Detail
### Welcome
### Locked
main.vaultDetail.lockedStatus=LOCKED
main.vaultDetail.unlockNowBtn=Unlock Now
main.vaultDetail.optionsBtn=Vault Options
### Unlocked
main.vaultDetail.unlockedStatus=UNLOCKED
main.vaultDetail.accessLocation=Your vault's contents are accessible here:
main.vaultDetail.revealBtn=Reveal Drive
main.vaultDetail.lockBtn=Lock
main.vaultDetail.throughput.idle=idle
main.vaultDetail.throughput.mbps=%.1f MiB/s
### Missing
### Needs Migration
main.vaultDetail.migrateButton=Upgrade Vault
### Error
# Wrong File Alert
# Vault Options
## General
vaultOptions.general=General
vaultOptions.general.vaultName=Vault Name
vaultOptions.general.actionAfterUnlock.reveal=Reveal Drive
## Mount
vaultOptions.mount=Mounting
vaultOptions.mount.mountPoint.directoryPickerButton=Choose…
## Master Key
vaultOptions.masterkey.changePasswordBtn=Change Password
## Hub
# Recovery Key
## Display Recovery Key
## Reset Password
### Enter Recovery Key
### Reset Password
### Recovery Key Password Reset Success
# Convert Vault
# New Password
passwordStrength.messageLabel.0=Very weak
passwordStrength.messageLabel.1=Weak
passwordStrength.messageLabel.2=Fair
passwordStrength.messageLabel.3=Strong
passwordStrength.messageLabel.4=Very strong
# Quit
# Forced Quit
# Update Reminder
#Dokany Support End
# Share Vault

View File

@@ -13,6 +13,7 @@ generic.button.copied=¡Copiado!
generic.button.done=Hecho
generic.button.next=Siguiente
generic.button.print=Imprimir
generic.button.remove=Eliminar
# Error
error.message=Ocurrió un error
@@ -105,7 +106,6 @@ addvaultwizard.success.unlockNow=Desbloquear ahora
removeVault.title=Eliminar "%s"
removeVault.message=¿Eliminar bóveda?
removeVault.description=Esto sólo hará que Cryptomator olvide la bóveda. Se la puede añadir de nuevo más tarde. Los archivos cifrados no se eliminarán del disco duro.
removeVault.confirmBtn=Eliminar bóveda
# Change Password
changepassword.title=Cambiar contraseña
@@ -176,7 +176,7 @@ hub.registerFailed.description.generic=Ha ocurrido un error al intentar registra
hub.registerFailed.description.deviceAlreadyExists=Este dispositivo ya se ha registrado para otro usuario. Intente cambiar la cuenta de usuario o utilice un dispositivo diferente.
### Unauthorized
hub.unauthorized.message=Acceso denegado
hub.unauthorized.description=Su dispositivo aún no ha sido autorizado para acceder a esta bóveda. Pídale al propietario de la bóveda que lo autorice.
hub.unauthorized.description=No tiene autorización para abrir esta bóveda. Contacta al propietario de la bóveda para solicitar acceso.
### Requires Account Initialization
hub.requireAccountInit.message=Acción requerida
hub.requireAccountInit.description.0=Para continuar, por favor complete los pasos necesarios en su
@@ -343,7 +343,6 @@ preferences.contribute.sponsor=Patrocinador
removeCert.title=Eliminar Certificado
removeCert.message=¿Eliminar certificado de soporte?
removeCert.description=Las características principales de Cryptomator no se ven afectadas por esto. No se restringe el acceso a sus bóvedas ni se reduce el nivel de seguridad.
removeCert.confirmBtn=Eliminar
#<-- Add entries for donations and code/translation/documentation contribution -->
## About
@@ -553,6 +552,12 @@ dokanySupportEnd.message=Fin de soporte para Dokany
dokanySupportEnd.description=El tipo de volumen Dokany ya no está soportado por Cryptomator. Su configuración se ajusta para utilizar el tipo de volumen predeterminado ahora. Puede ver el tipo predeterminado en las preferencias.
dokanySupportEnd.preferencesBtn=Abrir preferencias
#Retry If Readonly
retryIfReadonly.title=Acceso restringido a la Bóveda
retryIfReadonly.message=No tiene acceso de escritura al directorio de bóveda
retryIfReadonly.description=Cryptomator no puede escribir en el directorio de la bóveda. Puede cambiar la bóveda para que sea de solo lectura e inténtelo de nuevo. Esta opción puede desactivarse en las opciones de bóveda.
retryIfReadonly.retry=Cambiar y reintentar
# Share Vault
shareVault.title=Compartir bóveda
shareVault.message=¿Le gustaría compartir su bóveda con alguien más?

View File

@@ -13,6 +13,7 @@ generic.button.copied=کپی شد!
generic.button.done=انجام شده
generic.button.next=بعدی
generic.button.print=چاپ
generic.button.remove=حذف
# Error
error.message=خطایی رخ داده است
@@ -155,7 +156,6 @@ preferences.updates.upToDate=Cryptomator به روز می باشد.
## Contribution
### Remove License Key Dialog
removeCert.confirmBtn=حذف
#<-- Add entries for donations and code/translation/documentation contribution -->
## About
@@ -210,4 +210,6 @@ vaultOptions.mount.mountPoint.directoryPickerButton=انتخاب کنید…
#Dokany Support End
#Retry If Readonly
# Share Vault

View File

@@ -2,10 +2,10 @@
# Generics
## Button
generic.button.apply=Vahvista
generic.button.apply=Käytä
generic.button.back=Takaisin
generic.button.cancel=Peruuta
generic.button.change=Muuta
generic.button.change=Vaihda
generic.button.choose=Valitse…
generic.button.close=Sulje
generic.button.copy=Kopioi
@@ -13,6 +13,7 @@ generic.button.copied=Kopioitu!
generic.button.done=Valmis
generic.button.next=Seuraava
generic.button.print=Tulosta
generic.button.remove=Poista
# Error
error.message=Tapahtui virhe
@@ -22,27 +23,32 @@ error.hyperlink.report=Ilmoita ongelmasta
error.technicalDetails=Tiedot:
error.existingSolutionDescription=Cryptomator ei odottanut tämän tapahtuvan. Mutta löysimme olemassa olevan ratkaisun tähän virheeseen. Ole hyvä ja katso seuraavaa linkkiä.
error.hyperlink.solution=Etsi ratkaisu
error.lookupPermissionMessage=Cryptomator voi etsiä ratkaisun tähän ongelmaan verkosta. Tämä lähettää pyynnön ongelmatietokannallemme IP-osoitteestasi.
error.dismiss=Ohita
error.lookUpSolution=Etsi ratkaisu
# Defaults
defaults.vault.vaultName=Vault
defaults.vault.vaultName=Holvi
# Tray Menu
traymenu.showMainWindow=Näytä
traymenu.showPreferencesWindow=Asetukset
traymenu.lockAllVaults=Lukitse Kaikki
traymenu.lockAllVaults=Lukitse kaikki
traymenu.quitApplication=Sulje
traymenu.vault.unlock=Avaa
traymenu.vault.lock=Lukitse
traymenu.vault.reveal=Paljasta
# Add Vault Wizard
addvaultwizard.title=Lisää Vault
addvaultwizard.title=Lisää holvi
## New
addvaultwizard.new.title=Lisää uusi holvi
### Name
addvaultwizard.new.nameInstruction=Anna uusi nimi Vaultille
addvaultwizard.new.namePrompt=Vault Nimi
addvaultwizard.new.nameInstruction=Valitse holvin nimi
addvaultwizard.new.namePrompt=Holvin nimi
### Location
addvaultwizard.new.locationInstruction=Missä pitäisi Cryptomator tallentaa salattuja tiedostoja Vault?
addvaultwizard.new.locationInstruction=Missä Cryptomatorin tulisi säilyttää holvisi salattuja tiedostoja?
addvaultwizard.new.locationLoading=Etsitään paikallisesta tiedostojärjestelmästä pilvikansioita…
addvaultwizard.new.locationLabel=Tallennustilan sijainti
addvaultwizard.new.locationPrompt=
addvaultwizard.new.directoryPickerLabel=Oma sijainti
@@ -59,6 +65,11 @@ addvaultwizard.new.validCharacters.chars=Sanamerkit (e.g. a, ж or 수)
addvaultwizard.new.validCharacters.numbers=Numerot
addvaultwizard.new.validCharacters.dashes=Hyphen (%s) tai alaviiva (%s)
### Expert Settings
addvaultwizard.new.expertSettings.enableExpertSettingsCheckbox=Ota lisäasetukset käyttöön
addvaultwizard.new.expertSettings.shorteningThreshold.invalid=Syötä arvo väliltä 36 ja 220 (oletus 220)
addvaultwizard.new.expertSettings.shorteningThreshold.tooltip=Avaa dokumentaatio lisätietoja varten.
addvaultwizard.new.expertSettings.shorteningThreshold.title=Salattujen tiedostonimien enimmäispituus
addvaultwizard.new.expertSettings.shorteningThreshold.valid=Kelvollinen
### Password
addvaultwizard.new.createVaultBtn=Luo Uusi Vault
addvaultwizard.new.generateRecoveryKeyChoice=Et voi käyttää tietojasi ilman salasanaasi. Haluatko palautusavaimen siltä varalta, että menetät salasanasi?
@@ -82,6 +93,7 @@ addvault.new.readme.accessLocation.2=Tämä on salatun holvisi tallennuskansio.
addvault.new.readme.accessLocation.3=Cryptomator salaa kaikki tänne siirtämäsi tiedostot. Voit työskennellä tässä kansiossa aivan samalla tavalla kuin muutenkin. Tämä on ainoastaan näkymä jossa salaus on purettu. Todellisuudessa kaikki tiedostot pysyvät salattuina aina.
addvault.new.readme.accessLocation.4=Voit halutessasi poistaa tämän tiedoston. Poistaminen ei vaikuta Cryptomatorin toimintaan.
## Existing
addvaultwizard.existing.title=Lisää olemassa oleva holvi
addvaultwizard.existing.instruction=Valitse olemassa olevan Cryptomator holvin "vault.cryptomator" -tiedosto. Mikäli "vault.cryptomator" -tiedostoa ei ole, valitse "masterkey.cryptomator" -tiedosto.
addvaultwizard.existing.chooseBtn=Valitse…
addvaultwizard.existing.filePickerTitle=Valitse Holvi -tiedosto
@@ -93,32 +105,31 @@ addvaultwizard.success.unlockNow=Avaa Nyt
# Remove Vault
removeVault.title=Poista "%s"
removeVault.message=Poistetaanko holvi?
removeVault.description=Tämä toiminto ainoastaan poistaa valitun holvin Cryptomatorin näkymästä. Salattuja tiedostoja tai holvia itsessään ei poisteta.
removeVault.confirmBtn=Poista Holvi
removeVault.description=Tämä toiminto ainoastaan poistaa valitun holvin Cryptomatorin näkymästä. Voit lisätä sen uudelleen. Salattuja tiedostoja ei poisteta levyltäsi.
# Change Password
changepassword.title=Vaihda salasana
changepassword.enterOldPassword=Syötä "%s": n nykyinen salasana
changepassword.enterOldPassword=Kirjoita holvin "%s" nykyinen salasana
changepassword.finalConfirmation=Ymmärrän, että tiedostojani ei voi palauttaa, mikäli unohdan salasanani.
# Forget Password
forgetPassword.title=Unohda Salasana
forgetPassword.title=Unohda salasana
forgetPassword.message=Unohda tallennetut salasanat?
forgetPassword.description=Tämä poistaa valitun holvin tallennetun salasanan järjestelmäsi avainrenkaasta.
forgetPassword.confirmBtn=Unohda Salasana
forgetPassword.confirmBtn=Unohda salasana
# Unlock
unlock.title=Avaa "%s"
unlock.passwordPrompt=Syötä salasana "%s":lle
unlock.passwordPrompt=Syötä holvin "%s" salasana:
unlock.savePassword=Muista salasana
unlock.unlockBtn=Avaa
## Select
unlock.chooseMasterkey.message=Masterkey -tiedostoa ei löydy
unlock.chooseMasterkey.description=Cryptomator ei paikantanut masterkey -tiedostoa holville "%s". Ole hyvä ja valitse tiedosto manuaalisesti.
unlock.chooseMasterkey.filePickerTitle=Valitse Masterkey -tiedosto
unlock.chooseMasterkey.filePickerMimeDesc=Cryptomator Masterkey
unlock.chooseMasterkey.message=Masterkey-tiedostoa ei löydy
unlock.chooseMasterkey.description=Cryptomator ei paikantanut masterkey-tiedostoa holville "%s". Ole hyvä ja valitse tiedosto manuaalisesti.
unlock.chooseMasterkey.filePickerTitle=Valitse masterkey-tiedosto
unlock.chooseMasterkey.filePickerMimeDesc=Cryptomator masterkey
## Success
unlock.success.message=Lukituksen purku onnistui
unlock.success.message=Avaus onnistui
unlock.success.description="%s" holvin sisältö on nyt saatavilla sen hallinnointikohteessa.
unlock.success.rememberChoice=Muista valintani. Älä kysy uudelleen.
unlock.success.revealBtn=Paljasta Asema
@@ -126,6 +137,14 @@ unlock.success.revealBtn=Paljasta Asema
unlock.error.customPath.message=Holvia ei pystytty yhdistämään valittuun polkuun
unlock.error.customPath.description.notSupported=Mikäli haluat jatkaa mukautetun polun käyttöä, ole hyvä ja mene Asetuksiin ja valitse volyymityyppi mikä tukee sitä. Muussa tapauksessa avaa holvin asetukset ja valitse tuettu mukautettu polku.
unlock.error.customPath.description.notExists=Valitsemaasi mukautettua polkua ei ole olemassa. Voit joko luoda uuden polun tai muuttaa polkua holvisi asetuksissa.
unlock.error.customPath.description.inUse=Aseman kirjain tai mukautettu liitospolku "%s" on jo käytössä.
unlock.error.customPath.description.hideawayNotDir=Avaukseen käytettävää väliaikaista piilotettua tiedostoa "%3$s" ei voitu poistaa. Tarkista tiedosto ja poista se manuaalisesti.
unlock.error.customPath.description.couldNotBeCleaned=Holviasi ei voilu liittää polkuun "%s". Yritä uudelleen tai valitse toinen polku.
unlock.error.customPath.description.notEmptyDir=Mukautettu liitospolku "%s" ei ole tyhtjä kansio. Valitse tyhjä kansio ja yritä uudelleen.
unlock.error.customPath.description.generic=Olet valinnut mukautetun liitospolun holvillesi, mutta sen kanssa ilmeni ongelma: %2$s
unlock.error.restartRequired.message=Holvin avaus epäonnistui
unlock.error.restartRequired.description=Vaihda aseman tyyppiä holvin asetuksissa tai käynnistä Cryptomator uudelleen.
unlock.error.title="%s" avaaminen epäonnistui
## Hub
hub.noKeychain.message=Laitteen avainta ei löytynyt
hub.noKeychain.description=Hub-holvien purkamiseksi tarvitaan laiteavain joka on suojattu avainrenkaalla. Jatkaaksesi, kytke “%s” päälle ja valitse avainrengas asetuksista.
@@ -138,15 +157,30 @@ hub.auth.loginLink=Uudelleenohjaus epäonnistui? Avaa tästä manuaalisesti.
hub.receive.message=Odotetaan vastausta…
hub.receive.description=Cryptomator yhdistää Hub:iin. Ole hyvä ja odota.
### Register Device
hub.register.message=Uusi laite
hub.register.description=Tämä on ensimmäinen Hub-yhteys tästä laitteesta. Rekisteröi se käyttäen Account Keytäsi.
hub.register.nameLabel=Laitteen Nimi
hub.register.invalidAccountKeyLabel=Virheellinen Account Key
hub.register.registerBtn=Rekisteröidy
### Register Device Legacy
hub.register.legacy.occupiedMsg=Nimi on jo käytössä
hub.register.legacy.description=Tämä on ensimmäinen Hub-yhteys tästä laitteesta. Ole hyvä ja rekisteröi se.
### Registration Success
hub.registerSuccess.message=Laite rekisteröity
hub.registerSuccess.description=Laitteesi on rekisteröity onnistuneesti. Voit nyt avata holvin.
hub.registerSuccess.unlockBtn=Avaa
hub.registerSuccess.legacy.description=Käyttääksesi holvia, holvin omistajan on valtuutettava laitteesi.
### Registration Failed
hub.registerFailed.message=Laitteen rekisteröinti epäonnistui
hub.registerFailed.description.generic=Rekisteröinnissä tapahtui virhe. Löydät lisätietoja lokitiedostoista.
hub.registerFailed.description.deviceAlreadyExists=Tämä laite on jo rekisteröity toiselle käyttäjälle. Yritä vaihtaa käyttäjätiliä tai käytää toista laitetta.
### Unauthorized
hub.unauthorized.message=Pääsy estetty
hub.unauthorized.description=Laitteellasi ei ole pääsyvaltuutusta tähän holviin. Pyydä holvin omistajaa lisäämän valtuutus laitteellesi.
### Requires Account Initialization
hub.requireAccountInit.message=Toimia vaaditaan
hub.requireAccountInit.description.0=Jatkaaksesi, ole hyvä ja suorita tarvittavat toimenpiteet
hub.requireAccountInit.description.1=Hub käyttäjäprofiili
hub.requireAccountInit.description.2=.
### License Exceeded
hub.invalidLicense.message=Hub-lisenssi ei ole voimassa
hub.invalidLicense.description=Cryptomator Hub:illasi ei ole voimassa olevaa lisenssiä. Ole hyvä ja ilmoita Hubin järjestelmänvalvojalle lisenssin päivittämiseksi tai sen uusimiseksi.
@@ -194,82 +228,335 @@ migration.impossible.moreInfo=Varasto voidaan edelleen avata vanhemmalla versiol
## Start
health.title="%s" kuntotarkastus
health.intro.header=Kuntotarkastus
health.intro.text=Kuntotarkistus on kokoelma testejä, joilla havaitaan ja korjataan ongelmia holvissasi. Ole hyvä ja pidä mielessäsi:
health.intro.remarkSync=Varmista että kaikki laitteet ovat täysin synkronoitu, tämä ratkaisee useimmat ongelmat.
health.intro.remarkFix=Kaikkia ongelmia ei voida ratkaista.
health.intro.remarkBackup=Jos tiedot ovat korruptoituneita, vain varmuuskopiosta on apua.
health.intro.affirmation=Olen lukenut ja ymmärtänyt yllä mainitut huomiot
## Start Failure
health.fail.header=Virhe ladattaessa holvin asetuksia
health.fail.ioError=Asetustiedostoa lukiessa tapahtui virhe.
health.fail.parseError=Holvin asetuksia jäsentäessä tapahtui virhe.
health.fail.moreInfo=Lisätietoja
## Check Selection
health.checkList.description=Valitse testit vasemmalta luettelosta tai käytä alla olevia painikkeita.
health.checkList.selectAllButton=Valitse kaikki testit
health.checkList.deselectAllButton=Poista testivalinnat
health.check.runBatchBtn=Suorita valitut testit
## Detail view
health.check.detail.noSelectedCheck=Katsoaksesi tulokset, valitse suoritettu kuntotarkistus vasemmalta luettelosta.
health.check.detail.checkScheduled=Testi on ajoitettu.
health.check.detail.checkRunning=Testi on käynnissä…
health.check.detail.checkSkipped=Testiä ei valittu suoritettavaksi.
health.check.detail.checkFinished=Testi suoritettiin onnistuneesti.
health.check.detail.checkFinishedAndFound=Testi suorietttiin loppuun. Ole hyvä ja katso tulokset.
health.check.detail.checkFailed=Testi päättyi virheen vuoksi.
health.check.detail.checkCancelled=Testi peruutettiin.
health.check.detail.listFilters.label=Suodata
health.check.detail.fixAllSpecificBtn=Korjaa kaikki tyyppiä
health.check.exportBtn=Vie raportti
## Result view
health.result.severityFilter.all=Vakavuus - Kaikki
health.result.severityFilter.good=Hyvä
health.result.severityFilter.info=Huomio
health.result.severityFilter.warn=Varoitus
health.result.severityFilter.crit=Kriittinen
health.result.severityTip.good=Vakavuus: Hyvä\nNormaali holvirakenne.
health.result.severityTip.info=Vakavuus: Huomio\nHolvin rakenne ehjä. Ehdotetaan korjausta.
health.result.severityTip.warn=Vakavuus: Varoitus\nHolvin rakenne korruptoitunut. Korjaus erittäin suositeltavaa.
health.result.severityTip.crit=Vakavuus: Kriittinen\nHolvin rakenne korruptoitunut. Tietoja menetetty.
health.result.fixStateFilter.all=Korjauksen tila - Kaikki
health.result.fixStateFilter.fixable=Korjattavissa
health.result.fixStateFilter.notFixable=Ei korjattavissa
health.result.fixStateFilter.fixing=Korjataan…
health.result.fixStateFilter.fixed=Korjattu
health.result.fixStateFilter.fixFailed=Korjaus epäonnistui
## Fix Application
health.fix.fixBtn=Korjaa
health.fix.successTip=Korjaus onnistui
health.fix.failTip=Korjaus epäonnistui, katso lisätietoja lokista
# Preferences
preferences.title=Asetukset
## General
preferences.general=Yleiset
preferences.general.startHidden=Piilota ikkuna kun Cryptomator käynnistyy
preferences.general.autoCloseVaults=Lukitse avoimet holvit automaattisesti kun ohjelma sammutetaan
preferences.general.debugLogging=Ota virheloki käyttöön
preferences.general.debugDirectory=Näytä lokitiedostot
preferences.general.autoStart=Käynnistä Cryptomator järjestelmän käynnistyessä
preferences.general.keychainBackend=Tallenna salasanat käyttäen
preferences.general.quickAccessService=Lisää avatut holvit pikavalikkoon
## Interface
preferences.interface=Käyttöliittymä
preferences.interface.theme=Ulkonäkö
preferences.interface.theme.automatic=Automaattinen
preferences.interface.theme.dark=Tumma
preferences.interface.theme.light=Vaalea
preferences.interface.unlockThemes=Hanki tumma tila
preferences.interface.language=Kieli (vaatii uudelleenkäynnistyksen)
preferences.interface.language.auto=Järjestelmän oletus
preferences.interface.interfaceOrientation=Käyttöliittymän kätisyys
preferences.interface.interfaceOrientation.ltr=Vasemmalta oikealle
preferences.interface.interfaceOrientation.rtl=Oikealta vasemmalle
preferences.interface.showTrayIcon=Näytä ilmoitusalueen kuvake (vaatii uudelleenkäynnistyksen)
preferences.interface.compactMode=Käytä kompaktia holviluetteloa
## Volume
preferences.volume=Virtuaaliasema
preferences.volume.type=Aseman oletustyyppi
preferences.volume.type.automatic=Automaattinen
preferences.volume.docsTooltip=Lue lisää asematyypeistä dokumentaatiosta.
preferences.volume.fuseRestartRequired=Jotta muutokset tulevat voimaan, Cryptomator täytyy käynnistää uudelleen.
preferences.volume.tcp.port=Oletus TCP-portti
preferences.volume.supportedFeatures=Valittu asematyyppi tukee seuraavia ominaisuuksia:
preferences.volume.feature.mountAuto=Automaattinen liitospolun valinta
preferences.volume.feature.mountToDir=Mukautettu kansio litospolkuna
preferences.volume.feature.mountToDriveLetter=Aseman kirjain liitospolkuna
preferences.volume.feature.mountFlags=Mukautetut liitosasetukset
preferences.volume.feature.readOnly=Liitos vain lukuoikeuksilla
## Updates
preferences.updates=Päivitykset
preferences.updates.currentVersion=Nykyinen versio: %s
preferences.updates.autoUpdateCheck=Tarkista päivitykset automaattisesti
preferences.updates.checkNowBtn=Tarkista nyt
preferences.updates.updateAvailable=Päivitys versioon %s saatavilla.
preferences.updates.lastUpdateCheck=Edellinen tarkistus: %s
preferences.updates.lastUpdateCheck.never=ei koskaan
preferences.updates.lastUpdateCheck.recently=viimeaikoina
preferences.updates.lastUpdateCheck.daysAgo=%s päivää sitten
preferences.updates.lastUpdateCheck.hoursAgo=%s tuntia sitten
preferences.updates.checkFailed=Päivitysten etsiminen epäonnistui. Tarkista internetyhteys tai yritä myöhemmin uudelleen.
preferences.updates.upToDate=Cryptomator on ajan tasalla.
## Contribution
preferences.contribute=Tue meitä
preferences.contribute.noCertificate=Tue Cryptomatoria ja saa tukijasertifikaatti. Se on kuin lisenssiavain, mutta mahtaville ihmisille, jotka käyttävät vapaata ohjelmistoa. ;-)
preferences.contribute.getCertificate=Eikö sinulla ole sellaista? Lue lisää miten voit hankkia sellaisen.
preferences.contribute.promptText=Liitä tukijasertifikaatin koodi tähän
preferences.contribute.thankYou=Kiitos tuestasi Cryptomatorin avoimeen kehittämiseen!
preferences.contribute.donate=Lahjoita
preferences.contribute.sponsor=Sponsori
### Remove License Key Dialog
removeCert.title=Poista sertifikaatti
removeCert.message=Poista tukijasertifikaatti?
removeCert.description=Tämä ei vaikuta Cryptomatorin ydintoimintoihin. Holveihin pääsyä ei rajoiteta eikä turvallisuutta heikennetä.
#<-- Add entries for donations and code/translation/documentation contribution -->
## About
preferences.about=Tietoja
# Vault Statistics
stats.title=%s tilastot
## Read
stats.read.throughput.idle=Luku: toimeton
stats.read.throughput.kibs=Luku: %.2f KiB/s
stats.read.throughput.mibs=Luku: %.2f MiB/s
stats.read.total.data.none=Dataa luettu: -
stats.read.total.data.kib=Dataa luettu: %.1f KiB
stats.read.total.data.mib=Dataa luettu: %.1f MiB
stats.read.total.data.gib=Dataa luettu: %.1f GiB
stats.decr.total.data.none=Dataa purettu: -
stats.decr.total.data.kib=Dataa purettu: %.1f KiB
stats.decr.total.data.mib=Dataa purettu: %.1f MiB
stats.decr.total.data.gib=Dataa purettu: %.1f GiB
stats.read.accessCount=Lukuja yhteensä: %d
## Write
stats.write.throughput.idle=Kirjoitus: toimeton
stats.write.throughput.kibs=Kirjoitus: %.2f KiB/s
stats.write.throughput.mibs=Kirjoitus: %.2f MiB/s
stats.write.total.data.none=Dataa kirjoitettu: -
stats.write.total.data.kib=Dataa kirjoitettu: %.1f KiB
stats.write.total.data.mib=Dataa kirjoitettu: %.1f MiB
stats.write.total.data.gib=Dataa kirjoitettu: %.1f GiB
stats.encr.total.data.none=Dataa salattu: -
stats.encr.total.data.kib=Dataa salattu: %.1f KiB
stats.encr.total.data.mib=Dataa salattu: %.1f MiB
stats.encr.total.data.gib=Dataa salattu: %.1f GiB
stats.write.accessCount=Kirjoituksia yhteensä: %d
## Accesses
stats.access.current=Tiedostoja avattuna: %d
stats.access.total=Avauksia yhteensä: %d
# Main Window
## Vault List
main.vaultlist.emptyList.onboardingInstruction=Klikkaa tästä lisätäksesi holvin
main.vaultlist.contextMenu.remove=Poista…
main.vaultlist.contextMenu.lock=Lukitse
main.vaultlist.contextMenu.unlock=Avaa…
main.vaultlist.contextMenu.unlockNow=Avaa Nyt
main.vaultlist.contextMenu.vaultoptions=Näytä holvin asetukset
main.vaultlist.contextMenu.reveal=Paljasta Asema
main.vaultlist.addVaultBtn.menuItemNew=Luo uusi holvi...
main.vaultlist.addVaultBtn.menuItemExisting=Avaa olemassa oleva holvi...
##Notificaition
main.notification.updateAvailable=Päivitys on saatavilla.
main.notification.support=Tue Cryptomatoria.
## Vault Detail
### Welcome
main.vaultDetail.welcomeOnboarding=Kiitos kun valitsit Cryptomatorin tiedostojesi suojaamiseen. Mikäli tarvitset apua, tutustu aloitusoppaaseemme:
### Locked
main.vaultDetail.lockedStatus=LUKITTU
main.vaultDetail.unlockBtn=Avaa…
main.vaultDetail.unlockNowBtn=Avaa Nyt
main.vaultDetail.optionsBtn=Holvin asetukset
main.vaultDetail.passwordSavedInKeychain=Salasana on tallennettu
main.vaultDetail.share=Jaa…
### Unlocked
main.vaultDetail.unlockedStatus=AVATTU
main.vaultDetail.accessLocation=Holvisi sisältö on saatavilla täältä:
main.vaultDetail.revealBtn=Paljasta Asema
main.vaultDetail.copyUri=Kopioi URI
main.vaultDetail.lockBtn=Lukitse
main.vaultDetail.bytesPerSecondRead=Luku:
main.vaultDetail.bytesPerSecondWritten=Kirjoitus:
main.vaultDetail.throughput.idle=toimeton
main.vaultDetail.throughput.kbps=%.1f KiB/s
main.vaultDetail.throughput.mbps=%.1f MiB/s
main.vaultDetail.stats=Holvin tilastot
main.vaultDetail.locateEncryptedFileBtn=Etsi salattu tiedosto
main.vaultDetail.locateEncryptedFileBtn.tooltip=Valitse tiedosto holvistasi löytääksesi sen salatun vastineen
main.vaultDetail.encryptedPathsCopied=Polut kopioitu leikepöydälle!
main.vaultDetail.filePickerTitle=Valitse tiedosto holvin sisältä
### Missing
main.vaultDetail.missing.info=Cryptomator ei löytänyt täältä holvia.
main.vaultDetail.missing.recheck=Tarkista uudelleen
main.vaultDetail.missing.remove=Poista holvilistalta…
main.vaultDetail.missing.changeLocation=Vaihda holvin sijaintia…
### Needs Migration
main.vaultDetail.migrateButton=Päivitä Holvi
main.vaultDetail.migratePrompt=Holvisi täytyy muuntaa uuteen muotoon ennen kuin voit avata sen
### Error
main.vaultDetail.error.info=Tapahtui virhe ladatessa holvia levyltä.
main.vaultDetail.error.reload=Päivitä
main.vaultDetail.error.windowTitle=Virhe ladatessa holvia
# Wrong File Alert
wrongFileAlert.title=Kuinka tiedostoja salataan
wrongFileAlert.message=Yritkö salata nämä tiedostot?
wrongFileAlert.instruction.0=Salaa tiedostot seuraavasti:
wrongFileAlert.instruction.1=1. Avaa holvisi.
wrongFileAlert.instruction.2=2. Klikkaa "Paljasta" avataksesi aseman tiedostoselaimessasi.
wrongFileAlert.instruction.3=3. Siirrä tiedostosi asemalle.
wrongFileAlert.link=Lisäapua varten katso
# Vault Options
## General
vaultOptions.general.vaultName=Vault Nimi
vaultOptions.general=Yleiset
vaultOptions.general.vaultName=Holvin nimi
vaultOptions.general.autoLock.lockAfterTimePart1=Lukitse kun ollut käyttämättä
vaultOptions.general.autoLock.lockAfterTimePart2=minuuttia
vaultOptions.general.unlockAfterStartup=Avaa holvi kun Cryptomator käynnistyy
vaultOptions.general.actionAfterUnlock=Avauksen jälkeen
vaultOptions.general.actionAfterUnlock.ignore=Älä tee mitään
vaultOptions.general.actionAfterUnlock.reveal=Paljasta Asema
vaultOptions.general.actionAfterUnlock.ask=Kysy
vaultOptions.general.startHealthCheckBtn=Aloita kuntotarkastus
## Mount
vaultOptions.mount=Liittäminen
vaultOptions.mount.info=Avaa virtuaaliaseman asetukset muuttaaksesi oletuksia.
vaultOptions.mount.readonly=Vain luku
vaultOptions.mount.customMountFlags=Mukautetut liitosasetukset
vaultOptions.mount.winDriveLetterOccupied=käytössä
vaultOptions.mount.mountPoint=Liitoskohta
vaultOptions.mount.mountPoint.auto=Valitse sopiva sijainti automaattisesti
vaultOptions.mount.mountPoint.driveLetter=Käytä määritettyä asemakirjainta
vaultOptions.mount.mountPoint.custom=Käytä valittua kansiota
vaultOptions.mount.mountPoint.directoryPickerButton=Valitse…
vaultOptions.mount.mountPoint.directoryPickerTitle=Valitse kansio
vaultOptions.mount.volumeType.default=Oletus (%s)
vaultOptions.mount.volumeType.restartRequired=Jotta tätä asematyyppiä voidaan käyttää, Cryptomator täytyy käynnistää uudelleen.
vaultOptions.mount.volume.tcp.port=TCP-portti
vaultOptions.mount.volume.type=Aseman tyyppi
## Master Key
vaultOptions.masterkey=Salasana
vaultOptions.masterkey.changePasswordBtn=Vaihda salasana
vaultOptions.masterkey.forgetSavedPasswordBtn=Unohda tallennettu salasana
vaultOptions.masterkey.recoveryKeyExplanation=Palautusavain on ainoa tapa päästä käsiksi holviin jos unohdat salasanasi.
vaultOptions.masterkey.showRecoveryKeyBtn=Näytä Palautusavain
vaultOptions.masterkey.recoverPasswordBtn=Palauta salasana
## Hub
vaultOptions.hub=Palautus
vaultOptions.hub.convertInfo=Voit käyttää palautusavainta muuttaaksesi tämä Hub-holvin salasanapohjaiseksi holviksi hätätapauksessa.
vaultOptions.hub.convertBtn=Muunna salasanapohjaiseksi holviksi
# Recovery Key
## Display Recovery Key
recoveryKey.display.title=Näytä palautusavain
recoveryKey.create.message=Salasana vaaditaan
recoveryKey.create.description=Syötä salasana holville "%s" näyttääksesi sen palautusavaimen.
recoveryKey.display.description=Tällä palautusavaimella voidaan palauttaa pääsy holviin "%s":
recoveryKey.display.StorageHints=Pidä se hyvin tallessa, esimerkiksi\n • Säilytä se salasananhallintaohjelmassa\n • Tallenna se USB-asemalle\n • Tulosta se paperille
## Reset Password
### Enter Recovery Key
recoveryKey.recover.title=Palauta salasana
recoveryKey.recover.prompt=Syötä palautusavain holville "%s":
recoveryKey.recover.correctKey=Tämä palautusavain on oikea
recoveryKey.recover.wrongKey=Tämä palautusavain kuuluu jollekin toiselle holville
recoveryKey.recover.invalidKey=Tämä palautusavain ei ole kelvollinen
recoveryKey.printout.heading=Cryptomator palautusavain\n"%s"\n
### Reset Password
recoveryKey.recover.resetBtn=Palauta
### Recovery Key Password Reset Success
recoveryKey.recover.resetSuccess.message=Salasanan palautus onnistui
recoveryKey.recover.resetSuccess.description=Voit avata holvin uudella salasanalla.
# Convert Vault
convertVault.title=Muunna holvi
convertVault.convert.convertBtn.before=Muunna
convertVault.convert.convertBtn.processing=Muunnetaan…
convertVault.success.message=Muuntaminen onnistui
convertVault.hubToPassword.success.description=Voit nyt avata holvin valitulla salasanalla ilman Hub-yhteyttä.
# New Password
newPassword.promptText=Syötä uusi salasana
newPassword.reenterPassword=Vahvista uusi salasana
newPassword.passwordsMatch=Salasanat täsmäävät!
newPassword.passwordsDoNotMatch=Salasanat eivät täsmää
passwordStrength.messageLabel.tooShort=Käytä ainakin %d merkkiä
passwordStrength.messageLabel.0=Erittäin heikko
passwordStrength.messageLabel.1=Heikko
passwordStrength.messageLabel.2=Kohtalainen
passwordStrength.messageLabel.3=Vahva
passwordStrength.messageLabel.4=Erittäin vahva
# Quit
quit.title=Lopeta ohjelma
quit.message=Holveja on auki
quit.description=Vahvista että haluat lopettaa. Cryptomator lukitsee kaikki avatut holvit datan menetyksen ehkäisemiseksi.
quit.lockAndQuitBtn=Lukitse ja lopeta
# Forced Quit
quit.forced.message=Joitain holveja ei voitu lukita
quit.forced.description=Holvien lukiseminen estyi odottavien tehtävien tai avattujen tiedostojen vuoksi. Voit pakottaa lukituksen, mutta datasiirron keskeyttäminen voi johtaa datan menetykseen.
quit.forced.forceAndQuitBtn=Pakota ja lopeta
# Update Reminder
updateReminder.title=Päivitysten tarkistus
updateReminder.message=Tarkistetaanko päivitykset?
updateReminder.description=Pysy ajan tasalla uusista ominaisuuksista, korjauksista ja turvallisuusparannuksista. Suosittelemme tarkistamaan päivitykset automaattisesti.
updateReminder.notNow=Ei nyt
updateReminder.yesOnce=Kyllä, vain tämän kerran
updateReminder.yesAutomatically=Kyllä, automaattisesti
#Dokany Support End
dokanySupportEnd.preferencesBtn=Avaa asetukset
#Retry If Readonly
# Share Vault
shareVault.title=Jaa holvi
shareVault.message=Haluatko jakaa holvisi muiden kanssa?
shareVault.description=Ole aina varuillasi jakaessasi holvia muiden kanssa. Noudata näitä ohjeita:
shareVault.instruction.1=1. Jaa käyttöoikeus salattuun holvikansioon pilvipalvelun kautta.
shareVault.instruction.2=2. Jaa holvin salasana turvallisella tavalla.
shareVault.remarkBestPractices=Lisätietoja varten tutustu hyvien käytäntöjen suosituksiin dokumentaatiossamme.
shareVault.docsTooltip=Avaa dokumentaatio lukeaksesi lisää holvein jakamisesta.
shareVault.visitHub=Käy Cryptomator Hubissa
shareVault.hub.message=Kuinka jakaa Hub -holvi
shareVault.hub.instruction.1=1. Jaa käyttöoikeus salattuun holvikansioon pilvipalvelun kautta.
shareVault.hub.openHub=Avaa Cryptomator Hub

View File

@@ -13,6 +13,7 @@ generic.button.copied=Nakopya na!
generic.button.done=Tapos na
generic.button.next=Sunod
generic.button.print=I-print
generic.button.remove=Tanggalin
# Error
error.message=Error %s
@@ -105,7 +106,6 @@ addvaultwizard.success.unlockNow=I-unlock Ngayon
removeVault.title=Tanggalin %s
removeVault.message=Itangal ang vault?
removeVault.description=Makakalimutan lang nito ang Cryptomator tungkol sa vault na ito. Maaari mo itong idagdag muli. Walang matatanggal na mga naka-encrypt na file mula sa iyong hard drive.
removeVault.confirmBtn=Itangal ang vault
# Change Password
changepassword.title=Palitan ANG password
@@ -176,7 +176,6 @@ hub.registerFailed.description.generic=Nagkaroon ng error sa proseso ng pag regi
hub.registerFailed.description.deviceAlreadyExists=Ang device na ito ay registrado na sa ibang user. Subukang palitan ang user account o gumamit ng ibang device.
### Unauthorized
hub.unauthorized.message=Walang pahintulot
hub.unauthorized.description=Hindi pa pinahihintulutan ang iyong device na i-access ang vault na ito. Hilingin sa may-ari ng vault na pahintulutan ito.
### Requires Account Initialization
hub.requireAccountInit.message=Kinakailangan ang pagkilos
hub.requireAccountInit.description.0=Upang magpatuloy, mangyaring kumpletuhin ang mga hakbang na kinakailangan sa iyong
@@ -336,7 +335,6 @@ preferences.contribute.getCertificate=Wala ka na ba? Alamin kung paano mo ito ma
preferences.contribute.promptText=I-paste ang code ng certificate ng tagasuporta dito
### Remove License Key Dialog
removeCert.confirmBtn=Tanggalin
#<-- Add entries for donations and code/translation/documentation contribution -->
## About
@@ -542,6 +540,8 @@ dokanySupportEnd.message=Pagtatapos ng suporta para sa Dokany
dokanySupportEnd.description=Ang uri ng volume na Dokany ay hindi na sinusuportahan ng Cryptomator. Isinasaayos ang iyong mga setting upang magamit ang default na uri ng volume ngayon. Maaari mong tingnan ang default na uri sa mga kagustuhan.
dokanySupportEnd.preferencesBtn=Buksan ang Mga Kagustuhan
#Retry If Readonly
# Share Vault
shareVault.title=Ibahagi ang Vault
shareVault.message=Gusto mo bang ibahagi ang iyong vault sa iba?

View File

@@ -13,6 +13,7 @@ generic.button.copied=Copié !
generic.button.done=OK
generic.button.next=Suivant
generic.button.print=Imprimer
generic.button.remove=Supprimer
# Error
error.message=Une erreur s'est produite
@@ -22,9 +23,9 @@ error.hyperlink.report=Signaler cette erreur
error.technicalDetails=Détails :
error.existingSolutionDescription=Cryptomator ne s'attendait pas à ce que cela se produise. Mais nous avons trouvé une solution existante pour cette erreur. Veuillez consulter le lien suivant.
error.hyperlink.solution=Rechercher la solution
error.lookupPermissionMessage=Cryptomator peut trouver une solution à ce problème en ligne. Cela enverra une requête à notre base de données de problèmes à partir de votre adresse IP.
error.lookupPermissionMessage=Cryptomator peut chercher une solution à ce problème en ligne. Une requête sera envoyée à notre base de données de problèmes à partir de votre adresse IP.
error.dismiss=Ignorer
error.lookUpSolution=Rechercher la solution
error.lookUpSolution=Chercher une solution
# Defaults
defaults.vault.vaultName=Coffre
@@ -65,7 +66,7 @@ addvaultwizard.new.validCharacters.numbers=Nombres
addvaultwizard.new.validCharacters.dashes=Tiret (%s) ou tiret du bas (%s)
### Expert Settings
addvaultwizard.new.expertSettings.enableExpertSettingsCheckbox=Activer les paramètres experts
addvaultwizard.new.expertSettings.shorteningThreshold.invalid=Entrez une valeur entre 36 et 220 (par défaut 220)
addvaultwizard.new.expertSettings.shorteningThreshold.invalid=Entrez une valeur comprise entre 36 et 220 (par défaut 220)
addvaultwizard.new.expertSettings.shorteningThreshold.tooltip=Ouvrez la documentation pour en savoir plus.
addvaultwizard.new.expertSettings.shorteningThreshold.title=Longueur maximale des noms de fichiers chiffrés
addvaultwizard.new.expertSettings.shorteningThreshold.valid=Valide
@@ -94,7 +95,7 @@ addvault.new.readme.accessLocation.4=Vous pouvez supprimer ce fichier.
## Existing
addvaultwizard.existing.title=Ajouter un coffre existant
addvaultwizard.existing.instruction=Choisissez le fichier « vault.cryptomator » de votre volume existant. Si seul le fichier « masterkey.cryptomator » est présent, sélectionnez celui-là.
addvaultwizard.existing.chooseBtn=Choisir...
addvaultwizard.existing.chooseBtn=Choisir
addvaultwizard.existing.filePickerTitle=Sélectionnez le fichier correspondant au volume chiffré
addvaultwizard.existing.filePickerMimeDesc=Coffre-fort Cryptomator
## Success
@@ -105,7 +106,6 @@ addvaultwizard.success.unlockNow=Déverrouiller
removeVault.title=Supprimer "%s"
removeVault.message=Supprimer le coffre ?
removeVault.description=Ceci ne fera que retirer ce coffre de Cryptomator. Vous pourrez lajouter à nouveau plus tard. Aucun fichier chiffré ne sera supprimé de votre disque dur.
removeVault.confirmBtn=Supprimer le coffre
# Change Password
changepassword.title=Modifier le mot de passe
@@ -127,7 +127,7 @@ unlock.unlockBtn=Déverrouiller
unlock.chooseMasterkey.message=Fichier Masterkey introuvable
unlock.chooseMasterkey.description=Impossible de trouver le fichier clef à l'adresse attendue pour l'espace chiffré "%s". Veuillez sélectionner le fichier clef manuellement.
unlock.chooseMasterkey.filePickerTitle=Sélectionner le fichier clef
unlock.chooseMasterkey.filePickerMimeDesc=\ clé principale Cryptomator
unlock.chooseMasterkey.filePickerMimeDesc=Clé principale Cryptomator
## Success
unlock.success.message=Déverrouillage réussi
unlock.success.description=“%s” déverrouillé ! Le contenu de votre espace chiffré est maintenant accessible par son lecteur virtuel.
@@ -142,7 +142,7 @@ unlock.error.customPath.description.hideawayNotDir=Le fichier temporaire et cach
unlock.error.customPath.description.couldNotBeCleaned=Votre coffre n'a pas pu être monté au point "%s". Veuillez réessayer ou choisissez un autre point.
unlock.error.customPath.description.notEmptyDir=Le chemin de montage personnalisé "%s" n'est pas un dossier vide. Veuillez choisir un dossier vide et réessayez.
unlock.error.customPath.description.generic=Vous avez sélectionné un point de montage personnalisé pour ce coffre, mais son utilisation a échoué avec le message : %2$s
unlock.error.restartRequired.message=Impossible de déverrouiller le volume
unlock.error.restartRequired.message=Impossible de déverrouiller le coffre
unlock.error.restartRequired.description=Modifiez le type de volume dans les options du coffre ou redémarrez Cryptomator.
unlock.error.title=Échec du déverrouillage de "%s"
## Hub
@@ -152,7 +152,7 @@ hub.noKeychain.openBtn=Ouvrir les préférences
### Waiting
hub.auth.message=Authentification en cours…
hub.auth.description=Vous devriez automatiquement être redirigé vers la page de connexion.
hub.auth.loginLink=Vous n'avez pas été redirigé(e) ? Cliquez ici pour l'ouvrir.
hub.auth.loginLink=Vous n'êtes pas redirigé·e ? Cliquez ici pour l'ouvrir.
### Receive Key
hub.receive.message=Traitement de la réponse…
hub.receive.description=Cryptomator est en train de recevoir et de traiter la réponse de Hub. Veuillez patienter.
@@ -171,12 +171,12 @@ hub.registerSuccess.description=Votre appareil est enregistré avec succès. Vou
hub.registerSuccess.unlockBtn=Déverrouiller
hub.registerSuccess.legacy.description=Pour accéder au coffre, votre appareil doit être autorisé par le propriétaire du coffre.
### Registration Failed
hub.registerFailed.message=Echec de l'enregistrement de l'appareil
hub.registerFailed.message=Échec de l'enregistrement de l'appareil
hub.registerFailed.description.generic=Le processus de nommage a retourné une erreur. Pour plus de détails, regardez dans le journal de l'application.
hub.registerFailed.description.deviceAlreadyExists=Cet appareil est déjà enregistré pour un autre utilisateur. Essayez de changer de compte ou utilisez un autre appareil.
### Unauthorized
hub.unauthorized.message=Accès refusé
hub.unauthorized.description=Votre appareil n'a pas encore été autorisé à accéder à ce coffre. Demandez au propriétaire du coffre de l'autoriser.
hub.unauthorized.description=Vous n'êtes pas autorisé à ouvrir ce coffre. Contactez le propriétaire du coffre pour en demander l'accès.
### Requires Account Initialization
hub.requireAccountInit.message=Action requise
hub.requireAccountInit.description.0=Pour continuer, veuillez compléter les étapes requises
@@ -343,7 +343,6 @@ preferences.contribute.sponsor=Parrain
removeCert.title=Supprimer le certificat
removeCert.message=Supprimer le certificat de soutien ?
removeCert.description=
removeCert.confirmBtn=Retirer
#<-- Add entries for donations and code/translation/documentation contribution -->
## About
@@ -553,6 +552,12 @@ dokanySupportEnd.message=Fin de la prise en charge de Dokany
dokanySupportEnd.description=Le type de volume Dokany n'est plus pris en charge par Cryptomator. Vos paramètres sont à présent ajustés pour utiliser le type de volume par défaut. Vous pouvez voir le type par défaut dans les préférences.
dokanySupportEnd.preferencesBtn=Ouvrir les préférences
#Retry If Readonly
retryIfReadonly.title=Accès restreint au coffre
retryIfReadonly.message=Pas d'accès en écriture au dossier du coffre
retryIfReadonly.description=Cryptomator ne peut pas écrire dans le dossier du coffre. Vous pouvez passer le coffre en mode lecture seule et réessayer. Cette option peut être désactivée dans les options du coffre.
retryIfReadonly.retry=Changer et réessayer
# Share Vault
shareVault.title=Partager le coffre
shareVault.message=Vous aimeriez partager votre coffre avec d'autres personnes ?

View File

@@ -13,6 +13,7 @@ generic.button.copied=Copiado!
generic.button.done=Feito
generic.button.next=Seguinte
generic.button.print=Imprimir
generic.button.remove=Eliminar
# Error
error.message=Produciuse un erro
@@ -81,7 +82,6 @@ lock.forced.retryBtn=Tentar de novo
## Contribution
### Remove License Key Dialog
removeCert.confirmBtn=Eliminar
#<-- Add entries for donations and code/translation/documentation contribution -->
## About
@@ -132,4 +132,6 @@ removeCert.confirmBtn=Eliminar
#Dokany Support End
#Retry If Readonly
# Share Vault

View File

@@ -13,6 +13,7 @@ generic.button.copied=הועתק!
generic.button.done=סיום
generic.button.next=הבא
generic.button.print=הדפס
generic.button.remove=הסר
# Error
error.message=אירעה שגיאה
@@ -104,7 +105,6 @@ addvaultwizard.success.unlockNow=בטל נעילה כעת
removeVault.title=הסר כספת
removeVault.message=להסיר את ה vault?
removeVault.description=זה יגרום ל-Cryptomator לשכוח מהכספת הזו. תוכל/י להוסיף אותה שוב מאוחר יותר. קבצים מוצפנים לא ימחקו מהכונן שלך.
removeVault.confirmBtn=הסר כספת
# Change Password
changepassword.title=שנה סיסמה
@@ -159,7 +159,6 @@ hub.registerSuccess.unlockBtn=בטל נעילה
### Registration Failed
### Unauthorized
hub.unauthorized.message=הגישה נדחתה
hub.unauthorized.description=המכשיר שלך טרם אושר לגשת לכספת הזאת. יש לבקש אישור גישה מבעל הכספת.
### Requires Account Initialization
### License Exceeded
hub.invalidLicense.message=רישיון האב לא תקף
@@ -305,7 +304,6 @@ preferences.contribute.getCertificate=עדיין אין לכם אחד? לימד
preferences.contribute.promptText=הדבק את קוד תעודת התומך כאן
### Remove License Key Dialog
removeCert.confirmBtn=הסר
#<-- Add entries for donations and code/translation/documentation contribution -->
## About
@@ -493,4 +491,6 @@ updateReminder.notNow=לא עכשיו
#Dokany Support End
dokanySupportEnd.preferencesBtn=פתח העדפות
#Retry If Readonly
# Share Vault

View File

@@ -13,6 +13,7 @@ generic.button.copied=कॉपी हुआ!
generic.button.done=हो गया
generic.button.next=अगला
generic.button.print=प्रिंट करें
generic.button.remove=हटाएँ
# Error
error.message=एक त्रुटि पाई गई
@@ -100,7 +101,6 @@ addvaultwizard.success.unlockNow=अब अनलॉक करें
removeVault.title=वॉल्ट हटाए
removeVault.message=वॉल्ट हटाए?
removeVault.description=यह करने से सिर्फ क्रिप्टोमेटर इस वॉल्ट के बारे में भूल जाएगा। आप इस वॉल्ट को वापस ऐड कर पाएंगे। कोई भी एन्क्रिप्टेड फाइल आपकी हार्ड डिस्क से नहीं डिलीट होगी।
removeVault.confirmBtn=वॉल्ट हटाए
# Change Password
changepassword.title=पासवर्ड बदलें
@@ -221,7 +221,6 @@ preferences.updates.updateAvailable=संस्करण %s की तरफ
preferences.contribute=हमें सपोर्ट करें
### Remove License Key Dialog
removeCert.confirmBtn=हटाएँ
#<-- Add entries for donations and code/translation/documentation contribution -->
## About
@@ -315,4 +314,6 @@ quit.forced.message=कुछ वॉल्ट्स लॉक नहीं ह
#Dokany Support End
dokanySupportEnd.preferencesBtn=प्राथमिकताएँ खोलें
#Retry If Readonly
# Share Vault

View File

@@ -13,6 +13,7 @@ generic.button.copied=Kopirano!
generic.button.done=Gotovo
generic.button.next=Sljedeći
generic.button.print=Ispiši
generic.button.remove=Ukloni
# Error
error.message=Greška: %s
@@ -85,7 +86,6 @@ addvaultwizard.success.unlockNow=Otključaj sada
# Remove Vault
removeVault.title=Ukloni trezor
removeVault.description=Ovo će jedino učiniti da Cryptomator zaboravi trezor. Možete ga kasnije ponovno dodati. Niti jedna šifrirana datoteka neće biti uklonjena s Vašeg tvrdog diska.
removeVault.confirmBtn=Ukloni trezor
# Change Password
changepassword.title=Promijeni lozinku
@@ -232,7 +232,6 @@ preferences.contribute.getCertificate=Još ga nemate? Naučite kako ga dobiti.
preferences.contribute.promptText=Zalijepi certifikat podržavatelja ovdje
### Remove License Key Dialog
removeCert.confirmBtn=Ukloni
#<-- Add entries for donations and code/translation/documentation contribution -->
## About
@@ -382,4 +381,6 @@ quit.lockAndQuitBtn=Zaključaj i napusti
#Dokany Support End
#Retry If Readonly
# Share Vault

View File

@@ -13,6 +13,7 @@ generic.button.copied=Másolva!
generic.button.done=Kész
generic.button.next=Következő
generic.button.print=Nyomtatás
generic.button.remove=Eltávolítás
# Error
error.message=Hiba: %s
@@ -105,7 +106,6 @@ addvaultwizard.success.unlockNow=Azonnali feloldás
removeVault.title=Széf eltávolitása
removeVault.message=Vault eltávolitása?
removeVault.description=Ez kizárolag a Cryptomator-ból távolitja el ezt a széfet. Később hozzáadhatja újra. A titkosított fájlokat nem törli a merevlemezről.
removeVault.confirmBtn=Széf eltávolitása
# Change Password
changepassword.title=Jelszó megváltoztatása
@@ -176,7 +176,6 @@ hub.registerFailed.description.generic=Hiba történt a regisztrációs folyamat
hub.registerFailed.description.deviceAlreadyExists=Ez az eszköz már egy másik felhasználóhoz van regisztrálva. Próbáljon meg felhasználói fiókot váltani, vagy használjon egy másik eszközt.
### Unauthorized
hub.unauthorized.message=Hozzáférés megtagadva
hub.unauthorized.description=Eszköze még nem kapott engedélyt ehhez a széfhez. Kérje a széf tulajdonosát, hogy engedélyezze a hozzáférést.
### Requires Account Initialization
hub.requireAccountInit.message=Beavatkozás szükséges
hub.requireAccountInit.description.0=A folytatáshoz kérlek töltsd ki a szükséges lépéseket a te
@@ -343,7 +342,6 @@ preferences.contribute.sponsor=Szponzor
removeCert.title=Tanúsítvány eltávolítása
removeCert.message=Eltávolítja a támogatói tanúsítványt?
removeCert.description=A Cryptomator alapvető funkcióit ez nem érinti. Sem a széfekhez való hozzáférés nem korlátozott, sem a biztonsági szint nem csökken.
removeCert.confirmBtn=Eltávolítás
#<-- Add entries for donations and code/translation/documentation contribution -->
## About
@@ -553,6 +551,8 @@ dokanySupportEnd.message=Vége a Dokany támogatásának
dokanySupportEnd.description=A Cryptomator nem támogatja tovább a Dokany kötettípust. A beállítások az alapértelmezett kötettípus használatára lettek állítva. Az alapértelmezett típust a beállítások közt tekintheted meg.
dokanySupportEnd.preferencesBtn=Beállítások megnyitása
#Retry If Readonly
# Share Vault
shareVault.title=Széf megosztása
shareVault.message=Szeretné megosztani a széfét másokkal?

View File

@@ -13,6 +13,7 @@ generic.button.copied=Tersalin!
generic.button.done=Selesai
generic.button.next=Lanjut
generic.button.print=Cetak
generic.button.remove=Hapus
# Error
error.message=Terjadi kesalahan %s
@@ -27,7 +28,7 @@ error.dismiss=Tutup
error.lookUpSolution=Cari tahu solusinya
# Defaults
defaults.vault.vaultName=Vault
defaults.vault.vaultName=Brangkas
# Tray Menu
traymenu.showMainWindow=Tampilkan
@@ -41,7 +42,7 @@ traymenu.vault.reveal=Perlihatkan
# Add Vault Wizard
addvaultwizard.title=Tambah Brankas
## New
addvaultwizard.new.title=Tambah Vault baru
addvaultwizard.new.title=Tambah Brankas Baru
### Name
addvaultwizard.new.nameInstruction=Buat sebuah nama untuk brankas
addvaultwizard.new.namePrompt=Nama Brankas
@@ -57,8 +58,8 @@ addvaultwizard.new.fileAlreadyExists=Sudah ada file atau direktori dengan nama v
addvaultwizard.new.locationDoesNotExist=Direktori pada path yang dipilih tidak tersedia atau tidak dapat diakses
addvaultwizard.new.locationIsNotWritable=Anda tidak memiliki hak akses untuk menulis pada path yang dipilih
addvaultwizard.new.locationIsOk=Lokasi yang sesuai dengan vault Anda
addvaultwizard.new.invalidName=Nama Vault tidak valid
addvaultwizard.new.validName=Nama vault yang valid
addvaultwizard.new.invalidName=Nama brangkas tidak valid
addvaultwizard.new.validName=Nama brangkas yang valid
addvaultwizard.new.validCharacters.message=Nama vault mungkin berisi karakter berikut:
addvaultwizard.new.validCharacters.chars=Karakter kata (mis. a, ж or 수)
addvaultwizard.new.validCharacters.numbers=Angka
@@ -70,7 +71,7 @@ addvaultwizard.new.expertSettings.shorteningThreshold.tooltip=Buka dokumentasi u
addvaultwizard.new.expertSettings.shorteningThreshold.title=Panjang maksimum nama file terenkripsi
addvaultwizard.new.expertSettings.shorteningThreshold.valid=Valid
### Password
addvaultwizard.new.createVaultBtn=Buat Vault
addvaultwizard.new.createVaultBtn=Buat Brangkas
addvaultwizard.new.generateRecoveryKeyChoice=Anda tidak dapat mengakses data tanpa kata sandi yang Anda miliki. Apa Anda ingin sebuah kunci pemulihan untuk berjaga-jaga jika seandainya Anda kehilangan kata sandi?
addvaultwizard.new.generateRecoveryKeyChoice.yes=Ya tolong, Lebih baik aman daripada menyesal
addvaultwizard.new.generateRecoveryKeyChoice.no=Tidak terima kasih, Saya tidak akan kehilangan kata sandi saya
@@ -105,7 +106,6 @@ addvaultwizard.success.unlockNow=Buka Kunci Sekarang
removeVault.title=Hapus Vault
removeVault.message=Hapus vault?
removeVault.description=Tindakan ini hanya akan membuat Cryptomator melupakan vault ini. Anda dapat menambahkan vault ini lagi nanti. File yang telah dienkripsi tidak akan dihapus dari hard drive Anda.
removeVault.confirmBtn=Hapus Vault
# Change Password
changepassword.title=Ubah Kata Sandi
@@ -176,7 +176,6 @@ hub.registerFailed.description.generic=Kesalahan terjadi dalam proses pendaftara
hub.registerFailed.description.deviceAlreadyExists=Perangkat ini sudah terdaftar untuk pengguna lain. Cobalah menggunakan akun pengguna atau perangkat yang berbeda.
### Unauthorized
hub.unauthorized.message=Akses ditolak
hub.unauthorized.description=Perangkat Anda belum diizinkan mengakses vault ini. Mintalah pemilik vault untuk mengizinkannya.
### Requires Account Initialization
hub.requireAccountInit.message=Tindakan diperlukan
hub.requireAccountInit.description.0=Untuk melanjutkan, silakan lengkapi langkah-langkah yang diperlukan
@@ -287,6 +286,7 @@ preferences.general.debugLogging=Aktifkan pencatatan debug
preferences.general.debugDirectory=Perlihatkan file log
preferences.general.autoStart=Jalankan Cryptomator saat sistem dimulai
preferences.general.keychainBackend=Simpan kata sandi dengan
preferences.general.quickAccessService=Tambahkan brankas terbuka ke area akses cepat
## Interface
preferences.interface=Tampilan
preferences.interface.theme=Tampilan & Suasana
@@ -300,6 +300,7 @@ preferences.interface.interfaceOrientation=Orientasi Antarmuka
preferences.interface.interfaceOrientation.ltr=Kiri ke Kanan
preferences.interface.interfaceOrientation.rtl=Kanan ke Kiri
preferences.interface.showTrayIcon=Tampilkan ikon tray (aplikasi perlu dimuat ulang)
preferences.interface.compactMode=Aktifkan daftar brankas kompak
## Volume
preferences.volume=Drive Virtual
preferences.volume.type=Jenis Default Volume
@@ -319,6 +320,13 @@ preferences.updates.currentVersion=Versi Saat Ini: %s
preferences.updates.autoUpdateCheck=Otomatis periksa update
preferences.updates.checkNowBtn=Periksa Sekarang
preferences.updates.updateAvailable=Pembaharuan ke versi %s tersedia.
preferences.updates.lastUpdateCheck=Terakhir Diperiksa: %s
preferences.updates.lastUpdateCheck.never=jangan pernah
preferences.updates.lastUpdateCheck.recently=baru-baru ini
preferences.updates.lastUpdateCheck.daysAgo=%s hari yang lalu
preferences.updates.lastUpdateCheck.hoursAgo=%s jam yang lalu
preferences.updates.checkFailed=Gagal mencari pembaruan. Harap periksa koneksi internet Anda atau coba lagi nanti.
preferences.updates.upToDate=Cryptomator versi terkini.
## Contribution
preferences.contribute=Dukung Kami
@@ -326,9 +334,14 @@ preferences.contribute.registeredFor=Sertifikat supporter terdaftar atas nama %s
preferences.contribute.noCertificate=Dukung Cryptomator dan terima sebuah sertifikat supporter. Sertifikat ini layaknya kunci lisensi, tetapi hanya untuk orang-orang hebat yang menggunakan aplikasi versi gratis. ;-)
preferences.contribute.getCertificate=Belum punya? Pelajari bagaimana Anda bisa mendapatkannya.
preferences.contribute.promptText=Tempel kode sertifikat supporter di sini
preferences.contribute.thankYou=Terima kasih telah mendukung pengembangan open-source Cryptomator!
preferences.contribute.donate=Donasi
preferences.contribute.sponsor=Sponsor
### Remove License Key Dialog
removeCert.confirmBtn=Hapus
removeCert.title=Hapus Sertifikat
removeCert.message=Hapus sertifikat dukungan?
removeCert.description=Fitur inti Cryptomator tidak terpengaruh oleh hal ini. Akses ke brankas Anda tidak dibatasi dan tingkat keamanannya tidak diturunkan.
#<-- Add entries for donations and code/translation/documentation contribution -->
## About
@@ -378,7 +391,11 @@ main.vaultlist.contextMenu.unlock=Buka Kunci…
main.vaultlist.contextMenu.unlockNow=Buka Kunci Sekarang
main.vaultlist.contextMenu.vaultoptions=Tampilkan Opsi Vault
main.vaultlist.contextMenu.reveal=Buka Drive
main.vaultlist.addVaultBtn.menuItemNew=Buat Vault Baru...
main.vaultlist.addVaultBtn.menuItemExisting=Buka Vault yang Tersedia...
##Notificaition
main.notification.updateAvailable=Pembaruan tersedia.
main.notification.support=Dukung Cryptomator.
## Vault Detail
### Welcome
main.vaultDetail.welcomeOnboarding=Terima kasih telah memilih Cryptomator untuk melindungi file Anda. Jika Anda memerlukan bantuan, lihat panduan awal kami:
@@ -529,8 +546,13 @@ updateReminder.yesOnce=Ya, Sekali
updateReminder.yesAutomatically=Ya, Secara Otomatis
#Dokany Support End
dokanySupportEnd.title=Pemberitahuan penghentian
dokanySupportEnd.message=Dukungan untuk Dokany telah berakhir
dokanySupportEnd.description=Volume berjenis Dokany sudah tidak didukung oleh Cryptomator. Konfigurasi Anda telah disesuai kan dengan tipe volume yang saat ini. Anda dapat melihat tipe baku dipreferensi.
dokanySupportEnd.preferencesBtn=Buka Preferensi
#Retry If Readonly
# Share Vault
shareVault.title=Bagikan Vault
shareVault.message=Apakah Anda ingin berbagi vault dengan orang lain?

View File

@@ -13,6 +13,7 @@ generic.button.copied=Copiato!
generic.button.done=Fatto
generic.button.next=Avanti
generic.button.print=Stampa
generic.button.remove=Rimuovi
# Error
error.message=Si è verificato un errore
@@ -105,7 +106,6 @@ addvaultwizard.success.unlockNow=Sblocca Ora
removeVault.title=Rimuovi Cassaforte
removeVault.message=Rimuovere cassaforte?
removeVault.description=Questo farà solo dimenticare questa cassaforte a Cryptomator. Puoi aggiungerla nuovamente in seguito. Nessun file crittografato sarà eliminato dal tuo disco rigido.
removeVault.confirmBtn=Rimuovi Cassaforte
# Change Password
changepassword.title=Modifica la Password
@@ -176,7 +176,7 @@ hub.registerFailed.description.generic=Si è verificato un errore nel processo d
hub.registerFailed.description.deviceAlreadyExists=Questo dispositivo è già registrato per un utente diverso. Prova a cambiare l'account utente o usa un altro dispositivo.
### Unauthorized
hub.unauthorized.message=Accesso negato
hub.unauthorized.description=Il tuo dispositivo non è ancora stato autorizzato ad accedere a questa cassaforte. Chiedi al proprietario della cassaforte di autorizzarlo.
hub.unauthorized.description=Non sei autorizzato ad aprire questa cassaforte. Chiedi l'accesso al proprietario.
### Requires Account Initialization
hub.requireAccountInit.message=Azione richiesta
hub.requireAccountInit.description.0=Per procedere, completa i passaggi richiesti nel tuo
@@ -343,7 +343,6 @@ preferences.contribute.sponsor=Sponsor
removeCert.title=Rimuovi Certificato
removeCert.message=Rimuovere il certificato supporter?
removeCert.description=Questo non incide sulle funzionalità principali di Cryptomator. Non ti viene negato l'accesso alle tue casseforti e non viene abbassato il livello di sicurezza.
removeCert.confirmBtn=Rimuovi
#<-- Add entries for donations and code/translation/documentation contribution -->
## About
@@ -553,6 +552,12 @@ dokanySupportEnd.message=Supporto terminato per Dokany
dokanySupportEnd.description=Il tipo di volume Dokany non è più supportato da Cryptomator. Le impostazioni sono state aggiornate per utilizzare il tipo di volume ora predefinito. È possibile visualizzare il tipo predefinito nelle preferenze.
dokanySupportEnd.preferencesBtn=Apri Preferenze
#Retry If Readonly
retryIfReadonly.title=Accesso Limitato Cassaforte
retryIfReadonly.message=Accesso negato in scrittura alla cartella della cassaforte
retryIfReadonly.description=Cryptomator non può scrivere nella cartella della cassaforte. Puoi cambiare l'impostazione "sola lettura" della cassaforte e riprovare. Questa opzione può essere impostata nelle opzioni della cassaforte.
retryIfReadonly.retry=Modifica e riprova
# Share Vault
shareVault.title=Condividi cassaforte
shareVault.message=Vuoi condividere la tua cassaforte con altri?

View File

@@ -13,6 +13,7 @@ generic.button.copied=コピー完了!
generic.button.done=完了
generic.button.next=次へ
generic.button.print=印刷
generic.button.remove=削除
# Error
error.message=エラー %s
@@ -105,7 +106,6 @@ addvaultwizard.success.unlockNow=今すぐ解錠
removeVault.title=金庫を削除
removeVault.message=金庫を削除しますか?
removeVault.description=この操作で Cryptomator がこの金庫を認識しなくなります。あとで再度追加することが可能です。暗号化されたファイルがドライブから削除されることはありません。
removeVault.confirmBtn=金庫を削除
# Change Password
changepassword.title=パスワードの変更
@@ -176,7 +176,6 @@ hub.registerFailed.description.generic=登録中にエラーが発生しまし
hub.registerFailed.description.deviceAlreadyExists=このデバイスは既に別のユーザーに登録されています。ユーザーアカウントを変更するか、別のデバイスを使用してください。
### Unauthorized
hub.unauthorized.message=アクセスが拒否されました
hub.unauthorized.description=お使いのデバイスはまだこの金庫にアクセスする権限がありません。金庫のオーナーに権限を与えてもらってください。
### Requires Account Initialization
hub.requireAccountInit.message=アクションが必要です
hub.requireAccountInit.description.0=続行するには以下のサイトで必要な手順を完了してください
@@ -336,7 +335,6 @@ preferences.contribute.getCertificate=まだ証明書を手に入れていませ
preferences.contribute.promptText=サポーター証明書をここに張り付けてください
### Remove License Key Dialog
removeCert.confirmBtn=削除
#<-- Add entries for donations and code/translation/documentation contribution -->
## About
@@ -542,6 +540,8 @@ dokanySupportEnd.message=Dokany のサポート終了
dokanySupportEnd.description=ボリュームタイプ
dokanySupportEnd.preferencesBtn=環境設定を開く
#Retry If Readonly
# Share Vault
shareVault.title=保管庫を共有する
shareVault.message=保管庫を他の人と共有しますか?

View File

@@ -6,21 +6,26 @@ generic.button.apply=적용
generic.button.back=이전
generic.button.cancel=취소
generic.button.change=변경
generic.button.choose=선택
generic.button.choose=선택
generic.button.close=닫기
generic.button.copy=복사
generic.button.copied=복사됨!
generic.button.done=완료
generic.button.next=다음
generic.button.print=인쇄
generic.button.remove=제거
# Error
error.message=오류 발생했습니다
error.description=예상치 못한 에러가 발생했습니다. 온라인에 에러를 검색해서 해결하십시오. 만약 고된 적이 없는 에러일 경우, 새로 신고해도 좋습니다.
error.message=오류 발생
error.description=예상치 못한 에러가 발생했습니다. 해결법을 검색하십시오. 만약 고된 적이 없는 에러일 경우, 새로 신고해도 좋습니다.
error.hyperlink.lookup=에러 검색하기
error.hyperlink.report=에러 보고하기
error.technicalDetails=상세 정보:
error.existingSolutionDescription=Cryptomator에 알 수 없는 문제가 발생했습니다. 하지만 이 오류에 대한 기존 해결법이 있습니다. 다음 링크를 살펴보십시오.
error.hyperlink.solution=해결법 찾기
error.lookupPermissionMessage=Cryptomator는 온라인에서 이 문제에 대한 해결책을 찾아볼 수 있습니다. 그러면 귀하의 IP 주소가 문제 데이터베이스로 전송됩니다.
error.dismiss=무시
error.lookUpSolution=해결법 찾기
# Defaults
defaults.vault.vaultName=Vault
@@ -37,16 +42,17 @@ traymenu.vault.reveal=표시
# Add Vault Wizard
addvaultwizard.title=Vault 추가
## New
addvaultwizard.new.title=새로운 금고 추가
addvaultwizard.new.title=새로운 Vault 추가
### Name
addvaultwizard.new.nameInstruction=새 Vault의 이름을 입력하십시
addvaultwizard.new.nameInstruction=새 Vault의 이름을 입력하십시
addvaultwizard.new.namePrompt=Vault 이름
### Location
addvaultwizard.new.locationInstruction=Cryptomator Vault의 암호화 파일을 어디에 저장하시겠습니까?
addvaultwizard.new.locationInstruction=Cryptomator Vault의 암호화 파일을 어디에 저장하시겠습니까?
addvaultwizard.new.locationLoading=기본 클라우드 저장소 디렉터리에 대한 로컬 파일 시스템을 확인하는 중…
addvaultwizard.new.locationLabel=저장 위치
addvaultwizard.new.locationPrompt=
addvaultwizard.new.directoryPickerLabel=사용자 지정 위치
addvaultwizard.new.directoryPickerButton=선택
addvaultwizard.new.directoryPickerButton=선택
addvaultwizard.new.directoryPickerTitle=디렉터리 선택
addvaultwizard.new.fileAlreadyExists=Vault 내에 이미 존재하는 파일 또는 디렉터리 이름입니다.
addvaultwizard.new.locationDoesNotExist=지정된 디렉터리가 존재하지 않거나 접근 할 수 없습니다.
@@ -59,7 +65,7 @@ addvaultwizard.new.validCharacters.chars=문자 (예시: a, ж or 수)
addvaultwizard.new.validCharacters.numbers=숫자
addvaultwizard.new.validCharacters.dashes=대시 (%s) 또는 언더바 (%s)
### Expert Settings
addvaultwizard.new.expertSettings.enableExpertSettingsCheckbox=전문가 설정 활성화
addvaultwizard.new.expertSettings.enableExpertSettingsCheckbox=전문가 설정 활성화
addvaultwizard.new.expertSettings.shorteningThreshold.invalid=36과 220 사이 숫자를 입력해주세요 (기본값: 220)
addvaultwizard.new.expertSettings.shorteningThreshold.tooltip=더 자세한 정보는 관련 문서에서 볼 수 있습니다.
addvaultwizard.new.expertSettings.shorteningThreshold.title=암호화된 파일명의 최대 길이
@@ -67,29 +73,29 @@ addvaultwizard.new.expertSettings.shorteningThreshold.valid=유효
### Password
addvaultwizard.new.createVaultBtn=Vault 생성
addvaultwizard.new.generateRecoveryKeyChoice=비밀번호가 없으면 데이터에 접근할 수 없습니다. 비밀번호를 잊었을 때를 대비한 복구 키를 원하십니까?
addvaultwizard.new.generateRecoveryKeyChoice.yes=네, 보안보다 비밀번호를 잊어버리는 것이 더 걱정됩니다
addvaultwizard.new.generateRecoveryKeyChoice.yes=네, 보안보다 비밀번호를 잊어버리는 것이 더 걱정됩니다.
addvaultwizard.new.generateRecoveryKeyChoice.no=아니요, 나는 비밀번호를 잊지 않을겁니다.
### Information
addvault.new.readme.storageLocation.fileName=IMPORTANT.rtf
addvault.new.readme.storageLocation.1=⚠️ VAULT 파일 ⚠️
addvault.new.readme.storageLocation.2=해당 디렉토리는 당신의 Vault 저장 위치 입니다.
addvault.new.readme.storageLocation.3=금지사항
addvault.new.readme.storageLocation.2=해당 디렉토리는 당신의 Vault 저장 위치입니다.
addvault.new.readme.storageLocation.3=금지 사항
addvault.new.readme.storageLocation.4=• 이 디렉터리를 포함한 어떤 파일도 다른 파일로 교체하거나
addvault.new.readme.storageLocation.5=• 암호화를 위한 파일을 이 디렉터리에 붙여넣지 마십시.
addvault.new.readme.storageLocation.5=• 암호화하고자 하는 파일을 이 디렉터리에 붙여넣지 마십시.
addvault.new.readme.storageLocation.6=파일을 암호화하고 Vault 의 내용을 보려면 다음을 수행하십시오.
addvault.new.readme.storageLocation.7=1. 이 Vault를 Cryptomator에 추가하십시.
addvault.new.readme.storageLocation.8=2. Cryptomator에서 Vault 잠금을 해제하십시.
addvault.new.readme.storageLocation.9=3. "표시" 버튼을 클릭하여 Vault에 접근하십시.
addvault.new.readme.storageLocation.10=만일 도움이 필요하신 경우, 다음의 문서를 참조하십시: %s
addvault.new.readme.storageLocation.7=1. 이 Vault를 Cryptomator에 추가하십시.
addvault.new.readme.storageLocation.8=2. Cryptomator에서 Vault 잠금을 해제하십시.
addvault.new.readme.storageLocation.9=3. "표시" 버튼을 클릭하여 Vault에 접근하십시.
addvault.new.readme.storageLocation.10=만일 도움이 필요하신 경우, 다음의 문서를 참조하십시: %s
addvault.new.readme.accessLocation.fileName=WELCOME.rtf
addvault.new.readme.accessLocation.1=🔐️ 암호화 된 볼륨 🔐️
addvault.new.readme.accessLocation.2=이것은 당신의 Vault 접근 위치입니다.
addvault.new.readme.accessLocation.3=이 볼륨에 추가된 모든 파일은 Cryptomator로 암호화됩니다. 다른 드라이브/폴더처럼 작업할 수 있습니다. 볼륨의 내용은 복호화 된 것 처럼 보여지지만, 모든 파일은 항상 암호화되어 하드디스크에 저장됩니다.
addvault.new.readme.accessLocation.3=이 볼륨에 추가된 모든 파일은 Cryptomator로 암호화됩니다. 다른 드라이브/폴더처럼 작업할 수 있습니다. 볼륨의 내용은 복호화 된 것처럼 보지만, 모든 파일은 항상 암호화되어 하드디스크에 저장됩니다.
addvault.new.readme.accessLocation.4=이 파일은 지우셔도 무방합니다.
## Existing
addvaultwizard.existing.title=기존 금고 추가
addvaultwizard.existing.instruction=이미 존재하는 vault 폴더 내에서 "vault.cryptomator" 파일을 선택하세요. 만약 "masterkey.cryptomator"만 있다면 그걸 대신 선택하세요.
addvaultwizard.existing.chooseBtn=선택
addvaultwizard.existing.chooseBtn=선택
addvaultwizard.existing.filePickerTitle=Vault 파일 선택
addvaultwizard.existing.filePickerMimeDesc=Cryptomator Vault
## Success
@@ -99,59 +105,83 @@ addvaultwizard.success.unlockNow=지금 잠금해제
# Remove Vault
removeVault.title=Vault 제거
removeVault.message=Vault를 삭제하시겠습니까?
removeVault.description=이 행위는 단지 Cryptomator에서 이 Vault를 잊게합니다. 나중에 다시 추가 할 수 있습니다. 암호화된 파일은 하드디스크에서 삭제되지 않을 것입니다.
removeVault.confirmBtn=Vault 제거
removeVault.description=이 행위는 Cryptomator에서 이 Vault를 지웁니다. 나중에 다시 추가할 수 있습니다. 암호화된 파일은 하드디스크에서 삭제되지 않니다.
# Change Password
changepassword.title=비밀번호 변경
changepassword.enterOldPassword="%s"의 비밀번호를 입력하여 주십시요.
changepassword.finalConfirmation=비밀번호를 잊어버리면, 데이터에 접근할 수 없을 이해했습니다.
changepassword.finalConfirmation=비밀번호를 잊어버리면, 데이터에 접근할 수 없다는 것을 이해했습니다.
# Forget Password
forgetPassword.title=비밀번호 분실
forgetPassword.title=비밀번호 삭제
forgetPassword.message=저장된 비밀번호를 삭제할까요?
forgetPassword.description=시스템 키체인에서 이 Vault의 저장된 비밀번호가 삭제될 것입니다.
forgetPassword.confirmBtn=비밀번호 분실
forgetPassword.confirmBtn=비밀번호 삭제
# Unlock
unlock.title="%s" 잠금 해제
unlock.passwordPrompt="%s"의 비밀번호를 입력하십시.
unlock.passwordPrompt="%s"의 비밀번호를 입력하십시.
unlock.savePassword=비밀번호 기억
unlock.unlockBtn=잠금해제
## Select
unlock.chooseMasterkey.message=마스터키 파일을 찾을 수 없습니다
unlock.chooseMasterkey.description=추정되는 위치에서 이 Vault의 마스터 키를 찾지 못했습니다. 마스터 키 위치를 수동으로 선택하여 주십시.
unlock.chooseMasterkey.filePickerTitle=마스터키 파일 선택
unlock.chooseMasterkey.filePickerMimeDesc=Cryptomator 마스터키
unlock.chooseMasterkey.description=이 Vault의 Masterkey를 찾지 못했습니다. 마스터 키 위치를 수동으로 선택하여 주십시.
unlock.chooseMasterkey.filePickerTitle=Masterkey 파일 선택
unlock.chooseMasterkey.filePickerMimeDesc=Cryptomator Masterkey
## Success
unlock.success.message=잠금 해제 성공
unlock.success.description="%s"이(가) 성공적으로 잠금해제되었습니다. 이제 이 Vault를 가상드라이브로 접근할 수 있습니다.
unlock.success.rememberChoice=선택 기억, 다시 묻지 않음
unlock.success.description="%s"이(가) 성공적으로 잠금 해제되었습니다. 이제 이 Vault를 마운트 지점으로 접근할 수 있습니다.
unlock.success.rememberChoice=선택 기억하기, 다시 묻지 않음
unlock.success.revealBtn=드라이브 표시
## Failure
unlock.error.customPath.message=Vault를 사용자 정의 경로에 마운트할 수 없습니다.
unlock.error.customPath.description.notSupported=사용자 지정 경로를 계속 사용하려면 설정으로 이동하여 이를 지원하는 볼륨 유형을 선택하십시오. 그렇지 않으면 볼트 옵션으로 이동하여 지원되는 마운트 지점을 선택하십시오.
unlock.error.customPath.description.notExists=사용자 정의 마운트 경로가 존재하지 않습니다. 로컬 파일 시스템에서 생성하거나 볼트 옵션에서 변경하세요.
unlock.error.customPath.description.inUse=드라이브 문자 또는 사용자 정의 마운트 경로 "%s"가 이미 사용 중입니다.
unlock.error.customPath.description.hideawayNotDir=잠금 해제에 사용된 임시 숨김 파일 "%3$s"을 제거할 수 없습니다. 파일을 확인한 후 수동으로 삭제해 주세요.
unlock.error.customPath.description.couldNotBeCleaned=Vault를 "%s" 경로에 마운트할 수 없습니다. 다시 시도하거나 다른 경로를 선택하세요.
unlock.error.customPath.description.notEmptyDir=사용자 정의 마운트 경로 "%s"은 빈 폴더가 아닙니다. 빈 폴더를 선택하고 다시 시도하세요.
unlock.error.customPath.description.generic=이 볼트에 대한 사용자 정의 마운트 경로를 선택했지만 다음 메시지와 함께 해당 경로를 사용하지 못했습니다: %2$s
unlock.error.restartRequired.message=Vault을 잠금 해제할 수 없습니다.
unlock.error.restartRequired.description=볼트 옵션에서 볼륨 유형을 변경하거나 Cryptomator를 다시 시작하십시오.
unlock.error.title="%s" 잠금 해제 실패
## Hub
hub.noKeychain.message=장치 키에 액세스할 수 없습니다
hub.noKeychain.description=허브 저장소를 잠금 해제하려면 키체인을 사용하여 보호되는 장치 키가 필요합니다. 계속하려면 "%s"을 활성화하고 기본 설정에서 키체인을 선택하십시오.
hub.noKeychain.openBtn=설정 열기
### Waiting
hub.auth.message=인증 대기중…
hub.auth.description=자동으로 로그인 페이지로 리다이렉트 될 것입니다.
hub.auth.loginLink=수동으로 열려면 클릭하십시오.
### Receive Key
hub.receive.message=응답 처리중…
hub.receive.description=Hub로부터 응답을 처리하고 있습니다. 잠시만 기다려 주십시오.
### Register Device
hub.register.message=새 기기
hub.register.description=이 기기로부터 첫번째 Hub 접근입니다. Account Key로 등록하십시오.
hub.register.nameLabel=기기 이름
hub.register.invalidAccountKeyLabel=유효하지 않은 계정 키
hub.register.registerBtn=등록
### Register Device Legacy
hub.register.legacy.occupiedMsg=이미 사용 중인 이름
hub.register.legacy.description=이 기기로부터 첫번째 Hub 접근입니다. 등록하십시오.
### Registration Success
hub.registerSuccess.message=기기 등록됨
hub.registerSuccess.unlockBtn=잠금해제
hub.registerSuccess.description=등록에 성공하였습니다. Vault를 잠금 해제할 수 있습니다.
hub.registerSuccess.unlockBtn=잠금 해제
hub.registerSuccess.legacy.description=Vault에 접근하기 위해서는 이 기기를 Vault 소유주가 추가적으로 허가해야 합니다.
### Registration Failed
hub.registerFailed.message=기기 등록 실패
hub.registerFailed.description.generic=등록 중에 에러가 발생했습니다. 앱 로그에서 자세한 정보를 확인할 수 있습니다.
hub.registerFailed.description.deviceAlreadyExists=이 기기는 이미 다른 사용자에 등록되어 있습니다. 다른 사용자 계정이나 다른 기기를 사용해보세요.
### Unauthorized
hub.unauthorized.message=액세스 거부
hub.unauthorized.description=귀하의 기기는 아직 이 저장소에 액세스할 수 있는 권한이 없습니다. Vault 소유자에게 승인을 요청하세요.
hub.unauthorized.message=액세스 거부
hub.unauthorized.description=해당 Vault에 접근하도록 허가되지 않았습니다. Vault 소유자에게 권한을 요청하세요.
### Requires Account Initialization
hub.requireAccountInit.message=조치가 필요함
hub.requireAccountInit.description.0=진행하려면 필요한 조치를 완료하십시오:
hub.requireAccountInit.description.1=Hub 사용자 프로필
hub.requireAccountInit.description.2=.
### License Exceeded
hub.invalidLicense.message=Hub 라이선스가 잘못되었습니다.
hub.invalidLicense.description=Cryptomator Hub 인스턴스에 잘못된 라이선스가 있습니다. 라이센스를 업그레이드하거나 갱신하려면 허브 관리자에게 알리십시오.
@@ -200,9 +230,10 @@ migration.impossible.moreInfo=Vault를 이전 버전으로 계속 열수 있습
health.title="%s"의 상태 검사
health.intro.header=상태 검사
health.intro.text=상태 검사는 Vault의 내부 구조의 문제점을 점검하고 해결할 수 있는 기능입니다. 다음 사항을 유의하시기 바랍니다:
health.intro.remarkSync=모든 장치가 완전히 동기화됐는지 확인하십시오. 대부분의 문제를 해결합니다.
health.intro.remarkFix=모든 문제를 해결할 수 있는 것은 아닙니다.
health.intro.remarkBackup=데이터가 손상된 경우 백업만이 유일한 해결책입니다.
health.intro.affirmation=나는 위 정보를 읽고 정말 이해했습니다.
health.intro.affirmation=나는 위 정보를 읽었으며, 이해했습니다.
## Start Failure
health.fail.header=Vault 설정을 불러오는 중 에러 발생
health.fail.ioError=설정 파일에 접근하는 중 에러가 발생했습니다.
@@ -223,13 +254,17 @@ health.check.detail.checkFinishedAndFound=검사가 완료되었습니다. 검
health.check.detail.checkFailed=오류로 인해 검사가 종료되었습니다.
health.check.detail.checkCancelled=검사가 취소되었습니다
health.check.detail.listFilters.label=필터
health.check.detail.fixAllSpecificBtn=모든 문제 형식 고치기
health.check.exportBtn=보고서 내보내기
## Result view
health.result.severityFilter.all=모든 상태 표시
health.result.severityFilter.good=양호
health.result.severityFilter.info=정보
health.result.severityFilter.warn=경고
health.result.severityFilter.crit=심각
health.result.severityTip.good=상태: 양호\n정상적인 vault 구조를 가지고 있습니다.
health.result.severityTip.info=상태: 정보\nVault 구조 온전함, 문제 해결 권장됨.
health.result.severityTip.warn=상태: 경고\nVault 구조 손상됨, 문제 해결 요구됨.
health.result.severityTip.crit=상태: 심각\nVault 구조가 손상되었습니다. 데이터 손실이 발생했습니다.
health.result.fixStateFilter.all=모든 문제 해결 상태
health.result.fixStateFilter.fixable=문제 해결 가능
@@ -238,7 +273,7 @@ health.result.fixStateFilter.fixing=문제 해결중…
health.result.fixStateFilter.fixed=문제 해결됨
health.result.fixStateFilter.fixFailed=문제 해결 실패
## Fix Application
health.fix.fixBtn=문제해결
health.fix.fixBtn=문제 해결
health.fix.successTip=문제 해결이 성공적으로 완료되었습니다
health.fix.failTip=문제 해결 실패, 상세 정보는 로그를 참조하십시요.
@@ -247,13 +282,15 @@ preferences.title=환경설정
## General
preferences.general=일반
preferences.general.startHidden=Cryptomator를 시작할 때 창 숨김
preferences.general.debugLogging=디버그 로그기록을 사용하도록 설정
preferences.general.debugDirectory=Log 파일 표시
preferences.general.autoCloseVaults=애플리케이션을 닫을 때 자동으로 열린 Vault를 잠그기.
preferences.general.debugLogging=디버그 로깅 활성화
preferences.general.debugDirectory=로그 파일 표시
preferences.general.autoStart=시스템 시작 시 Cryptomator 실행
preferences.general.keychainBackend=다음 경로에 비밀번호 저장
preferences.general.quickAccessService=열린 Vault를 빠른 접근 위치에 추가하기
## Interface
preferences.interface=인터페이스
preferences.interface.theme=테마설정
preferences.interface.theme=테마
preferences.interface.theme.automatic=자동
preferences.interface.theme.dark=어둡게
preferences.interface.theme.light=밝게
@@ -264,11 +301,16 @@ preferences.interface.interfaceOrientation=인터페이스 방향
preferences.interface.interfaceOrientation.ltr=왼쪽에서 오른쪽으로
preferences.interface.interfaceOrientation.rtl=오른쪽에서 왼쪽으로
preferences.interface.showTrayIcon=트레이 아이콘 보기 (재시작 필요)
preferences.interface.compactMode=간소화 Vault 리스트 활성화
## Volume
preferences.volume=가상 드라이브
preferences.volume.type=기본 볼륨 타입
preferences.volume.type.automatic=자동
preferences.volume.docsTooltip=다른 볼륨 타입에 대해서는 문서를 참조하십시오.
preferences.volume.fuseRestartRequired=변경 사항을 적용하기 위해, Cryptomator의 재시작이 필요합니다.
preferences.volume.tcp.port=기본 TCP 포트
preferences.volume.supportedFeatures=현재 선택한 볼륨 타입은 다음과 같은 기능들을 지원합니다:
preferences.volume.feature.mountAuto=마운트 지점 자동 지정
preferences.volume.feature.mountToDir=마운트할 폴더 지정
preferences.volume.feature.mountToDriveLetter=마운트할 드라이브 문자
preferences.volume.feature.mountFlags=사용자 정의 마운트 설정
@@ -289,13 +331,18 @@ preferences.updates.upToDate=현재 최신 버전의 Cryptomator를 사용하고
## Contribution
preferences.contribute=후원하기
preferences.contribute.registeredFor=%s (으)로 후원자 인증 등록됨
preferences.contribute.registeredFor=%s(으)로 후원자 인증 등록됨
preferences.contribute.noCertificate=Cryptomator를 후원하시고 후원자 인증을 받으십시요. 라이선스 키와 비슷하지만 무료 소프트웨어를 사용하는 멋진 사람들을 위한 것입니다. ;-)
preferences.contribute.getCertificate=아직 후원자 인증이 없으신가요? 어떻게 얻는지 배울 수 있습니다.
preferences.contribute.promptText=후원자 인증코드를 여기에 붙여넣기
preferences.contribute.thankYou=Cryptomator의 오픈 소스 개발을 지원해 주셔서 감사합니다!
preferences.contribute.donate=후원하기
preferences.contribute.sponsor=스폰서
### Remove License Key Dialog
removeCert.confirmBtn=제거
removeCert.title=인증서 제거
removeCert.message=서포터 인증서를 제거하시겠습니까?
removeCert.description=Cryptomator의 핵심 기능은 영향을 받지 않습니다. Vault에 대한 접근이 제한되거나 보안이 약화되지 않습니다.
#<-- Add entries for donations and code/translation/documentation contribution -->
## About
@@ -333,30 +380,35 @@ stats.write.accessCount=총 쓰기 횟수: %d
## Accesses
stats.access.current=접근: %d
stats.access.total=총 접근: %d
# Main Window
## Vault List
main.vaultlist.emptyList.onboardingInstruction=Vault를 추가하기 위해 이곳을 클릭합니다.
main.vaultlist.emptyList.onboardingInstruction=여기를 클릭하여 Vault를 추가하세요
main.vaultlist.contextMenu.remove=제거...
main.vaultlist.contextMenu.lock=잠금
main.vaultlist.contextMenu.unlock=잠금해제...
main.vaultlist.contextMenu.unlockNow=지금 잠금해제
main.vaultlist.contextMenu.unlock=잠금 해제...
main.vaultlist.contextMenu.unlockNow=지금 잠금 해제
main.vaultlist.contextMenu.vaultoptions=Vault 옵션 보기
main.vaultlist.contextMenu.reveal=드라이브 표시
main.vaultlist.addVaultBtn.menuItemNew=새 Vault 생성...
main.vaultlist.addVaultBtn.menuItemExisting=기존 Vault 열기...
##Notificaition
main.notification.updateAvailable=업데이트가 있습니다.
main.notification.support=Cryptomator 지원하기.
## Vault Detail
### Welcome
main.vaultDetail.welcomeOnboarding=파일을 보호하기 위해 Cryptomator를 선택해주셔서 감사합니다. 만약 다른 도움이 필요하시면, 시작안내서를 참조하시기 바랍니다.
main.vaultDetail.welcomeOnboarding=파일을 보호하기 위해 Cryptomator를 선택해주셔서 감사합니다. 만약 다른 도움이 필요하시면, 시작 안내서를 참조하시기 바랍니다.
### Locked
main.vaultDetail.lockedStatus=잠김
main.vaultDetail.unlockBtn=잠금해제...
main.vaultDetail.unlockNowBtn=지금 잠금해제
main.vaultDetail.unlockBtn=잠금 해제...
main.vaultDetail.unlockNowBtn=지금 잠금 해제
main.vaultDetail.optionsBtn=Vault 옵션
main.vaultDetail.passwordSavedInKeychain=비밀번호 저장됨
main.vaultDetail.share=공유하기
main.vaultDetail.share=공유하기
### Unlocked
main.vaultDetail.unlockedStatus=잠금해제됨
main.vaultDetail.unlockedStatus=잠금 해제됨
main.vaultDetail.accessLocation=이 Vault의 내용은 다음의 경로에서 접근할 수 있습니다:
main.vaultDetail.revealBtn=드라이브 표시
main.vaultDetail.copyUri=URI 복사
@@ -368,6 +420,9 @@ main.vaultDetail.throughput.kbps=%.1f KiB/s
main.vaultDetail.throughput.mbps=%.1f MiB/s
main.vaultDetail.stats=Vault 통계
main.vaultDetail.locateEncryptedFileBtn=암호화된 파일 위치
main.vaultDetail.locateEncryptedFileBtn.tooltip=암호화된 파일을 보기 위해 Vault에서 파일을 선택하십시오.
main.vaultDetail.encryptedPathsCopied=클립보드에 복사됨!
main.vaultDetail.filePickerTitle=Vault 내부에서 파일 선택
### Missing
main.vaultDetail.missing.info=Cryptomator가 이 경로에 있는 Vault를 찾지 못했습니다.
main.vaultDetail.missing.recheck=다시 시도
@@ -375,26 +430,27 @@ main.vaultDetail.missing.remove=Vault 목록에서 제거...
main.vaultDetail.missing.changeLocation=Vault 위치 변경
### Needs Migration
main.vaultDetail.migrateButton=Vault 업그레이드
main.vaultDetail.migratePrompt=Vault에 접근하기 전, 새로운 포으로 업그레이드가 필요합니다.
main.vaultDetail.migratePrompt=Vault에 접근하기 전, 새로운 포으로 업그레이드가 필요합니다.
### Error
main.vaultDetail.error.info=디스크에서 Vault를 로드 중 에러 발생
main.vaultDetail.error.reload=새로고침
main.vaultDetail.error.windowTitle=Vault 로중 에러 발생
main.vaultDetail.error.windowTitle=Vault 로중 에러 발생
# Wrong File Alert
wrongFileAlert.title=파일 암호화 방법
wrongFileAlert.message=이 파일들을 암호화하려고 하십니까?
wrongFileAlert.description=이 목적을 위해, Cryptomator는 파일 관리자에 볼륨을 제공합니다.
wrongFileAlert.instruction.0=파일을 암호화 하려면, 다음의 3단계를 따르십시:
wrongFileAlert.instruction.1=1. Vault 잠금해제
wrongFileAlert.instruction.2=2. 파일 관리자에서 열람된 볼륨의 "표시" 버튼 클릭
wrongFileAlert.instruction.3=3. 이 볼륨에 파일 추가
wrongFileAlert.link=추후 지원을 위해, 다음을 방문하십시
wrongFileAlert.instruction.0=파일을 암호화 하려면, 다음의 3단계를 따르십시:
wrongFileAlert.instruction.1=1. Vault 잠금 해제하십시오.
wrongFileAlert.instruction.2=2. "표시" 버튼 클릭해 파일 탐색기에서 볼륨을 여십시오.
wrongFileAlert.instruction.3=3. 이 볼륨에 파일 추가하십시오.
wrongFileAlert.link=더 많은 지원을 위해, 다음을 방문하십시
# Vault Options
## General
vaultOptions.general=일반
vaultOptions.general.vaultName=Vault 이름
vaultOptions.general.autoLock.lockAfterTimePart1=다음 시간동안 유휴상태 시 잠금 :
vaultOptions.general.autoLock.lockAfterTimePart1=다음 시간 동안 유휴상태 시 잠그기
vaultOptions.general.autoLock.lockAfterTimePart2=
vaultOptions.general.unlockAfterStartup=Cryptomator를 시작할 때 Vault 잠금 해제
vaultOptions.general.actionAfterUnlock=성공적으로 잠금해제 후
@@ -405,6 +461,7 @@ vaultOptions.general.startHealthCheckBtn=상태 검사 시작
## Mount
vaultOptions.mount=드라이브 구성
vaultOptions.mount.info=기본 설정을 바꾸기 위해 가상 드라이브 설정을 여십시오.
vaultOptions.mount.readonly=읽기 전용
vaultOptions.mount.customMountFlags=사용자 정의 매개변수 사용
vaultOptions.mount.winDriveLetterOccupied=사용됨
@@ -414,7 +471,10 @@ vaultOptions.mount.mountPoint.driveLetter=드라이브 문자를 지정하여
vaultOptions.mount.mountPoint.custom=선택한 디렉토리 사용
vaultOptions.mount.mountPoint.directoryPickerButton=선택
vaultOptions.mount.mountPoint.directoryPickerTitle=디렉토리 선택
vaultOptions.mount.volumeType.default=기본 (%s)
vaultOptions.mount.volumeType.restartRequired=이 볼륨 타입을 사용하기 위해, Cryptomator의 재시작이 필요합니다.
vaultOptions.mount.volume.tcp.port=TCP 포트
vaultOptions.mount.volume.type=볼륨 타입
## Master Key
vaultOptions.masterkey=비밀번호
vaultOptions.masterkey.changePasswordBtn=비밀번호 변경
@@ -424,6 +484,8 @@ vaultOptions.masterkey.showRecoveryKeyBtn=복구 키 표시
vaultOptions.masterkey.recoverPasswordBtn=비밀번호 재설정
## Hub
vaultOptions.hub=복구
vaultOptions.hub.convertInfo=비상상황에 이 Hub Vault를 비밀번호 기반 Vault로 변환하기 위해 복구 키를 사용할 수 있습니다.
vaultOptions.hub.convertBtn=비밀번호 기반 Vault로 변환하기
# Recovery Key
## Display Recovery Key
@@ -431,7 +493,7 @@ recoveryKey.display.title=복구 키 보기
recoveryKey.create.message=비밀번호가 필요합니다
recoveryKey.create.description="%s"의 복구 키를 표시하려면 비밀번호를 입력해 주세요.
recoveryKey.display.description="%s" 데이터 접근을 복원하는데 사용 할 수 있는 복구 키 입니다:
recoveryKey.display.StorageHints=매우 안전한곳에 보관하십시. 예시:\n • 비밀번호 관리자를 사용하여 저장\n • USB 플래시 드라이브에 저장\n • 종이 출력
recoveryKey.display.StorageHints=매우 안전한곳에 보관하십시. 예시:\n • 비밀번호 관리자를 사용하여 저장\n • USB 플래시 드라이브에 저장\n • 종이 출력
## Reset Password
### Enter Recovery Key
recoveryKey.recover.title=비밀번호 바꾸기
@@ -447,9 +509,11 @@ recoveryKey.recover.resetSuccess.message=비밀번호 재설정 성공
recoveryKey.recover.resetSuccess.description=이제 해당 vault를 새 비밀번호로 잠금 해제할 수 있습니다.
# Convert Vault
convertVault.title=Vault 변환
convertVault.convert.convertBtn.before=변환
convertVault.convert.convertBtn.processing=변환중…
convertVault.success.message=변환 완료
convertVault.hubToPassword.success.description=이제 Hub 접근 없이 지정된 비밀번호로 Vault를 잠금해제할 수 있습니다.
# New Password
newPassword.promptText=새 비밀번호를 입력하세요
@@ -466,16 +530,50 @@ passwordStrength.messageLabel.4=매우 강함
# Quit
quit.title=앱 종료
quit.message=잠금 해제된 vault들이 존재합니다
quit.description=정말로 나가시겠습니까? Cryptomator는 데이터 손실을 막기 위해 열린 Vault를 잠글 것입니다.
quit.lockAndQuitBtn=Vault 잠금 후 종료하기
# Forced Quit
quit.forced.message=일부 Vault를 잠글 수 없습니다.
quit.forced.description=대기 중인 작동이나 파일이 열려있어 Vault를 잠그는데 실패하였습니다. 남은 Vault를 강제로 잠글 수 있으나, 입/출력의 중단은 저장되지 않은 데이터의 유실을 초래할 수 있습니다.
quit.forced.forceAndQuitBtn=Vault 강제 잠금 후 종료하기
# Update Reminder
updateReminder.title=업데이트 확인
updateReminder.message=업데이트 확인
updateReminder.description=새로운 기능, 버그 수정, 보안 향상을 위해 업데이트하십시오. 업데이트 자동 확인을 권장합니다.
updateReminder.notNow=나중에
updateReminder.yesOnce=예, 한번만
updateReminder.yesAutomatically=예, 자동으로
#Dokany Support End
dokanySupportEnd.title=지원 중단 경고
dokanySupportEnd.message=Dokany에 대한 지원 중단
dokanySupportEnd.description=Cryptomator에서 Dokany 볼륨 형식은 더이상 지원되지 않습니다. 기본 볼륨 형식을 사용하도록 설정이 조정되었으며, 설정에서 기본 형식을 확인할 수 있습니다.
dokanySupportEnd.preferencesBtn=설정 열기
#Retry If Readonly
retryIfReadonly.title=Vault 접근 제한됨
retryIfReadonly.message=Vault 디렉터리에 쓰기 권한 없음
retryIfReadonly.description=Cryptomator가 Vault 디렉터리에 쓸 수 없습니다. Vault를 읽기 전용으로 설정하고 다시 시도할 수 있습니다. 이 옵션은 Vault 옵션에서 바꿀 수 있습니다.
retryIfReadonly.retry=바꾸고 다시 시도하기
# Share Vault
shareVault.title=Vault 공유
shareVault.message=Vault를 다른 사람과 공유하려 하십니까?
shareVault.description=Vault를 타인과 공유할 때에는 항상 주의하십시오. 간단히 이 단계들을 따르십시오.
shareVault.instruction.1=1. 암호화된 Vault 폴더를 클라우드 스토리지를 통해 공유하십시오.
shareVault.instruction.2=2. Vault의 비밀번호를 안전한 방식으로 전달하십시오.
shareVault.remarkBestPractices=문서에 있는 권장사항을 통해 더 많은 정보를 확인하십시오.
shareVault.docsTooltip=Vault의 공유에 대해서는 문서를 참조하십시오.
shareVault.hubAd.description=팀에서 작업하는 안전한 방법
shareVault.hubAd.keyManagement=• 사전지식 없는 키 관리
shareVault.hubAd.authentication=• 강력한 인증
shareVault.hubAd.encryption=• 종단간 암호화
shareVault.visitHub=Cryptomator Hub 방문하기
shareVault.hub.message=Hub Vault를 공유하는법
shareVault.hub.description=다른 팀 구성원과 Vault를 공유하기 위해서는 다음 단계를 따르십시오:
shareVault.hub.instruction.1=1. 암호화된 Vault 폴더를 클라우드 스토리지를 통해 공유하십시오.
shareVault.hub.instruction.2=2. Cryptomator Hub에서 팀 구성원에 접근을 허가하기
shareVault.hub.openHub=Cryptomator Hub 열기

View File

@@ -85,7 +85,6 @@ addvaultwizard.success.unlockNow=Atslēgt tagad
# Remove Vault
removeVault.title=Noņemt glabātuvi
removeVault.description=Šis tikai liks Cryptomator aizmirst šo glabātuvi. Jūs to variet pievienot vēlāk atkārtoti. Nekādi šifrētie dati no diska netiks dzēsti.
removeVault.confirmBtn=Noņemt glabātuvi
# Change Password
changepassword.title=Mainīt paroli
@@ -281,4 +280,6 @@ quit.lockAndQuitBtn=Aizslēgt un aizvērt
#Dokany Support End
#Retry If Readonly
# Share Vault

View File

@@ -164,4 +164,6 @@ vaultOptions.mount.mountPoint.directoryPickerButton=Избор…
#Dokany Support End
#Retry If Readonly
# Share Vault

View File

@@ -118,4 +118,6 @@
#Dokany Support End
#Retry If Readonly
# Share Vault

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