diff --git a/.reuse/dep5 b/.reuse/dep5 deleted file mode 100644 index 227d0b182..000000000 --- a/.reuse/dep5 +++ /dev/null @@ -1,163 +0,0 @@ -Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: CryptPad -Upstream-Contact: XWiki -Source: https://cryptpad.org - -# Sample paragraph, commented out: -# -# Files: src/* -# Copyright: $YEAR $NAME <$CONTACT> -# License: ... - -Files: *.png -Copyright: 2023 XWiki CryptPad Team and contributors -License: AGPL-3.0-or-later - -Files: *.json -Copyright: 2023 XWiki CryptPad Team and contributors -License: AGPL-3.0-or-later - -Files: .jshintignore -Copyright: 2023 XWiki CryptPad Team and contributors -License: AGPL-3.0-or-later - -Files: .jshintrc -Copyright: 2023 XWiki CryptPad Team and contributors -License: AGPL-3.0-or-later - -Files: .stylelintrc.js -Copyright: 2023 XWiki CryptPad Team and contributors -License: AGPL-3.0-or-later - -Files: scripts/tests/test-data/* -Copyright: 2024 XWiki CryptPad Team and contributors -License: AGPL-3.0-or-later - -## Dependencies - -Files: www/common/theme/* -Copyright: 2017 by Marijn Haverbeke and others -License: MIT - -Files: www/lib/mermaid/* -Copyright: (c) 2014 - 2021 Knut Sveidqvist -License: MIT - -Files: www/lib/calendar/moment.min.js -Copyright: (c) JS Foundation and other contributors -License: MIT - -Files: www/lib/pdfjs/* -Copyright: 2017 Mozilla Foundation -License: Apache-2.0 - -Files: www/lib/codemirror-extra-modes/asciidoc/* -Copyright: (c) 2015, the Asciidoctor Project -License: BSD-3-Clause - -Files: www/lib/datepicker/* -Copyright: 2017 Gregory Petrosyan -License: MIT - -Files: www/lib/diff-dom/* -Copyright: Johannes Wilm, Fidus Writer -License: LGPL-3.0-only - -Files: www/lib/fabric-history.min.js -Copyright: 2008-2015 Printio (Juriy Zaytsev, Maxim Chernyak) -License: MIT - -Files: www/lib/fabric.min.js -Copyright: 2008-2015 Printio (Juriy Zaytsev, Maxim Chernyak) -License: MIT - -Files: www/lib/pdfjs/* -Copyright: 2012 Mozilla Foundation -License: Apache-2.0 - -Files: www/lib/qrcode.min.js -Copyright: Sangmin Shim -License: MIT - -Files: www/lib/rangy/rangy-core.min.js -Copyright: 2015, Tim Down -License: MIT - -Files: www/lib/textFit.min.js -Copyright: 11/2014 by STRML (strml.github.com) -License: MIT - -Files: www/lib/tippy/* -Copyright: 2017 atomiks -License: MIT - -Files: www/lib/turndown.browser.umd.js -Copyright: 2017 Dom Christie -License: MIT - -Files: www/lib/markmap/* -Copyright: 2015 Jakub Dundalek -License: MIT - -Files: www/pad/mathjax/* -Copyright: 2009-2018 The MathJax Consortium -License: Apache-2.0 - -Files: www/pad/wordcount/* -Copyright: Ingo Herbote -License: MIT - -### same as CKEditor -Files: www/pad/wysiwygarea-plugin.js -Copyright: 2003-2017, CKSource - Frederico Knabben. All rights reserved -License: GPL-2.0-or-later - -Files: www/pad/icons/* -Copyright: unknown -License: GPL-2.0-or-later - -## OnlyOffice - -Files: www/common/onlyoffice/AllFonts.js -Copyright: Ascensio System Limited 2010-2022 -License: AGPL-3.0-or-later - -Files: www/common/onlyoffice/fonts_thumbnail.png -Copyright: Ascensio System Limited 2010-2022 -License: AGPL-3.0-or-later - -Files: www/common/onlyoffice/fonts_thumbnail@2x.png -Copyright: Ascensio System Limited 2010-2022 -License: AGPL-3.0-or-later - -Files: www/common/onlyoffice/plugins.json -Copyright: Ascensio System Limited 2010-2022 -License: AGPL-3.0-or-later - -Files: www/common/onlyoffice/v1/* -Copyright: Ascensio System Limited 2010-2022 -License: AGPL-3.0-or-later - -Files: www/common/onlyoffice/v2b/* -Copyright: Ascensio System Limited 2010-2022 -License: AGPL-3.0-or-later - -Files: www/common/onlyoffice/v4/* -Copyright: Ascensio System Limited 2010-2022 -License: AGPL-3.0-or-later - -Files: www/common/onlyoffice/v5/* -Copyright: Ascensio System Limited 2010-2022 -License: AGPL-3.0-or-later - -Files: www/common/onlyoffice/v6/* -Copyright: Ascensio System Limited 2010-2022 -License: AGPL-3.0-or-later - -Files: www/common/onlyoffice/v7/* -Copyright: Ascensio System Limited 2010-2022 -License: AGPL-3.0-or-later - -Files: www/common/onlyoffice/x2t/* -Copyright: Ascensio System Limited 2010-2022 -License: AGPL-3.0-or-later diff --git a/REUSE.toml b/REUSE.toml new file mode 100644 index 000000000..721bafd70 --- /dev/null +++ b/REUSE.toml @@ -0,0 +1,226 @@ +version = 1 +SPDX-PackageName = "CryptPad" +SPDX-PackageSupplier = "XWiki " +SPDX-PackageDownloadLocation = "https://cryptpad.org" + +[[annotations]] +path = "**.png" +precedence = "aggregate" +SPDX-FileCopyrightText = "2023 XWiki CryptPad Team and contributors" +SPDX-License-Identifier = "AGPL-3.0-or-later" + +[[annotations]] +path = "**.json" +precedence = "aggregate" +SPDX-FileCopyrightText = "2023 XWiki CryptPad Team and contributors" +SPDX-License-Identifier = "AGPL-3.0-or-later" + +[[annotations]] +path = ".jshintignore" +precedence = "aggregate" +SPDX-FileCopyrightText = "2023 XWiki CryptPad Team and contributors" +SPDX-License-Identifier = "AGPL-3.0-or-later" + +[[annotations]] +path = ".jshintrc" +precedence = "aggregate" +SPDX-FileCopyrightText = "2023 XWiki CryptPad Team and contributors" +SPDX-License-Identifier = "AGPL-3.0-or-later" + +[[annotations]] +path = ".stylelintrc.js" +precedence = "aggregate" +SPDX-FileCopyrightText = "2023 XWiki CryptPad Team and contributors" +SPDX-License-Identifier = "AGPL-3.0-or-later" + +[[annotations]] +path = "scripts/tests/test-data/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "2024 XWiki CryptPad Team and contributors" +SPDX-License-Identifier = "AGPL-3.0-or-later" + +[[annotations]] +path = "www/common/theme/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "2017 by Marijn Haverbeke and others" +SPDX-License-Identifier = "MIT" + +[[annotations]] +path = "www/lib/mermaid/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "(c) 2014 - 2021 Knut Sveidqvist" +SPDX-License-Identifier = "MIT" + +[[annotations]] +path = "www/lib/calendar/moment.min.js" +precedence = "aggregate" +SPDX-FileCopyrightText = "(c) JS Foundation and other contributors" +SPDX-License-Identifier = "MIT" + +[[annotations]] +path = "www/lib/pdfjs/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "2017 Mozilla Foundation" +SPDX-License-Identifier = "Apache-2.0" + +[[annotations]] +path = "www/lib/codemirror-extra-modes/asciidoc/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "(c) 2015, the Asciidoctor Project" +SPDX-License-Identifier = "BSD-3-Clause" + +[[annotations]] +path = "www/lib/datepicker/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "2017 Gregory Petrosyan" +SPDX-License-Identifier = "MIT" + +[[annotations]] +path = "www/lib/diff-dom/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "Johannes Wilm, Fidus Writer" +SPDX-License-Identifier = "LGPL-3.0-only" + +[[annotations]] +path = "www/lib/fabric-history.min.js" +precedence = "aggregate" +SPDX-FileCopyrightText = "2008-2015 Printio (Juriy Zaytsev, Maxim Chernyak)" +SPDX-License-Identifier = "MIT" + +[[annotations]] +path = "www/lib/fabric.min.js" +precedence = "aggregate" +SPDX-FileCopyrightText = "2008-2015 Printio (Juriy Zaytsev, Maxim Chernyak)" +SPDX-License-Identifier = "MIT" + +[[annotations]] +path = "www/lib/pdfjs/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "2012 Mozilla Foundation" +SPDX-License-Identifier = "Apache-2.0" + +[[annotations]] +path = "www/lib/qrcode.min.js" +precedence = "aggregate" +SPDX-FileCopyrightText = "Sangmin Shim" +SPDX-License-Identifier = "MIT" + +[[annotations]] +path = "www/lib/rangy/rangy-core.min.js" +precedence = "aggregate" +SPDX-FileCopyrightText = "2015, Tim Down" +SPDX-License-Identifier = "MIT" + +[[annotations]] +path = "www/lib/textFit.min.js" +precedence = "aggregate" +SPDX-FileCopyrightText = "11/2014 by STRML (strml.github.com)" +SPDX-License-Identifier = "MIT" + +[[annotations]] +path = "www/lib/tippy/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "2017 atomiks" +SPDX-License-Identifier = "MIT" + +[[annotations]] +path = "www/lib/turndown.browser.umd.js" +precedence = "aggregate" +SPDX-FileCopyrightText = "2017 Dom Christie" +SPDX-License-Identifier = "MIT" + +[[annotations]] +path = "www/lib/markmap/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "2015 Jakub Dundalek" +SPDX-License-Identifier = "MIT" + +[[annotations]] +path = "www/pad/mathjax/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "2009-2018 The MathJax Consortium" +SPDX-License-Identifier = "Apache-2.0" + +[[annotations]] +path = "www/pad/wordcount/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "Ingo Herbote" +SPDX-License-Identifier = "MIT" + +[[annotations]] +path = "www/pad/wysiwygarea-plugin.js" +precedence = "aggregate" +SPDX-FileCopyrightText = "2003-2017, CKSource - Frederico Knabben. All rights reserved" +SPDX-License-Identifier = "GPL-2.0-or-later" + +[[annotations]] +path = "www/pad/icons/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "unknown" +SPDX-License-Identifier = "GPL-2.0-or-later" + +[[annotations]] +path = "www/common/onlyoffice/AllFonts.js" +precedence = "aggregate" +SPDX-FileCopyrightText = "Ascensio System Limited 2010-2022" +SPDX-License-Identifier = "AGPL-3.0-or-later" + +[[annotations]] +path = "www/common/onlyoffice/fonts_thumbnail.png" +precedence = "aggregate" +SPDX-FileCopyrightText = "Ascensio System Limited 2010-2022" +SPDX-License-Identifier = "AGPL-3.0-or-later" + +[[annotations]] +path = "www/common/onlyoffice/fonts_thumbnail@2x.png" +precedence = "aggregate" +SPDX-FileCopyrightText = "Ascensio System Limited 2010-2022" +SPDX-License-Identifier = "AGPL-3.0-or-later" + +[[annotations]] +path = "www/common/onlyoffice/plugins.json" +precedence = "aggregate" +SPDX-FileCopyrightText = "Ascensio System Limited 2010-2022" +SPDX-License-Identifier = "AGPL-3.0-or-later" + +[[annotations]] +path = "www/common/onlyoffice/v1/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "Ascensio System Limited 2010-2022" +SPDX-License-Identifier = "AGPL-3.0-or-later" + +[[annotations]] +path = "www/common/onlyoffice/v2b/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "Ascensio System Limited 2010-2022" +SPDX-License-Identifier = "AGPL-3.0-or-later" + +[[annotations]] +path = "www/common/onlyoffice/v4/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "Ascensio System Limited 2010-2022" +SPDX-License-Identifier = "AGPL-3.0-or-later" + +[[annotations]] +path = "www/common/onlyoffice/v5/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "Ascensio System Limited 2010-2022" +SPDX-License-Identifier = "AGPL-3.0-or-later" + +[[annotations]] +path = "www/common/onlyoffice/v6/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "Ascensio System Limited 2010-2022" +SPDX-License-Identifier = "AGPL-3.0-or-later" + +[[annotations]] +path = "www/common/onlyoffice/v7/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "Ascensio System Limited 2010-2022" +SPDX-License-Identifier = "AGPL-3.0-or-later" + +[[annotations]] +path = "www/common/onlyoffice/x2t/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "Ascensio System Limited 2010-2022" +SPDX-License-Identifier = "AGPL-3.0-or-later" diff --git a/customize.dist/messages.js b/customize.dist/messages.js index abf96dbc0..a28190005 100755 --- a/customize.dist/messages.js +++ b/customize.dist/messages.js @@ -134,35 +134,7 @@ define(req, function(AppConfig, Default, Language) { } }; - Messages.addItemBottom = 'Add item to bottom of the board'; // XXX or 'Add card..' - Messages.addItemTop = 'Add item to top of the board'; // XXX or 'Add card..' - - Messages.admin_logoSize_error = "The logo size is too large"; // XXX - Messages.limit_error = "Please enter a valid number"; // XXX - Messages.positiveNumber_error = "Please enter a positive number"; // XXX - Messages.answerType_error = "Please select how to answer the form"; // XXX - - // XXX - Messages.admin_cat_admins = "Administrators"; - Messages.admin_admin = "Admin"; - Messages.admin_listAdminsTitle = "Current administrators"; - Messages.admin_listAdminsHint = "View and remove administrators"; - Messages.admin_addAdminsTitle = "Add administrators"; - Messages.admin_addAdminsHint = "Add administrators from their public key or from your contacts list"; - Messages.admin_addAdminsAdd = "Promote a contact to admin"; - Messages.admin_addKeyLabel = "Add an admin using their public key"; - Messages.admin_errorAddKeyLabel = "Add a valid public key"; - Messages.admin_errorAddAdmins = "Pick a contact to promote to admin"; - - Messages.admin_listName = "Admin name"; - Messages.admin_listKey = "Admin key"; - Messages.admin_listAction = "Remove admin rights"; - - Messages.admin_listHardcoded = "Admin added into config.js. Can only be removed by editing the config file."; - Messages.admin_listConfirm = "Are you sure you want to remove the admin rights of this user?"; - - Messages.fm_link_invalid = "Please provide a valid URL"; // XXX - Messages.skipLink = "Skip to main content"; // XXX + return Messages; diff --git a/customize.dist/src/less2/include/colortheme-dark.less b/customize.dist/src/less2/include/colortheme-dark.less index 1f5aee211..ed31b18b6 100644 --- a/customize.dist/src/less2/include/colortheme-dark.less +++ b/customize.dist/src/less2/include/colortheme-dark.less @@ -162,10 +162,11 @@ // Buttons @cp_buttons-fg: @cryptpad_color_brand_300; @cp_buttons-hover: @cryptpad_color_brand_fadest; -@cp_buttons-default: @cryptpad_color_grey_700; @cp_buttons-default-color: @cryptpad_text_col; -@cp_buttons-default-alt-color: @cryptpad_color_grey_700; -@cp_buttons-default-border: @cryptpad_text_col; +@cp_buttons-default-bg: @cryptpad_text_col; +@cp_buttons-default-fg: @cryptpad_color_grey_900; +@cp_buttons-default-alt-bg: @cryptpad_color_grey_900; +@cp_buttons-default-alt-fg: @cryptpad_text_col; @cp_buttons-red: #E55236; @cp_buttons-red-text: @cryptpad_color_light_red; @cp_buttons-red-color: #FFF; diff --git a/customize.dist/src/less2/include/colortheme.less b/customize.dist/src/less2/include/colortheme.less index ece9f6fe0..316f1d06c 100644 --- a/customize.dist/src/less2/include/colortheme.less +++ b/customize.dist/src/less2/include/colortheme.less @@ -161,10 +161,11 @@ // Buttons @cp_buttons-fg: @cryptpad_color_brand; @cp_buttons-hover: @cryptpad_color_brand_fadest; -@cp_buttons-default: #CCC; @cp_buttons-default-color: @cryptpad_text_col; -@cp_buttons-default-border: @cryptpad_text_col; -@cp_buttons-default-alt-color: @cryptpad_color_grey_50; +@cp_buttons-default-bg: @cryptpad_color_grey_200; +@cp_buttons-default-fg: @cryptpad_text_col; +@cp_buttons-default-alt-bg: @cryptpad_color_white; +@cp_buttons-default-alt-fg: @cryptpad_text_col; @cp_buttons-red: #E55236; @cp_buttons-red-text: @cp_buttons-red; @cp_buttons-red-color: #FFF; diff --git a/customize.dist/src/less2/include/forms.less b/customize.dist/src/less2/include/forms.less index 745d24ab0..e2e96f4a3 100644 --- a/customize.dist/src/less2/include/forms.less +++ b/customize.dist/src/less2/include/forms.less @@ -191,22 +191,21 @@ } &.btn-default { - border-color: @cp_buttons-default-border; - color: @cp_buttons-default-color; + background-color: @cp_buttons-default-bg; + color: @cp_buttons-default-fg; + border-color: @cp_buttons-default-bg; &:hover, &:not(:disabled):active, &:focus { - border-color: @cp_buttons-default-border; - color: @cp_buttons-default-color; - background-color: @cp_buttons-default; + background-color: fade(@cryptpad_text_col, 20%); + border-color: @cryptpad_text_col; + color: @cryptpad_text_col; } } &.btn-default-alt { - border-color: @cp_buttons-default-alt-color; - color: @cp_buttons-default-alt-color; - background-color: @cp_buttons-default-color; + border-color: @cp_buttons-default-alt-fg; + color: @cp_buttons-default-alt-fg; + background-color: @cp_buttons-default-alt-bg; &:hover, &:not(:disabled):active, &:focus { - border-color: @cp_buttons-default-color; - color: @cp_buttons-default-color; - background-color: @cp_toolbar-fade3; + background-color: fade(@cryptpad_text_col, 20%); } } diff --git a/docs/example-advanced.nginx.conf b/docs/example-advanced.nginx.conf index 64e226bcc..e9458dbab 100644 --- a/docs/example-advanced.nginx.conf +++ b/docs/example-advanced.nginx.conf @@ -89,16 +89,6 @@ server { # HSTS (ngx_http_headers_module is required) (63072000 seconds) add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always; - # OCSP stapling - ssl_stapling on; - ssl_stapling_verify on; - - # verify chain of trust of OCSP response using Root CA and Intermediate certs - ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt; - - # replace with the IP address of your resolver - resolver 8.8.8.8 8.8.4.4 1.1.1.1 1.0.0.1 9.9.9.9 149.112.112.112 208.67.222.222 208.67.220.220; - # OnlyOffice fonts may be loaded from both domains if ($uri ~ ^/common/onlyoffice/.*/fonts/) { set $allowed_origins "*"; } diff --git a/docs/example.nginx.conf b/docs/example.nginx.conf index eae30310a..23ccf2182 100644 --- a/docs/example.nginx.conf +++ b/docs/example.nginx.conf @@ -65,16 +65,6 @@ server { # HSTS (ngx_http_headers_module is required) (63072000 seconds) add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always; - # OCSP stapling - ssl_stapling on; - ssl_stapling_verify on; - - # verify chain of trust of OCSP response using Root CA and Intermediate certs - ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt; - - # replace with the IP address of your resolver - resolver 8.8.8.8 8.8.4.4 1.1.1.1 1.0.0.1 9.9.9.9 149.112.112.112 208.67.222.222 208.67.220.220; - location / { proxy_pass http://localhost:3000; proxy_set_header X-Real-IP $remote_addr; diff --git a/lib/http-worker.js b/lib/http-worker.js index b98e00eac..161dac8be 100644 --- a/lib/http-worker.js +++ b/lib/http-worker.js @@ -145,7 +145,7 @@ var cacheHeaders = function (Env, key, headers) { var getHeaders = function (Env, type) { var key = type + 'HeadersCache'; - if (Env[key]) { return Env[key]; } + if (Env[key]) { return Util.clone(Env[key]); } var headers = Default.httpHeaders(Env); @@ -165,7 +165,7 @@ var getHeaders = function (Env, type) { // when duplicated by NGINX in production environments if (type === 'api') { delete headers['Content-Security-Policy']; } - return headers; + return Util.clone(headers); }; var setHeaders = function (req, res) { diff --git a/src/worker/async-store.js b/src/worker/async-store.js index 8cccfe526..82a9e8688 100644 --- a/src/worker/async-store.js +++ b/src/worker/async-store.js @@ -1236,7 +1236,7 @@ const factory = (ApiConfig = {}, Sortify, UserObject, ProxyManager, } // Check if the pad is already stored in the specified drive (data.teamId) - if ((!s.id && !data.teamId) || Number(s.id) === data.teamId) { + if ((!s.id && (!data.teamId || data.teamId === -1)) || Number(s.id) === data.teamId) { if (!inTargetDrive) { inTargetDrive = res.length; } diff --git a/www/admin/inner.js b/www/admin/inner.js index 2da209bd5..60f9b6d65 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -1839,7 +1839,7 @@ define([ validate: function () { var l = parseInt($(newLimit).val()); if (isNaN(l)) { - return UI.warn(Messages.limit_error); + return UI.warn(Messages.error_limit); } return true; } @@ -3916,14 +3916,14 @@ define([ validate: function () { var l = parseInt($(newDuration).val()); if (isNaN(l)) { - return void UI.warn(Messages.limit_error); + return void UI.warn(Messages.error_limit); } return true; } }, function () { var d = parseInt($(newDuration).val()); if (!isPositiveInteger(d)) { - return void UI.warn(Messages.positiveNumber_error); + return void UI.warn(Messages.error_positiveNumber); } var data = [d]; diff --git a/www/code/app-code.less b/www/code/app-code.less index 740468821..c6da5960b 100644 --- a/www/code/app-code.less +++ b/www/code/app-code.less @@ -137,7 +137,6 @@ @media (max-width: @browser_media-medium-screen) { #cp-app-code-editor { &.cp-app-code-present { - #cp-app-code-container { display: none !important; } #cp-app-code-preview { flex: 1; max-width: 100%; @@ -156,9 +155,6 @@ padding-bottom: 100px; } } - #cp-app-code-preview { - display: none !important; - } } } } diff --git a/www/code/inner.js b/www/code/inner.js index fa97426d4..b445aaa20 100644 --- a/www/code/inner.js +++ b/www/code/inner.js @@ -177,6 +177,8 @@ define([ }); }; + + var isSmallScreen = () => window.innerWidth <= 600; var mkPreviewPane = function (editor, CodeMirror, framework, isPresentMode) { var $previewContainer = $('#cp-app-code-preview'); var $preview = $('#cp-app-code-preview-content'); @@ -210,30 +212,88 @@ define([ }, 400); var previewTo; + + var togglePreview = function (show) { + if (show && previews[CodeMirror.highlightMode]) { + $previewContainer.show(); + $codeMirrorContainer.hide(); + $previewButton.addClass('cp-toolbar-button-active'); + drawPreview(); + } else { + $previewContainer.hide(); + $codeMirrorContainer.show(); + $previewButton.removeClass('cp-toolbar-button-active'); + } + framework._.sfCommon.setPadAttribute('previewMode', show); + }; + + var isVisible = function () { + return $previewContainer.is(':visible'); + }; + + var handleResize = function () { + var wasPreviewVisible = isVisible(); // Capture preview state before resize + + // Present mode: always draw preview + if (isPresentMode && previews[CodeMirror.highlightMode]) { + $previewContainer.show(); + $codeMirrorContainer.hide(); + $previewButton.hide(); + return drawPreview(); + } + // Small screen: toggle between editor and preview + if (isSmallScreen()) { + return togglePreview(wasPreviewVisible); + } + // Normal screen: split view to editor only + if (wasPreviewVisible) { + $previewContainer.show(); + $codeMirrorContainer.show(); + $codeMirrorContainer.removeClass('cp-app-code-fullpage'); + $previewButton.addClass('cp-toolbar-button-active'); + return drawPreview(); + } + // Normal screen: editor only to split view + $previewContainer.hide(); + $codeMirrorContainer.addClass('cp-app-code-fullpage'); + $previewButton.removeClass('cp-toolbar-button-active'); + }; + + $previewButton.click(function () { clearTimeout(previewTo); $codeMirror.addClass('transition'); previewTo = setTimeout(function () { $codeMirror.removeClass('transition'); }, 500); + + var show = !isVisible(); + + // Small screen: toggle between editor and preview + if (isSmallScreen()) { + return togglePreview(show); + } + if (!previews[CodeMirror.highlightMode]) { $previewContainer.show(); } $previewContainer.toggle(); - if ($previewContainer.is(':visible')) { - forceDrawPreview(); + //Normal screen: split view to editor only + if (isVisible()) { $codeMirrorContainer.removeClass('cp-app-code-fullpage'); $previewButton.addClass('cp-toolbar-button-active'); framework._.sfCommon.setPadAttribute('previewMode', true, function (e) { if (e) { return console.log(e); } }); - } else { - $codeMirrorContainer.addClass('cp-app-code-fullpage'); - $previewButton.removeClass('cp-toolbar-button-active'); - framework._.sfCommon.setPadAttribute('previewMode', false, function (e) { - if (e) { return console.log(e); } - }); + return forceDrawPreview(); } + + // Normal screen: editor only to split view + $codeMirrorContainer.addClass('cp-app-code-fullpage'); + $previewButton.removeClass('cp-toolbar-button-active'); + framework._.sfCommon.setPadAttribute('previewMode', false, function (e) { + if (e) { return console.log(e); } + }); }); framework._.toolbar.$bottomM.append($previewButton); @@ -260,9 +320,12 @@ define([ var modeChange = function (mode) { if (previews[mode]) { $previewButton.show(); + if(isSmallScreen()) { + return togglePreview(false); + } framework._.sfCommon.getPadAttribute('previewMode', function (e, data) { if (e) { return void console.error(e); } - if (data !== false) { + if (data !== false && data !== undefined) { $previewContainer.show(); $previewButton.addClass('cp-toolbar-button-active'); $codeMirrorContainer.removeClass('cp-app-code-fullpage'); @@ -278,14 +341,15 @@ define([ $previewButton.hide(); $previewContainer.hide(); $previewButton.removeClass('active'); + $codeMirrorContainer.show(); $codeMirrorContainer.addClass('cp-app-code-fullpage'); }; - var isVisible = function () { - return $previewContainer.is(':visible'); - }; framework.onReady(function () { + handleResize(); + window.addEventListener('resize', handleResize); + // add the splitter var splitter = $('
', { 'class': 'cp-splitter' diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index ab574f101..c6f5ef6c3 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -597,10 +597,11 @@ define([ let btnClass = $button.attr('class'); let btnId = $button.attr('id'); let btnTitle = $button.attr('title'); + let btnVisibility = $button.attr('style'); if (btnClass) { attributes['class'] = btnClass; } if (btnId) { attributes['id'] = btnId; } if (btnTitle && !attributes.title) { attributes['title'] = btnTitle; } - + if (btnVisibility) { attributes['style'] = btnVisibility; } return UIElements.createDropdownEntry({ tag: 'a', attributes: attributes, @@ -871,7 +872,7 @@ define([ h('i.fa.fa-hdd-o'), h('span.cp-toolbar-name.cp-toolbar-drawer-element', Messages.toolbar_storeInDrive) ])).click(common.prepareFeedback(type)).click(function () { - $(button).hide(); + $('.cp-toolbar-storeindrive').hide(); common.getSframeChannel().query("Q_AUTOSTORE_STORE", { forceOwnDrive: true, }, function (err, obj) { @@ -904,6 +905,7 @@ define([ case 'toggle': button = $(h('button.cp-toolbar-tools', { //title: data.title || '', // TODO display if the label text is collapsed + 'aria-label': data.text || Messages.toolbar_tools // Fallback }, [ h('i.fa.' + (data.icon || 'fa-wrench')), h('span.cp-toolbar-name', data.text || Messages.toolbar_tools) diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index 804662430..42c647c31 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -4025,9 +4025,10 @@ define([ var header7, header28, headerOld; var i = 0; var channels = []; + var toShow = []; if (typeFilter) { - var ids = filesList.map(function (arr) { return arr[0]; }); + let ids = filesList.map(function (arr) { return arr[0]; }); var idsFilter = filterPads(ids, typeFilter, false, true); filesList = filesList.filter(function (arr) { return (idsFilter.indexOf(arr[0]) !== -1); @@ -4046,15 +4047,18 @@ define([ return true; } - var paths = manager.findFile(id); - if (!paths.length) { return; } - var path = paths[0]; - if (manager.isPathIn(path, [TRASH])) { return; } - if (!file.channel) { file.channel = id; } if (channels.indexOf(file.channel) !== -1) { return; } channels.push(file.channel); + toShow.push({id, file}); + i++; + }); + let ids = toShow.map(obj => { return obj.id }); + var allPaths = manager.findFiles(ids); + toShow.forEach(obj => { + let file = obj.file; + let id = obj.id; if (!header7 && file.atime < last1) { $list.append(h('li.cp-app-drive-element-separator', h('span', Messages.drive_active7Days))); header7 = true; @@ -4078,6 +4082,12 @@ define([ var $element = $('
  • ', { 'class': 'cp-app-drive-element cp-app-drive-element-notrash cp-app-drive-element-file cp-app-drive-element-row' + roClass, });*/ + var paths = allPaths[id]; + if (paths.every(path => { + return manager.isPathIn(path, [TRASH]) + })) { return; } + var path = paths[0]; + var parentPath = path.slice(); var key = parentPath.pop(); var root = manager.find(parentPath); @@ -4085,7 +4095,6 @@ define([ $element.off('contextmenu').contextmenu(openContextMenu('default')); $element.data('context', 'default'); $list.append($element); - i++; }); }; diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index da0e1f187..b7f75321f 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -233,11 +233,25 @@ const factory = (UserObject, Util, Hash, var findFile = function (Env, id) { var ret = []; var userObjects = _getUserObjects(Env); + let mainRes = {}; userObjects.forEach(function (uo) { - var fPath = _getUserObjectPath(Env, uo); - var results = uo.findFile(id); - if (fPath) { + var fId = Number(uo.id); + let results; + if (!fId) { + // Main drive: get the paths of all the SF + // in addition to the paths of the requested file + let ids = [id]; + let fIds = userObjects.map(uo => { + return +uo.id; + }).filter(Boolean); + Array.prototype.push.apply(ids, fIds); + mainRes = uo.findFiles(ids); // Store paths of each SF + results = mainRes[id]; // Paths of requested file + } else { + results = uo.findFile(id); // This is a shared folder, we have to fix the paths in the results + let fPath = (mainRes[fId] || [])[0]; + if (!fPath) { return; } // Can't search into this sf results.forEach(function (p) { Array.prototype.unshift.apply(p, fPath); }); @@ -247,6 +261,41 @@ const factory = (UserObject, Util, Hash, }); return ret; }; + var findFiles = function (Env, ids) { + var ret = {}; + var userObjects = _getUserObjects(Env); + let mainRes = {}; + userObjects.forEach(function (uo) { + //var fPath = _getUserObjectPath(Env, uo); + var fId = Number(uo.id); + if (!uo.id) { + let fIds = userObjects.map(uo => { + return +uo.id; + }).filter(Boolean); + Array.prototype.push.apply(ids, fIds); + } + var results = uo.findFiles(ids); + if (!uo.id) { mainRes = results; } + //console.error(results); + if (fId) { + // This is a shared folder, we have to fix the paths in the results + let fPath = (mainRes[fId] || [])[0]; + if (!fPath) { return; } // Can't search into this sf + Object.keys(results).forEach(file => { + results[file].forEach(p => { + Array.prototype.unshift.apply(p, fPath); + }); + }); + } + // Push the results from this proxy + Object.keys(results).forEach(file => { + ret[file] ||= []; + Array.prototype.push.apply(ret[file], results[file]); + }); + }); + return ret; + }; + // Returns file IDs corresponding to the provided channels var _findChannels = function (Env, channels, onlyMain) { @@ -1752,6 +1801,7 @@ const factory = (UserObject, Util, Hash, getOwnedPads: callWithEnv(getOwnedPads), getTagsList: callWithEnv(getTagsList), findFile: callWithEnv(findFile), + findFiles: callWithEnv(findFiles), findChannels: callWithEnv(findChannels), getSharedFolderData: callWithEnv(getSharedFolderData), getFolderData: callWithEnv(getFolderData), diff --git a/www/common/translations/messages.bg.json b/www/common/translations/messages.bg.json index 56ac012e0..0d833a25e 100644 --- a/www/common/translations/messages.bg.json +++ b/www/common/translations/messages.bg.json @@ -599,5 +599,77 @@ "sharedFolders_create": "Създаване на споделена папка", "sharedFolders_create_name": "Име на папка", "sharedFolders_create_owned": "Собствена папка", - "convertFolderToSF_SFParent": "Тази папка не може да бъде преобразувана в споделена папка в текущото си местоположение. Преместете го извън споделената папка, за да продължите." + "convertFolderToSF_SFParent": "Тази папка не може да бъде преобразувана в споделена папка в текущото си местоположение. Преместете го извън споделената папка, за да продължите.", + "convertFolderToSF_confirm": "Тази папка трябва да бъде преобразувана в споделена папка, за да могат другите да я видят. Продължавате ли?", + "chrome68": "Изглежда, че използвате браузъра Chrome или Chromium версия 68. Той съдържа грешка, която води до това, че страницата става напълно бяла след няколко секунди или страницата не реагира на кликвания. За да коригирате този проблем, можете да превключите на друг раздел и да се върнете след това или да превъртите в страницата. Тази грешка трябва да бъде коригирана в следващата версия на вашия браузър.", + "autostore_file": "файл", + "autostore_sf": "папка", + "autostore_pad": "Оформяне на текст", + "autostore_notstored": "Този {0} не е във вашия CryptDrive. Искате ли да го съхраните сега?", + "autostore_settings": "Можете да активирате автоматичното съхранение на документите във вашата страница Настройки.", + "autostore_store": "Хранилище", + "autostore_hide": "Не съхранявайте", + "autostore_error": "Неочаквана грешка: не можахме да съхраним този документ, опитайте отново.", + "autostore_saved": "Документът беше успешно съхранен във вашия CryptDrive!", + "autostore_forceSave": "Съхранявайте файла във вашия CryptDrive", + "autostore_notAvailable": "Трябва да съхраните този документ във вашия CryptDrive, преди да можете да използвате тази функция.", + "crowdfunding_button": "Поддръжка на CryptPad", + "crowdfunding_button2": "Даряване", + "crowdfunding_popup_text": "

    Имаме нужда от вашата помощ!

    За да сме сигурни, че CryptPad се разработва активно, помислете за подкрепа на проекта чрез страницата OpenCollective, където можете да видите нашата Пътна карта и Цели за финансиране.", + "crowdfunding_popup_no": "Не сега", + "survey": "Проучване на CryptPad", + "markdown_toc": "Съдържание", + "fm_expirablePad": "Изтича: {0}", + "admin_authError": "Само администраторите имат достъп до тази страница", + "admin_cat_general": "Главен", + "admin_cat_stats": "Статистика", + "adminPage": "Администрация", + "admin_activeSessionsTitle": "Активни връзки", + "admin_activePadsTitle": "Активни документи", + "admin_activePadsHint": "Брой уникални документи, които в момента се разглеждат или редактират", + "admin_registeredTitle": "Потребителски и екипни дискове", + "admin_registeredHint": "Брой активни дискове на вашето копие", + "admin_updateLimitButton": "Обновяване на квоти", + "admin_updateLimitDone": "Обновяването завърши успешно", + "admin_flushCacheTitle": "Изчистване на HTTP кеша", + "admin_flushCacheButton": "Изчистване на кеша", + "admin_flushCacheDone": "Кешът е изчистен успешно", + "footer_donate": "Даряване", + "contact_admin": "Свържете се с администраторите за: {0}", + "contact_dev": "Свързване с разработчиците", + "contact_devHint": "За заявяване на функции, подобрения на използваемостта или за да кажете благодаря.", + "contact_bug": "Докладване за грешка", + "contact_chat": "Чат", + "contact_email": "Имейл", + "admin_flushCacheHint": "Принуждава всички потребители да изтеглят най-новите активи след промяна в персонализирането или конфигурацията им. Избягва рестартирането на сървъра, но кара всеки активен потребител да нулира връзката си, моля, използвайте пестеливо.", + "contact_adminHint": "За всякакви проблеми, свързани с акаунта ви, ограничение за съхранение или наличност на услугата.\n", + "admin_activeSessionsHint": "Брой активни уебсокет връзки (и свързани уникални IP адреси)", + "admin_updateLimitTitle": "Обновяване на потребителските квоти", + "admin_updateLimitHint": "Принудителното обновяване на лимитите за потребителското хранилище може да се извърши по всяко време, но е необходимо само в случай на грешка", + "timeoutError": "Грешка прекъсна връзката ви със сървъра.
    Натиснете Esc, за да презаредите страницата.", + "admin_diskUsageTitle": "Използване на диска", + "admin_diskUsageHint": "Размер на изразходеното пространство за съхранение, чрез различни ресурси на CryptPad", + "admin_diskUsageButton": "Генериране на отчет", + "settings_codeSpellcheckTitle": "Проверка на правописа", + "settings_codeSpellcheckLabel": "Активиране на проверката на правописа в редактора на кода", + "drive_active1Day": "Последните 24 часа", + "drive_active7Days": "Последните 7 дни", + "drive_active28Days": "Последните 4 седмици", + "drive_activeOld": "По-малко нови документи", + "friendRequest_later": "Решете по-късно", + "friendRequest_accept": "Приемам (Въвеждам)", + "friendRequest_decline": "Отказване", + "friendRequest_declined": "{0} отхвърляне на искането ви за контакт", + "friendRequest_accepted": "{0} приемане на вашата заявка за връзка", + "friendRequest_received": "{0} би искал да бъде ваш контакт", + "friendRequest_notification": "{0} ви изпрати заявка за контакт", + "notifications_empty": "Няма налични известия", + "profile_addDescription": "Добавяне на описание", + "profile_editDescription": "Редактиране на вашето описание", + "profile_addLink": "Добавяне на връзка към сайта си", + "profile_friendRequestSent": "Изчакваща заявка за контакт...", + "isContact": "{0} е един от вашите контакти", + "isNotContact": "{0} is not един от вашите контакти", + "profile_info": "Другите потребители могат да намерят профила ви чрез аватара ви в списъците с потребители на документи.", + "notification_padShared": "{0} сподели документ с вас: {1}" } diff --git a/www/common/translations/messages.ca.json b/www/common/translations/messages.ca.json index ef795961f..46afc871e 100644 --- a/www/common/translations/messages.ca.json +++ b/www/common/translations/messages.ca.json @@ -658,7 +658,7 @@ "form_cantFindAnswers": "No s'han pogut recuperar les respostes existents per a aquest formulari.", "calendar_errorNoCalendar": "No s'ha seleccionat cap calendari editable", "form_editor": "Editor", - "admin_setlimitTitle": "Aplica un límit personalitzat", + "admin_setlimitTitle": "Estableix un límit personalitzat", "broadcast_preview": "Previsualitza la notificació", "settings_deleteSubscription": "Gestiona la meva subscripció", "footer_roadmap": "Full de ruta", @@ -690,7 +690,7 @@ "settings_trimHistoryTitle": "Suprimeix l'historial", "form_notAnswered": "{0} respostes buides", "snapshots_delete": "Suprimeix", - "oo_version_latest": "Més tard", + "oo_version_latest": "Últim", "oo_version": "Versió: ", "mediatag_loadButton": "Carrega l'adjunt", "notification_fileShared": "{0} us ha compartit un fitxer: {1}", @@ -814,7 +814,7 @@ "crowdfunding_button": "Doneu suport al CryptPad", "settings_codeSpellcheckLabel": "Activa la verificació ortogràfica a l'editor de codi", "admin_activeSessionsTitle": "Connexions actives", - "admin_registeredTitle": "Usuaris registrats", + "admin_registeredTitle": "Unitats d'usuari i d'equip", "admin_updateLimitDone": "L'actualització s'ha completat correctament", "isNotContact": "{0} no és un dels vostres contactes", "teams_table_role": "Rol", @@ -890,7 +890,7 @@ "fm_restricted": "No teniu accés", "settings_kanbanTagsTitle": "Filtre d'etiquetes", "settings_kanbanTagsAnd": "AND", - "history_cantRestore": "Ha fallat la restauració. Està desconnectat.", + "history_cantRestore": "Ha fallat la restauració. Esteu desconnectat.", "history_fastPrev": "Sessió d'edició anterior", "history_userNext": "Autor següent", "snaphot_title": "Instantània", @@ -976,7 +976,7 @@ "calendar_nth_last": "últim", "admin_cat_support": "Assistència", "friendRequest_later": "Decideix més tard", - "history_restoreDrivePrompt": "Esteu segur que voleu substituir la versió actual de CryptDrive per la versió mostrada?", + "history_restoreDrivePrompt": "Segur que voleu substituir la versió actual de CryptDrive per la versió mostrada?", "owner_add": "{0} vol que sigueu propietari del document {1}. Ho accepteu?", "owner_team_add": "{0} vol que sigueu propietari/a de l'equip {1}. Accepteu?", "sent": "Missatge enviat", @@ -992,7 +992,7 @@ "friendRequest_declined": "{0} ha rebutjat la sol·licitud de contacte", "form_alreadyAnsweredMult": "Heu respost a aquest formulari el:", "form_responseNotification": "Respostes noves al formulari: {0}", - "snapshots_cantMake": "No s'ha pogut crear la instantània. Està desconnectat.", + "snapshots_cantMake": "No s'ha pogut crear la instantània. Esteu sense connexió.", "calendar_rec_no": "Una vegada", "admin_defaultlimitTitle": "Límit d'emmagatzematge (MB)", "calendar_rec_monthly_pick": "En dies", @@ -1009,7 +1009,7 @@ "admin_limitSetNote": "Nota", "admin_invalKey": "Clau pública no vàlida", "admin_invalLimit": "El valor límit no és vàlid", - "admin_cat_quota": "Emmagatzematge d'usuaris", + "admin_cat_quota": "Emmagatzematge d'usuari", "team_exportTitle": "Descarrega la unitat de l'equip", "form_condition_q": "Trieu una pregunta", "home_location": "Les dades xifrades estan allotjades a {0}", @@ -1125,7 +1125,7 @@ "adminPage": "Administració", "admin_activeSessionsHint": "Nombre de connexions websocket actives (i adreces IP úniques connectades)", "admin_activePadsHint": "Nombre de documents únics que s'estan visualitzant o editant actualment", - "admin_registeredHint": "Nombre d'usuaris registrats a la vostra instància", + "admin_registeredHint": "Nombre d'unitats actives a la vostra instància", "admin_updateLimitTitle": "Actualitzar les quotes d'usuari", "admin_updateLimitButton": "Actualitzar les quotes", "admin_flushCacheTitle": "Neteja la memòria cau HTTP", @@ -1332,12 +1332,12 @@ "settings_cat_kanban": "Kanban", "history_restore": "Restaura", "history_close": "Tanca", - "history_shareTitle": "Comparteix un enllaç a aquesta versió", - "share_versionHash": "Esteu a punt de compartir la versió seleccionada de l'historial del document en mode només de lectura. Això també farà que doni accés a la vista per a totes les versions del document.", + "history_shareTitle": "Compartiu un enllaç a aquesta versió", + "share_versionHash": "Esteu a punt de compartir la versió seleccionada de l'historial del document en mode només de lectura. Això també farà que doneu accés de lectura per a totes les versions del document.", "history_userPrev": "Autor anterior", - "history_fastNext": "Següent sessió d'edició", + "history_fastNext": "Sessió d'edició següent", "history_restoreDriveTitle": "Restaura la versió seleccionada del CryptDrive", - "snapshots_ooPickVersion": "Heu de seleccionar una versió abans de crear una instantània", + "snapshots_ooPickVersion": "Cal seleccionar una versió abans de crear una instantània", "snapshot_error_exists": "Ja hi ha una instantània d'aquesta versió", "snapshots_notFound": "Aquesta instantània ja no existeix perquè s'ha suprimit l'historial del document.", "admin_registrationHint": "Els visitants de la instància no poden crear comptes. Els administradors poden crear invitacions.", @@ -1350,13 +1350,13 @@ "team_exportButton": "Baixa", "admin_limitUser": "Clau pública de l'usuari", "fm_deletedFolder": "S'ha suprimit la carpeta", - "access_destroyPad": "Destrueix permanentment aquest document o carpeta", + "access_destroyPad": "Esborra permanentment aquest document o carpeta", "fm_shareFolderPassword": "Protegeix aquesta carpeta amb una contrasenya (opcional)", "loading_state_0": "Interfície de construcció", "loading_state_1": "Carrega la unitat", "loading_state_2": "Actualitza el contingut", "loading_state_3": "Carrega les carpetes compartides", - "loading_state_4": "Carrega els equips", + "loading_state_4": "Carrega equips", "loading_state_5": "Reconstrueix el document", "tag_add": "Afegeix", "tag_edit": "Edita", @@ -1762,5 +1762,30 @@ "support_userNotification": "Tiquet d'assistència o resposta nou: {0}", "install_instance": "Creeu el primer compte d'administrador, després personalitzeu la instància", "install_header": "Instal·lació", - "install_launch": "Configuració de la instància" + "install_launch": "Configuració de la instància", + "fm_restoreMultipleDialog": "Segur que voleu restablir {0} arxius o carpetes a les seves ubicacions anteriors?", + "calendar_show": "Mostra els calendaris", + "install_notes": "
      Creeu el primer compte d'administrador en aquesta pàgina. Els administradors editen la configuració de la instància, incloent-hi les quotes d'emmagatzematge, i tenen accés a les eines de moderació.
    • La vostra constrasenya és la clau secreta que encripta tots els vostres documents i privilegis d'administrador d'aquesta instància. Si la perdeu, no hi ha manera de recuperar les vostres dades.
    • Si esteu utilitzant un ordinador compartit, recordeu de tancar la sessió quan hagueu acabat. El fet de simplement tancar la finestra del navegador deixa el vostre compte exposat.
    ", + "admin_mfa_confirm_enable": "Esteu segur que voleu activar l'autentificació multi-factor?", + "form_passwordWarning": "Tingueu en compte que la constrasenya de formulari només es pot establir ara, el moment de creació, i que després no es pot canviar.", + "calendar_hide": "Amaga els calendaris", + "team_autoTrim": "S'està esborrant l'historial de la unitat d'equip.", + "admin_mfa_confirm_disable": "Esteu segur que voleu desactivar l'autentificació multi-factor?", + "support_recordedEmpty": "No hi ha cap fragment", + "support_recordedId": "Identificador únic de fragment", + "support_recordedTitle": "Fragments", + "support_insertRecorded": "Inseriu un fragment", + "install_token": "Token d'instal·lació", + "admin_appSelection": "Configuració de l'aplicació", + "admin_appsTitle": "Aplicacions de la instància", + "onboarding_save_error": "Algunes opcions no s'han pogut desar correctament. Visiteu el panell d'administrador per comprovar-ne els valors.", + "admin_appsHint": "Trieu quines aplicacions voleu habilitar per aquesta instància.", + "admin_cat_apps": "Aplicacions", + "onboarding_upload": "Trieu un logotip", + "admin_onboardingNameTitle": "Us donem la benvinguda a la vostra instància de CryptPad", + "admin_onboardingNameHint": "Trieu un títol, una descripció, un color de ressaltat i un logotip (tots son opcionals)", + "admin_onboardingOptionsTitle": "Paràmetres de la instància", + "admin_onboardingNamePlaceholder": "Títol de la instància", + "admin_onboardingDescPlaceholder": "Descripció de la instància", + "admin_onboardingOptionsHint": "Trieu la opció apropiada per la vostra instància.
    Aquests paràmetres es poden canviar després des del panell d'administració." } diff --git a/www/common/translations/messages.cs.json b/www/common/translations/messages.cs.json index 8769febb3..884509cf6 100644 --- a/www/common/translations/messages.cs.json +++ b/www/common/translations/messages.cs.json @@ -70,10 +70,10 @@ "pad_mediatagOpen": "Otevřit soubor", "pad_mediatagShare": "Sdílet soubor", "importButton": "Importovat", - "formattedKB": "{0} KB", + "formattedKB": "{0} kB", "formattedGB": "{0} GB", "formattedMB": "{0} MB", - "KB": "KB", + "KB": "kB", "GB": "GB", "MB": "MB", "language": "Jazyk", @@ -320,7 +320,7 @@ "chatButton": "Chat", "userListButton": "Seznam uživatelů", "shareButton": "Sdílet", - "movedToTrash": "Dokument byl přesunut do koše.
    Otevřít CryptDrive", + "movedToTrash": "Dokument byl přesunut do koše.
    Otevřít CryptDrive", "forgetPrompt": "Kliknutí na OK přesune dokument do koše. Jste si jistí?", "forgetButton": "Smazat", "saveTitle": "Uložit název (enter)", diff --git a/www/common/translations/messages.da.json b/www/common/translations/messages.da.json index a062fed39..bb5445efa 100644 --- a/www/common/translations/messages.da.json +++ b/www/common/translations/messages.da.json @@ -21,5 +21,164 @@ "typeError": "Dette dokument er ikke kompatibelt med det valgte program", "main_title": "CryptPad: Zero Knowledge, Collaborative Real Time Editing", "common_connectionLost": "Serverforbindelse afbrudt
    Du er nu i skrivebeskyttet tilstand, indtil forbindelsen er tilbage.", - "onLogout": "Du er logget ud, {0}klik her{1} for at logge ind
    eller tryk på Esc for at få adgang til dit dokument i skrivebeskyttet tilstand." + "onLogout": "Du er logget ud, {0}klik her{1} for at logge ind
    eller tryk på Esc for at få adgang til dit dokument i skrivebeskyttet tilstand.", + "historyText": "Redigeringshistorik", + "uploadButton": "Upload filer", + "padNotPinned": "Dette dokument vil udløbe efter 3 måneder af inaktivitet, {0}login{1} eller {2}lav en konto{3} for at bevare det.", + "padNotPinnedVariable": "Dette dokument wil udløbe efter {4} dage af inaktivitet, {0}login{1} eller {2}lav en konto{3} for at bevare det.", + "anonymousStoreDisabled": "Administratoren af denne Cryptpad-instans har deaktiveret opbevaring for gæster. Log ind for at tilgå dit eget CryptDrive.", + "history_prev": "Tidligere version", + "chainpadError": "En kritisk fejl har fundet sted i forbindelse med at updatere dit indhold. Denne side er i skrive-beskyttet tilstand for at garantere at du ikke mister dit arbejde.
    Tryk Esc for at fortsætte med se dette dokument, eller genindlæs siden for at prøve at redigere igen.", + "errorCopy": " Du kan stadig bruge den nuværende version i skrive-beskyttet tilstand ved at trykke Esc.", + "storageStatus": "Plads:
    {0} brugt ud af {1}", + "newVersionError": "En ny version af CryptPad er tilgængelig .
    Genindlæs for at bruge den nye version eller tryk Esc for at tilgå dit indhold i offline tilstand.", + "pinLimitReachedAlertNoAccounts": "Du har nået din opbevaringsplads grænse", + "initializing": "Opstarter...", + "forgetPrompt": "Når du klikker OK, bliver dette dokument rykket til papirkurven. Er du sikker?", + "selectTemplate": "Vælg en skabelon eller tryk Esc", + "useTemplateCancel": "Start frisk (Esc)", + "forgotten": "Flyttet til papirkurven", + "readonly": "Skrivebeskyttet", + "pinLimitDrive": "Du har nået din opbevaringsplads grænse.
    Du kan ikke lave nye dokumenter.", + "clickToEdit": "Klik for at redigere", + "uploadButtonTitle": "Upload en ny fil til dit CryptDrive", + "pinLimitReachedAlert": "Du har nået din opbevaringsplads grænse. Nye dokumenter vil ikke blive opbevaret i dit CryptDruve.
    Du kan enten slette dokumenter fra CryptDrive eller abonnere på et premium tilbud for at forøge din grænse.", + "exportPrompt": "Hvad vil du navngive din fil?", + "user_rename": "Ændre dit kaldenavn", + "newButtonTitle": "Lav et nyt dokument", + "backgroundButtonTitle": "Ændre baggrundens farve i præsentationen", + "printBackgroundRemove": "Fjern dette baggrundsbilled", + "colorButtonTitle": "Ændre tekst farven i præsentations tilstanden", + "printCSS": "Brugerdefineret stil-regler (CSS):", + "printBackgroundNoValue": "Intet baggrunds billed valgt", + "themeButtonTitle": "Vælg farveskemaet for kode og slide-editors", + "tags_add": "Opdater tags for de valgte dokumenter", + "tags_duplicate": "Duplikere tag: {0}", + "languageButtonTitle": "Vælg sproget til at bruge for sytaks highlighting", + "viewEmbedTag": "For at indlejre dette dokument, skal du inkludere denne iframe i din web-side hvor end du vil. Du kan stilisere det med CSS eller HTML attributer.", + "forgetButton": "Slet", + "shareButton": "Del", + "tags_noentry": "Du kan ikke tag et slettet dokument", + "notifyJoined": "{0} har joinet samarbejds-sessionen", + "kanban_done": "Færdig", + "poll_userPlaceholder": "Dit navn", + "poll_removeOption": "Er du sikker på at du vil fjerne denne valg-mulighed?", + "fileEmbedScript": "For at indlejre denne fil, inkluder dette script et sted i din web-side for at load Media-Tag'et:", + "fileEmbedTag": "Da placere dette Media Tag, hvor end på din web-side hvor du har lyst til at indlejre det:", + "history_restorePrompt": "Er du sikker på at du vil erstatte den nuværende version af dokumentet med den fremviste version?", + "history_loadMore": "Vis mere af historikken", + "poll_publish_button": "Offentliggør", + "poll_create_user": "Tilføj en ny bruger", + "expiredError": "Dette dokument har nået dets destruktions dato og er ikke længere tilgængeligt.", + "invalidHashError": "Dokumentet som du har anmodet har en invalid URL.", + "errorRedirectToHome": "Tryk Esc for at blive omdirigeret til dit CryptDrive.", + "loading": "Indlæser...", + "saved": "Gemt", + "deletedFromServer": "Dokument destrueret", + "disconnected": "Frakoblet", + "synchronizing": "Synkronisere", + "reconnecting": "Genforbinder", + "typing": "Det bliver redigeret", + "errorState": "Kritisk fejl: {0}", + "users": "Bruger", + "editor": "Redaktør", + "userlist_offline": "Du er iøjeblikket offline, bruger-listen er ikke tilgængelig.", + "language": "Sprog", + "upgrade": "Upgrade", + "MB": "MB", + "GB": "GB", + "formattedMB": "{0} MB", + "formattedGB": "{0} GB", + "pinLimitReached": "Du har nået din opbevaringsplads grænse", + "importButtonTitle": "Importer et dokument fra en lokal fil", + "exportButton": "Exporter", + "exportButtonTitle": "Exporter dette dokument til en lokal fil", + "user_displayName": "Kaldenavn", + "user_accountName": "Kontonavn", + "saveTitle": "Gem titlen (enter)", + "movedToTrash": "Det dokument er blevet rykket til papirkurven.
    Tilgå mit drive", + "userListButton": "Bruger liste", + "chatButton": "Chat", + "userAccountButton": "Bruger menu", + "newButton": "Ny", + "uploadFolderButton": "Upload mappe", + "saveTemplateButton": "Gem som en skabelon", + "saveTemplatePrompt": "Vælg en titel for skabelonen", + "templateSaved": "Skabelon gemt!", + "useTemplate": "Start med en skabelon?", + "useTemplateOK": "Vælg en skabelon (Enter)", + "template_import": "Importer en skabelon", + "template_empty": "Ingen skabelon tilgængelig", + "previewButtonTitle": "Vis eller gem Markdown viseren", + "presentButtonTitle": "Aktiver præsentations tilstand", + "propertiesButton": "Egenskaber", + "propertiesButtonTitle": "Se dokumentets egenskaber", + "printButton": "Print (Enter)", + "printButtonTitle2": "Print dit dokument eller eksporter det som en pdf fil", + "printOptions": "Layout indstillinger", + "printSlideNumber": "Vis slide nummeret", + "printDate": "Vis datoen", + "printTitle": "Vis dokument titlen", + "printTransition": "Aktiver overgangs animationer", + "printBackground": "Brug et baggrundsbilled", + "printBackgroundButton": "Vælg et billed", + "printBackgroundValue": "Nuværende baggrund:{0}", + "filePickerButton": "Indlejre et dokument opbevaret i CryptDrive", + "filePicker_close": "Luk", + "filePicker_description": "Vælg en fil fra dit CryptDrive som du vil indlejre eller upload en ny fil", + "filePicker_filter": "Filterere filer efter navn", + "tags_title": "Tags (kun for dig)", + "tags_notShared": "Dine tags er ikke delt med andre brugere", + "slideOptionsText": "Indstillinger", + "slideOptionsTitle": "Tilpas dine slides", + "slide_invalidLess": "Brugerdefineret stil er ugyldig", + "languageButton": "Sprog", + "themeButton": "Tema", + "viewShare": "Skrive-beskyttet link", + "notifyRenamed": "{0} er nu kendt som {1}", + "notifyLeft": "{0} har forladt samarbejds-sessionen", + "ok": "OK", + "okButton": "OK (Enter)", + "cancel": "Afbryd", + "cancelButton": "Afbryd (Esc)", + "show_help_button": "Vis hjælp", + "help_button": "Hjælp", + "historyButton": "Vis dokumentets redigeringshistorik", + "history_next": "Næste version", + "history_closeTitle": "Luk historikken", + "history_restoreTitle": "Genopret den valgte version af dokumentet", + "history_restoreDone": "Dokument genoprettet", + "openLinkInNewTab": "Åben link i en ny fane", + "pad_mediatagTitle": "Media-Tag indstillinger", + "pad_mediatagWidth": "Bredte (px)", + "pad_mediatagHeight": "Højde (px)", + "pad_mediatagRatio": "Bevar ratio", + "pad_mediatagBorder": "Rammens bredde (px)", + "pad_mediatagPreview": "Forevisning", + "pad_mediatagImport": "Gem i dit CryptDrive", + "pad_mediatagOptions": "Billed egenskaber", + "kanban_newBoard": "Nyt board", + "kanban_item": "Forekomst", + "kanban_todo": "Mangler at gøres", + "kanban_working": "Igangværende", + "kanban_addBoard": "Tilføj et board", + "poll_create_option": "Tilføj en ny mulighed", + "poll_commit": "Indsend", + "poll_optionPlaceholder": "Mulighed", + "poll_removeUser": "Er du sikker på at du vil fjerne denne bruger?", + "printText": "Print", + "deletedError": "Dette dokument er blevet slettet og er ikke længere tilgængeligt.", + "inactiveError": "Dette dokument er blevet slettet grundet inaktivitet. Tryk Esc for at lave et nyt dokument.", + "deleted": "Slettet", + "mustLogin": "Du må være logget ind, for at kunne tilgå denne side", + "disabledApp": "Denne applikation er blevet deaktiveret. Kontakt administratoren af denne Cryptpad for mere information.", + "realtime_unrecoverableError": "En ikke reperarbar fejl har fundet sted. Klik OK for at genindlæse.", + "anonymous": "Gæst", + "upgradeAccount": "Opgrader konto", + "pinLimitNotPinned": "Du har nået din opbevaringsplads grænse.
    Dette dokument er ikke opbevaret i dit CryptDrive.", + "importButton": "Importer", + "editShare": "Rediger link", + "error": "Fejl", + "KB": "kB", + "formattedKB": "{0} kB" } diff --git a/www/common/translations/messages.es.json b/www/common/translations/messages.es.json index 0892a210c..4769479e2 100644 --- a/www/common/translations/messages.es.json +++ b/www/common/translations/messages.es.json @@ -16,7 +16,8 @@ "teams": "Equipos", "form": "Formulario", "presentation": "Presentación", - "doc": "Documento" + "doc": "Documento", + "diagram": "Diagrama" }, "disconnected": "Desconectado", "synchronizing": "Sincronizando", @@ -1573,5 +1574,13 @@ "team_linkUsesInfinite": "(sin límite de usos)", "form_settingsButton": "Configuración del formulario", "form_editable_on": "Una vez y editar", - "form_responseNotification": "Nuevas respuestas a la forma: {0}" + "form_responseNotification": "Nuevas respuestas a la forma: {0}", + "settings_mfaHint": "Proteja su cuenta con un código de verificación adicional proporcionado por una aplicación autenticadora de su elección.", + "form_anonymized": "Las respuestas son anónimas", + "form_condorcetSchulze": "Schulze", + "form_showCondorcetWinner": "ganador: ", + "form_showDetails": "Detalles", + "form_condorcetExtendedDisplay": "Número de partidos ganados por cada candidato: ", + "form_type_date": "Fecha", + "team_linkUses": "({0}/{1} restante)" } diff --git a/www/common/translations/messages.eu.json b/www/common/translations/messages.eu.json index 50ffbce38..53aea674f 100644 --- a/www/common/translations/messages.eu.json +++ b/www/common/translations/messages.eu.json @@ -1783,5 +1783,9 @@ "admin_onboardingOptionsHint": "Mesedez, hautatu aukera egokia zure instantziarako.
    Ezarpen hauek geroago alda daitezke administrazio panelean.", "admin_mfa_confirm_disable": "Ziur faktore anitzeko autentifikazioa desgaitu nahi duzula?", "admin_mfa_confirm_enable": "Ziur faktore anitzeko autentifikazioa gaitu nahi duzula?", - "team_autoTrim": "Taldeko diskoen historia mozten... Itxaron mesedez." + "team_autoTrim": "Taldeko diskoen historia mozten... Itxaron mesedez.", + "fm_restoreMultipleDialog": "Ziur {0} fitxategi edo/eta karpeta lehengo kokapenetara leheneratu nahi dituzula?", + "calendar_show": "Erakutsi egutegiak", + "calendar_hide": "Ezkutatu egutegiak", + "form_passwordWarning": "Kontuan izan Inprimakiaren pasahitza orain bakarrik ezar daitekeela sortzean eta ezin dela geroago aldatu." } diff --git a/www/common/translations/messages.it.json b/www/common/translations/messages.it.json index 9aab3c535..5eb8cda4f 100644 --- a/www/common/translations/messages.it.json +++ b/www/common/translations/messages.it.json @@ -1771,5 +1771,10 @@ "admin_onboardingOptionsHint": "Scegli l’opzione appropriata per la tua istanza.
    Queste configurazioni possono essere cambiate successivamente nel pannello di amministrazione.", "team_autoTrim": "Eliminazione della cronologia del drive del gruppo... Si prega di attendere.", "admin_mfa_confirm_enable": "Sei sicuro/a di voler attivare l'autenticazione a più fattori?", - "admin_mfa_confirm_disable": "Sei sicuro/a di voler disattivare l'autenticazione a più fattori?" + "admin_mfa_confirm_disable": "Sei sicuro/a di voler disattivare l'autenticazione a più fattori?", + "fm_restoreMultipleDialog": "Sei sicuro/a di voler ripristinare {0} file e/o cartelle nelle loro posizioni precedenti?", + "calendar_hide": "Nascondi i calendari", + "calendar_show": "Mostra i calendari", + "form_passwordWarning": "La password del modulo può essere impostata solo al momento della creazione e non può essere modificata in seguito.", + "admin_blockKey": "Chiave pubblica di blocco" } diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json index fa940fb1f..1a97ce4c8 100644 --- a/www/common/translations/messages.json +++ b/www/common/translations/messages.json @@ -1154,7 +1154,7 @@ "calendar_deleteConfirm": "Are you sure you want to delete this calendar from your account?", "calendar_deleteTeamConfirm": "Are you sure you want to delete this calendar from the team?", "calendar_deleteOwned": "It will remain visible to other users it has been shared with.", - "calendar_errorNoCalendar": "No editable calendar selected", + "calendar_errorNoCalendar": "No calendar available", "calendar_import": "Add to my calendars", "calendar_newEvent": "New event", "calendar_dateRange": "{0} - {1}", @@ -1328,7 +1328,7 @@ "form_anonName": "Your name", "form_answerAs": "Answer as", "fm_link_warning": "Warning: the URL exceeds 200 characters", - "fm_link_invalid": "Invalid URL", + "fm_link_invalid": "Please provide a valid URL", "ui_collapse": "Collapse", "ui_expand": "Expand", "form_totalResponses": "Total responses: {0}", @@ -1787,5 +1787,35 @@ "form_passwordWarning": "Please note that a Form password can only be set now at creation time and cannot be changed later.", "fm_restoreMultipleDialog": "Are you sure you want to restore {0} files and/or folders to their previous locations?", "calendar_show": "Show calendars", - "calendar_hide": "Hide calendars" + "calendar_hide": "Hide calendars", + "admin_logoSize_error": "The logo size is too large", + "admin_listAdminsHint": "View and remove administrators", + "error_limit": "Please enter a valid number", + "form_answerType_error": "Please select how to answer the form", + "admin_addKeyLabel": "Add an admin using their public key", + "error_positiveNumber": "Please enter a positive number", + "admin_cat_admins": "Administrators", + "admin_admin": "Admin", + "admin_listAdminsTitle": "Current administrators", + "admin_addAdminsAdd": "Promote a contact to admin", + "admin_addAdminsTitle": "Add administrators", + "admin_errorAddAdmins": "Pick a contact to promote to admin", + "admin_addAdminsHint": "Add administrators from their public key or from your contacts list", + "moveItemLeft": "Move item left", + "admin_errorAddKeyLabel": "Add a valid public key", + "skipLink": "Skip to main content", + "admin_listName": "Admin name", + "admin_listKey": "Admin key", + "moveItemRight": "Move item right", + "admin_listAction": "Remove admin rights", + "kanban_moveBoardRight": "Move board right", + "admin_listHardcoded": "Admin added into config.js. Can only be removed by editing the config file.", + "addItemBottom": "Add card to the bottom of the board", + "admin_listConfirm": "Are you sure you want to remove the admin rights of this user?", + "addItemTop": "Add card to the top of the board", + "kanban_moveBoardLeft": "Move board left", + "toggleDrag": "Drag to move items", + "moveItemUp": "Move item up", + "moveItemDown": "Move item down", + "toggleArrows": "Arrow buttons to move items" } diff --git a/www/common/translations/messages.nl.json b/www/common/translations/messages.nl.json index 400941007..671725eee 100644 --- a/www/common/translations/messages.nl.json +++ b/www/common/translations/messages.nl.json @@ -121,7 +121,7 @@ "pinLimitReachedAlertNoAccounts": "U heeft uw opslaglimiet bereikt", "pinLimitReachedAlert": "U heeft uw opslaglimiet bereikt. Nieuwe documenten worden niet opgeslagen in uw CryptDrive.
    U kunt documenten verwijderen van uw CryptDrive of opwaarderen naar een premium-account om uw opslaglimiet te verhogen.", "pinLimitReached": "U heeft uw opslaglimiet bereikt", - "formattedKB": "{0} KB", + "formattedKB": "{0} kB", "formattedGB": "{0} GB", "formattedMB": "{0} MB", "KB": "KB", diff --git a/www/common/translations/messages.pt-br.json b/www/common/translations/messages.pt-br.json index 8026159d8..206fff4eb 100644 --- a/www/common/translations/messages.pt-br.json +++ b/www/common/translations/messages.pt-br.json @@ -352,7 +352,7 @@ "settings_autostoreMaybe": "Manual (sempre perguntar)", "settings_autostoreYes": "Automático", "settings_autostoreHint": "Automatico Todos os documentos que você visitou estão armazenados em seu CryptDrive.
    Manual (sempre pergunta) Se você ainda não armazenou documentos, será questionado se deseja armazená-los em seu CryptDrive.
    Manual (nunca pergunta) Os documentos não são armazenados automaticamente em seu CryptDrive. A opção para armazená-los estará escondida.", - "settings_autostoreTitle": "Bloco armazenado no CryptDrive", + "settings_autostoreTitle": "Documento armazenado no CryptDrive", "settings_resetThumbnailsDone": "Todas as miniaturas foram apagadas.", "settings_resetThumbnailsDescription": "Limpar todas as miniaturas de documentos armazenadas em seu navegador.", "settings_resetThumbnailsAction": "Limpar", @@ -464,8 +464,8 @@ "admin_updateLimitButton": "Atualizar cotas", "admin_updateLimitHint": "Forçar uma atualização dos limites de armazenamento do usuário pode ser feito a qualquer momento, mas só é necessário em caso de erro", "admin_updateLimitTitle": "Atualizar cotas de usuários", - "admin_registeredHint": "Número de usuários registrados na sua instância", - "admin_registeredTitle": "Usuários registrados", + "admin_registeredHint": "Número de usuários ativos na sua instância", + "admin_registeredTitle": "Drives do usuário e equipe", "admin_activePadsHint": "Número de documentos exclusivos atualmente sendo visualizados ou editados", "admin_activePadsTitle": "documentos ativos", "admin_activeSessionsHint": "Número de conexões websocket ativas (e único endereço de IP conectado)", @@ -816,7 +816,7 @@ "footer_donate": "Doe", "admin_flushCacheDone": "Cache limpo com sucesso", "admin_flushCacheButton": "Limpar cache", - "admin_flushCacheHint": "Força os usuários a baixar os ativos do cliente mais recentes (apenas se o seu servidor estiver no modo novo)", + "admin_flushCacheHint": "Força os usuários a baixar os ativos do cliente mais recentes (apenas se o seu servidor estiver no modo novo) após uma customização ou alteração nas configurações. Evita reiniciar o servidor mas reinicia as conexões de todos os usuários, por favor use com cautela.", "admin_flushCacheTitle": "Limpar cache HTTP", "settings_padNotifTitle": "Notificações de comentários", "comments_comment": "Comentário", @@ -1018,7 +1018,7 @@ "history_cantRestore": "Restauração falhou. Você está desconectado.", "history_close": "Fechar", "history_restore": "Restaurar", - "admin_registrationHint": "Não permitir que nenhum novo usuário se registre", + "admin_registrationHint": "Visitantes da instância não podem criar contas. Convites podem ser criados pelos administradores.", "fm_sort": "Ordenar", "comments_error": "Não é possível acrescentar um comentário aqui", "settings_padNotifCheckbox": "Desabilitar notificações de comentários", @@ -1666,5 +1666,6 @@ "admin_diskUsageWarning": "Use com cuidado! Dependendo do tamanho dos dados armazenados na instância, a geração deste relatório pode consumir toda a memória disponível no servidor e causar travamento.", "goRight": "Direita", "dph_pad_pw": "Este documento está protegido por uma nova senha", - "goLeft": "Esquerda" + "goLeft": "Esquerda", + "calendar_rec_change_first": "Movendo o primeiro evento duplicado para uma agenda diferente. Todos os eventos duplicados serão movidos." } diff --git a/www/common/translations/messages.ro.json b/www/common/translations/messages.ro.json index 7a531df8d..f07bc6485 100644 --- a/www/common/translations/messages.ro.json +++ b/www/common/translations/messages.ro.json @@ -1783,5 +1783,9 @@ "install_header": "Instalare", "team_autoTrim": "Scurtăm istoricul drive-ului de echipa... Vă rugăm să așteptați.", "admin_mfa_confirm_enable": "Sunteți sigur că doriți să activați Autentificarea În Mai Mulți Pași?", - "admin_mfa_confirm_disable": "Sunteți sigur că doriți să dezactivați Autentificarea În Mai Mulți Pași?" + "admin_mfa_confirm_disable": "Sunteți sigur că doriți să dezactivați Autentificarea În Mai Mulți Pași?", + "form_passwordWarning": "Vă rugăm să țineți minte că parola la Form poate fi setată doar acum, în momentul creării și nu poate fi schimbată mai târziu.", + "fm_restoreMultipleDialog": "Sigur doriți să restaurați {0} fișiere și/sau dosare către locația lor anterioară?", + "calendar_show": "Arată calendare", + "calendar_hide": "Ascunde calendare" } diff --git a/www/common/translations/messages.ru.json b/www/common/translations/messages.ru.json index a1d23562b..96359d187 100644 --- a/www/common/translations/messages.ru.json +++ b/www/common/translations/messages.ru.json @@ -1783,5 +1783,9 @@ "admin_onboardingDescPlaceholder": "Текст описания экземпляра", "admin_mfa_confirm_disable": "Вы уверены, что хотите выключить многофакторную аутентификацию (MFA)?", "admin_mfa_confirm_enable": "Вы уверены, что хотите включить многофакторную аутентификацию (MFA)?", - "team_autoTrim": "Оптимизация (усечение) истории хранилища Команды... Пожалуйста, подождите." + "team_autoTrim": "Оптимизация (усечение) истории хранилища Команды... Пожалуйста, подождите.", + "form_passwordWarning": "Обратите внимание, что пароль Формы можно установить только сейчас, во время создания, и его нельзя изменить позже.", + "calendar_hide": "Скрыть календари", + "fm_restoreMultipleDialog": "Вы уверены, что хотите восстановить {0} файлов и/или папок в прежнее расположение?", + "calendar_show": "Показать календари" } diff --git a/www/common/translations/messages.sk.json b/www/common/translations/messages.sk.json index fd5637e4e..aae5ceed2 100644 --- a/www/common/translations/messages.sk.json +++ b/www/common/translations/messages.sk.json @@ -13,23 +13,28 @@ "login_confirm": "Opakujte heslo", "login_password": "Heslo", "login_username": "Uživatelské jméno", - "padNotPinned": "Tento dokument expiruje za 3 měsíce neaktivity, {0}přihlašte se{1} nebo {2}se registrujte{3} pro jeho uchování.", - "onLogout": "Jste odhlášení, {0}klikněte zde{1} pro přihlášení
    nebo zmáčkněte Esc pro čtení dokumentu.", - "typeError": "Tento dokument není kompatibilní s vybranou aplikací", - "common_connectionLost": "Spojení se serverem ztraceno
    Nyní jste v režimu čtení, dokud nebude spojení obnoveno.", + "padNotPinned": "Tento dokument expiruje po 3 mesiacoch neakivity, {0}prihláste sa{1} alebo {2}registrujte{3}, aby ste si ho ponechali.", + "onLogout": "Ste odhlásený, {0}kliknite sem{1} pre prihlásenie
    alebo stlačte Esc pre čítanie dokumentu.", + "typeError": "Tento dokument nie je kompatibilný s vybranou aplikáciou", + "common_connectionLost": "Strata spojenia so serverom
    Ste v režime na čítanie, pokým nebude spojenie obnovené.", "type": { - "teams": "Týmy", - "sheet": "Tabulka", + "teams": "Tímy", + "sheet": "Tabuľka", "contacts": "Kontakty", - "todo": "Úkol", - "media": "Média", - "file": "Soubor", - "whiteboard": "Tabule", + "todo": "Dokončiť", + "media": "Médiá", + "file": "Súbor", + "whiteboard": "Whiteboard", "drive": "CryptDrive", - "slide": "Prezentace", - "poll": "Hlasování", + "slide": "Prezentácia", + "poll": "Hlasovanie", "code": "Kód", - "pad": "Formátovaný text" + "pad": "Dokument", + "form": "Formulár", + "doc": "Dokument", + "presentation": "Prezentácia", + "diagram": "Diagram", + "kanban": "Kanban" }, "logoutEverywhere": "Odhlásit se všude", "login_login": "Přihlásit se", @@ -42,14 +47,263 @@ "register_cancel": "Zrušit", "register_writtenPassword": "Své uživatelské jméno a heslo jsem si zapsal, pokračovat", "register_header": "Registrovat", - "deletedFromServer": "Dokument zničen", - "deleted": "Smazáno", - "saved": "Uloženo", + "deletedFromServer": "Dokument bol zničený", + "deleted": "Zmazané", + "saved": "Uložené", "error": "Chyba", - "loading": "Načítání...", - "invalidHashError": "Požadovaný dokument má neplatné URL.", - "inactiveError": "Tento dokument byl smazán kvůli neaktivitě. Zmáčkněte Escape pro vytvoření nového dokumentu.", - "deletedError": "Tento dokument byl smazán a není již dostupný.", - "expiredError": "Tento dokument expiroval a není již dostupný.", - "padNotPinnedVariable": "Tento dokument expiruje za {4} dny neaktivity, {0}přihlašte se{1} nebo {2}se registrujte{3} pro jeho uchování." + "loading": "Načítavanie...", + "invalidHashError": "Požadovaný dokument má neplatnú adresu URL.", + "inactiveError": "Tento dokument bol vymazaný kvôli neaktivite. Stlačte Esc na vytvorenie nového dokumentu.", + "deletedError": "Tento dokument bol vymazaný a už nie je dostupný.", + "expiredError": "Tento dokument expiroval a už nie je dostupný.", + "padNotPinnedVariable": "Tento dokument expiruje po {4}dňoch neaktivity, {0}prihláste sa{1} alebo {2}registrujte{3}, aby ste si ho ponechali.", + "editor": "redaktor", + "viewer": "čitateľ", + "viewers": "čitatelia", + "errorCopy": " Stále môžete použiť súcasnú verziu v režime iba na čítanie stlačením Esc.", + "errorRedirectToHome": "Stlačte Esc na presmerovanie do vášho CryptDrive.", + "newVersionError": "K dispozíci je novšia verzia CryptPad.
    Obnovte stránku pre zobrazenie novšej verzie alebo stlačte escape pre pokračovanie v offline režime.", + "mustLogin": "Musíte byť prihlásený pre prístup k tejto stránke", + "realtime_unrecoverableError": "Vyskytla sa neopraviteľná chyba. Kliknite OK pre obnovenie stránky.", + "disconnected": "Odpojené", + "synchronizing": "Synchronizácia", + "reconnecting": "Prebieha opätovné pripojenie", + "typing": "Úprava", + "initializing": "Inicializovanie...", + "forgotten": "Presunuté do koša", + "errorState": "Kritická chyba: {0}", + "anonymousStoreDisabled": "Administrátor tejto CryptPad inštancie zakázal úložisko pre hostí. Prihlásením získate prístup k vašemu CryptDrive.", + "chainpadError": "Pri aktualizovaní obsahu došlo ku kritickej chybe. Táto stránka je v režime len na čítanie, aby ste nestratili svoju prácu.
    Stlačte Esc na zobrazenie dokumentu alebo znovu načítajte pre pokračovanie v úpravách.", + "users": "Používatelia", + "language": "Jazyk", + "upgrade": "Upgrade", + "upgradeAccount": "Upgrade účtu", + "MB": "MB", + "GB": "GB", + "formattedMB": "{0} MB", + "formattedGB": "{0} GB", + "pinLimitReached": "Dosiahli ste limit úložiska", + "pinLimitReachedAlertNoAccounts": "Dosiahli ste limit úložiska", + "pinLimitNotPinned": "Dosiahli ste limit úložiska.
    Tento dokument nie je uložený vo vašom CryptDrive.", + "pinLimitDrive": "Dosiahli ste limit úložiska.
    Nemôžete vytvoriť nové dokumenty.", + "importButton": "Importovať", + "importButtonTitle": "Importovať dokument zo súboru", + "exportButton": "Exportovať", + "exportButtonTitle": "Exportovať dokument do súboru", + "exportPrompt": "Ako chcete pomenovať váš súbor?", + "user_rename": "Zmeniť meno", + "user_displayName": "Meno", + "user_accountName": "Užívateľské meno", + "clickToEdit": "Kliknite pre úpravu", + "saveTitle": "Uložiť názov (enter)", + "forgetButton": "Zmazať", + "movedToTrash": "Dokument bol presunutý do koša.
    Otvoriť CryptDrive", + "shareButton": "Zdieľať", + "shareSuccess": "Odkaz bol skopírovaný do schránky", + "userListButton": "Zoznam používateľov", + "chatButton": "Chat", + "userAccountButton": "Používateľské menu", + "newButton": "Nový", + "uploadButton": "Nahrať súbory", + "uploadFolderButton": "Nahrať priečinok", + "uploadButtonTitle": "Nahrať nový súbor na CryptDrive", + "saveTemplatePrompt": "Zvoľte názov pre šablónu", + "saveTemplateButton": "Uložiť ako šablónu", + "templateSaved": "Šablóna uložená!", + "useTemplate": "Začať so šablónou?", + "useTemplateOK": "Vybrať šablónu (Enter)", + "useTemplateCancel": "Začať bez šablóny (Esc)", + "template_empty": "Nie je k dispozícii žiadna šablóna", + "previewButtonTitle": "Zobraziť alebo skyť Markdown náhľad", + "presentButtonTitle": "Spustiť režim prezentácie", + "colorButtonTitle": "Zmeniť farbu textu v režime prezentácie", + "propertiesButton": "Vlastnosti", + "propertiesButtonTitle": "Zistiť vlastnosti dokumentu", + "printButton": "Tlačiť (enter)", + "printOptions": "Možnosti rozloženia", + "printSlideNumber": "Zobraziť číslo snímky", + "printDate": "Zobraziť dátum", + "printTitle": "Zobraziť názov dokumentu", + "printCSS": "Vlastné pravidlá štýlu (CSS):", + "printTransition": "Povoliť animáciu prechodov", + "printBackground": "Použiť obrázok na pozadí", + "printBackgroundButton": "Vybrať obrázok", + "printBackgroundRemove": "Odstrániť obrázok na pozadí", + "filePickerButton": "Vložiť súbor uložený v CryptDrive", + "filePicker_close": "Zavrieť", + "filePicker_filter": "Filtrovať súbory podľa názvu", + "tags_title": "Štítky (len pre vás)", + "tags_add": "Upraviť štítky pre vybrané dokumenty", + "tags_notShared": "Vaše štítky nie sú zdieľané s ostatnými používateľmi", + "tags_duplicate": "Duplicitný štítok : {0}", + "tags_noentry": "Nemôžete pridať štítok ku vymazanému dokumentu", + "slideOptionsText": "Možnosti", + "slide_invalidLess": "Neplatný vlastný štýl", + "languageButton": "Jazyk", + "themeButton": "Motív", + "themeButtonTitle": "Vybrať farebný motív pre editory kódu a snímkov", + "viewShare": "Odkaz len na čítanie", + "fileEmbedScript": "Pre vloženie súboru vložte tento skript raz do svojej stránky, aby sa načítal Media Tag:", + "fileEmbedTag": "Potom umiestnite Media Tag kamkoľvek na stránku, ktorú chcete vložiť:", + "notifyJoined": "{0} sa pripojil ku spolupráci", + "notifyRenamed": "{0} je teraz {1}", + "notifyLeft": "{0} odišiel/a", + "ok": "OK", + "okButton": "OK (enter)", + "editShare": "Odkaz pre úpravy", + "cancelButton": "Zrušiť (esc)", + "show_help_button": "Zobraziť nápovedu", + "help_button": "Nápoveda", + "historyText": "História", + "main_title": "CryptPad: Zero Knowledge, Collaborative Real Time Editing", + "userlist_offline": "Aktuálne ste offline, zoznam používateľov nie je dostupný.", + "pinLimitReachedAlert": "Dosiahli ste limit úložiska. Nové dokumenty sa nebudú ukladať vo vašom CryptDrive.
    Buď vymažte dokumenty zo svojho CryptDrive alebo si zakúpte prémiovú ponuku pre zvýšenie limitu.", + "newButtonTitle": "Vytvoriť nový dokument", + "selectTemplate": "Vyberte šablónu alebo stlačte escape", + "readonly": "Iba na čítanie", + "disabledApp": "Táto aplikácia bola zakázaná. Kontaktujte administrátora tejto CryptPad inštancie pre viac informácii.", + "formattedKB": "{0} kB", + "template_import": "Importovať šablónu", + "forgetPrompt": "Kliknutím na OK presuniete dokument do koša. Ste si istý?", + "backgroundButtonTitle": "Zmena farby pozadia v prezentácii", + "printButtonTitle2": "Vytlačiť dokument alebo exportovať ako PDF súbor", + "printText": "Tlačiť", + "printBackgroundValue": "Aktuálne pozadie: {0}", + "slideOptionsTitle": "Prispôsobiť snímky", + "filePicker_description": "Vyberte súbor z CryptDrive alebo nahrajte nový súbor pre vloženie", + "cancel": "Zrušiť", + "viewEmbedTag": "Tento iframe môžete vložiť na svoju stránku a upraviť ho pomocou CSS alebo HTML.", + "historyButton": "Zobraziť históriu dokumentu", + "anonymous": "Hosť", + "KB": "kB", + "storageStatus": "Úložisko:
    {0} využité z {1}", + "printBackgroundNoValue": "Nezobrazuje sa žiadny obrázok na pozadí", + "languageButtonTitle": "Vybrať jazyk pre zvýraznenie syntaxe", + "history_next": "Ďalšia verzia", + "history_prev": "Predchádzajúca verzia", + "history_loadMore": "Načítať ďalšiu históriu", + "history_closeTitle": "Zavrieť históriu", + "history_restoreTitle": "Obnoviť vybranú verziu dokumentu", + "history_restorePrompt": "Ste si istý, že chcete nahradiť súčasnú verziu dokumentu vybranou verziou?", + "history_restoreDone": "Dokument obnovený", + "openLinkInNewTab": "Otvoriť odkaz v novej karte", + "pad_mediatagTitle": "Nastavenia Media-Tag", + "pad_mediatagWidth": "Šírka (px)", + "pad_mediatagHeight": "Výška (px)", + "pad_mediatagRatio": "Zachovať pomer", + "pad_mediatagBorder": "Širka okraja (px)", + "pad_mediatagPreview": "Náhľad", + "pad_mediatagImport": "Uložiť do CryptDrive", + "pad_mediatagOptions": "Vlastnosti obrázku", + "kanban_item": "Položka {0}", + "kanban_todo": "Dokončiť", + "kanban_done": "Hotovo", + "kanban_working": "Prebieha", + "kanban_addBoard": "Pridať stĺpec", + "poll_publish_button": "Zverejniť", + "poll_create_user": "Pridať nového používateľa", + "poll_create_option": "Pridať novú možnosť", + "poll_commit": "Odoslať", + "poll_userPlaceholder": "Vaše meno", + "poll_removeOption": "Ste si istý, že chcete odstrániť túto možnosť?", + "poll_remove": "Odstrániť", + "poll_edit": "Upraviť", + "poll_locked": "Uzamknuté", + "poll_unlocked": "Odomknuté", + "poll_bookmark_col": "Tento stĺpec si môžeťe pridať do záložiek, aby sa vám vždy odomkol a zobrazil na začiatku", + "poll_bookmarked_col": "Toto je pripnutý stĺpec. Bude vždy odomknutý a zobrazí sa na začiatku.", + "poll_total": "SUMA", + "poll_comment_list": "Komentáre", + "poll_comment_add": "Pridať komentár", + "poll_comment_submit": "Odoslať", + "poll_comment_remove": "Odstrániť komentár", + "poll_comment_placeholder": "Váš komentár", + "oo_cantUpload": "Nahrávanie nie je povolené pokiaľ sú pripojený ostatný používatelia.", + "oo_uploaded": "Nahrávanie dokončené. Kliknite OK pre obnovenie stránky alebo zrušiť pre pokračovanie v režime iba na čítanie.", + "canvas_clear": "Vymazať", + "canvas_delete": "Vymazať výber", + "canvas_width": "Šírka", + "canvas_opacity": "Priehľadnosť", + "canvas_opacityLabel": "Priehľadnosť: {0}", + "canvas_widthLabel": "Šírka: {0}", + "canvas_currentBrush": "Aktuálny štetec", + "canvas_imageEmbed": "Vložiť obrázok z počítača", + "profileButton": "Profil", + "profile_upload": " Nahrať nového avatara", + "profile_uploadSizeError": "Chyba: váš avatar musí byť menší ako {0}", + "profile_error": "Nastala chyba počas vytvárania vášho profilu: {0}", + "profile_register": "Pre vytvorenie profilu sa musíte zaregistrovať!", + "profile_viewMyProfile": "Zobraziť môj profil", + "userlist_addAsFriendTitle": "Odoslať \"{0}\" žiadosť o kontakt", + "contacts_title": "Kontakty", + "contacts_rejected": "Žiadosť o kontakt zamietnutá", + "contacts_request": "{0}si vás chce pridať do kontaktov.Prijať?", + "contacts_send": "Odoslať", + "contacts_remove": "Odstrániť kontakt", + "contacts_typeHere": "Tu napíšte správu...", + "contacts_padTitle": "Chat", + "contacts_info1": "Toto sú vaše kontakty. Odtiaľto možete:", + "contacts_info2": "Kliknite na ikonu kontaktu pre začatie chatu", + "contacts_info3": "Dvakrát kliknite na ikonu pre zobrazenie profilu", + "contacts_info4": "Každý z účastníkovv môže trvale zmazať históriu chatu", + "contacts_removeHistoryTitle": "Vymazať históriu chatu", + "contacts_confirmRemoveHistory": "Ste si istý že chcete natrvalo odstrániť históriu chatu? Dáta nemôžu byť obnovené", + "contacts_removeHistoryServerError": "Pri odstraňovaní histórie nastala chyba. Skúste to neskôr", + "contacts_fetchHistory": "Načítať staršiu históriu", + "contacts_rooms": "Miestnosti", + "contacts_leaveRoom": "Opustiť miestnosť", + "fm_rootName": "Drive", + "fm_trashName": "Kôš", + "fm_filesDataName": "Všetky súbory", + "fm_templateName": "Šablóny", + "fm_ownedPadsName": "Vlastné", + "fm_tagsName": "Štítky", + "fm_sharedFolderName": "Zdieľaný priečinok", + "fm_searchPlaceholder": "Vyhľadávanie...", + "fm_newButton": "Nový", + "fm_newFolder": "Nový priečinok", + "fm_newFile": "Nový dokument", + "ui_more": "Viac", + "fm_folder": "Zložka", + "fm_sharedFolder": "Zdielaná zložka", + "fm_folderName": "Názov zložky", + "fm_numberOfFolders": "# zložiek", + "fm_numberOfFiles": "# súborov", + "fm_fileName": "Názov súboru", + "fm_type": "Typ", + "fm_lastAccess": "Posledný prístup", + "fm_creation": "Vytvorené", + "fm_forbidden": "Zakázaná akcia", + "fm_originalPath": "Pôvodná cesta", + "fm_openParent": "Zobraziť v priečinku", + "fm_noname": "Dokument bez názvu", + "kanban_newBoard": "Nový stĺpec", + "canvas_saveToDrive": "Uložiť obrázok ako súbor v CryptDrive", + "contacts_added": "Žiadosť o kontakt prijatá.", + "contacts_confirmRemove": "Ste si istý, že chcete odstrániť {0}z kontaktov?", + "poll_removeUser": "Ste si istý, že chcete odstrániť tohto používateľa?", + "fm_emptyTrashDialog": "Naozaj chcete vyprázdniť kôš?", + "poll_optionPlaceholder": "Možnosť", + "oo_reconnect": "Pripojenie k serveru je obnovené. Kliknite OK pre obnovenie stránky a pokračovanie v úpravách.", + "profile_uploadTypeError": "Chyba: formát vašeho avatara nie je povolený. Povolené formáty sú: {0}", + "poll_descriptionHint": "Popíšte svoju anketu a použite tlačidlo ✓ (publikovať).\nPopis sa dá napísať iba pomocou syntaxe markdown, môžete tiež vložiť médiá zo svojho CryptDrive.\nKtokoľvek s odkazom môže popis zmeniť, ale to neodporúčame.", + "poll_comment_disabled": "Zverejnite anketu pomocou tlačidla ✓ aby boli povolené komentáre.", + "fm_searchName": "Hľadať", + "fm_removeSeveralPermanentlyDialog": "Ste si istý, že chcete odstrániť tieto súbory z vášho disku? Ostanú v diskoch ostatných používateľov, ktorý si ich uložili.", + "contacts_warning": "Všetko čo sem napíšete, je trvalé a dostupné všetkým súčasným aj budúcim používateľom tohto dokumentu. Buďte opatrní pri nakladaní s citlivými informáciami!", + "contacts_online": "Ďalší používateľ z tejto miestnosti je online", + "fm_recentPadsName": "Nedávne", + "fm_newButtonTitle": "Vytvorte nový dokument alebo priečinok, importujte súbor do aktuálneho priečinku.", + "fm_removePermanentlyDialog": "Ste si istý, že chcete odstrániť túto položku zo svojho disku? Položka ostane na diskoch používateľov ktorý si ho uložili.", + "fm_deleteOwnedPad": "Určite chcete natrvalo odstrániť tento dokument?", + "fm_deleteOwnedPads": "Určite chcete natrvalo odstrániť tieto dokumenty?", + "fm_restoreDialog": "Chcete obnoviť {0} na pôvodné miesto?", + "fm_unknownFolderError": "Vybraný alebo naposledy navštívený priečinok už neexistuje. Otváram nadradený priečinok...", + "fm_contextMenuError": "Nepodarilo sa otvoriť kontextové menu pre tento prvok. Ak problém pretrváva, skúste obnoviť stránku.", + "fm_selectError": "Nepodarilo sa vybrať zvolený prvok. Ak problém pretrváva, skúste stránku znova načítať.", + "fm_categoryError": "Nepodarilo sa otvoriť zvolenú kategóriu, zobrazuje sa koreňový adresár.", + "fm_info_root": "Môžete vytvoriť ľubovolné množstvo podpriečinkov pre triedenie súborov.", + "fm_info_template": "Tieto dokumenty sú uložené ako šablóny. Môžu sa znova použiť pri vytváraní nových dokumentov.", + "fm_info_recent": "Tieto dokumenty boli nedávno upravené alebo otvorené vami alebo ľuďmi, s ktorými spolupracujete.", + "fm_info_trash": "Vyprázdnite kôš pre uvoľnenie miesta na CryptDrive." } diff --git a/www/common/translations/messages.zh.json b/www/common/translations/messages.zh.json index f611b25c8..6ce783f91 100644 --- a/www/common/translations/messages.zh.json +++ b/www/common/translations/messages.zh.json @@ -1,220 +1,220 @@ { - "main_title": "CryptPad: 零知識, 即時協作編寫", + "main_title": "CryptPad:零知识,协同实时编辑", "type": { "pad": "富文本", - "code": "編碼", + "code": "代码", "poll": "投票", "slide": "Markdown 幻灯片", - "drive": "磁碟", + "drive": "CryptDrive", "whiteboard": "白板", - "file": "檔案", - "media": "多媒體", - "kanban": "任务看板", + "file": "文件", + "media": "媒体", + "kanban": "看板", "todo": "待办事项", "teams": "团队", "sheet": "工作表", "contacts": "联系人", "form": "表单", - "presentation": "演示文档", + "presentation": "演示文稿", "doc": "文档", "diagram": "图表" }, - "common_connectionLost": "伺服器連線中斷
    現在是唯讀狀態,直到連線恢復正常。", + "common_connectionLost": "服务器连接中断
    您现在处于只读模式,直到连接恢复。", "typeError": "此文档与所选应用不兼容", - "onLogout": "您已退出登录,{0}点击此处{1}登录
    或按 Esc 以只读模式访问您的文档。", - "loading": "載入中...", - "error": "錯誤", - "saved": "儲存", + "onLogout": "您已登出,{0}点击此处{1}登录
    或按 Esc 键以只读模式访问您的文档。", + "loading": "正在加载…", + "error": "错误", + "saved": "已保存", "deleted": "已删除", - "disconnected": "已斷線", - "synchronizing": "同步中", - "reconnecting": "重新連結...", - "readonly": "唯讀", + "disconnected": "已断开连接", + "synchronizing": "正在同步", + "reconnecting": "正在重新连接", + "readonly": "只读", "anonymous": "访客", - "users": "用戶", + "users": "用户", "viewer": "檢視者", "viewers": "檢視群", "editor": "編輯者", - "language": "語言", - "upgrade": "昇級", + "language": "语言", + "upgrade": "升级", "MB": "MB", "GB": "GB", "KB": "kB", "formattedMB": "{0} MB", "formattedGB": "{0} GB", "formattedKB": "{0} kB", - "pinLimitReached": "你已達到儲存容量上限", - "pinLimitReachedAlert": "您已达到存储空间上限。 新的文档不会存储在您的 CryptDrive 中。
    您可以从 CryptDrive 中删除文档或订阅高级优惠以提高您的存储空间上限。", - "pinLimitNotPinned": "已达到存储空间上限。
    此文档未存储在您的 CryptDrive 中。", - "pinLimitDrive": "您已达到存储空间上限。
    您无法创建新文档。", - "importButtonTitle": "从本地文档导入文档", - "exportButtonTitle": "将此文档导出到本地文档", - "exportPrompt": "你希望怎麼命名你的檔案?", - "user_rename": "改變顯示名稱", - "user_displayName": "顯示名稱", - "user_accountName": "帳號名稱", - "clickToEdit": "點擊以編輯", - "forgetPrompt": "点击确定会将此文档移至回收站。 确定吗?", + "pinLimitReached": "您已达到存储限制", + "pinLimitReachedAlert": "您已达到存储限制。新文档不会存储在您的 CryptDrive 中。
    您可以从 CryptDrive 中移除文档或订阅高级优惠以增加限额。", + "pinLimitNotPinned": "您已达到存储限制。
    此文档未存储在您的 CryptDrive 中。", + "pinLimitDrive": "您已达到存储限制。
    您无法创建新文档。", + "importButtonTitle": "从本地文件导入文档", + "exportButtonTitle": "将此文档导出到本地文件", + "exportPrompt": "是否命名您的文件?", + "user_rename": "更改显示名称", + "user_displayName": "显示名称", + "user_accountName": "账号名称", + "clickToEdit": "点击编辑", + "forgetPrompt": "点击确定会将此文档移至回收站。是否确定?", "movedToTrash": "该文档已移至回收站。
    访问我的云盘", "shareButton": "分享", - "shareSuccess": "複製連結到剪貼版", + "shareSuccess": "已将链接复制到剪贴板", "newButton": "新", - "newButtonTitle": "创建一个新文档", - "saveTemplateButton": "存成模版", - "saveTemplatePrompt": "為這個模版選一個標題", - "templateSaved": "模版已儲存!", - "selectTemplate": "選擇一個模版或是按 escape 跳出", - "previewButtonTitle": "顯示或隱藏 Markdown 預覽模式", - "presentButtonTitle": "輸入簡報模式", - "backgroundButtonTitle": "改變簡報的顏色背景", - "colorButtonTitle": "在簡報模式下改變文字顏色", - "printButton": "列印 (enter)", - "printOptions": "版型選項", - "printSlideNumber": "顯示投影片號碼", - "printDate": "顯示日期", + "newButtonTitle": "创建新文档", + "saveTemplateButton": "另存为模板", + "saveTemplatePrompt": "为模板选择标题", + "templateSaved": "模板已保存!", + "selectTemplate": "选择模板或按 Esc 键", + "previewButtonTitle": "显示或隐藏 Markdown 预览模式", + "presentButtonTitle": "进入演示模式", + "backgroundButtonTitle": "更改演示文稿中的背景颜色", + "colorButtonTitle": "在演示模式下更改文本颜色", + "printButton": "打印(Enter)", + "printOptions": "布局选项", + "printSlideNumber": "显示幻灯片编号", + "printDate": "显示日期", "printTitle": "显示文档标题", - "printCSS": "自定風格規則 (CSS):", - "printTransition": "啟用轉場動畫", - "slideOptionsTitle": "自定你的投影片", - "editShare": "編輯連結", - "viewShare": "唯讀連結", - "notifyJoined": "{0} 已加入此協作期間", - "notifyRenamed": "{0} 現在改名為 {1}", - "notifyLeft": "{0} 已離開了這個協作期間", - "okButton": "OK (enter)", + "printCSS": "自定义样式规则(CSS):", + "printTransition": "启用过渡动画", + "slideOptionsTitle": "自定义幻灯片", + "editShare": "编辑链接", + "viewShare": "只读链接", + "notifyJoined": "{0} 加入了协作会话", + "notifyRenamed": "{0} 现在已改名为 {1}", + "notifyLeft": "{0} 离开了协作会话", + "okButton": "确定(Enter)", "cancel": "取消", - "cancelButton": "取消 (esc)", - "historyButton": "顯示文件歷史", + "cancelButton": "取消(Esc)", + "historyButton": "显示文档历史记录", "history_next": "下个版本", "history_prev": "先前版本", - "history_closeTitle": "關閉歷史記錄", - "history_restoreTitle": "將此文件重建到所挑選的版本", - "history_restorePrompt": "您确定要用显示的版本替换文档的当前版本吗?", - "history_restoreDone": "文件已重建", - "poll_publish_button": "發佈", - "poll_create_user": "新增使用者", - "poll_create_option": "新增選項", - "poll_commit": "投入", - "poll_optionPlaceholder": "選項", - "poll_userPlaceholder": "你的名稱", - "poll_removeOption": "確定要移除這個選項嗎?", - "poll_removeUser": "確定要移除這位使用者嗎?", - "poll_descriptionHint": "請簡述這個調查目的,完成時使用「發佈鍵」。任何知道此調查連結者可以更改這裏的描述內容,但我們不鼓勵這麼做。.", + "history_closeTitle": "关闭历史记录", + "history_restoreTitle": "还原所选文档版本", + "history_restorePrompt": "是否确定要用显示的版本替换文档的当前版本?", + "history_restoreDone": "文档已还原", + "poll_publish_button": "发布", + "poll_create_user": "添加新用户", + "poll_create_option": "添加新选项", + "poll_commit": "提交", + "poll_optionPlaceholder": "选项", + "poll_userPlaceholder": "您的名字", + "poll_removeOption": "是否确定要移除此选项?", + "poll_removeUser": "是否确定要移除此用户?", + "poll_descriptionHint": "描述您的投票,并在完成后使用 ✓(发布)按钮。\n描述可以使用 Markdown 语法编写,您可以从 CryptDrive 嵌入媒体元素。\n任何拥有链接的人都可以更改描述,但不鼓励这样做。", "canvas_clear": "清除", - "canvas_delete": "刪除所選", - "canvas_width": "寛度", - "canvas_opacity": "透明度", + "canvas_delete": "删除所选内容", + "canvas_width": "宽度", + "canvas_opacity": "不透明度", "fm_rootName": "云盘", - "fm_trashName": "垃圾桶", - "fm_filesDataName": "所有檔案", - "fm_templateName": "模版", - "fm_searchName": "搜尋", - "fm_searchPlaceholder": "搜尋...", + "fm_trashName": "回收站", + "fm_filesDataName": "所有文件", + "fm_templateName": "模板", + "fm_searchName": "搜索", + "fm_searchPlaceholder": "搜索…", "fm_newButton": "新的", - "fm_newButtonTitle": "创建一个新的文档或文件夹,在当前文件夹中导入一个文件。", - "fm_newFolder": "新資料夾", + "fm_newButtonTitle": "创建新文档或文件夹,在当前文件夹中导入文件。", + "fm_newFolder": "新建文件夹", "fm_newFile": "新文档", - "fm_folder": "資料夾", - "fm_folderName": "資料夾名稱", - "fm_numberOfFolders": "# 個資料夾", - "fm_numberOfFiles": "# 檔案", - "fm_fileName": "檔案名", - "fm_type": "類型", - "fm_lastAccess": "上回使用", - "fm_creation": "創建", - "fm_forbidden": "禁止的行為", - "fm_originalPath": "原始路徑", - "fm_openParent": "顯示在目錄夾中", - "fm_noname": "無標題文件", - "fm_emptyTrashDialog": "確定要清理垃圾筒嗎?", + "fm_folder": "文件夹", + "fm_folderName": "文件夹名称", + "fm_numberOfFolders": "# 文件夹", + "fm_numberOfFiles": "# 文件", + "fm_fileName": "文件名", + "fm_type": "类型", + "fm_lastAccess": "上次访问", + "fm_creation": "创建", + "fm_forbidden": "禁止的操作", + "fm_originalPath": "原始路径", + "fm_openParent": "在文件夹中显示", + "fm_noname": "无标题文档", + "fm_emptyTrashDialog": "是否确定要清空回收站?", "fm_removeSeveralPermanentlyDialog": "您确定要从您的云盘中删除这些{0}项目吗? 它们将留在已存储它们的其他用户的云盘中。", "fm_removePermanentlyDialog": "您确定要从云盘中删除此项目吗?它将保留在已存储它的其他用户的云盘中。", - "fm_restoreDialog": "確定要重置 {0} 到它之前的位置嗎?", - "fm_unknownFolderError": "所選或上回訪問的目錄不再存在了,正開啟上層目錄中...", - "fm_contextMenuError": "無法在此元件下打開文本選單。如果這個問題一直發生,請試著重新載入此頁。", - "fm_selectError": "無法選取目標的要素。如果這個問題一直發生,請試著重新載入此頁。", - "fm_categoryError": "無法打開所選的類別,正在顯示根目錄。", - "fm_info_root": "在此建立任何巢狀目錄夾以便於整理分類你的檔案。", + "fm_restoreDialog": "是否确定要将 {0} 还原到之前的位置?", + "fm_unknownFolderError": "所选或上次访问的目录不再存在。正在打开上层文件夹…", + "fm_contextMenuError": "无法打开该元素的上下文菜单。如果问题仍然存在,请尝试重新加载页面。", + "fm_selectError": "无法选择目标元素。如果问题仍然存在,请尝试重新加载页面。", + "fm_categoryError": "无法打开所选类别,显示根目录。", + "fm_info_root": "在此处创建任意数量的嵌套文件夹以便对文件进行分类。", "fm_info_template": "这些文档存储为模板。 创建新文档时可以重复使用它们。", - "fm_info_trash": "清空垃圾筒好讓 CryptDrive 多出一些空間", + "fm_info_trash": "清空回收站以释放 CryptDrive 中的空间。", "fm_info_anonymous": "您尚未登录,因此您的文档将在 {0} 天后过期。清除浏览器历史记录可能会导致它们消失。
    注册(无需提供个人信息)或登录即可将文档无限期地存储在您的云盘中。阅读有关注册账号的更多信息。", - "fm_error_cantPin": "內部伺服器出錯,請重新載入本頁並再試一次。", - "fc_newfolder": "新資料夾", - "fc_rename": "重新命名", - "fc_open": "打開", - "fc_open_ro": "打開 (唯讀)", - "fc_delete": "刪除", - "fc_restore": "重置", + "fm_error_cantPin": "内部服务器错误,请重新加载页面并重试。", + "fc_newfolder": "新建文件夹", + "fc_rename": "重命名", + "fc_open": "打开", + "fc_open_ro": "打开(只读)", + "fc_delete": "移至回收站", + "fc_restore": "还原", "fc_remove": "删除", - "fc_empty": "清理垃圾筒", + "fc_empty": "清空回收站", "fc_prop": "Properties", - "fo_moveUnsortedError": "你不能移動資料夾到未整理的工作檔案清單", - "fo_existingNameError": "名稱已被使用,請選擇其它名稱", - "fo_moveFolderToChildError": "你不能移動資料夾到它的子資料夾底下", - "fo_unavailableName": "在新位置裏同名的檔案或資料夾名稱已存在,請重新命名後再試看看。", - "login_login": "登入", - "login_register": "註冊", + "fo_moveUnsortedError": "您无法将文件夹移动到模板列表", + "fo_existingNameError": "名称已在该目录中使用,请选择其他名称。", + "fo_moveFolderToChildError": "您无法将文件夹移至其子文件夹", + "fo_unavailableName": "新位置已存在同名文件或文件夹,重命名元素并重试。", + "login_login": "登录", + "login_register": "注册", "logoutButton": "登出", - "settingsButton": "設定", - "login_username": "用戶名", - "login_password": "密碼", - "login_confirm": "確認你的密碼", - "login_hashing": "散列你的密碼中,這要花上一點時間", + "settingsButton": "设置", + "login_username": "用户名", + "login_password": "密码", + "login_confirm": "确认您的密码", + "login_hashing": "正在散列您的密码,这可能需要一些时间。", "login_noSuchUser": "用户名或密码无效", - "login_invalUser": "要求用戶名", - "login_invalPass": "要求密碼", - "login_unhandledError": "發生了未預期的錯誤 :(", - "register_importRecent": "从您的访客会话中导入文档", - "register_acceptTerms": "我同意 服務條款", - "register_passwordsDontMatch": "密碼不相符!", - "register_mustAcceptTerms": "你必須同意我們的服務條款。", + "login_invalUser": "请填写用户名", + "login_invalPass": "请填写密码", + "login_unhandledError": "发生意外错误 :(", + "register_importRecent": "从访客会话导入文档", + "register_acceptTerms": "我接受服务条款", + "register_passwordsDontMatch": "密码不匹配!", + "register_mustAcceptTerms": "您必须接受服务条款。", "register_header": "注册", - "register_writtenPassword": "我已記下了我的用戶名和密碼,請繼續", + "register_writtenPassword": "我已记下我的用户名和密码,继续", "register_cancel": "取消", "register_warning": "警告", - "register_alreadyRegistered": "這名用戶己存在了,你要登入嗎?", - "settings_title": "設定", - "settings_save": "儲存", - "settings_backup": "備份", - "settings_restore": "重建", - "settings_reset": "從你的 CryptDrive 移除所有的檔案和資料夾", + "register_alreadyRegistered": "此用户已存在,是否要登录?", + "settings_title": "设置", + "settings_save": "保存", + "settings_backup": "备份", + "settings_restore": "还原", + "settings_reset": "从 CryptDrive 移除所有文件和文件夹", "settings_resetPrompt": "此操作将从您的云盘中删除所有文档。
    确定要继续吗?
    输入“我喜欢 CryptPad”进行确认。", - "settings_resetDone": "你的目錄現已清空!", - "settings_resetError": "不正確的認證文字,你的 CryptDrive 並未更改。", - "settings_resetTips": "使用 CryptDrive 的竅門", - "settings_resetTipsButton": "在 CryptDrive 下重置可用的訣竅", - "settings_resetTipsDone": "所有的訣竅現在都可再次看到了。", + "settings_resetDone": "您的云盘现在为空!", + "settings_resetError": "验证文本不正确,您的 CryptDrive 尚未更改。", + "settings_resetTips": "提示", + "settings_resetTipsButton": "重置 CryptDrive 中的可用提示", + "settings_resetTipsDone": "现在可以再次看到所有提示。", "settings_importTitle": "将此浏览器的最近文档导入您的 CryptDrive 中", - "settings_import": "滙入", - "settings_importConfirm": "您确定要将最近的文档从此浏览器导入到您用户帐户的 CryptDrive 吗?", - "settings_importDone": "滙入完成", + "settings_import": "导入", + "settings_importConfirm": "是否确定要将最近的文档从此浏览器导入到您用户账号的 CryptDrive?", + "settings_importDone": "导入已完成", "settings_userFeedbackHint1": "CryptPad 會提供一些基本的反饋到伺服器,以讓我們知道如何改善用戶體驗。", "settings_userFeedbackHint2": "您的文档内容永远不会与服务器共享。", - "settings_userFeedback": "啟用用戶反饋功能", - "settings_anonymous": "你尚未登入,在此瀏覽器上進行特別設定。", - "settings_publicSigningKey": "公開金鑰簽署", + "settings_userFeedback": "启用用户反馈", + "settings_anonymous": "您尚未登录,此处的设置仅适用于此浏览器。", + "settings_publicSigningKey": "公开签名密钥", "settings_logoutEverywhereTitle": "关闭远程会话", - "settings_logoutEverywhere": "自所有其它的網頁期間登出", - "settings_logoutEverywhereConfirm": "你確定嗎?你將需要登入到所有用到設置。", - "upload_serverError": "伺服器出錯:本次無法上傳你的檔案", - "upload_uploadPending": "你欲上傳檔案正在傳輸中,要取消並上傳新檔案嗎?", - "upload_success": "你的檔案 ({0}) 已成功地上傳並放入到你的網路磁碟中。", - "upload_notEnoughSpace": "你的 CryptDrive 無足夠空間來存放這個檔案。", - "upload_tooLarge": "该文档超过了您的帐户允许的最大上传大小。", - "upload_choose": "選擇一個檔案", - "upload_pending": "待處理", - "upload_cancelled": "已取消的", + "settings_logoutEverywhere": "强制登出所有其他网页会话", + "settings_logoutEverywhereConfirm": "是否确定?您需要登录所有的设备。", + "upload_serverError": "服务器错误:此时无法上传文件。", + "upload_uploadPending": "您已经有正在上传的文件,取消并上传新文件?", + "upload_success": "您的文件({0})已成功上传并添加到云盘。", + "upload_notEnoughSpace": "CryptDrive 中没有足够的空间容纳此文件。", + "upload_tooLarge": "此文件超过了您账号允许的最大上传大小。", + "upload_choose": "选择文件", + "upload_pending": "待处理", + "upload_cancelled": "已取消", "upload_size": "大小", - "about": "關於", - "privacy": "隐私", - "contact": "聯繫", + "about": "关于", + "privacy": "隐私政策", + "contact": "联系我们", "terms": "服务条款", - "header_logoTitle": "回到主頁", - "edit": "編輯", - "view": "檢視", + "header_logoTitle": "转到您的 CryptDrive", + "edit": "编辑", + "view": "查看", "feedback_about": "如果您正在阅读本文,您可能会好奇为什幺 CryptPad 在您执行某些操作时会请求网页。", - "feedback_privacy": "我們注重你的隱私,同時也要讓 CryptPad 容易使用。我們利用這個檔案來了解哪一種介面設計為用戶所重視,透過它來請求特別的功能參數。", - "feedback_optout": "如果欲退出客戶資料收集, 請到 用戶設定頁, 可以找到勾選項目來啟用或關閉用戶回饋功能。", + "feedback_privacy": "我们注重您的隐私,同时也希望 CryptPad 非常易于使用。我们使用此文件来了解哪些用户界面功能对我们的用户很重要,通过请求它以及指定已执行的操作的参数。", + "feedback_optout": "如果您想选择退出,请访问您的用户设置页面,找到可以启用或禁用用户反馈复选框。", "settings_cat_kanban": "看板", "themeButton": "主题", "languageButton": "语言", @@ -226,15 +226,15 @@ "forgetButton": "删除", "exportButton": "导出", "importButton": "导入", - "forgotten": "移到回收站", - "initializing": "初始化中…", - "typing": "编辑中", + "forgotten": "已移至回收站", + "initializing": "正在初始化…", + "typing": "正在编辑", "profile_editDescription": "编辑描述", "profile_addDescription": "添加描述", "poll_comment_submit": "发送", "poll_comment_list": "评论", "poll_edit": "编辑", - "poll_remove": "删除", + "poll_remove": "移除", "kanban_done": "完成", "pad_mediatagPreview": "预览", "historyText": "历史", @@ -255,29 +255,29 @@ "fm_deleteOwnedPads": "您确定要永久销毁这些文档吗?", "fm_deleteOwnedPad": "您确定要永久销毁此文档吗?", "fm_sharedFolder": "共享文件夹", - "ui_more": "更多的", + "ui_more": "更多", "fm_sharedFolderName": "共享文件夹", "fm_tagsName": "标签", "fm_ownedPadsName": "拥有的", "fm_recentPadsName": "最近", "contacts_online": "此房间的另一位用户在线", - "contacts_leaveRoom": "离开这个房间", + "contacts_leaveRoom": "离开此房间", "contacts_rooms": "房间", "contacts_fetchHistory": "检索更早的历史记录", - "contacts_removeHistoryServerError": "删除您的聊天记录时出错。 稍后再试", - "contacts_confirmRemoveHistory": "您确定要永久删除您的聊天记录吗? 数据无法恢复", + "contacts_removeHistoryServerError": "移除聊天记录时出错,请稍后重试", + "contacts_confirmRemoveHistory": "是否确定要永久移除您的聊天记录?数据无法恢复", "contacts_removeHistoryTitle": "清理聊天记录", - "contacts_info4": "任何一个参与者都可以永久清除聊天记录", - "contacts_info3": "双击他们的图标以查看他们的个人资料", - "contacts_info2": "单击联系人的图标与他们聊天", - "contacts_info1": "这些是您的联系人。 从这里,您可以:", + "contacts_info4": "任一参与者均可永久清除聊天记录", + "contacts_info3": "双击联系人图标查看其个人资料", + "contacts_info2": "点击联系人图标与其聊天", + "contacts_info1": "这些是您的联系人。从这里,您可以:", "contacts_padTitle": "聊天", - "contacts_warning": "您在此处键入的所有内容都是持久存在的,可供本文档的所有现有和未来用户使用。 小心敏感信息!", - "contacts_typeHere": "在此处输入消息...", - "contacts_confirmRemove": "确定要从联系人中删除 {0} 吗?", - "contacts_remove": "删除此联系人", + "contacts_warning": "您在此输入的所有内容都将持续存在,本文档的所有现有用户及未来用户都可访问。请注意敏感信息!", + "contacts_typeHere": "在此处输入消息…", + "contacts_confirmRemove": "是否确定要从您的联系人移除 {0}?", + "contacts_remove": "移除此联系人", "contacts_send": "发送", - "contacts_request": "{0} 想将您添加为联系人。 要接受吗?", + "contacts_request": "{0} 想将您添加为联系人。接受吗?", "contacts_rejected": "联系人邀请被拒绝", "contacts_added": "联系人已接受邀请。", "contacts_title": "联系人", @@ -285,34 +285,34 @@ "profile_viewMyProfile": "查看我的个人资料", "profile_register": "您必须注册才能创建个人资料!", "profile_error": "创建您的个人资料时出错:{0}", - "profile_uploadTypeError": "错误:您的头像类型不被允许。 允许的类型是:{0}", + "profile_uploadTypeError": "错误:不允许您的头像类型。允许的类型为:{0}", "profile_uploadSizeError": "错误:您的头像必须小于 {0}", "profile_upload": " 上传新头像", "profileButton": "个人资料", "canvas_currentBrush": "当前画笔", - "canvas_imageEmbed": "从您的计算机中嵌入图像", - "canvas_saveToDrive": "将此图像另存为 CryptDrive 中的文档", + "canvas_imageEmbed": "从您的计算机嵌入图片", + "canvas_saveToDrive": "将此图片保存为 CryptDrive 中的文件", "canvas_widthLabel": "宽度:{0}", "canvas_opacityLabel": "不透明度:{0}", "oo_uploaded": "上传已完成。点击确定重新加载页面或点击取消以只读模式继续。", "oo_cantUpload": "其他用户在场时不允许上传。", - "oo_reconnect": "服务器已恢复连接。 单击确定以重新加载并继续编辑。", + "oo_reconnect": "服务器连接已恢复,点击确定重新加载并继续编辑。", "poll_comment_disabled": "使用 ✓ 按钮发布此投票以启用评论。", "poll_comment_placeholder": "您的评论", "poll_comment_remove": "删除此评论", "poll_comment_add": "添加评论", - "poll_total": "全部的", + "poll_total": "总计", "poll_bookmarked_col": "这是您的书签专栏。它将始终为您解锁并在开始时显示。", "poll_bookmark_col": "将此列添加为书签,以便它始终解锁并在开始时为您显示", - "poll_unlocked": "解锁", - "poll_locked": "锁定", - "kanban_addBoard": "添加新看板", + "poll_unlocked": "已解锁", + "poll_locked": "已锁定", + "kanban_addBoard": "添加面板", "kanban_working": "进行中", "kanban_todo": "待办事项", "kanban_item": "项目 {0}", - "kanban_newBoard": "新看板", - "pad_mediatagOptions": "图像属性", - "pad_mediatagImport": "保存到您的 CryptDrive 中", + "kanban_newBoard": "新面板", + "pad_mediatagOptions": "图片属性", + "pad_mediatagImport": "保存在您的 CryptDrive 中", "pad_mediatagBorder": "边框宽度(像素)", "pad_mediatagRatio": "保持比例", "pad_mediatagHeight": "高度(像素)", @@ -324,59 +324,59 @@ "ok": "确定", "fileEmbedTag": "然后将此媒体标签放置在您要嵌入的页面中的任何位置:", "fileEmbedScript": "要嵌入此文件,请在您的页面中包含此脚本一次以加载媒体标签:", - "viewEmbedTag": "要嵌入此文档,请将此 iframe 包含在您的页面中任何想要的位置。您可以使用 CSS 或 HTML 属性对其进行样式设置。", + "viewEmbedTag": "要嵌入此文档,请将此 iframe 包含在您想要的页面中的任何位置。您可以使用 CSS 或 HTML 属性对其进行样式设置。", "themeButtonTitle": "选择用于代码和幻灯片编辑器的颜色主题", "languageButtonTitle": "选择用于语法突出显示的语言", "slide_invalidLess": "自定义样式无效", - "tags_noentry": "您不能标记已删除的文档", + "tags_noentry": "您无法标记已删除的文档", "tags_duplicate": "重复标签:{0}", - "tags_notShared": "您的标签未与其他用户共享", + "tags_notShared": "您的标签不会与其他用户共享", "tags_add": "更新所选文档的标签", - "tags_title": "标签(仅供自己使用)", - "filePicker_filter": "按名称筛选文档", - "filePicker_description": "从您的 CryptDrive 中选择一个文件以嵌入它或上传一个新文件", - "filePickerButton": "嵌入存储在 CryptDrive 中的文档", + "tags_title": "标签(仅供您使用)", + "filePicker_filter": "按名称筛选文件", + "filePicker_description": "从 CryptDrive 中选择文件以嵌入或上传新文件", + "filePickerButton": "嵌入存储在 CryptDrive 中的文件", "printBackgroundRemove": "移除此背景图片", - "printBackgroundNoValue": " 不显示背景图片 ", - "printBackgroundValue": " 当前背景: {0} ", - "printBackgroundButton": "选择一张图片", + "printBackgroundNoValue": "不显示背景图片", + "printBackgroundValue": "当前背景:{0}", + "printBackgroundButton": "选择图片", "printBackground": "使用背景图片", - "printButtonTitle2": "打印您的文档或将其导出为 PDF 文档", + "printButtonTitle2": "打印文档或将其导出为 PDF 文件", "propertiesButtonTitle": "获取文档属性", "template_empty": "没有可用的模板", "template_import": "导入模板", - "useTemplateCancel": "重新开始 (Esc)", - "useTemplateOK": "选择一个模板(Enter)", + "useTemplateCancel": "重新开始(Esc)", + "useTemplateOK": "选择模板(Enter)", "useTemplate": "从模板开始?", - "uploadButtonTitle": "上传新文件到您的 CryptDrive", + "uploadButtonTitle": "将新文件上传到您的 CryptDrive", "uploadFolderButton": "上传文件夹", - "uploadButton": "上传文档", + "uploadButton": "上传文件", "form_required_on": "必要的", "form_required_off": "选项", "form_preview": "表格预览", "form_changeTypeConfirm": "选择新的问题类型。", "form_corruptAnswers": "此表单已经有回复。 更改此问题类型可能会使以前的响应数据无效。", - "userAccountButton": "用户中心", + "userAccountButton": "用户菜单", "userListButton": "用户列表", - "saveTitle": "保存标题(enter)", - "pinLimitReachedAlertNoAccounts": "您已达到存储空间上限", - "storageStatus": "存储:
    {0}已用完{1}", + "saveTitle": "保存标题(Enter)", + "pinLimitReachedAlertNoAccounts": "您已达到存储限制", + "storageStatus": "存储:
    已使用 {0}(共 {1})", "upgradeAccount": "升级账号", "userlist_offline": "您当前处于离线状态,用户列表不可用。", "errorState": "严重错误:{0}", - "realtime_unrecoverableError": "发生了不可恢复的错误。 单击确定以重新加载。", - "disabledApp": "此应用已被禁用。 请联系此 CryptPad 的管理员了解详细信息。", + "realtime_unrecoverableError": "发生了不可恢复的错误,点击确定重新加载。", + "disabledApp": "已禁用此应用程序。如需了解详情,请联系此 CryptPad 的管理员。", "mustLogin": "您必须登录才能访问此页面", "deletedFromServer": "文档已销毁", - "newVersionError": "有新版本的 CryptPad 可用。
    重新加载以使用新版本,或按 Esc 键以离线模式访问您的内容。", - "errorRedirectToHome": "按 Esc 重定向到您的 CryptDrive。", - "errorCopy": " 您仍然可以按只读模式使用当前版本 Esc 。", + "newVersionError": "CryptPad 的新版本可用。
    重新加载以使用新版本,或按 Esc 键在离线模式下访问您的内容。", + "errorRedirectToHome": "按 Esc 键重定向到您的 CryptDrive。", + "errorCopy": " 您仍然可以通过按 Esc 键在只读模式下使用当前版本。", "invalidHashError": "您请求的文档的 URL 无效。", - "chainpadError": "更新内容时出现严重错误。 此页面处于只读模式,以确保您不会丢失您的工作。
    点击 Esc 以继续查看此文档,或重新加载后再次尝试编辑。", - "inactiveError": "由于缺少活动,此文档已被删除。 按 Esc 创建一个新文档。", - "deletedError": "该文档已被删除,不再可用。", + "chainpadError": "更新内容时出现严重错误。此页面处于只读模式,以确保不会丢失工作。
    按 Esc 键继续查看此文档,或重新加载以尝试再次编辑。", + "inactiveError": "由于不活动,此文档已被删除。按 Esc 键创建新文档。", + "deletedError": "此文档已被删除,不再可用。", "expiredError": "此文档已达到销毁日期,不再可用。", - "anonymousStoreDisabled": "此 CryptPad 实例的管理员已禁用访客存储服务。 请登录以访问您自己的 CryptDrive。", + "anonymousStoreDisabled": "此 CryptPad 实例的管理员已禁用访客存储服务。请登录以访问您自己的 CryptDrive。", "padNotPinnedVariable": "此文档将在 {4} 天不活动后过期,请{0}登录{1}或{2}注册{3}以保留它。", "padNotPinned": "此文档将在 3 个月不活动后过期,请{0}登录{1}或{2}注册{3}以保留它。", "download_step2": "解密中", @@ -411,15 +411,15 @@ "settings_changePasswordNew": "新密码", "settings_changePasswordCurrent": "当前密码", "settings_changePasswordButton": "更改密码", - "settings_changePasswordHint": "更改您的帐户密码。 输入您当前的密码,然后输入两次以确认新密码。
    如果您忘记了密码,我们将无法重置您的密码,因此请务必小心!", + "settings_changePasswordHint": "更改您的账号密码。输入您当前的密码,然后输入两次以确认新密码。
    如果您忘记了密码,我们将无法重置您的密码,因此请务必小心!", "settings_changePasswordTitle": "更改您的密码", - "settings_ownDrivePending": "您的帐户正在升级。 在该过程完成之前,请不要关闭或重新加载此页面。", - "settings_ownDriveConfirm": "升级您的帐户可能需要一些时间。您需要在所有设备上重新登录。确定吗?", - "settings_ownDriveButton": "升级您的帐户", - "settings_ownDriveHint": "由于技术原因,较旧的帐户无法访问最新功能。 免费更新将启用当前功能,并为之后的更新准备好您的 CryptDrive。", + "settings_ownDrivePending": "正在升级您的账号。在过程完成之前,请勿关闭或重新加载此页面。", + "settings_ownDriveConfirm": "升级您的账号可能需要一些时间。您需要在所有设备上重新登录。是否确定?", + "settings_ownDriveButton": "升级您的账号", + "settings_ownDriveHint": "由于技术原因,旧账号无法访问最新功能。免费更新将启用当前功能,并为 CryptDrive 的未来更新做准备。", "settings_ownDriveTitle": "更新账号", "settings_padOpenLinkLabel": "启用打开直接链接的功能", - "settings_padOpenLinkHint": "使用此选项,您可以在单击时打开嵌入式链接而无需弹出预览窗口", + "settings_padOpenLinkHint": "使用此选项无需预览弹窗就可以在点击时打开嵌入式链接", "settings_padOpenLinkTitle": "首次点击时打开链接", "settings_padSpellcheckLabel": "在富文本文档中启用拼写检查", "settings_padSpellcheckHint": "此选项允许您在富文本文档中启用拼写检查。 拼写错误将带有红色下划线,您必须在右键单击时按住 Ctrl 或 Meta 键才能看到正确的选项。", @@ -434,11 +434,11 @@ "settings_driveDuplicateHint": "当您将拥有的文档移动到共享文件夹时,您的 CryptDrive 中会保留一份副本,以确保您保留对它的控制权。您可以隐藏重复的文档。除非被删除,否则只有共享版本可见,在这种情况下,原始版本将显示在其先前的位置。", "settings_driveDuplicateTitle": "您拥有的重复文档", "settings_logoutEverywhereButton": "退出登录", - "settings_deleted": "您的用户帐号现已删除。 按 确定 进入主页。", + "settings_deleted": "现已删除您的用户账号,按“确定”转到主页。", "settings_deleteButton": "删除您的帐号", "settings_deleteModal": "与您的 CryptPad 管理员共享以下信息,以便从他们的服务器中删除您的数据。", - "settings_deleteHint": "删除账号是永久性的。 您的 CryptDrive 和您的文档列表将从服务器中删除。 如果没有其他人将它们存储在他们的 CryptDrive 中,您的其余文档将在 90 天内被删除。", - "settings_deleteTitle": "删除账号", + "settings_deleteHint": "账号删除是永久的。将从服务器删除您的 CryptDrive 和文档列表。如果没有其他人在其 CryptDrive 中存储您的文档,将在 90 天后删除其余文档。", + "settings_deleteTitle": "账号删除", "settings_userFeedbackTitle": "反馈", "settings_autostoreMaybe": "手动(总是询问)", "settings_autostoreNo": "手动(从不询问)", @@ -460,9 +460,9 @@ "settings_exportErrorDescription": "我们无法将以下文档添加到导出文档中:", "settings_exportError": "查看错误", "settings_export_done": "您的下载已准备就绪!", - "settings_export_compressing": "压缩数据...", - "settings_export_download": "正在下载和解密您的文档...", - "settings_export_reading": "正在读取您的 CryptDrive...", + "settings_export_compressing": "正在压缩数据…", + "settings_export_download": "正在下载和解密您的文档…", + "settings_export_reading": "正在读取您的 CryptDrive…", "settings_exportCancel": "您确定要取消导出吗? 下次您将不得不从头开始。", "settings_exportWarning": "注意:此工具仍处于公测版本,可能存在可扩展性问题。为了获得更好的性能,建议让此选项卡保持焦点。", "settings_exportFailed": "如果文档需要 1 分钟以上的时间才能下载,则它不会包含在导出文档中。 将显示一个指向尚未导出的文档链接。", @@ -490,7 +490,7 @@ "fc_delete_owned": "销毁", "fc_collapseAll": "全部收起", "fc_expandAll": "展开全部", - "fc_color": "换颜色", + "fc_color": "更改颜色", "fc_newsharedfolder": "新建共享文件夹", "fm_passwordProtected": "密码保护", "fm_moveNestedSF": "您不能将一个共享文件夹放在另一个共享文件夹中。 文件夹 {0} 未移动。", @@ -530,7 +530,7 @@ "autostore_notstored": "{0}不在您的 CryptDrive 里。您要继续保存吗?", "autostore_pad": "pad", "autostore_sf": "文件夹", - "autostore_file": "文档", + "autostore_file": "文件", "chrome68": "您似乎在使用 Chrome 或者 Chromium 68 版本。这个版本的错误会导致页面变白或者失去响应。碰到这个问题的时候,您可以切换到其他标签页然后再切回来,或者滚动页面。这个问题会在浏览器未来的版本中修复。", "convertFolderToSF_confirm": "这个目录必须要转成共享目录才能被其他用户访问,继续?", "convertFolderToSF_SFChildren": "已经在共享目录里面的目录不能再次被共享。可以将目录移到其他地方继续。", @@ -548,7 +548,7 @@ "share_embedCategory": "内嵌", "main_catch_phrase": "协同套件
    端到端加密并开源", "features_f_social": "社交功能", - "features_f_devices_note": "在任何地方使用您的帐号访问 CryptDrive", + "features_f_devices_note": "使用您的用户账号随时随地访问您的 CryptDrive", "features_f_devices": "所有设备上的文档", "features_f_cryptdrive1_note": "目录,共享目录,模板,标签", "features_f_cryptdrive1": "全部CryptDrive功能", @@ -609,11 +609,11 @@ "support_disabledTitle": "未启用支持", "admin_supportListHint": "这是用户发送到支持邮箱的工单列表。 所有管理员都可以看到消息及其答案。 已关闭的票无法重新打开。 您只能删除(隐藏)已关闭的工单,其他管理员仍然可以看到已删除的工单。", "admin_supportListTitle": "支持邮箱", - "admin_supportInitHint": "您可以配置一个邮箱以方便用户以安全的方式反馈使用信息给您。", + "admin_supportInitHint": "您可以配置支持邮箱,以便您的 CryptPad 实例用户在账号有问题时有安全联系您的方式。", "admin_supportInitTitle": "支持邮箱初始化", "admin_supportAddError": "无效的私钥", "admin_supportAddKey": "添加私钥", - "admin_supportInitPrivate": "您的 CryptPad 实例配置了邮箱,但您的帐户没有正确的私钥来访问它。 请在下面的输入框里面添将私钥添更新到您的帐户里。", + "admin_supportInitPrivate": "您的 CryptPad 实例配置为使用支持邮箱,但您的账号没有正确的私钥来访问它。请使用下表将私钥添加或更新到您的账号。", "admin_supportInitHelp": "您的服务器尚未配置支持邮箱。 如果您希望支持邮箱接收来自您的用户的消息,您应该让您的服务器管理员运行位于“./scripts/generate-admin-keys.js”中的脚本,然后将公钥存储在“config.js”中 \" 文档并将私钥发送给您。", "admin_cat_support": "支持", "supportPage": "支持", @@ -627,7 +627,7 @@ "notification_padShared": "{0} 与您共享了一个文档:{1}", "isNotContact": "{0}不是您的联系人", "isContact": "{0} 是您的联系人之一", - "profile_friendRequestSent": "联系请求待处理...", + "profile_friendRequestSent": "联系请求待处理…", "profile_info": "其他用户可以通过您在文档用户列表中的头像找到您的个人资料。", "profile_addLink": "添加指向您网站的链接", "notifications_empty": "没有可用的通知", @@ -646,14 +646,14 @@ "settings_codeSpellcheckTitle": "拼写检查", "admin_diskUsageButton": "生成报告", "admin_diskUsageHint": "各种 CryptPad 资源占用的存储空间量", - "admin_diskUsageTitle": "磁盘使用情况", + "admin_diskUsageTitle": "云盘使用量", "timeoutError": "一个错误中断了您与服务器的连接。
    点击 Esc 重新加载页面。", "contact_email": "电子邮件", "contact_chat": "聊天", "contact_bug": "Bug报告", "contact_devHint": "用于功能请求、可用性改进或者说声谢谢。", "contact_dev": "联系开发人员", - "contact_adminHint": "关于账户、存储限制或者服务可用性相关的任务问题。\n", + "contact_adminHint": "有关您的账号、存储限制或服务可用性的任何问题。\n", "contact_admin": "联系管理员:{0}", "footer_donate": "捐献", "admin_flushCacheDone": "清除缓存成功", @@ -674,7 +674,7 @@ "settings_cat_security": "安全和隐私", "imprint": "法律声明", "oo_sheetMigration_anonymousEditor": "本文档需要升级。 在注册用户打开之前,访客无法进行编辑。", - "oo_sheetMigration_complete": "可用更新版本,按 OK 重新加载。", + "oo_sheetMigration_complete": "有可用的更新版本,按“确定”重新加载。", "oo_sheetMigration_loading": "将您的文档升级到最新版本。 请等待大约 1 分钟。", "oo_exportInProgress": "正在导出", "oo_importInProgress": "正在导入", @@ -682,7 +682,7 @@ "burnAfterReading_warningDeleted": "此文档已被永久删除,一旦您关闭此窗口,您将无法再次访问它。", "burnAfterReading_proceed": "查看和删除", "burnAfterReading_warningAccess": "该文档将自毁。 当您单击下面的按钮时,您将在永久删除之前看到一次内容。 当您关闭此窗口时,您将无法再次访问它。 如果您还没有准备好继续,您可以关闭此窗口并稍后再回来。", - "burnAfterReading_generateLink": "单击下面的按钮以生成链接。", + "burnAfterReading_generateLink": "点击下方按钮生成链接。", "team_inviteJoin": "加入团队", "team_inviteLinkCreate": "创建链接", "burnAfterReading_warningLink": "您已将此文档设置为自毁。 收件人访问此链接后,他们将能够看到该文档一次,然后将其永久删除。", @@ -700,7 +700,7 @@ "team_inviteFrom": "从:", "team_inviteLinkCopy": "创建链接", "team_inviteLinkErrorName": "请为您邀请的人添加姓名。 他们可以稍后更改。 ", - "team_inviteLinkWarning": "访问此链接的人员将能够加入此团队并查看其内容。请谨慎分享。", + "team_inviteLinkWarning": "访问此链接的人员将能够加入此团队并查看其内容,请谨慎分享。", "team_inviteLinkLoading": "生成您的链接", "team_inviteLinkNoteMsg": "此消息将在收件人决定是否加入此团队之前显示。", "share_contactPasswordAlert": "此项目受密码保护。 因为您与 CryptPad 联系人共享它,所以收件人不必输入密码。", @@ -713,7 +713,7 @@ "team_inviteLinkTempName": "临时名称(在待处理的邀请列表中可见)", "team_inviteLinkTitle": "为该团队创建个性化邀请", "contacts_muteInfo": "您不会收到来自禁言用户的任何通知或消息。
    他们不会知道您已将他们禁言。 ", - "contacts_mutedUsers": "禁言帐户", + "contacts_mutedUsers": "已禁言账号", "contacts_manageMuted": "管理禁言", "contacts_unmute": "取消禁言", "contacts_mute": "禁言", @@ -759,7 +759,7 @@ "owner_team_add": "{0} 希望您成为团队 {1} 的所有者。要接受吗?", "team_listSlot": "可用的团队名额", "team_listTitle": "您的团队", - "team_maxTeams": "每个用户帐户只能是 {0} 个团队的成员。", + "team_maxTeams": "每个用户账号只能是 {0} 个团队的成员。", "team_infoContent": "每个团队都有自己的 CryptDrive、存储配额、聊天和成员列表。 团队所有者可以删除整个团队,管理员可以邀请或踢除成员,成员可以离开团队。", "team_avatarHint": "最大尺寸为 500 kB(png、jpg、jpeg、gif)", "team_avatarTitle": "团队头像", @@ -778,10 +778,10 @@ "team_createLabel": "创建一个新团队", "team_infoLabel": "关于团队", "team_cat_admin": "管理员", - "team_cat_drive": "磁盘", + "team_cat_drive": "云盘", "team_cat_chat": "聊天", "team_cat_members": "成员", - "team_cat_back": "回到团队", + "team_cat_back": "返回团队", "team_cat_create": "新建", "team_cat_list": "团队", "team_cat_general": "关于", @@ -843,7 +843,7 @@ "properties_changePassword": "改变密码", "properties_addPassword": "添加一个密码", "password_submit": "递交", - "password_placeholder": "在此处输入密码...", + "password_placeholder": "在此处输入密码…", "password_error": "找不到文档
    此错误可能由两个因素引起:密码无效或文档已被破坏。", "password_info": "您尝试打开的文档不再存在或受新密码保护。 输入正确的密码以访问内容。", "creation_newPadModalDescription": "单击一个应用进程以创建一个新文档。 您也可以按 Tab 选择应用进程,然后按 Enter 确认。", @@ -851,7 +851,7 @@ "creation_expiration": "销毁日期", "creation_noOwner": "没有拥有者", "creation_owners": "拥有者", - "creation_create": "新建", + "creation_create": "创建", "creation_newTemplate": "新模板", "creation_noTemplate": "空白文档", "creation_password": "密码\n", @@ -866,7 +866,7 @@ "help_genericMore": "阅读我们的文档,详细了解 CryptPad 如何为您工作", "header_homeTitle": "转到 CryptPad 主页", "four04_pageNotFound": "我们找不到您要查找的页面。", - "features_f_subscribe_note": "订阅需要注册账号", + "features_f_subscribe_note": "需要注册账号才能订阅", "features_f_subscribe": "订阅", "features_f_supporter_note": "帮助 CryptPad 实现财务可持续发展,并表明由用户自愿资助的隐私增强软件应该成为常态", "features_f_supporter": "支持隐私", @@ -887,16 +887,16 @@ "snapshots_delete": "删除", "oo_deletedVersion": "这个版本在历史上已经不存在了。", "snapshots_close": "关闭", - "snapshots_restore": "恢复", + "snapshots_restore": "还原", "snapshots_open": "打开", "snapshots_placeholder": "快照标题", "snapshots_new": "新快照", "snapshots_button": "快照", "snaphot_title": "快照", "infobar_versionHash": "您当前正在查看此文档 ({0}) 的旧版本。", - "history_restoreDriveDone": "CryptDrive 已恢复", + "history_restoreDriveDone": "CryptDrive 已还原", "history_restoreDrivePrompt": "您确定要用显示的版本替换 CryptDrive 的当前版本吗?", - "history_restoreDriveTitle": "恢复所选版本的 CryptDrive", + "history_restoreDriveTitle": "还原所选版本的 CryptDrive", "history_userNext": "下一个作者", "history_fastNext": "下一个编辑会话", "history_userPrev": "以前的作者", @@ -904,8 +904,8 @@ "history_shareTitle": "分享此版本的链接", "share_versionHash": "您即将以只读模式共享文档的选定历史版本。 这也将授予文档所有版本的查看权限。", "history_close": "关闭", - "history_cantRestore": "恢复失败。 您已断开连接。", - "history_restore": "恢复", + "history_cantRestore": "还原失败,您已断开连接。", + "history_restore": "还原", "share_bar": "创建链接", "settings_kanbanTagsOr": "或", "settings_kanbanTagsAnd": "并", @@ -927,7 +927,7 @@ "support_cat_other": "其他", "support_cat_bug": "错误报告", "support_cat_data": "内容丢失", - "support_cat_account": "用户帐号", + "support_cat_account": "用户账号", "info_privacyFlavour": "此实例的隐私政策", "user_about": "关于 CryptPad", "info_imprintFlavour": "关于此实例的管理员的法律信息", @@ -935,9 +935,9 @@ "support_languagesPreamble": "支持团队使用以下语言:", "slide_textCol": "文本颜色", "slide_backCol": "背景颜色", - "toolbar_file": "文档", + "toolbar_file": "文件", "code_editorTheme": "编辑器主题", - "drive_treeButton": "文档", + "drive_treeButton": "文件", "toolbar_tools": "工具", "toolbar_savetodrive": "另存为图像", "toolbar_insert": "插入", @@ -973,8 +973,8 @@ "admin_openFilesTitle": "打开文档", "profile_copyKey": "复制公钥", "oo_isLocked": "正在同步更改,请稍候", - "kanban_editBoard": "编辑此板", - "kanban_editCard": "编辑这张卡片", + "kanban_editBoard": "编辑此面板", + "kanban_editCard": "编辑此卡片", "kanban_clearFilter": "清除过滤器", "kanban_conflicts": "目前正在编辑:", "kanban_noTags": "没有标签", @@ -1005,8 +1005,8 @@ "trimHistory_currentSize": "当前历史记录大小:{0}", "trimHistory_needMigration": "请更新您的 CryptDrive 以启用此功能。", "settings_safeLinksTitle": "安全链接", - "register_instance": "在 {0} 上创建一个新帐户", - "login_instance": "在 {0} 上连接到您的帐户", + "register_instance": "在 {0} 上创建新账号", + "login_instance": "在 {0} 上连接到您的账号", "home_morestorage": "如需更多存储空间:", "home_location": "加密数据托管在 {0}", "footer_website": "项目网站", @@ -1028,7 +1028,7 @@ "premiumAccess": "作为 {0} 的订阅者,您可以在此抢先体验应用进程中创建新文档。 请注意,它是实验性的,不应信任重要数据。", "earlyAccessBlocked": "此应用进程在此实例上尚不可用", "premiumOnly": "在此应用进程中创建新文档目前仅限于 {0} 上的订阅者。 这是一个用于测试目的的早期访问实验应用进程。 它很快就会在 {0} 上提供给所有人。", - "download_step3": "转换...", + "download_step3": "正在转换…", "fc_openIn": "在{0}打开", "creation_new": "新{0}", "form_conditional_hint": "要使此部分有条件,请在其上方添加选择或复选框问题", @@ -1120,7 +1120,7 @@ "admin_updateAvailableTitle": "新版本", "admin_cat_network": "网络", "mdToolbar_embed": "嵌入的文件", - "restrictedLoginPrompt": "您无权访问此文档。 如果您认为您的帐户应该能够访问它,请登录。", + "restrictedLoginPrompt": "您无权访问此文档。如果您认为您的账号应该能够访问它,请登录。", "copyToClipboard": "复制到剪贴板", "settings_driveRedirect": "自动重定向我", "settings_driveRedirectHint": "默认情况下不再启用登录时从主页自动重定向到云盘。 可以在下面启用旧版行为。", @@ -1247,7 +1247,7 @@ "calendar_errorNoCalendar": "未选择可编辑的日历", "calendar_deleteOwned": "与它共享的其他用户仍然可以看到它。", "calendar_deleteTeamConfirm": "确定要从团队中删除此日历吗?", - "calendar_deleteConfirm": "您确定要从您的帐户中删除此日历吗?", + "calendar_deleteConfirm": "是否确定要从您的账号中删除此日历?", "calendar_today": "今天", "calendar_month": "月", "calendar_week": "星期", @@ -1262,8 +1262,8 @@ "oo_cantMigrate": "此工作表超过了最大上传大小,并且太大而无法迁移。", "footer_roadmap": "路线图", "settings_deleteSubscription": "管理我的订阅", - "settings_deleteContinue": "删除我的账户", - "settings_deleteWarning": "警告:您当前订阅了高级计划(由其他用户付费或提供)。 请在删除您的帐户之前取消您的计划,因为一旦您的帐户被删除,您将无法联系支持人员。", + "settings_deleteContinue": "删除我的账号", + "settings_deleteWarning": "警告:您当前订阅了高级计划(由其他用户付费或提供)。请在删除账号前取消您的计划,因为一旦删除账号,不联系支持人员就无法取消计划。", "broadcast_newCustom": "来自管理员的消息", "broadcast_preview": "预览通知", "broadcast_defaultLanguage": "回退到此语言", @@ -1324,8 +1324,8 @@ "docs_link": "文档", "creation_helperText": "在文档中打开", "creation_expiresIn": "销毁于", - "register_warning_note": "由于 CryptPad 的加密特性,如果您忘记了用户名和/或密码,服务管理员将无法恢复数据。 请将它们保存在安全的地方。", - "register_notes": "
    • 您的密码是加密所有文档的密钥。 如果您丢失了,我们将无法恢复您的数据。
    • 如果您使用的是共享计算机,请记住 完成后退出。 只有关闭浏览器窗口才会暴露您的帐户。
    • 要在不登录的情况下保留您创建和/或存储的文档,请勾选“从您的访客会话导入文档”。
    ", + "register_warning_note": "由于 CryptPad 的加密特性,如果您忘记了用户名和/或密码,服务管理员将无法恢复数据。请将它们保存在安全的地方。", + "register_notes": "
    • 您的密码是加密所有文档的密钥。如果您丢失了,我们将无法恢复您的数据。
    • 如果您使用的是共享计算机,请记住在完成后登出。仅关闭浏览器窗口会暴露您的账号。
    • 要保留您在未登录时创建和/或存储的文档,请勾选“从访客会话导入文档”。
    ", "register_notes_title": "重要笔记", "offlineError": "无法同步最新数据,此时无法显示此页面。 当您与服务的连接恢复时,加载将继续。", "share_noContactsOffline": "您目前处于离线状态。 联系人不可用。", @@ -1352,11 +1352,11 @@ "fileTableHeader": "下载和上传", "allowNotifications": "允许通知", "archivedFromServer": "文档已归档", - "restoredFromServer": "文档已恢复", + "restoredFromServer": "文档已还原", "admin_archiveInput2": "文档密码", "admin_archiveInput": "文档网址", - "admin_unarchiveButton": "恢复", - "admin_unarchiveHint": "恢复以前存档的文档", + "admin_unarchiveButton": "还原", + "admin_unarchiveHint": "还原之前归档的文档", "admin_archiveButton": "归档", "admin_archiveHint": "在不永久删除文档的情况下使文档不可用。 它将被放置在“存档”目录中,并在几天后删除(可在服务器配置文档中配置)。", "errorPopupBlocked": "CryptPad 需要能够打开新标签才能操作。 请允许在浏览器的地址栏中弹出窗口。 这些窗口永远不会用于向您展示广告。", @@ -1365,7 +1365,7 @@ "error_unhelpfulScriptError": "脚本错误:有关详细信息,请参阅浏览器控制台", "tag_edit": "编辑", "tag_add": "添加", - "loading_state_5": "重建文档", + "loading_state_5": "重构文档", "loading_state_4": "加载团队", "loading_state_3": "加载共享文件夹", "loading_state_2": "更新内容", @@ -1394,7 +1394,7 @@ "admin_defaultlimitTitle": "存储限制 (MB)", "admin_defaultlimitHint": "未应用自定义规则时 CryptDrives(用户和团队)的最大存储限制", "admin_registrationTitle": "关闭注册", - "admin_registrationHint": "实例的访问者无法创建账号。管理员可以创建邀请。", + "admin_registrationHint": "实例的访问者无法创建账号,管理员可以创建邀请。", "snapshots_cantMake": "无法创建快照。 您已断开连接。", "snapshots_notFound": "此快照不再存在,因为文档的历史记录已被删除。", "snapshot_error_exists": "已经有这个版本的快照", @@ -1429,11 +1429,11 @@ "support_warning_bug": "请指定出现问题的浏览器以及是否安装了任何扩展。 请提供尽可能多的有关问题的详细信息以及重现问题所需的步骤", "support_warning_document": "请说明导致问题的文档类型并提供文档标识符或链接", "support_warning_drives": "请注意,管理员无法按名称识别文件夹和文档。 对于共享文件夹,请提供文档标识符", - "support_warning_account": "请注意,管理员无法重置密码。 如果您丢失了帐户凭据但仍处于登录状态,您可以将数据迁移到新帐户", + "support_warning_account": "请注意,管理员无法重置密码。如果您丢失了账号凭据但仍在登录,可以将数据迁移到新账号", "support_warning_prompt": "请为您的问题选择最相关的类别。 这有助于管理员进行分类,并为提供哪些信息提供进一步的建议", "info_sourceFlavour": "CryptPad 的源代码", "info_termsFlavour": "此实例的服务条款", - "ui_restore": "恢复", + "ui_restore": "还原", "ui_archive": "归档", "ui_undefined": "未知", "admin_documentType": "類型", @@ -1448,10 +1448,10 @@ "ui_success": "成功", "ui_fetch": "获取", "ui_confirm": "确定", - "admin_archiveReason": "请说明存档原因并确认您要继续", - "admin_restoreReason": "请说明恢复原因并确认您要继续", - "admin_accountMetadataTitle": "帐户信息", - "admin_accountMetadataHint": "输入用户的公钥以获取有关其帐户的数据。", + "admin_archiveReason": "请说明归档的原因,并确认您要继续", + "admin_restoreReason": "请说明还原的原因,并确认您要继续", + "admin_accountMetadataTitle": "账号信息", + "admin_accountMetadataHint": "输入用户的公钥以获取有关其账号的数据。", "admin_documentMetadataTitle": "文档信息", "admin_documentMetadataHint": "通过其 id 或 URL 查询文档或文件", "admin_documentSize": "文档尺寸", @@ -1460,14 +1460,14 @@ "admin_documentModifiedTime": "上一次更改", "admin_currentlyOpen": "当前打开的", "admin_channelAvailable": "可用的", - "admin_channelArchived": "存档", + "admin_channelArchived": "已归档", "admin_blockAvailable": "块可用", "admin_blockArchived": "块已存档", "admin_archiveBlock": "归档块", - "admin_documentConflict": "归档/恢复", - "admin_restoreBlock": "恢复归档块", + "admin_documentConflict": "归档/还原", + "admin_restoreBlock": "还原已归档的块", "admin_getPinList": "当前的pin列表", - "admin_restoreDocument": "恢复文档", + "admin_restoreDocument": "还原文档", "admin_planlimit": "存储限制", "fm_filterBy": "筛选", "fm_rmFilter": "删除过滤器", @@ -1485,7 +1485,7 @@ "calendar_rec_edit": "这是一个重复的事件", "calendar_str_filter_day": "天数: {0}", "calendar_rec_weekdays": "平日每天", - "admin_archiveDocument": "存档文档", + "admin_archiveDocument": "归档文档", "ui_jsRequired": "必须启用 JavaScript 才能在浏览器中进行加密", "admin_reportContent": "举报内容", "admin_getRawMetadata": "元数据历史", @@ -1493,14 +1493,14 @@ "og_teamDrive": "团队云盘", "og_default": "CryptPad:端到端加密协作套件", "og_login": "登录 {0}", - "og_register": "在 {0} 上注册一个帐户", + "og_register": "在 {0} 上注册账号", "og_contact": "{0} 联系人", "og_pricing": "{0} 价格", "og_features": "{0} 特色", "og_encryptedAppType": "已加密 {0}", "admin_documentMetadataPlaceholder": "文档网址或id", "admin_blockMetadataTitle": "登录阻止信息", - "admin_blockMetadataHint": "登录块允许帐户使用用户名 + 密码的组合登录 CryptPad", + "admin_blockMetadataHint": "登录块允许账号使用用户名 + 密码的组合登录 CryptPad", "admin_blockMetadataPlaceholder": "绝对或相对块网址", "admin_accountMetadataPlaceholder": "用户 ID(公共签名密钥)", "admin_firstPinTime": "第一给个pin的活动时间", @@ -1514,7 +1514,7 @@ "admin_pinLogAvailable": "Pin 日志可用", "admin_pinLogArchived": "Pin 日志已存档", "admin_blockKey": "阻止公钥", - "admin_conflictExplanation": "本文件有两个版本。 恢复存档版本将覆盖实时版本。 存档实时版本将覆盖存档版本。 这两项一旦操作都无法撤消。", + "admin_conflictExplanation": "此文档存在两个版本。还原已归档的版本将覆盖实时版本。归档实时版本将覆盖已归档的版本。这两种操作都无法撤销。", "settings_mfaHint": "使用您选择的身份验证应用提供的额外验证码保护您的账号", "done": "完成", "mfa_setup_button": "开始 2FA 设置", @@ -1605,11 +1605,11 @@ "dph_reason": "原因:{0}", "dph_sf_destroyed": "所有者销毁了分享的文件夹 {0}", "dph_sf_destroyed_team": "所有者销毁了团队云盘 {1} 中分享的文件夹 {0}", - "admin_archiveAccount": "存档此账号", - "admin_archiveAccountInfo": "包括其拥有的文件", + "admin_archiveAccount": "归档此账号", + "admin_archiveAccountInfo": "包括其拥有的文档", "admin_restoreAccount": "还原此账号", - "admin_accountSuspended": "管理员存档的账号", - "admin_accountReport": "账号存档报告", + "admin_accountSuspended": "管理员归档的账号", + "admin_accountReport": "账号归档报告", "admin_accountReportFull": "获取详情报告", "admin_channelPlaceholder": "已销毁的文档占位符", "dph_default": "此内容不再可用", @@ -1666,7 +1666,7 @@ "ssoauth_form_hint_login": "请输入您的 CryptPad 密码", "kanban_hideTags": "查看更少的标签", "kanban_showTags": "查看全部标签", - "loading_mfa_required": "此实例需要双因素身份验证。请使用身份验证应用和下方表单更新您的账号。", + "loading_mfa_required": "此实例需要双因素身份验证,请使用身份验证应用和下表更新您的账号。", "team_autoTrim": "正在精简团队云盘历史…请稍候。", "admin_mfa_confirm_enable": "是否确定要启用多因素身份验证?", "admin_mfa_confirm_disable": "是否确定要禁用多因素身份验证?", @@ -1710,7 +1710,7 @@ "support_pasteUserData": "在此处粘贴用户数据", "support_legacyButton": "获取活动工单", "support_recordedTitle": "片段", - "support_recordedHint": "将常用文本存储为单击快捷方式以插入支持消息中。", + "support_recordedHint": "将常用文本存储为一键式快捷方式,以便在支持消息中插入。", "support_recordedContent": "内容", "support_recordedEmpty": "没有片段", "support_legacyTitle": "查看旧的支持数据", @@ -1720,7 +1720,7 @@ "support_legacyClear": "为此账号删除", "support_team": "支持团队", "support_answerAs": "作为 {0} 回答", - "support_movePending": "移动到存档", + "support_movePending": "移至归档", "support_moveActive": "移动到活动", "support_copyUserData": "复制用户数据", "support_insertRecorded": "插入片段", @@ -1773,7 +1773,7 @@ "admin_totpRecoveryHint": "用户可以在 2FA 恢复页面 /recovery/ 复制恢复数据,然后将其通过电子邮件发送给实例管理员。粘贴以下恢复数据即可为账号禁用 2FA", "label_logo": "CryptPad 徽标", "team_nameAlreadySet": "团队名称已设置为 {0}", - "admin_archiveAccountConfirm": "请指定存档的原因,这将显示给用户。", + "admin_archiveAccountConfirm": "请说明归档的原因,这将显示给用户。", "calendar_rec_change_first": "将第一个重复事件移动到不同的日历。也将移动所有重复事件。", "ssoauth_form_hint_register": "添加 CryptPad 密码以增强安全性,或留空并继续。如果不添加密码,实例管理员将可以使用保护数据的密钥。", "admin_forcemfaHint": "将要求此实例上的全部用户设置双因素身份验证才能登录其账号。请注意,现有用户如果不设置 TOTP 应用程序将无法继续使用其账号。", diff --git a/www/common/user-object.js b/www/common/user-object.js index 999ecd212..5a6ec3c73 100644 --- a/www/common/user-object.js +++ b/www/common/user-object.js @@ -573,56 +573,65 @@ const factory = (Util, Hash, }; // SEARCH - var _findFileInRoot = function (path, file) { + var _findFileInRoot = function (path, files) { if (!isPathIn(path, [ROOT, TRASH])) { return []; } - var paths = []; + files = Array.isArray(files) ? files : [files]; + var paths = {}; var root = find(path); var addPaths = function (p) { - if (paths.indexOf(p) === -1) { - paths.push(p); - } + Object.keys(p).forEach(file => { + paths[file] ||= []; + Array.prototype.push.apply(paths[file], p[file]); + }); }; if (isFile(root) || isSharedFolder(root)) { - if (compareFiles(file, root)) { - if (paths.indexOf(path) === -1) { - paths.push(path); + files.some(file => { + if (compareFiles(file, root)) { + paths[file] ||= []; + paths[file].push(path); } - } + }); return paths; } if (isFolder(root)) { for (var e in root) { - var nPath = path.slice(); + let nPath = path.slice(); nPath.push(e); - _findFileInRoot(nPath, file).forEach(addPaths); + addPaths(_findFileInRoot(nPath, files)); } } return paths; }; - exp.findFileInRoot = function (file) { - return _findFileInRoot([ROOT], file); + /* + exp.findFileInRoot = function (files) { + return _findFileInRoot([ROOT], files); }; - var _findFileInHrefArray = function (rootName, file) { - if (sharedFolder) { return []; } - if (!files[rootName]) { return []; } + */ + var _findFileInHrefArray = function (rootName, toFind) { + if (sharedFolder) { return {}; } + if (!files[rootName]) { return {}; } var unsorted = files[rootName].slice(); - var ret = []; + var ret = {}; var i = -1; - while ((i = unsorted.indexOf(file, i+1)) !== -1){ - ret.push([rootName, i]); - } + toFind.forEach(file => { + while ((i = unsorted.indexOf(file, i+1)) !== -1){ + ret[file] ||= []; + ret[file].push([rootName, i]); + } + }); return ret; }; - var _findFileInTrash = function (path, file) { + var _findFileInTrash = function (path, files) { if (sharedFolder) { return []; } var root = find(path); - var paths = []; + var paths = {}; var addPaths = function (p) { - if (paths.indexOf(p) === -1) { - paths.push(p); - } + Object.keys(p).forEach(file => { + paths[file] ||= []; + Array.prototype.push.apply(paths[file], p[file]); + }); }; if (path.length === 1 && typeof(root) === 'object') { Object.keys(root).forEach(function (key) { @@ -630,7 +639,7 @@ const factory = (Util, Hash, if (!Array.isArray(arr)) { return; } var nPath = path.slice(); nPath.push(key); - _findFileInTrash(nPath, file).forEach(addPaths); + addPaths(_findFileInTrash(nPath, files)); }); } if (path.length === 2) { @@ -640,24 +649,39 @@ const factory = (Util, Hash, nPath.push(i); nPath.push('element'); if (isFile(el.element)) { - if (compareFiles(file, el.element)) { - addPaths(nPath); - } + files.some(file => { + if (compareFiles(file, el.element)) { + paths[file] ||= []; + paths[file].push(nPath); + } + }); return; } - _findFileInTrash(nPath, file).forEach(addPaths); + addPaths(_findFileInTrash(nPath, files)); }); } if (path.length >= 4) { - _findFileInRoot(path, file).forEach(addPaths); + addPaths(_findFileInRoot(path, files)); } return paths; }; + var findFiles = exp.findFiles = function (files) { + var rootpaths = _findFileInRoot([ROOT], files); + var templatepaths = _findFileInHrefArray(TEMPLATE, files); + var trashpaths = _findFileInTrash([TRASH], files); + let res = {}; + files.forEach(file => { res[file] = []; }); + [rootpaths, templatepaths, trashpaths].forEach(r => { + Object.keys(r).forEach(file => { + res[file] ||= []; + Array.prototype.push.apply(res[file], r[file]); + }); + }); + return res; + }; var findFile = exp.findFile = function (file) { - var rootpaths = _findFileInRoot([ROOT], file); - var templatepaths = _findFileInHrefArray(TEMPLATE, file); - var trashpaths = _findFileInTrash([TRASH], file); - return rootpaths.concat(templatepaths, trashpaths); + let res = findFiles([file]); + return res[file] || []; }; // Get drive ids of files from their channel ids diff --git a/www/diagram/util.js b/www/diagram/util.js index b6cdf0067..d2c836c97 100644 --- a/www/diagram/util.js +++ b/www/diagram/util.js @@ -10,7 +10,6 @@ define([ '/components/pako/dist/pako.min.js', '/common/common-hash.js', '/api/config', - 'jquery', ], function ( Util, FileCrypto, @@ -19,7 +18,6 @@ define([ pako, Hash, ApiConfig, - $, ) { const Nacl = window.nacl; const x2js = new X2JS(); @@ -82,11 +80,6 @@ define([ } }; - const xmlAsJsonContent = (xml) => { - var decompressedXml = decompressDrawioXml(xml); - return numbersToNumbers(x2js.xml2js(decompressedXml)); - }; - // As described here: https://drawio-app.com/extracting-the-xml-from-mxfiles/ const decompressDrawioXml = function(xmlDocStr) { var TEXT_NODE = 3; @@ -122,6 +115,12 @@ define([ return result; }; + const xmlAsJsonContent = (xml) => { + var decompressedXml = decompressDrawioXml(xml); + return numbersToNumbers(x2js.xml2js(decompressedXml)); + }; + + const parseDrawioStyle = (styleAttrValue) => { if (!styleAttrValue) { return {}; diff --git a/www/form/app-form.less b/www/form/app-form.less index 2042999ce..1e9ae02a5 100644 --- a/www/form/app-form.less +++ b/www/form/app-form.less @@ -133,6 +133,19 @@ } } + .cp-form-iseditor { + .cp-form-block header { + display: flex !important; + } + } + .cp-form-creator-results { + .cp-form-block-type { + float: right; + margin-top: -10px; + margin-right: -10px; + } + } + &.cp-form-readonly { .cp-form-creator-inline-add { display: none; @@ -203,6 +216,32 @@ //flex-wrap: wrap; overflow: auto; + .cp-drag-container { + display: flex; + flex-direction: row; + + button.cp-form-view-drag { + margin: 0; + padding: 1px 4px; + width: 30px; + height: 30px; + border: none; + border-radius: @variables_radius 0px 0px @variables_radius; + background-color: @cp_form-bg1; + color: @cryptpad_text_col; + &:focus-visible { + outline: @variables_focus_style; + } + &.cp-toggle-active { + color: @cp_form-bg1; + background-color: @cryptpad_text_col; + } + } + #cp-toggle-drag-on { + border-radius: 0px @variables_radius @variables_radius 0px !important; + } + } + @media screen and (max-width: 1000px) { flex-wrap: wrap; justify-content: flex-start; @@ -295,7 +334,6 @@ div.cp-form-creator-content { position: relative; .cp-form-block-type { - margin-top: -35px; &.editable { cursor: pointer; } @@ -369,6 +407,29 @@ display: flex; flex-flow: column; flex: 1 1 1000px; + &.cp-no-drag { + .cp-form-block { + .cp-form-block-arrows { + padding-left: 5px; + border-radius: 0px @variables_radius 0px 0px; + display: flex; + column-gap: 10px; + .cp-form-arrow { + display: block; + background-color: transparent; + border: none; + color: @cryptpad_text_col; + &:focus-visible { + border-radius: @variables_radius; + outline: @variables_focus_style; + } + } + } + .cp-form-block-drag-handle { + display: none !important; + } + } + } .cp-form-creator-add-inline { display: flex; @@ -560,6 +621,14 @@ margin-bottom: 20px; } + header { + display: none; + justify-content: space-between; + margin-top: -10px; + margin-left: -10px; + margin-right: -10px; + } + .cp-form-disabled { .cp-form-poll-choice, .cp-form-type-sort { cursor: not-allowed !important; @@ -575,18 +644,22 @@ .cp-form-block-drag-handle { display: flex; flex-flow: column; - height: 25px; - align-items: center; + width: 50px; + justify-content: center; + padding-left: 10px; + font-size: 20px; color: @cp_sidebar-hint; i { cursor: grab; &:first-child { height: 3px; - margin-top: -10px; - margin-bottom: 1px; + margin-bottom: 2px; } } } + .cp-form-block-arrows { + display: none; + } &.sortable-ghost { visibility: hidden; } &.sortable-drag { opacity: 0.9 !important; } @@ -605,15 +678,19 @@ } .cp-form-block-question-text { flex: 1; + word-wrap: break-word; + overflow: hidden; } .cp-form-required-tag { padding: 5px; margin-top: -10px; margin-right: -10px; &.cp-is-empty { + height: fit-content; padding: 3px; - border: 2px solid @cryptpad_color_red; - color: @cp_form-invalid; + border-radius: 0 @variables_radius 0 0; + background-color: @cp_alerts-danger-bg; + color: @cp_alerts-danger-text; } } } @@ -963,10 +1040,10 @@ } } .cp-form-block-type { - float: right; + //float: right; padding: 5px; - margin-top: -10px; - margin-right: -10px; + //margin-top: -10px; + //margin-right: -10px; border-radius: 0px @variables_radius 0px 0px; i { margin-right: 5px; } background: fade(@cryptpad_text_col, 10%); diff --git a/www/form/command-handler.js b/www/form/command-handler.js index dc49a9e18..2592d11ab 100644 --- a/www/form/command-handler.js +++ b/www/form/command-handler.js @@ -215,8 +215,8 @@ define([ formData = Utils.Hash.getFormData(Utils.secret); keys = Utils.secret && Utils.secret.keys; } - privateKey = formData.form_private; - publicKey = formData.form_public; + privateKey = formData?.form_private; + publicKey = formData?.form_public; var curvePrivate = privateKey || data.privateKey; if (!curvePrivate) { return void cb({error: 'EFORBIDDEN'}); } var crypto = Utils.Crypto.Mailbox.createEncryptor({ diff --git a/www/form/inner.js b/www/form/inner.js index cd4ee4121..5543433ac 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -3565,7 +3565,7 @@ define([ }); var $send = $(send).click(function () { if (!$radio.find('input[type="radio"]:checked').length) { - return UI.warn(Messages.answerType_error); + return UI.warn(Messages.form_answerType_error); } var results = getFormResults(); @@ -3765,8 +3765,8 @@ define([ } }); $body.addClass('cp-form-palette-'+color); - - $container.attr('class', 'cp-form-creator-content'+(APP.isEditor? ' cp-form-iseditor': '')); + var containerDragClass = ('ontouchstart' in window || APP.drag === false) ? ' cp-no-drag' : ''; + $container.attr('class', 'cp-form-creator-content'+(APP.isEditor? ' cp-form-iseditor': '')+ containerDragClass); if (APP.isClosed && content.answers.privateKey && !APP.isEditor && !APP.hasAnswered) { var sframeChan = framework._.sfCommon.getSframeChannel(); @@ -3894,7 +3894,7 @@ define([ var updateAddInline = APP.updateAddInline = function () { $container.find('.cp-form-creator-add-inline').remove(); // Add before existing question - $container.find('.cp-form-block:not(.nodrag)').each(function (i, el) { + $container.find('.cp-form-block:not(.cp-form-submit-message)').each(function (i, el) { var $el = $(el); var uid = $el.attr('data-id'); $el.before(getFormCreator(uid)); @@ -4009,13 +4009,47 @@ define([ var changeType; + let shiftButtons; if (editable) { - // Drag handle - dragHandle = h('span.cp-form-block-drag-handle', [ - h('i.fa.fa-ellipsis-h'), - h('i.fa.fa-ellipsis-h'), + // Arrows + var upButton = h('button.cp-form-arrow', { + 'data-notippy':1, + 'title': Messages.moveItemUp, + 'aria-label': Messages.moveItemUp + }, [h('i.fa.fa-arrow-up', {'aria-hidden': true})]); + var downButton = h('button.cp-form-arrow', { + 'data-notippy':1, + 'title': Messages.moveItemDown, + 'aria-label': Messages.moveItemDown + }, [h('i.fa.fa-arrow-down', {'aria-hidden': true})]); + var shiftBlock = function(direction) { + var blockIndex = content.order.indexOf(uid); + if (direction === 'up' && blockIndex > 0) { + content.order.splice(blockIndex-1, 0, content.order.splice(blockIndex, 1)[0]); + updateForm(framework, content, true); + framework.localChange(); + } else if (direction === 'down' && blockIndex < content.order.length-1) { + content.order.splice(blockIndex+1, 0, content.order.splice(blockIndex, 1)[0]); + updateForm(framework, content, true); + framework.localChange(); + } + }; + $(upButton).click(function () { + shiftBlock('up'); + }); + $(downButton).click(function () { + shiftBlock('down'); + }); + shiftButtons = h('div.cp-form-block-arrows', [ + upButton, + downButton ]); + + // Drag handle + var dragEllipses = [h('i.fa.fa-ellipsis-h'), h('i.fa.fa-ellipsis-h')]; + dragHandle = h('span.cp-form-block-drag-handle', dragEllipses); + // Question var inputQ = h('input', { value: block.q || Messages.form_default @@ -4251,13 +4285,18 @@ define([ } } } + var editableCls = editable ? ".editable" : ""; - elements.push(h('div.cp-form-block'+editableCls, { + var draggable = APP.drag ? '' : '.nodrag'; + elements.push(h('div.cp-form-block'+editableCls+draggable, { 'data-id':uid, 'data-type':type }, [ - APP.isEditor ? dragHandle : undefined, - changeType, + h('header', [ + APP.isEditor ? dragHandle : undefined, + shiftButtons, + changeType + ]), isStatic ? undefined : q, h('div.cp-form-block-content', [ APP.isEditor && !isStatic ? requiredDiv : undefined, @@ -4536,6 +4575,8 @@ define([ } } }); + APP.mainSortable.options.disabled = 'ontouchstart' in window ? true : false; + return; } @@ -5102,9 +5143,37 @@ define([ editableStr ]); + var toggleOffclass = 'ontouchstart' in window ? 'cp-toggle-active' : undefined; + var toggleOnclass = 'ontouchstart' in window ? undefined : 'cp-toggle-active'; + var toggleDragOff = h(`button#cp-toggle-drag-off.cp-form-view-drag.${toggleOffclass}.fa.fa-arrows`, {'title': Messages.toggleArrows, 'tabindex': 0}); + var toggleDragOn = h(`button#cp-toggle-drag-on.cp-form-view-drag.${toggleOnclass}.fa.fa-hand-o-up`, {'title': Messages.toggleDrag, 'tabindex': 0}); + const updateDrag = state => { + return function () { + var $container = $('.cp-form-creator-content'); + $(toggleDragOn).toggleClass('cp-toggle-active', state); + $(toggleDragOff).toggleClass('cp-toggle-active', !state); + APP.mainSortable.options.disabled = !state; + APP.drag = state; + if (state) { + $container.removeClass('cp-no-drag'); + } else { + $container.addClass('cp-no-drag'); + } + }; + }; + + $(toggleDragOn).click(updateDrag(true)); + $(toggleDragOff).click(updateDrag(false)); + + var drag = h('div.cp-drag-container', [ + toggleDragOff, + toggleDragOn + ]); + return [ preview, previewSettings, + drag, colorTheme ]; }; @@ -5220,7 +5289,7 @@ define([ fillerContainer = h('div.cp-form-filler-container'); } - var contentContainer = h('div.cp-form-creator-content' + (APP.isEditor ? '.cp-form-iseditor' : '')); + var contentContainer = h('div.cp-form-creator-content' + (APP.isEditor ? '.cp-form-iseditor' : '') + ('ontouchstart' in window ? '.cp-no-drag' : '')); var resultsContainer = h('div.cp-form-creator-results'); var answeredContainer = h('div.cp-form-creator-answered', { style: 'display: none;' @@ -5490,7 +5559,7 @@ define([ var editButtons = h('div.cp-form-edit-buttons-container', [ preview, edit, del ]); var editDiv, previewDiv; - var div = h('div.cp-form-block.editable.nodrag', [ + var div = h('div.cp-form-block.editable.nodrag.cp-form-submit-message', [ h('div.cp-form-block-content', [ p, editDiv = h('div.cp-form-response-modal', t), diff --git a/www/kanban/app-kanban.less b/www/kanban/app-kanban.less index b050791b7..700712758 100644 --- a/www/kanban/app-kanban.less +++ b/www/kanban/app-kanban.less @@ -34,7 +34,7 @@ background-color: @palette0; color: @cryptpad_color_grey_800; border-radius: @variables_radius @variables_radius 0px 0px; - button.kanban-edit-item { + button.kanban-edit-item, .cp-kanban-arrow { color: @cryptpad_color_grey_800; } } @@ -177,8 +177,7 @@ overflow: hidden; } - .kanban-edit-item { - padding: 5px; + .kanban-edit-item, .cp-kanban-arrow { border: 0; background: transparent; align-self: flex-start; @@ -187,15 +186,27 @@ &:focus-visible { outline: @variables_focus_style; } - @media (hover: none) { - margin-right: 20px; - } @media(max-width:500px) or (max-height:700px) { margin-right:0px; } } + .item-icon-container{ // Board arrows + display: flex; + width: 100%; + justify-content: space-between; + } + + .item-arrow-container { // Card arrows + width: 100%; + margin-top: 0.25rem; + display: flex; + justify-content: space-between; + align-items: center; + } + + .cp-kanban-cursors { &:empty { display: none; } order: 2; @@ -221,6 +232,7 @@ } .kanban-item { display: flex; + flex-direction: column; align-items: center; justify-content: space-between; padding: 5px; @@ -230,8 +242,10 @@ box-shadow: @cryptpad_ui_shadow; .tools_unselectable(); touch-action: none; - cursor: move; - cursor: grab; + &:not(.no-drag) { + cursor: move; + cursor: grab; + } margin-bottom: 5px; &:last-child { @@ -308,10 +322,12 @@ font-size: 12px; } } - .kanban-item-text { + .kanban-item-text-container, .kanban-item-text { + width: 100%; .tools_unselectable(); cursor: text; overflow-wrap: anywhere; + display: flex; flex: 1; &:empty::before { content: "\200b"; @@ -321,6 +337,9 @@ padding: 0; height: auto; } + .kanban-item-text { + width: 100%; + } } &.kanban-item-hidden { display: none; @@ -354,9 +373,6 @@ overflow-y: auto; justify-content: space-around; min-height: 38px; // Size of one card - @media (hover: none) { - padding-right: 30px; - } @media(max-width:500px) or (max-height:700px) { padding-right:5px; @@ -367,8 +383,10 @@ flex-wrap: wrap; align-items: center; padding: 5px 10px; - cursor: move; - cursor: grab; + &:not(.no-drag) { + cursor: move; + cursor: grab; + } .kanban-title-board { flex: 1; min-width: 0; @@ -504,13 +522,21 @@ right: 10px; height: 30px; width: 60px; - span { + &.drag { + margin-right: 10px; + } + + button { + border: 0; height: 30px; width: 30px; + margin: 0; + padding: 1px 4px; line-height: 30px; text-align: center; display: inline-block; background-color: @board-bg; + color: @cp_kanban-fg !important; cursor: pointer; &:hover { background-color: darken(@board-bg, 10%); @@ -521,6 +547,9 @@ &:last-child { border-radius: 0px @variables_radius @variables_radius 0px; } + &:focus-visible { + outline: @variables_focus_style; + } } } } @@ -528,23 +557,19 @@ &:not(.cp-kanban-quick) { #cp-kanban-controls { .cp-kanban-changeView { - span.cp-kanban-view { - background-color: @cp_kanban-fg !important; - color: @cp_app-bg; + button.cp-kanban-view { + background-color: @cp_kanban-fg; + color: @cp_app-bg !important; } - // span.cp-kanban-view-small { - // } } } } &.cp-kanban-quick { #cp-kanban-controls { .cp-kanban-changeView { - // span.cp-kanban-view { - // } - span.cp-kanban-view-small { - background-color: @cp_kanban-fg !important; - color: @cp_app-bg; + button.cp-kanban-view-small { + background-color: @cp_kanban-fg; + color: @cp_app-bg !important; } } } @@ -554,6 +579,18 @@ } } } + button.cp-kanban-view-drag { + &:focus-visible { + outline: @variables_focus_style; + } + &.cp-toggle-active { + background-color: @cp_kanban-fg; + color: @cp_app-bg !important; + } + &.cp-toggle-inactive { + color: @cp_kanban-fg; + } + } } #cp-app-kanban-content { diff --git a/www/kanban/inner.js b/www/kanban/inner.js index c2db93513..7f9fbdad4 100644 --- a/www/kanban/inner.js +++ b/www/kanban/inner.js @@ -151,6 +151,7 @@ define([ }; var addEditItemButton = function () {}; + var addMoveElementButton = function () {}; var onRemoteChange = Util.mkEvent(); var now = function () { return +new Date(); }; @@ -161,6 +162,7 @@ define([ kanban.setBoards(Util.clone(boards)); kanban.inEditMode = false; addEditItemButton(framework, kanban); + addMoveElementButton(framework, kanban); restoreCursor(cursor); onRemoteChange.fire(); }; @@ -540,6 +542,140 @@ define([ UI.openCustomModal(editModal.modal); }; + addMoveElementButton = function (framework, kanban) { + if (!kanban) { return; } + if (framework.isReadOnly() || framework.isLocked()) { return; } + var $container = $(kanban.element); + var drag = kanban.drag; + kanban.options.dragBoards = drag; + kanban.options.dragItems = drag; + $container.find('.kanban-board').each(function (i, el) { + $(el).find('.item-icon-container').remove(); + $(el).find('.kanban-board-header').removeClass('no-drag'); + }); + $container.find('.kanban-item').each(function (i, el) { + $(el).find('.item-arrow-container').remove(); + $(el).removeClass('no-drag'); + }); + if (drag === false) { + var move = function (arr, oldIndex, newIndex) { + arr.splice(newIndex, 0, arr.splice(oldIndex, 1)[0]); + _updateBoards(framework, kanban, kanban.options.boards, false); + }; + + var moveBetweenBoards = function (nextBoardItems, elId, boardItems, index, boards) { + nextBoardItems.unshift(elId); + boardItems.splice(index, 1); + _updateBoards(framework, kanban, boards, false); + $(`.kanban-item[data-eid="${elId}"]`)[0].scrollIntoView(); + }; + + var shiftItem = function (direction, el) { + var board = $(el).closest('.kanban-board'); + var boards = kanban.options.boards; + var elId = parseInt($(el).attr("data-eid")); + var boardId = parseInt($(board).attr("data-id")); + var boardItems = boards.data[boardId].item; + var index = boardItems.indexOf(elId); + var boardIndex = boards.list.indexOf(parseInt(boardId)); + let nextBoardItems; + + if (direction === 'up' && index > 0) { + move(boardItems, index, index-1); + } else if (direction === 'down' && index < boardItems.length-1) { + move(boardItems, index, index+1); + } else if (direction === 'left' && boardIndex > 0) { + nextBoardItems = boards.data[boards.list[boardIndex-1]].item; + moveBetweenBoards(nextBoardItems, elId, boardItems, index, boards, boardId); + } else if (direction === 'right' && boardIndex < kanban.options.boards.list.length-1){ + nextBoardItems = boards.data[boards.list[boardIndex+1]].item; + moveBetweenBoards(nextBoardItems, elId, boardItems, index, boards, boardId); + } + }; + + var shiftBoards = function (direction, el) { + var elId = $(el).attr("data-id"); + var index = kanban.options.boards.list.indexOf(parseInt(elId)); + if (direction === 'left' && index > 0) { + move(kanban.options.boards.list, index, index-1); + } else if (direction === 'right' && index < kanban.options.boards.list.length-1) { + move(kanban.options.boards.list, index, index+1); + } + $(`.kanban-board[data-id="${elId}"]`)[0].scrollIntoView(); + }; + $container.find('.kanban-board').each(function (i, el) { + $(el).find('.kanban-board-header').addClass('no-drag'); + var arrowContainer = h('div.item-icon-container'); + $(arrowContainer).appendTo($(el).find('.kanban-board-header')); + $(h('button', { + 'class': 'cp-kanban-arrow board-arrow', + 'title': Messages.kanban_moveBoardLeft, + 'aria-label': Messages.kanban_moveBoardLeft + }, [ + h('i.fa.fa-arrow-left', {'aria-hidden': true}) + ])).click(function () { + shiftBoards('left', el); + }).appendTo(arrowContainer); + $(h('button', { + 'class': 'cp-kanban-arrow board-arrow', + 'title': Messages.kanban_moveBoardRight, + 'aria-label': Messages.kanban_moveBoardRight + }, [ + h('i.fa.fa-arrow-right', {'aria-hidden': true}) + ])).click(function () { + shiftBoards('right', el); + }).appendTo(arrowContainer); + }); + $container.find('.kanban-item').each(function (i, el) { + $(el).addClass('no-drag'); + var arrowContainerItem = h('div.item-arrow-container'); + $(arrowContainerItem).appendTo((el)); + $(h('button', { + 'data-notippy':1, + 'class': 'cp-kanban-arrow item-arrow', + 'title': Messages.moveItemLeft, + 'aria-label': Messages.moveItemLeft + }, [ + h('i.fa.fa-arrow-left', {'aria-hidden': true}) + ])).click(function () { + shiftItem('left', el); + }).appendTo(arrowContainerItem); + var centralArrowContainerItem = h('div.item-central-arrow-container'); + $(centralArrowContainerItem).appendTo(arrowContainerItem); + $(h('button', { + 'data-notippy':1, + 'class': 'cp-kanban-arrow item-arrow', + 'title': Messages.moveItemDown, + 'aria-label': Messages.moveItemDown + }, [ + h('i.fa.fa-arrow-down', {'aria-hidden': true}) + ])).click(function () { + shiftItem('down', el); + }).appendTo(centralArrowContainerItem); + $(h('button', { + 'data-notippy':1, + 'class': 'cp-kanban-arrow item-arrow', + 'title': Messages.moveItemUp, + 'aria-label': Messages.moveItemUp + }, [ + h('i.fa.fa-arrow-up', {'aria-hidden': true}) + ])).click(function () { + shiftItem('up', el); + }).appendTo(centralArrowContainerItem); + $(h('button', { + 'data-notippy':1, + 'class': 'cp-kanban-arrow item-arrow', + 'title': Messages.moveItemRight, + 'aria-label': Messages.moveItemRight + }, [ + h('i.fa.fa-arrow-right', {'aria-hidden': true}) + ])).click(function () { + shiftItem('right', el); + }).appendTo(arrowContainerItem); + }); + } + }; + addEditItemButton = function (framework, kanban) { if (!kanban) { return; } if (framework.isReadOnly() || framework.isLocked()) { return; } @@ -547,20 +683,26 @@ define([ $container.find('.kanban-edit-item').remove(); $container.find('.kanban-item').each(function (i, el) { var itemId = $(el).attr('data-eid'); - $('