Browse Source

Merge branch 'develop' into release/1.12.3

Armin Schrenk 1 year ago
parent
commit
3acdef1dd0

+ 1 - 1
.github/workflows/appimage.yml

@@ -168,7 +168,7 @@ jobs:
             cryptomator-*.asc
           if-no-files-found: error
       - name: Publish AppImage on GitHub Releases
-        if: startsWith(github.ref, 'refs/tags/') && github.event_name == 'published'
+        if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published'
         uses: softprops/action-gh-release@v1
         with:
           fail_on_unmatched_files: true

+ 0 - 1
.github/workflows/debian.yml

@@ -142,7 +142,6 @@ jobs:
       - name: Publish on PPA
         if: inputs.dput
         run: dput ppa:sebastian-stenzel/cryptomator-beta cryptomator_*_source.changes
-      
       # If ref is a tag, also upload to GitHub Releases:
       - name: Publish Debian package on GitHub Releases
         if: startsWith(github.ref, 'refs/tags/') && inputs.dput

+ 88 - 0
.github/workflows/flathub.yml

@@ -0,0 +1,88 @@
+name: Create PR for flathub
+
+on:
+  release:
+    types: [published]
+  workflow_dispatch:
+    inputs:
+      tag:
+        description: 'Release tag'
+        required: true
+
+jobs:
+  get-version:
+    uses: ./.github/workflows/get-version.yml
+    with:
+      version: ${{ inputs.tag }}
+  tarball:
+    name: Determines tarball url and compute checksum
+    runs-on: ubuntu-latest
+    needs: [get-version]
+    if:  github.event_name == 'workflow_dispatch' || needs.get-version.outputs.versionType == 'stable'
+    outputs:
+      url: ${{ steps.url.outputs.url}}
+      sha512: ${{ steps.sha512.outputs.sha512}}
+    steps:
+      - name: Determine tarball url
+        id: url
+        run: |
+          URL="";
+          if [[ -n "${{ inputs.tag }}"  ]]; then
+            URL="https://github.com/cryptomator/cryptomator/archive/refs/tags/${{ inputs.tag }}.tar.gz"
+          else
+            URL="https://github.com/cryptomator/cryptomator/archive/refs/tags/${{ github.event.release.tag_name }}.tar.gz"
+          fi
+          echo "url=${URL}" >> "$GITHUB_OUTPUT"
+      - name: Download source tarball and compute checksum
+        id: sha512
+        run: |
+          curl --silent --fail-with-body -L -H "Accept: application/vnd.github+json" ${{ steps.url.outputs.url }} --output cryptomator.tar.gz
+          TARBALL_SHA512=$(sha512sum cryptomator.tar.gz | cut -d ' ' -f1)
+          echo "sha512=${TARBALL_SHA512}" >> "$GITHUB_OUTPUT"
+  flathub:
+    name: Create PR for flathub
+    runs-on: ubuntu-latest
+    needs: [tarball, get-version]
+    env:
+      FLATHUB_PR_URL: tbd
+    steps:
+      - uses: actions/checkout@v4
+        with:
+          repository: 'flathub/org.cryptomator.Cryptomator'
+          token: ${{ secrets.CRYPTOBOT_WINGET_TOKEN }}
+      - name: Checkout release branch
+        run: |
+          git checkout -b release/${{ needs.get-version.outputs.semVerStr }}
+      - name: Update build file
+        run: |
+          sed -i -e 's/VERSION: [0-9]\+\.[0-9]\+\.[0-9]\+.*/VERSION: ${{ needs.get-version.outputs.semVerStr }}/g' org.cryptomator.Cryptomator.yaml
+          sed -i -e 's/sha512: [0-9A-Za-z_-\+]\{128\} #CRYPTOMATOR/sha512: ${{ needs.tarball.outputs.sha512 }} #CRYPTOMATOR/g' org.cryptomator.Cryptomator.yaml
+          sed -i -e 's;url: https://github.com/cryptomator/cryptomator/archive/refs/tags/[^[:blank:]]\+;url: ${{ needs.tarball.outputs.url }};g' org.cryptomator.Cryptomator.yaml
+      - name: Commit and push
+        run: |
+          git config user.name "${{ github.actor }}"
+          git config user.email "${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com"
+          git config push.autoSetupRemote true
+          git stage .
+          git commit -m "Prepare release ${{needs.get-version.outputs.semVerStr}}"
+          git push
+      - name: Create pull request
+        run: |
+          echo "> [!IMPORTANT]\n> Todos:\n> - [ ] Update maven dependencies\n> - [ ] Check for JDK update\n> - [ ] Check for JFX update" > pr_body.md
+          PR_URL=$(gh pr create --title "Release ${{ needs.get-version.outputs.semVerStr }}" --body-file pr_body.md)
+          echo "FLATHUB_PR_URL=$PR_URL" >> "$GITHUB_ENV"
+        env:
+          GH_TOKEN: ${{ secrets.CRYPTOBOT_WINGET_TOKEN }}
+      - name: Slack Notification
+        uses: rtCamp/action-slack-notify@v2
+        if: github.event_name == 'release'
+        env:
+          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
+          SLACK_USERNAME: 'Cryptobot'
+          SLACK_ICON: false
+          SLACK_ICON_EMOJI: ':bot:'
+          SLACK_CHANNEL: 'cryptomator-desktop'
+          SLACK_TITLE: "Flathub release PR created for ${{ github.event.repository.name }} ${{ github.event.release.tag_name }} created."
+          SLACK_MESSAGE: "See <${{ env.FLATHUB_PR_URL }}|PR> on how to proceed.>."
+          SLACK_FOOTER: false
+          MSG_MINIMAL: true

+ 2 - 2
.github/workflows/get-version.yml

@@ -50,7 +50,7 @@ jobs:
           if [[ $GITHUB_REF =~ refs/tags/[0-9]+\.[0-9]+\.[0-9]+.* ]]; then
             SEM_VER_STR=${GITHUB_REF##*/}
           elif [[ "${{ inputs.version }}" =~ [0-9]+\.[0-9]+\.[0-9]+.* ]]; then
-            SEM_VER_STR="${{ github.event.inputs.version }}"
+            SEM_VER_STR="${{ inputs.version }}"
           else
             SEM_VER_STR=`mvn help:evaluate -Dexpression=project.version -q -DforceStdout`
           fi
@@ -73,4 +73,4 @@ jobs:
       - name: Validate Version
         uses: skymatic/semver-validation-action@v2
         with:
-          version: ${{ steps.versions.outputs.semVerStr }} 
+          version: ${{ steps.versions.outputs.semVerStr }}

+ 1 - 1
.github/workflows/mac-dmg.yml

@@ -258,7 +258,7 @@ jobs:
             Cryptomator-*.asc
           if-no-files-found: error
       - name: Publish dmg on GitHub Releases
-        if: startsWith(github.ref, 'refs/tags/') && github.event_name == 'published'
+        if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published'
         uses: softprops/action-gh-release@v1
         with:
           fail_on_unmatched_files: true

+ 4 - 4
.github/workflows/win-exe.yml

@@ -255,7 +255,7 @@ jobs:
             Cryptomator-*.asc
           if-no-files-found: error
       - name: Publish .msi on GitHub Releases
-        if: startsWith(github.ref, 'refs/tags/') && github.event_name == 'published'
+        if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published'
         uses: softprops/action-gh-release@v1
         with:
           fail_on_unmatched_files: true
@@ -366,7 +366,7 @@ jobs:
             Cryptomator-*.asc
           if-no-files-found: error
       - name: Publish .msi on GitHub Releases
-        if: startsWith(github.ref, 'refs/tags/') && github.event_name == 'published'
+        if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published'
         uses: softprops/action-gh-release@v1
         with:
           fail_on_unmatched_files: true
@@ -377,7 +377,7 @@ jobs:
 
   allowlist:
     name: Anti Virus Allowlisting
-    if: startsWith(github.ref, 'refs/tags/') && github.event_name == 'published'
+    if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published'
     runs-on: ubuntu-latest
     needs: [build-msi, build-exe]
     steps:
@@ -416,7 +416,7 @@ jobs:
           local-dir: files/
   notify-winget:
     name: Notify for winget-release
-    if: startsWith(github.ref, 'refs/tags/') && github.event_name == 'published' && needs.get-version.outputs.versionType == 'stable'
+    if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published' && needs.get-version.outputs.versionType == 'stable'
     needs: [build-msi, get-version]
     runs-on: ubuntu-latest
     steps:

+ 20 - 16
dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml

@@ -5,26 +5,27 @@
 	<metadata_license>FSFAP</metadata_license>
 	<project_license>GPL-3.0-or-later</project_license>
 	<name>Cryptomator</name>
-	<summary>Multi-platform client-side encryption tool optimized for cloud storages</summary>
+	<summary>Encryption made easy and optimized for the cloud</summary>
 
 	<description>
 		<p>
-			Cryptomator provides transparent, client-side encryption for your cloud. Protect your documents from unauthorized
-			access. Cryptomator is free and open source software, so you can rest assured there are no backdoors.
+			Cryptomator provides easy-to-use, transparent, client-side encryption for your cloud.
+			It protects your documents from unauthorized access and prying eyes, while you will still be able to view and edit your documents locally.
+			By not requiring any registration or account and performing all encryption locally, it gives you back control over your data and ensures your privacy.
+			Cryptomator is offered for all major platforms (including Android and iOS).
 		</p>
 		<p>
-			Cryptomator encrypts file contents and names using AES. Your passphrase is protected against bruteforcing attempts
-			using scrypt. Directory structures get obfuscated. The only thing which cannot be encrypted without breaking your
-			cloud synchronization is the modification date of your files.
+			Cryptomator encrypts file contents and names using the widespread industry standard AES.
+			Your passphrase is protected against brute forcing attempts using scrypt.
+			Additionally, directory structures get obfuscated.
+			For more info about the Cryptomator encryption scheme, check out the online documentation.
 		</p>
 		<p>
-			Cryptomator is a free and open source software licensed under the GPLv3. This allows anyone to check our code. It
-			is impossible to introduce backdoors for third parties. Also we cannot hide vulnerabilities. And the best thing
-			is: There is no need to trust us, as you can control us!
-		</p>
-		<p>
-			Vendor lock-ins are impossible. Even if we decided to stop development: The source code is already cloned by
-			hundreds of other developers. As you don't need an account, you will never stand in front of locked doors.
+			Cryptomator is a free and open-source software licensed under the GPLv3.
+			This allows anyone to check our code.
+			Thus, it is impossible to introduce backdoors for third parties or to hide vulnerabilities, so you do not need to trust Cryptomator.
+			Also, vendor lock-ins are impossible.
+			Even if we decided to stop development: The source code is already cloned by hundreds of other developers and development can be picked up by others.
 		</p>
 	</description>
 
@@ -42,7 +43,7 @@
 	</provides>
 
 	<screenshots>
-		<screenshot>
+		<screenshot type="default">
 			<caption>Light theme</caption>
 			<image>https://user-images.githubusercontent.com/11858409/156986109-6e58f59c-8b8c-4501-b33b-bb1e33007cea.png</image>
 		</screenshot>
@@ -56,10 +57,13 @@
 	<url type="bugtracker">https://github.com/cryptomator/cryptomator/issues/</url>
 	<url type="donation">https://cryptomator.org/donate</url>
 	<url type="faq">https://community.cryptomator.org/c/kb/faq</url>
-	<url type="help">https://community.cryptomator.org/</url>
+	<url type="help">https://docs.cryptomator.org/</url>
 	<url type="translate">https://translate.cryptomator.org</url>
 
-	<developer_name>Skymatic GmbH</developer_name>
+	<developer id="de.skymatic">
+		<name>Skymatic GmbH</name>
+	</developer>
+		
 
 	<content_rating type="oars-1.1">
 		<content_attribute id="social-info">mild</content_attribute> <!-- update checker connects to https://api.cryptomator.org/updates/latestVersion.json -->

+ 2 - 2
pom.xml

@@ -3,7 +3,7 @@
 	<modelVersion>4.0.0</modelVersion>
 	<groupId>org.cryptomator</groupId>
 	<artifactId>cryptomator</artifactId>
-	<version>1.12.3</version>
+	<version>1.13.0-SNAPSHOT</version>
 	<name>Cryptomator Desktop App</name>
 
 	<organization>
@@ -34,7 +34,7 @@
 
 		<!-- cryptomator dependencies -->
 		<cryptomator.cryptofs.version>2.6.9</cryptomator.cryptofs.version>
-		<cryptomator.integrations.version>1.3.0</cryptomator.integrations.version>
+		<cryptomator.integrations.version>1.3.1</cryptomator.integrations.version>
 		<cryptomator.integrations.win.version>1.2.5</cryptomator.integrations.win.version>
 		<cryptomator.integrations.mac.version>1.2.3</cryptomator.integrations.mac.version>
 		<cryptomator.integrations.linux.version>1.4.4</cryptomator.integrations.linux.version>

+ 1 - 15
src/main/java/org/cryptomator/common/mount/Mounter.java

@@ -119,14 +119,8 @@ public class Mounter {
 					Files.createDirectories(defaultMountPointBase);
 					builder.setMountpoint(defaultMountPointBase);
 				} else if (canMountToDir) {
-					var dirName = vaultSettings.mountName.get();
-					//required for https://github.com/cryptomator/cryptomator/issues/3272
-					if(service.getClass().getCanonicalName().equals("org.cryptomator.frontend.fuse.mount.FuseTMountProvider")) {
-						dirName = vaultSettings.id;
-					}
-					var mountPoint = defaultMountPointBase.resolve(dirName);
+					var mountPoint = defaultMountPointBase.resolve(vaultSettings.mountName.get());
 					Files.createDirectories(mountPoint);
-					cleanup = () -> removeCreatedDirectory(mountPoint);
 					builder.setMountpoint(mountPoint);
 				}
 			} else {
@@ -162,14 +156,6 @@ public class Mounter {
 
 	}
 
-	private void removeCreatedDirectory(Path toDelete) {
-		try {
-			Files.delete(toDelete);
-		} catch (IOException e) {
-			LOG.warn("Unable to remove {} after unmount: {}.", toDelete, e.getMessage());
-		}
-	}
-
 	public MountHandle mount(VaultSettings vaultSettings, Path cryptoFsRoot) throws IOException, MountFailedException {
 		var mountService = mountProviders.stream().filter(s -> s.getClass().getName().equals(vaultSettings.mountService.getValue())).findFirst().orElse(defaultMountService.getValue());
 

+ 3 - 0
src/main/java/org/cryptomator/ui/error/ErrorController.java

@@ -75,6 +75,7 @@ public class ErrorController implements FxController {
 	private final BooleanExpression errorSolutionFound = matchingErrorDiscussion.isNotNull();
 	private final BooleanProperty isLoadingHttpResponse = new SimpleBooleanProperty();
 	private final BooleanProperty askedForLookupDatabasePermission = new SimpleBooleanProperty();
+	private final boolean formerSceneWasResizable;
 
 	@Inject
 	ErrorController(Application application, @Named("stackTrace") String stackTrace, ErrorCode errorCode, @Nullable Scene previousScene, Stage window, Environment environment, ExecutorService executorService) {
@@ -85,12 +86,14 @@ public class ErrorController implements FxController {
 		this.window = window;
 		this.environment = environment;
 		this.executorService = executorService;
+		this.formerSceneWasResizable = window.isResizable();
 	}
 
 	@FXML
 	public void back() {
 		if (previousScene != null) {
 			window.setScene(previousScene);
+			window.setResizable(formerSceneWasResizable);
 		}
 	}
 

+ 4 - 1
src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java

@@ -116,7 +116,10 @@ public class UnlockWorkflow extends Task<Void> {
 				double x = mainWindow.getX() + (mainWindow.getWidth() - window.getWidth()) / 2;
 				double y = mainWindow.getY() + (mainWindow.getHeight() - window.getHeight()) / 2;
 				if(!mainWindow.isShowing()) {
-					Screen screen = Screen.getScreensForRectangle(mainWindow.getX(), mainWindow.getY(), mainWindow.getWidth(), mainWindow.getHeight()).get(0);
+					Screen screen = Screen.getScreensForRectangle(mainWindow.getX(), mainWindow.getY(), mainWindow.getWidth(), mainWindow.getHeight())
+							.stream()
+							.findFirst()
+							.orElse(Screen.getPrimary());
 					Rectangle2D bounds = screen.getVisualBounds();
 					x = bounds.getMinX() + (bounds.getWidth() - window.getWidth()) / 2;
 					y = bounds.getMinY() + (bounds.getHeight() - window.getHeight()) / 2;

+ 68 - 57
src/main/resources/fxml/error.fxml

@@ -9,86 +9,97 @@
 <?import javafx.scene.control.Hyperlink?>
 <?import javafx.scene.control.Label?>
 <?import javafx.scene.control.TextArea?>
+<?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?>
-<VBox xmlns:fx="http://javafx.com/fxml"
+<HBox xmlns:fx="http://javafx.com/fxml"
 	  xmlns="http://javafx.com/javafx"
 	  fx:controller="org.cryptomator.ui.error.ErrorController"
+	  minWidth="450"
+	  minHeight="450"
 	  prefWidth="450"
 	  prefHeight="450"
-	  spacing="18"
-	  alignment="TOP_CENTER">
+	  spacing="12">
 	<padding>
 		<Insets topRightBottomLeft="24"/>
 	</padding>
-	<children>
-		<HBox spacing="12" VBox.vgrow="NEVER">
-			<StackPane alignment="CENTER" HBox.hgrow="NEVER">
-				<Circle styleClass="glyph-icon-primary" radius="24"/>
-				<FontAwesome5IconView styleClass="glyph-icon-white" glyph="EXCLAMATION" glyphSize="24"/>
-			</StackPane>
-			<VBox spacing="6" HBox.hgrow="ALWAYS">
-				<FormattedLabel styleClass="label-extra-large" format="%error.message" arg1="${controller.errorCode}"/>
-				<VBox visible="${!controller.askedForLookupDatabasePermission}" managed="${!controller.askedForLookupDatabasePermission}">
-					<Label text="%error.lookupPermissionMessage" wrapText="true"/>
-					<Region VBox.vgrow="ALWAYS" minHeight="18"/>
-					<ButtonBar buttonMinWidth="120" buttonOrder="+NY">
-						<buttons>
-							<Button text="%error.dismiss" ButtonBar.buttonData="NO" onAction="#dismiss"/>
-							<Button text="%error.lookUpSolution" ButtonBar.buttonData="YES" defaultButton="true" onAction="#lookUpSolution"/>
-						</buttons>
-					</ButtonBar>
-				</VBox>
-				<VBox visible="${controller.askedForLookupDatabasePermission}" managed="${controller.askedForLookupDatabasePermission}">
-					<FontAwesome5Spinner glyphSize="24" visible="${controller.isLoadingHttpResponse}" managed="${controller.isLoadingHttpResponse}"/>
-					<VBox visible="${!controller.isLoadingHttpResponse}" managed="${!controller.isLoadingHttpResponse}">
-						<Label text="%error.existingSolutionDescription" wrapText="true" visible="${controller.errorSolutionFound}" managed="${controller.errorSolutionFound}"/>
-						<Hyperlink styleClass="hyperlink-underline" text="%error.hyperlink.solution" onAction="#showSolution" contentDisplay="LEFT" visible="${controller.errorSolutionFound}" managed="${controller.errorSolutionFound}">
-							<graphic>
-								<FontAwesome5IconView glyph="LINK" glyphSize="12"/>
-							</graphic>
-						</Hyperlink>
-						<Label text="%error.description" wrapText="true" visible="${!controller.errorSolutionFound}" managed="${!controller.errorSolutionFound}"/>
-						<Hyperlink styleClass="hyperlink-underline" text="%error.hyperlink.lookup" onAction="#searchError" contentDisplay="LEFT" visible="${!controller.errorSolutionFound}" managed="${!controller.errorSolutionFound}">
-							<graphic>
-								<FontAwesome5IconView glyph="LINK" glyphSize="12"/>
-							</graphic>
-						</Hyperlink>
-						<Hyperlink styleClass="hyperlink-underline" text="%error.hyperlink.report" onAction="#reportError" contentDisplay="LEFT" visible="${!controller.errorSolutionFound}" managed="${!controller.errorSolutionFound}">
-							<graphic>
-								<FontAwesome5IconView glyph="LINK" glyphSize="12"/>
-							</graphic>
-						</Hyperlink>
-					</VBox>
-				</VBox>
-			</VBox>
-		</HBox>
-		<VBox spacing="6" VBox.vgrow="ALWAYS">
-			<HBox>
-				<Label text="%error.technicalDetails"/>
-				<Region HBox.hgrow="ALWAYS"/>
-				<Hyperlink styleClass="hyperlink-underline" text="%generic.button.copy" onAction="#copyDetails" contentDisplay="LEFT" visible="${!controller.copiedDetails}" managed="${!controller.copiedDetails}">
+	<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">
+		<FormattedLabel styleClass="label-extra-large" format="%error.message" arg1="${controller.errorCode}">
+			<padding>
+				<Insets bottom="6" top="6"/>
+			</padding>
+		</FormattedLabel>
+
+		<VBox visible="${!controller.askedForLookupDatabasePermission}" managed="${!controller.askedForLookupDatabasePermission}">
+			<Label text="%error.lookupPermissionMessage" wrapText="true"/>
+			<Region minHeight="12"/>
+			<ButtonBar buttonMinWidth="120" buttonOrder="+NY">
+				<buttons>
+					<Button text="%error.dismiss" ButtonBar.buttonData="NO" onAction="#dismiss"/>
+					<Button text="%error.lookUpSolution" ButtonBar.buttonData="YES" defaultButton="true" onAction="#lookUpSolution"/>
+				</buttons>
+			</ButtonBar>
+		</VBox>
+		<VBox visible="${controller.askedForLookupDatabasePermission}" managed="${controller.askedForLookupDatabasePermission}">
+			<FontAwesome5Spinner glyphSize="24" visible="${controller.isLoadingHttpResponse}" managed="${controller.isLoadingHttpResponse}"/>
+			<VBox visible="${!controller.isLoadingHttpResponse}" managed="${!controller.isLoadingHttpResponse}">
+				<Label text="%error.existingSolutionDescription" wrapText="true" visible="${controller.errorSolutionFound}" managed="${controller.errorSolutionFound}"/>
+				<Hyperlink styleClass="hyperlink-underline" text="%error.hyperlink.solution" onAction="#showSolution" contentDisplay="LEFT" visible="${controller.errorSolutionFound}" managed="${controller.errorSolutionFound}">
 					<graphic>
-						<FontAwesome5IconView glyph="CLIPBOARD" glyphSize="12"/>
+						<FontAwesome5IconView glyph="LINK" glyphSize="12"/>
 					</graphic>
 				</Hyperlink>
-				<Hyperlink styleClass="hyperlink-underline" text="%generic.button.copied" onAction="#copyDetails" contentDisplay="LEFT" visible="${controller.copiedDetails}" managed="${controller.copiedDetails}">
+				<Label text="%error.description" wrapText="true" visible="${!controller.errorSolutionFound}" managed="${!controller.errorSolutionFound}"/>
+				<Hyperlink styleClass="hyperlink-underline" text="%error.hyperlink.lookup" onAction="#searchError" contentDisplay="LEFT" visible="${!controller.errorSolutionFound}" managed="${!controller.errorSolutionFound}">
 					<graphic>
-						<FontAwesome5IconView glyph="CHECK" glyphSize="12"/>
+						<FontAwesome5IconView glyph="LINK" glyphSize="12"/>
 					</graphic>
 				</Hyperlink>
-			</HBox>
-			<TextArea VBox.vgrow="ALWAYS" text="${controller.detailText}" prefRowCount="5" editable="false"/>
+				<Hyperlink styleClass="hyperlink-underline" text="%error.hyperlink.report" onAction="#reportError" contentDisplay="LEFT" visible="${!controller.errorSolutionFound}" managed="${!controller.errorSolutionFound}">
+					<graphic>
+						<FontAwesome5IconView glyph="LINK" glyphSize="12"/>
+					</graphic>
+				</Hyperlink>
+			</VBox>
 		</VBox>
+		<Region minHeight="12"/>
+		<HBox>
+			<padding>
+				<Insets top="6" bottom="6"/>
+			</padding>
+			<Label text="%error.technicalDetails"/>
+			<Region HBox.hgrow="ALWAYS"/>
+			<Hyperlink styleClass="hyperlink-underline" text="%generic.button.copy" onAction="#copyDetails" contentDisplay="LEFT" visible="${!controller.copiedDetails}" managed="${!controller.copiedDetails}">
+				<graphic>
+					<FontAwesome5IconView glyph="CLIPBOARD" glyphSize="12"/>
+				</graphic>
+			</Hyperlink>
+			<Hyperlink styleClass="hyperlink-underline" text="%generic.button.copied" onAction="#copyDetails" contentDisplay="LEFT" visible="${controller.copiedDetails}" managed="${controller.copiedDetails}">
+				<graphic>
+					<FontAwesome5IconView glyph="CHECK" glyphSize="12"/>
+				</graphic>
+			</Hyperlink>
+		</HBox>
+		<TextArea VBox.vgrow="ALWAYS" text="${controller.detailText}" prefRowCount="5" editable="false"/>
 
+		<Region minHeight="18"/>
 		<ButtonBar buttonMinWidth="120" buttonOrder="B+C">
 			<buttons>
 				<Button text="%generic.button.back" ButtonBar.buttonData="BACK_PREVIOUS" onAction="#back" visible="${controller.previousScenePresent}"/>
 				<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" onAction="#close"/>
 			</buttons>
 		</ButtonBar>
-	</children>
-</VBox>
+	</VBox>
+</HBox>

+ 13 - 1
src/main/resources/i18n/strings_fr.properties

@@ -535,7 +535,19 @@ updateReminder.yesAutomatically=Oui, automatiquement
 # Share Vault
 shareVault.title=Partager le coffre
 shareVault.message=Vous aimeriez partager votre coffre avec d'autres personnes ?
+shareVault.description=Soyez toujours prudent lorsque vous partagez votre coffre avec d'autres personnes. En bref, suivez ces étapes :
+shareVault.instruction.1=1. Partagez l'accès du dossier de coffre chiffré via le stockage cloud.
+shareVault.instruction.2=2. Partagez le mot de passe du coffre de manière sécurisée.
+shareVault.remarkBestPractices=Pour plus d'informations, consultez les suggestions des meilleures pratiques de notre documentation.
+shareVault.docsTooltip=Ouvrez la documentation pour en savoir plus sur le partage des coffres.
+shareVault.hubAd.description=La façon sécurisée de travailler en équipe
+shareVault.hubAd.keyManagement=• Gestion des clés sans connaissance
+shareVault.hubAd.authentication=• Authentification forte
 shareVault.hubAd.encryption=Chiffrement de bout en bout
 shareVault.visitHub=Visiter le Hub Cryptomator
 
-shareVault.hub.openHub=Visiter le Hub Cryptomator
+shareVault.hub.message=Comment partager un coffre central
+shareVault.hub.description=Afin de partager le contenu du coffre avec un autre membre de l'équipe, vous devez effectuer deux étapes :
+shareVault.hub.instruction.1=1. Partagez l'accès du dossier de coffre chiffré via le stockage cloud.
+shareVault.hub.instruction.2=2. Accorder l'accès au membre de l'équipe dans Cryptomator Hub.
+shareVault.hub.openHub=Ouvrir le Hub Cryptomator

+ 11 - 0
src/main/resources/i18n/strings_ja.properties

@@ -141,6 +141,8 @@ unlock.error.customPath.description.hideawayNotDir=ロック解除に使用さ
 unlock.error.customPath.description.couldNotBeCleaned=金庫を "%s" にマウントすることができませんでした。もう一度試すか、別のパスを選択してください。
 unlock.error.customPath.description.notEmptyDir=カスタムマウントパス「%s」は空のフォルダではありません。空のフォルダを選択して再度お試し下さい。
 unlock.error.customPath.description.generic=この金庫に対してカスタムマウントパスを選択しましたが、以下のメッセージとともに失敗しました:%2$s
+unlock.error.restartRequired.message=金庫を解錠できません
+unlock.error.restartRequired.description=金庫のオプションからボリュームタイプを変更するか、Cryptomatorを再起動してください。
 ## Hub
 hub.noKeychain.message=デバイス キーにアクセスできません
 hub.noKeychain.description=ハブ金庫を解錠するには、キーチェーンが保護するデバイス キーが必要です。続行するには、"%s" を有効にし環境設定からキーチェーンを選択します。
@@ -154,12 +156,21 @@ hub.receive.message=応答を処理中…
 hub.receive.description=Cryptomator が Hub からの応答を受信、処理中です。しばらくお待ちください。
 ### Register Device
 hub.register.message=新しいデバイス
+hub.register.description=このデバイスからの最初のハブアクセスです。アカウントキーを使用して登録してください。
 hub.register.nameLabel=デバイス名
 hub.register.registerBtn=登録
 ### Register Device Legacy
+hub.register.legacy.occupiedMsg=この名前は既に使われています
+hub.register.legacy.description=このデバイスからの最初のハブへのアクセスです。登録してください。
 ### Registration Success
+hub.registerSuccess.message=デバイスが登録されました
+hub.registerSuccess.description=デバイスの登録が完了しました。続いて金庫のロックを解除することができます。
 hub.registerSuccess.unlockBtn=解錠
+hub.registerSuccess.legacy.description=金庫にアクセスするためには金庫のオーナーが端末を認証する必要があります。
 ### Registration Failed
+hub.registerFailed.message=デバイスの登録に失敗しました
+hub.registerFailed.description.generic=登録中にエラーが発生しました。エラーの詳細についてはアプリケーションログを参照してください。
+hub.registerFailed.description.deviceAlreadyExists=このデバイスは既に別のユーザーに登録されています。ユーザーアカウントを変更するか、別のデバイスを使用してください。
 ### Unauthorized
 hub.unauthorized.message=アクセスが拒否されました
 hub.unauthorized.description=お使いのデバイスはまだこの金庫にアクセスする権限がありません。金庫のオーナーに権限を与えてもらってください。

+ 33 - 1
src/main/resources/i18n/strings_nl.properties

@@ -47,6 +47,7 @@ addvaultwizard.new.nameInstruction=Kies een naam voor de kluis
 addvaultwizard.new.namePrompt=Kluisnaam
 ### Location
 addvaultwizard.new.locationInstruction=Waar moet Cryptomator de versleutelde bestanden van je kluis opslaan?
+addvaultwizard.new.locationLoading=Lokaal bestandssysteem controleren op standaard cloud opslag mappen…
 addvaultwizard.new.locationLabel=Opslaglocatie
 addvaultwizard.new.locationPrompt=…
 addvaultwizard.new.directoryPickerLabel=Andere locatie
@@ -141,6 +142,8 @@ unlock.error.customPath.description.hideawayNotDir=Het tijdelijk verborgen besta
 unlock.error.customPath.description.couldNotBeCleaned=Uw kluis kon niet worden gekoppeld aan het pad "%s". Probeer het opnieuw of kies een ander pad.
 unlock.error.customPath.description.notEmptyDir=Het aangepaste pad "%s" is geen lege map. Kies een lege map en probeer het opnieuw.
 unlock.error.customPath.description.generic=Je hebt een aangepast koppelpad voor deze kluis geselecteerd, maar gebruik ervan is mislukt met het bericht: %2$s
+unlock.error.restartRequired.message=Kan kluis niet ontgrendelen
+unlock.error.restartRequired.description=Wijzig het type volume in de opties voor de kluis of herstart Cryptomator.
 unlock.error.title=Ontgrendelen "%s" mislukt
 ## Hub
 hub.noKeychain.message=Geen toegang tot de apparaatsleutel
@@ -155,13 +158,22 @@ hub.receive.message=Antwoord verwerken…
 hub.receive.description=Cryptomator ontvangt en verwerkt de reactie van Hub. Een ogenblik geduld.
 ### Register Device
 hub.register.message=Nieuw apparaat
+hub.register.description=Dit is de eerste Hub toegang vanaf dit apparaat. Bevestig deze toegang met behulp van uw Account Key.
 hub.register.nameLabel=Apparaatnaam
 hub.register.invalidAccountKeyLabel=Ongeldige Account Key
 hub.register.registerBtn=Registreren
 ### Register Device Legacy
+hub.register.legacy.occupiedMsg=Naam al in gebruik
+hub.register.legacy.description=Dit is de eerste keer dat dit apparaat toegang heeft tot de Hub. Registreer dit aub.
 ### Registration Success
-hub.registerSuccess.unlockBtn=Ontgrendel
+hub.registerSuccess.message=Apparaat geregistreerd
+hub.registerSuccess.description=Uw apparaat is met succes geregistreerd. Y kunt nu doorgaan met het ontgrendelen van de kluis.
+hub.registerSuccess.unlockBtn=Ontgrendelen
+hub.registerSuccess.legacy.description=Om toegang te krijgen tot de kluis, moet je toestel bovendien worden gemachtigd door de eigenaar van de kluis.
 ### Registration Failed
+hub.registerFailed.message=Registratie van Apparaat mislukt
+hub.registerFailed.description.generic=Er is een fout gemaakt in het registratieproces. Kijk voor meer details in het logbestand van de applicatie.
+hub.registerFailed.description.deviceAlreadyExists=Dit apparaat is al geregistreerd voor een andere gebruiker. Probeer de account te wijzigen of gebruik een ander apparaat.
 ### Unauthorized
 hub.unauthorized.message=Toegang geweigerd
 hub.unauthorized.description=Uw apparaat is nog niet gemachtigd om toegang te krijgen tot deze kluis. Vraag de eigenaar van de kluis om toestemming te geven.
@@ -380,6 +392,7 @@ main.vaultDetail.unlockBtn=Ontgrendelen…
 main.vaultDetail.unlockNowBtn=Nu Ontgrendelen
 main.vaultDetail.optionsBtn=Kluis-instellingen
 main.vaultDetail.passwordSavedInKeychain=Wachtwoord opgeslagen
+main.vaultDetail.share=Delen...
 ### Unlocked
 main.vaultDetail.unlockedStatus=ONTGRENDELD
 main.vaultDetail.accessLocation=De inhoud van uw kluis is hier toegankelijk:
@@ -445,6 +458,7 @@ vaultOptions.mount.mountPoint.custom=Gebruik gekozen map
 vaultOptions.mount.mountPoint.directoryPickerButton=Kies…
 vaultOptions.mount.mountPoint.directoryPickerTitle=Selecteer een map
 vaultOptions.mount.volumeType.default=Standaard (%s)
+vaultOptions.mount.volumeType.restartRequired=Om dit type volume te kunnen gebruiken, moet Cryptomator opnieuw worden opgestart.
 vaultOptions.mount.volume.tcp.port=TCP-poort
 vaultOptions.mount.volume.type=Volumetype
 ## Master Key
@@ -519,3 +533,21 @@ updateReminder.yesOnce=Ja, Eenmaal
 updateReminder.yesAutomatically=Ja, automatisch
 
 # Share Vault
+shareVault.title=Kluis delen
+shareVault.message=Wilt u uw kluis met anderen delen?
+shareVault.description=Wees altijd voorzichtig bij het delen van je kluis met andere mensen. Kortom, volg deze stappen:
+shareVault.instruction.1=1. Deel toegang van de versleutelde kluis map via de cloud opslag.
+shareVault.instruction.2=2. Deel het wachtwoord van de kluis op een veilige manier.
+shareVault.remarkBestPractices=Kijk voor meer informatie naar de suggesties voor beste praktijken in onze documenten.
+shareVault.docsTooltip=Open de documentatie om meer te leren over het delen van kluizen.
+shareVault.hubAd.description=De veilige manier om in teams te werken
+shareVault.hubAd.keyManagement=• Zero-knowledge sleutelbeheer
+shareVault.hubAd.authentication=• Sterke authenticatie
+shareVault.hubAd.encryption=• End-to-end versleuteling
+shareVault.visitHub=Bezoek Cryptomator Hub
+
+shareVault.hub.message=Hoe een Hub kluis delen
+shareVault.hub.description=Om de inhoud van de kluis te delen met een ander teamlid, moet u twee stappen uitvoeren:
+shareVault.hub.instruction.1=1. Deel toegang van de versleutelde kluismap via de cloud opslag.
+shareVault.hub.instruction.2=2. Geef teamlid toegang in Cryptomator Hub.
+shareVault.hub.openHub=Open Cryptomator Hub

+ 32 - 0
src/main/resources/i18n/strings_pt.properties

@@ -47,6 +47,7 @@ addvaultwizard.new.nameInstruction=Escolha um nome para o cofre
 addvaultwizard.new.namePrompt=Nome do Cofre
 ### Location
 addvaultwizard.new.locationInstruction=Onde deve o Cryptomator armazenar os arquivos criptografados do cofre?
+addvaultwizard.new.locationLoading=Verificando o sistema de arquivos por diretórios padrão de armazenamento na nuvem…
 addvaultwizard.new.locationLabel=Local de armazenamento
 addvaultwizard.new.locationPrompt=…
 addvaultwizard.new.directoryPickerLabel=Outro Local
@@ -141,6 +142,8 @@ unlock.error.customPath.description.hideawayNotDir=O arquivo oculto temporário
 unlock.error.customPath.description.couldNotBeCleaned=Não foi possível montar o seu cofre no caminho "%s". Tente novamente ou escolha um caminho diferente.
 unlock.error.customPath.description.notEmptyDir=O caminho de montagem personalizado "%s" não é uma pasta vazia. Escolha uma pasta vazia e tente novamente.
 unlock.error.customPath.description.generic=Selecionou um caminho de montagem personalizado para este cofre, mas o seu uso falhou com a mensagem: %2$s
+unlock.error.restartRequired.message=Não foi possível desbloquear o cofre
+unlock.error.restartRequired.description=Altere o tipo de volume nas opções do cofre ou reinicie o Cryptomator.
 unlock.error.title=Desbloqueio "%s" falhou
 ## Hub
 hub.noKeychain.message=Não foi possível aceder à chave do dispositivo
@@ -155,13 +158,22 @@ hub.receive.message=A processar a resposta…
 hub.receive.description=Cryptomator está a receber e a processar a resposta do Hub. Por favor aguarde.
 ### Register Device
 hub.register.message=Novo dispositivo
+hub.register.description=Este é o primeiro acesso do Hub a partir deste dispositivo. Por favor, autorize-o usando a sua chave de conta.
 hub.register.nameLabel=Nome do dispositivo
 hub.register.invalidAccountKeyLabel=Chave da conta inválida
 hub.register.registerBtn=Registo
 ### Register Device Legacy
+hub.register.legacy.occupiedMsg=Nome já em utilização
+hub.register.legacy.description=Este é o primeiro acesso ao Hub a partir deste dispositivo. Por favor, registe-o.
 ### Registration Success
+hub.registerSuccess.message=Dispositivo registado
+hub.registerSuccess.description=O seu dispositivo foi registado com sucesso. Pode continuar e desbloquear o cofre.
 hub.registerSuccess.unlockBtn=Desbloquear
+hub.registerSuccess.legacy.description=Para aceder ao cofre, o seu dispositivo precisa de ser autorizado pelo proprietário do cofre.
 ### Registration Failed
+hub.registerFailed.message=Registo do dispositivo falhou
+hub.registerFailed.description.generic=Ocorreu um erro no processo de registo. Para mais informação, ver os registos da aplicação.
+hub.registerFailed.description.deviceAlreadyExists=Este dispositivo já está registado para um utilizador diferente. Tente alterar a conta de utilizador ou use um dispositivo diferente.
 ### Unauthorized
 hub.unauthorized.message=Acesso negado
 hub.unauthorized.description=O seu dispositivo ainda não foi autorizado a aceder a este cofre. Peça ao proprietário do cofre para o autorizar.
@@ -380,6 +392,7 @@ main.vaultDetail.unlockBtn=Desbloquear…
 main.vaultDetail.unlockNowBtn=Desbloquear agora
 main.vaultDetail.optionsBtn=Opções do Cofre
 main.vaultDetail.passwordSavedInKeychain=Palavra-passe guardada
+main.vaultDetail.share=Partilhar…
 ### Unlocked
 main.vaultDetail.unlockedStatus=DESBLOQUEADO
 main.vaultDetail.accessLocation=O conteúdo do seu cofre está acessível aqui:
@@ -445,6 +458,7 @@ vaultOptions.mount.mountPoint.custom=Usar diretório escolhido
 vaultOptions.mount.mountPoint.directoryPickerButton=Escolher…
 vaultOptions.mount.mountPoint.directoryPickerTitle=Escolher um diretório
 vaultOptions.mount.volumeType.default=Predefinição (%1$s)
+vaultOptions.mount.volumeType.restartRequired=Para usar este tipo de volume, o Cryptomator precisa de ser reiniciado.
 vaultOptions.mount.volume.tcp.port=Porta TCP
 vaultOptions.mount.volume.type=Tipo de Volume
 ## Master Key
@@ -519,3 +533,21 @@ updateReminder.yesOnce=Sim, Uma Vez
 updateReminder.yesAutomatically=Sim, Automaticamente
 
 # Share Vault
+shareVault.title=Partilhar cofre
+shareVault.message=Quer partilhar o seu cofre com outros?
+shareVault.description=Tenha sempre cuidado ao partilhar o seu cofre com outras pessoas. Resumindo, siga esses passos:
+shareVault.instruction.1=1. Partilhe o acesso à pasta encriptada do cofre via armazenamento na nuvem.
+shareVault.instruction.2=2. Partilhe a palavra-passe do cofre de forma segura.
+shareVault.remarkBestPractices=Para mais informações, verifique as sugestões de melhores práticas, nos nossos documentos.
+shareVault.docsTooltip=Abra a documentação para saber mais sobre partilha de cofres.
+shareVault.hubAd.description=A maneira segura de trabalhar em equipa
+shareVault.hubAd.keyManagement=• Gestão de chaves de conhecimento-zero
+shareVault.hubAd.authentication=• Autenticação forte
+shareVault.hubAd.encryption=• Encriptação ponta-a-ponta
+shareVault.visitHub=Visitar o Hub Cryptomator
+
+shareVault.hub.message=Como partilhar um cofre do Hub
+shareVault.hub.description=Para partilhar o conteúdo do cofre com outro membro da equipa, precisa executar duas etapas:
+shareVault.hub.instruction.1=1. Partilhe o acesso à pasta encriptada do cofre via armazenamento na nuvem.
+shareVault.hub.instruction.2=2. Conceder acesso ao membro da equipe no Hub Cryptomator.
+shareVault.hub.openHub=Abrir Hub do Cryptomator

+ 6 - 1
src/main/resources/i18n/strings_ru.properties

@@ -544,5 +544,10 @@ shareVault.hubAd.description=Безопасный способ работы в 
 shareVault.hubAd.keyManagement=• Управление ключами без разглашения
 shareVault.hubAd.authentication=• Надёжная аутентификация
 shareVault.hubAd.encryption=• Сквозное шифрование
+shareVault.visitHub=Посетить хаб Cryptomator
 
-shareVault.hub.instruction.1=1. Делитесь доступом к зашифрованной папке хранилища через облако.
+shareVault.hub.message=Как поделиться хранилищем в хабе
+shareVault.hub.description=Чтобы поделиться содержимым хранилища с другим членом команды:
+shareVault.hub.instruction.1=1. Делитесь доступом к зашифрованной папке хранилища через облако.
+shareVault.hub.instruction.2=2. Предоставьте доступ члену команды в хабе Cryptomator.
+shareVault.hub.openHub=Открыть хаб Cryptomator

+ 8 - 0
src/main/resources/i18n/strings_sk.properties

@@ -141,6 +141,7 @@ unlock.error.customPath.description.hideawayNotDir=Dočasne, skrytý súbor "%3$
 unlock.error.customPath.description.couldNotBeCleaned=Váš trezor sa nepodarilo pripojiť na cestu "%s". Skúste to prosím znova alebo vyberte inú cestu.
 unlock.error.customPath.description.notEmptyDir=Vlastná cesta pripojenia "%s" nie je prázdny priečinok. Vyberte prázdny priečinok a skúste to znova.
 unlock.error.customPath.description.generic=Pre tento trezor ste vybrali vlastnú cestu pripojenia, ale jej použitie zlyhalo so správou: %2$s
+unlock.error.restartRequired.message=Nie je možné odomknúť trezor
 unlock.error.title=Odomknutie "%s" zlyhalo
 ## Hub
 hub.noKeychain.message=Nemôžem pristúpiť ku kľúču zariadenia
@@ -159,9 +160,12 @@ hub.register.nameLabel=Názov zariadenia
 hub.register.invalidAccountKeyLabel=Neplatný kľúč účtu
 hub.register.registerBtn=Registrovať
 ### Register Device Legacy
+hub.register.legacy.occupiedMsg=Názov sa už používa
 ### Registration Success
+hub.registerSuccess.message=Zariadenie registrované
 hub.registerSuccess.unlockBtn=Odomknúť
 ### Registration Failed
+hub.registerFailed.message=Registrácia zariadenia zlyhala
 ### Unauthorized
 hub.unauthorized.message=Prístup zamietnutý
 hub.unauthorized.description=Vaše zaradenie zatiaľ ešte nebolo autorizované pre pristúp tohto trezora. Požiadajte majiteľa trezora o autorizovanie.
@@ -380,6 +384,7 @@ main.vaultDetail.unlockBtn=Odomknúť…
 main.vaultDetail.unlockNowBtn=Odomknúť teraz
 main.vaultDetail.optionsBtn=Nastavenia trezora
 main.vaultDetail.passwordSavedInKeychain=Heslo uložené
+main.vaultDetail.share=Zdieľať…
 ### Unlocked
 main.vaultDetail.unlockedStatus=Odomknutý
 main.vaultDetail.accessLocation=Obsah Vášho trezora je dostupný tu:
@@ -519,3 +524,6 @@ updateReminder.yesOnce=Áno, raz
 updateReminder.yesAutomatically=Áno, automaticky
 
 # Share Vault
+shareVault.title=Zdielať trezor
+shareVault.hubAd.authentication=* Silná autentifikácia
+shareVault.hubAd.encryption=* Šifrovanie end-to-end

+ 29 - 0
src/main/resources/i18n/strings_sv.properties

@@ -158,13 +158,22 @@ hub.receive.message=Bearbetar svar…
 hub.receive.description=Cryptomator tar emot och bearbetar svaret från Hub. Vänligen vänta.
 ### Register Device
 hub.register.message=Ny enhet
+hub.register.description=Detta är den första navåtkomsten från den här enheten. Vänligen registrera enheten med hjälp av din kontonyckel.
 hub.register.nameLabel=Enhetsnamn
 hub.register.invalidAccountKeyLabel=Ogiltig kontonyckel
 hub.register.registerBtn=Skapa konto
 ### Register Device Legacy
+hub.register.legacy.occupiedMsg=Namnet används redan
+hub.register.legacy.description=Detta är första navåtkomsten från den här enheten. Vänligen registrera den.
 ### Registration Success
+hub.registerSuccess.message=Enhet registrerad
+hub.registerSuccess.description=Din enhet är registrerad. Du kan nu fortsätta att låsa upp valvet.
 hub.registerSuccess.unlockBtn=Lås upp
+hub.registerSuccess.legacy.description=För att komma åt valvet måste din enhet godkännas av valvägaren.
 ### Registration Failed
+hub.registerFailed.message=Enhetsregistrering misslyckades
+hub.registerFailed.description.generic=Ett fel uppstod i registreringsprocessen. För mer information, titta in i programloggen.
+hub.registerFailed.description.deviceAlreadyExists=Denna enhet är redan registrerad för en annan användare. Försök att ändra användarkontot eller använda en annan enhet.
 ### Unauthorized
 hub.unauthorized.message=Åtkomst nekad
 hub.unauthorized.description=Din enhet har ännu inte behörighet att komma åt detta valv. Be valvägaren att godkänna det.
@@ -383,6 +392,7 @@ main.vaultDetail.unlockBtn=Lås upp…
 main.vaultDetail.unlockNowBtn=Lås upp nu
 main.vaultDetail.optionsBtn=Valv-inställningar
 main.vaultDetail.passwordSavedInKeychain=Lösenord sparat
+main.vaultDetail.share=Dela…
 ### Unlocked
 main.vaultDetail.unlockedStatus=UPPLÅST
 main.vaultDetail.accessLocation=Valvets innehåll kan nås härifrån:
@@ -448,6 +458,7 @@ vaultOptions.mount.mountPoint.custom=Använd vald mapp
 vaultOptions.mount.mountPoint.directoryPickerButton=Välj…
 vaultOptions.mount.mountPoint.directoryPickerTitle=Välj mapp
 vaultOptions.mount.volumeType.default=Standard (%s)
+vaultOptions.mount.volumeType.restartRequired=För att använda denna volymtyp måste Cryptomator startas om.
 vaultOptions.mount.volume.tcp.port=TCP-port
 vaultOptions.mount.volume.type=Volymtyp
 ## Master Key
@@ -522,3 +533,21 @@ updateReminder.yesOnce=Ja, en gång
 updateReminder.yesAutomatically=Ja, automatiskt
 
 # Share Vault
+shareVault.title=Dela valv
+shareVault.message=Vill du dela ditt valv med andra?
+shareVault.description=Var alltid försiktig när du delar ditt valv med andra människor. Kort sagt, följ dessa steg:
+shareVault.instruction.1=1. Dela åtkomst till den krypterade valvmappen via molnlagring.
+shareVault.instruction.2=2. Dela valvlösenordet på ett säkert sätt.
+shareVault.remarkBestPractices=För mer information, kolla in förslag för god sed i våra dokument.
+shareVault.docsTooltip=Öppna dokumentationen för att lära dig mer om att dela valv.
+shareVault.hubAd.description=Det säkra sättet att arbeta i grupper
+shareVault.hubAd.keyManagement=• Nyckelhantering med noll-kunskap
+shareVault.hubAd.authentication=• Stark autentisering
+shareVault.hubAd.encryption=• Slutpunktskryptering
+shareVault.visitHub=Besök Cryptomatornavet
+
+shareVault.hub.message=Hur man delar ett navvalv
+shareVault.hub.description=För att kunna dela valvinnehållet med en annan gruppmedlem måste du utföra två steg:
+shareVault.hub.instruction.1=1. Dela åtkomst till den krypterade valvmappen via molnlagring.
+shareVault.hub.instruction.2=2. Ge åtkomst till gruppmedlemmen i Cryptomatornavet.
+shareVault.hub.openHub=Öppna kryptomatornav

+ 32 - 0
src/main/resources/i18n/strings_zh.properties

@@ -47,6 +47,7 @@ addvaultwizard.new.nameInstruction=为保险库创建一个名称
 addvaultwizard.new.namePrompt=保险库名称
 ### Location
 addvaultwizard.new.locationInstruction=Cryptomator 应该在哪里存储您保险库的加密文件?
+addvaultwizard.new.locationLoading=正在检查本地文件系统默认云存储目录…
 addvaultwizard.new.locationLabel=存储位置
 addvaultwizard.new.locationPrompt=…
 addvaultwizard.new.directoryPickerLabel=自定义位置
@@ -141,6 +142,8 @@ unlock.error.customPath.description.hideawayNotDir=用于解锁的临时隐藏
 unlock.error.customPath.description.couldNotBeCleaned=无法将您的保险库挂载到路径 "%s"。请重试或选择其他路径。
 unlock.error.customPath.description.notEmptyDir=自定义挂载路径 "%s" 不是一个空文件夹。请选择一个空文件夹并重试。
 unlock.error.customPath.description.generic=您为此保险库选择了自定义挂载路径,但使用它时出现了错误信息:%2$s。
+unlock.error.restartRequired.message=无法解锁保险库
+unlock.error.restartRequired.description=请在保险库选项内更改卷类型或重启 Cryptomator
 unlock.error.title=解锁“%s”失败
 ## Hub
 hub.noKeychain.message=无法访问设备密钥
@@ -155,13 +158,22 @@ hub.receive.message=正在处理响应…
 hub.receive.description=Cryptomator 正在接收和处理来自 Hub 的响应,请稍等
 ### Register Device
 hub.register.message=新设备
+hub.register.description=这是此设备首次访问 Hub。请使用您的账户密钥进行注册。
 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.description=您的设备已成功注册。现在您可以继续解锁保险库。
 hub.registerSuccess.unlockBtn=解锁
+hub.registerSuccess.legacy.description=若要访问保险库,设备保险库所有者额外的授权。
 ### Registration Failed
+hub.registerFailed.message=设备注册失败
+hub.registerFailed.description.generic=注册过程中出现错误。详情请查看应用程序日志。
+hub.registerFailed.description.deviceAlreadyExists=此设备已被注册给另一位用户。请尝试更改用户帐户或使用别的设备。
 ### Unauthorized
 hub.unauthorized.message=拒绝访问
 hub.unauthorized.description=您的设备尚未授权访问此保险库,请联系保险库所有者,
@@ -380,6 +392,7 @@ main.vaultDetail.unlockBtn=解锁…
 main.vaultDetail.unlockNowBtn=立即解锁
 main.vaultDetail.optionsBtn=保险库选项
 main.vaultDetail.passwordSavedInKeychain=密码已保存
+main.vaultDetail.share=共享…
 ### Unlocked
 main.vaultDetail.unlockedStatus=已解锁
 main.vaultDetail.accessLocation=您的保险库内容在此处访问:
@@ -445,6 +458,7 @@ 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
@@ -519,3 +533,21 @@ updateReminder.yesOnce=是的,仅此次
 updateReminder.yesAutomatically=是的,自动
 
 # Share Vault
+shareVault.title=共享保险库
+shareVault.message=是否要与他人共享你的保险库?
+shareVault.description=与他人共享保险库时请务必小心。简而言之,请遵循以下步骤:
+shareVault.instruction.1=1:通过云存储共享加密保险库文件夹的访问权限。
+shareVault.instruction.2=2:通过安全的方式共享保险库密码。
+shareVault.remarkBestPractices=有关更多信息,请查看我们文档中的最佳实践建议。
+shareVault.docsTooltip=打开文档以了解有关共享保险库的更多信息。
+shareVault.hubAd.description=安全的团队合作方式
+shareVault.hubAd.keyManagement=• 零知识密钥管理
+shareVault.hubAd.authentication=• 强认证
+shareVault.hubAd.encryption=• 端到端加密
+shareVault.visitHub=访问 Cryptomator Hub
+
+shareVault.hub.message=如何共享 Hub 保险库
+shareVault.hub.description=为了与其他团队成员共享保险库内容,您必须执行以下两步:
+shareVault.hub.instruction.1=1:通过云存储共享加密保险库文件夹的访问权限。
+shareVault.hub.instruction.2=2:在 Cryptomator Hub 内授予团队成员访问权限。
+shareVault.hub.openHub=打开 Cryptomator Hub