From bad3ae3efd5c1e03053155121d8aa3824e52f6c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Benqu=C3=A9?= Date: Tue, 24 Mar 2020 19:34:17 +0000 Subject: [PATCH 01/22] move copy key button --- www/profile/inner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/profile/inner.js b/www/profile/inner.js index ba348d829..5c31e95d7 100644 --- a/www/profile/inner.js +++ b/www/profile/inner.js @@ -506,7 +506,7 @@ define([ addFriendRequest($rightside); addMuteButton($rightside); addDescription(APP.$rightside); - addPublicKey(APP.$rightside); + addPublicKey($rightside); addViewButton($rightside); APP.initialized = true; createLeftside(); From 479b76f848ac7d64b46447108d9d9a18b3a66f5c Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 24 Mar 2020 17:40:07 -0400 Subject: [PATCH 02/22] lint compliance --- lib/commands/core.js | 4 ---- lib/workers/check-signature.js | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/commands/core.js b/lib/commands/core.js index e3ec3469b..f4e6a9f70 100644 --- a/lib/commands/core.js +++ b/lib/commands/core.js @@ -5,10 +5,6 @@ const Util = require("../common-util"); const escapeKeyCharacters = Util.escapeKeyCharacters; //const { fork } = require('child_process'); -/* Use Nacl for checking signatures of messages */ -const Nacl = require("tweetnacl/nacl-fast"); - - Core.DEFAULT_LIMIT = 50 * 1024 * 1024; Core.SESSION_EXPIRATION_TIME = 60 * 1000; diff --git a/lib/workers/check-signature.js b/lib/workers/check-signature.js index 37fca3783..846f41d3b 100644 --- a/lib/workers/check-signature.js +++ b/lib/workers/check-signature.js @@ -66,7 +66,7 @@ const checkDetachedSignature = function (signedMsg, signature, publicKey) { COMMANDS.DETACHED = function (data, cb) { try { - checkDetachedSignature(data.msg, data.sig, data.key) + checkDetachedSignature(data.msg, data.sig, data.key); } catch (err) { return void cb(err && err.message); } From 471e374533cd6d39c9ab8c5c0b453f0f84c24e59 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 24 Mar 2020 17:43:15 -0400 Subject: [PATCH 03/22] compute metadata in the same child process that builds indexes --- lib/commands/metadata.js | 10 +---- lib/historyKeeper.js | 3 +- lib/hk-util.js | 58 ++++++++++++++++++++-------- lib/workers/compute-index.js | 74 +++++++++++++++++++++++------------- 4 files changed, 93 insertions(+), 52 deletions(-) diff --git a/lib/commands/metadata.js b/lib/commands/metadata.js index 802942fcb..1d758564b 100644 --- a/lib/commands/metadata.js +++ b/lib/commands/metadata.js @@ -18,15 +18,7 @@ Data.getMetadataRaw = function (Env, channel /* channelName */, _cb) { } Env.batchMetadata(channel, cb, function (done) { - var ref = {}; - var lineHandler = Meta.createLineHandler(ref, Env.Log.error); - return void Env.msgStore.readChannelMetadata(channel, lineHandler, function (err) { - if (err) { - // stream errors? - return void done(err); - } - done(void 0, ref.meta); - }); + Env.computeMetadata(channel, done); }); }; diff --git a/lib/historyKeeper.js b/lib/historyKeeper.js index 2f6043dfd..c8356b908 100644 --- a/lib/historyKeeper.js +++ b/lib/historyKeeper.js @@ -247,11 +247,10 @@ module.exports.create = function (config, cb) { channelExpirationMs: config.channelExpirationMs, verbose: config.verbose, openFileLimit: config.openFileLimit, - }, w(function (err, computeIndex) { + }, w(function (err) { if (err) { throw new Error(err); } - Env.computeIndex = computeIndex; })); }).nThen(function (w) { // create a task store diff --git a/lib/hk-util.js b/lib/hk-util.js index 9b0c4dd24..513fac04f 100644 --- a/lib/hk-util.js +++ b/lib/hk-util.js @@ -337,7 +337,7 @@ const storeMessage = function (Env, channel, msg, isCp, optionalMessageHash) { * -1 if you didn't find it */ -const getHistoryOffset = (Env, channelName, lastKnownHash, _cb) => { +const getHistoryOffset = (Env, channelName, lastKnownHash, _cb) => { // XXX child process const cb = Util.once(Util.mkAsync(_cb)); const store = Env.store; const Log = Env.Log; @@ -454,7 +454,7 @@ const getHistoryAsync = (Env, channelName, lastKnownHash, beforeHash, handler, c Used by: * GET_HISTORY_RANGE */ -const getOlderHistory = function (Env, channelName, oldestKnownHash, cb) { +const getOlderHistory = function (Env, channelName, oldestKnownHash, cb) { // XXX child process const store = Env.store; const Log = Env.Log; var messageBuffer = []; @@ -833,7 +833,14 @@ HK.initializeIndexWorkers = function (Env, config, _cb) { }); worker.on('message', function (res) { - if (!res || !res.txid) { return; } + if (!res) { return; } + if (!res.txid) { + // !report errors... + if (res.error) { + Env.Log.error(res.error, res.value); + } + return; + } //console.log(res); try { response.handle(res.txid, [res.error, res.value]); @@ -860,20 +867,18 @@ HK.initializeIndexWorkers = function (Env, config, _cb) { }; var workerIndex = 0; - var sendCommand = function (Env, channel, cb) { + var sendCommand = function (msg, _cb) { + var cb = Util.once(Util.mkAsync(_cb)); + workerIndex = (workerIndex + 1) % workers.length; if (workers.length === 0 || typeof(workers[workerIndex].send) !== 'function') { return void cb("NO_WORKERS"); } - Env.store.getWeakLock(channel, function (next) { - const txid = Util.uid(); - response.expect(txid, Util.both(next, cb), 45000); - workers[workerIndex].send({ - txid: txid, - args: channel, - }); - }); + const txid = Util.uid(); + msg.txid = txid; + response.expect(txid, cb, 45000); + workers[workerIndex].send(msg); }; nThen(function (w) { @@ -885,6 +890,30 @@ HK.initializeIndexWorkers = function (Env, config, _cb) { })); }); }).nThen(function () { + Env.computeIndex = function (Env, channel, cb) { + Env.store.getWeakLock(channel, function (next) { + sendCommand({ + channel: channel, + command: 'COMPUTE_INDEX', + }, function (err, index) { + next(); + cb(err, index); + }); + }); + }; + + Env.computeMetadata = function (channel, cb) { + Env.store.getWeakLock(channel, function (next) { + sendCommand({ + channel: channel, + command: 'COMPUTE_METADATA', + }, function (err, metadata) { + next(); + cb(err, metadata); + }); + }); + }; + //console.log("index workers ready"); cb(void 0, sendCommand); }); @@ -925,14 +954,13 @@ HK.initializeValidationWorkers = function (Env) { var nextWorker = 0; const send = function (msg, _cb) { + var cb = Util.once(Util.mkAsync(_cb)); // let's be paranoid about asynchrony and only calling back once.. nextWorker = (nextWorker + 1) % workers.length; if (workers.length === 0 || typeof(workers[nextWorker].send) !== 'function') { - console.error(workers); - throw new Error("INVALID_WORKERS"); + return void cb("INVALID_WORKERS"); } - var cb = Util.once(Util.mkAsync(_cb)); var txid = msg.txid = Util.uid(); // expect a response within 15s diff --git a/lib/workers/compute-index.js b/lib/workers/compute-index.js index f1da2628c..17a292059 100644 --- a/lib/workers/compute-index.js +++ b/lib/workers/compute-index.js @@ -5,6 +5,7 @@ const HK = require("../hk-util"); const Store = require("../storage/file"); const Util = require("../common-util"); const nThen = require("nthen"); +const Meta = require("../metadata"); const Env = {}; @@ -46,7 +47,13 @@ const tryParse = function (Env, str) { * including the initial metadata line, if it exists */ -const computeIndex = function (channelName, cb) { +const computeIndex = function (data, cb) { + if (!data || !data.channel) { + return void cb('E_NO_CHANNEL'); + } + + const channelName = data.channel; + const cpIndex = []; let messageBuf = []; let i = 0; @@ -125,45 +132,60 @@ const computeIndex = function (channelName, cb) { }); }; +const computeMetadata = function (data, cb, errorHandler) { + const ref = {}; + const lineHandler = Meta.createLineHandler(ref, errorHandler); + return void store.readChannelMetadata(data.channel, lineHandler, function (err) { + if (err) { + // stream errors? + return void cb(err); + } + cb(void 0, ref.meta); + }); +}; + +const COMMANDS = { + COMPUTE_INDEX: computeIndex, + COMPUTE_METADATA: computeMetadata, +}; + process.on('message', function (data) { if (!data || !data.txid) { return void process.send({ error:'E_INVAL' }); } - const txid = data.txid; + + const cb = function (err, value) { + if (err) { + return void process.send({ + txid: data.txid, + error: err, + }); + } + process.send({ + txid: data.txid, + value: value, + }); + }; if (!ready) { return void init(data.config, function (err) { - if (err) { - return void process.send({ - txid: txid, - error: err, - }); - } + if (err) { return void cb(err); } ready = true; - process.send({txid: txid,}); + cb(); }); } - const channel = data.args; - if (!channel) { - return void process.send({ - error: 'E_NO_CHANNEL', - }); + const command = COMMANDS[data.command]; + if (typeof(command) !== 'function') { + return void cb("E_BAD_COMMAND"); } - - // computeIndex - computeIndex(channel, function (err, index) { - if (err) { - return void process.send({ - txid: txid, - error: err, - }); - } - return void process.send({ - txid: txid, - value: index, + command(data, cb, function (label, info) { + // for streaming errors + process.send({ + error: label, + value: info, }); }); }); From 320778f54f524569042036618062feb7410bb321 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 25 Mar 2020 09:45:55 -0400 Subject: [PATCH 04/22] use latest chainpad-server --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 99f65cf27..8d0cebc6b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -190,9 +190,9 @@ } }, "chainpad-server": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/chainpad-server/-/chainpad-server-4.0.8.tgz", - "integrity": "sha512-QlmomAMQN4msdYnRqGEjL12FAeOPIJ5yoxIzROohWt/31SwF1UlyV+zFp1M1dhtV8PoS7JXvLyBBLCEEVN73Cg==", + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/chainpad-server/-/chainpad-server-4.0.9.tgz", + "integrity": "sha512-8h1W41ktE05TM6LuXrklpW2TUxWeNyIDiRaQygKsXaA/7pyJxF7+AmPVS+xW0c31VkHjQDPiaMzPoxhcxXnIyA==", "requires": { "nthen": "0.1.8", "pull-stream": "^3.6.9", diff --git a/package.json b/package.json index a12997e39..668eb53a0 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "chainpad-crypto": "^0.2.2", - "chainpad-server": "^4.0.8", + "chainpad-server": "^4.0.9", "express": "~4.16.0", "fs-extra": "^7.0.0", "get-folder-size": "^2.0.1", From 50e8893b24a0a503c2023340d93d2576439c03bf Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 25 Mar 2020 10:54:29 -0400 Subject: [PATCH 05/22] move the 'getOlderHistory' call into the database worker --- lib/hk-util.js | 60 ++++++++++-------------------------- lib/workers/compute-index.js | 44 ++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 44 deletions(-) diff --git a/lib/hk-util.js b/lib/hk-util.js index 513fac04f..0fafcdb91 100644 --- a/lib/hk-util.js +++ b/lib/hk-util.js @@ -445,48 +445,6 @@ const getHistoryAsync = (Env, channelName, lastKnownHash, beforeHash, handler, c }); }; -/* getOlderHistory - * allows clients to query for all messages until a known hash is read - * stores all messages in history as they are read - * can therefore be very expensive for memory - * should probably be converted to a streaming interface - - Used by: - * GET_HISTORY_RANGE -*/ -const getOlderHistory = function (Env, channelName, oldestKnownHash, cb) { // XXX child process - const store = Env.store; - const Log = Env.Log; - var messageBuffer = []; - var found = false; - store.getMessages(channelName, function (msgStr) { - if (found) { return; } - - let parsed = tryParse(Env, msgStr); - if (typeof parsed === "undefined") { return; } - - // identify classic metadata messages by their inclusion of a channel. - // and don't send metadata, since: - // 1. the user won't be interested in it - // 2. this metadata is potentially incomplete/incorrect - if (isMetadataMessage(parsed)) { return; } - - var content = parsed[4]; - if (typeof(content) !== 'string') { return; } - - var hash = getHash(content, Log); - if (hash === oldestKnownHash) { - found = true; - } - messageBuffer.push(parsed); - }, function (err) { - if (err && err.code !== 'ENOENT') { - Log.error("HK_GET_OLDER_HISTORY", err); - } - cb(messageBuffer); - }); -}; - const handleRPC = function (Env, Server, seq, userId, parsed) { const HISTORY_KEEPER_ID = Env.id; @@ -662,7 +620,11 @@ const handleGetHistoryRange = function (Env, Server, seq, userId, parsed) { } Server.send(userId, [seq, 'ACK']); - return void getOlderHistory(Env, channelName, oldestKnownHash, function (messages) { + Env.getOlderHistory(channelName, oldestKnownHash, function (err, messages) { + if (err && err.code !== 'ENOENT') { + Env.Log.error("HK_GET_OLDER_HISTORY", err); + } + var toSend = []; if (typeof (desiredMessages) === "number") { toSend = messages.slice(-desiredMessages); @@ -914,8 +876,18 @@ HK.initializeIndexWorkers = function (Env, config, _cb) { }); }; + Env.getOlderHistory = function (channel, oldestKnownHash, cb) { + Env.store.getWeakLock(channel, function (next) { + sendCommand({ + channel: channel, + command: "GET_OLDER_HISTORY", + hash: oldestKnownHash, + }, Util.both(next, cb)); + }); + }; + //console.log("index workers ready"); - cb(void 0, sendCommand); + cb(void 0); }); }; diff --git a/lib/workers/compute-index.js b/lib/workers/compute-index.js index 17a292059..e46e40bcc 100644 --- a/lib/workers/compute-index.js +++ b/lib/workers/compute-index.js @@ -144,9 +144,53 @@ const computeMetadata = function (data, cb, errorHandler) { }); }; +/* getOlderHistory + * allows clients to query for all messages until a known hash is read + * stores all messages in history as they are read + * can therefore be very expensive for memory + * should probably be converted to a streaming interface + + Used by: + * GET_HISTORY_RANGE +*/ + +const getOlderHistory = function (data, cb) { + const oldestKnownHash = data.hash; + const channelName = data.channel; + + //const store = Env.store; + //const Log = Env.Log; + var messageBuffer = []; + var found = false; + store.getMessages(channelName, function (msgStr) { + if (found) { return; } + + let parsed = tryParse(Env, msgStr); + if (typeof parsed === "undefined") { return; } + + // identify classic metadata messages by their inclusion of a channel. + // and don't send metadata, since: + // 1. the user won't be interested in it + // 2. this metadata is potentially incomplete/incorrect + if (HK.isMetadataMessage(parsed)) { return; } + + var content = parsed[4]; + if (typeof(content) !== 'string') { return; } + + var hash = HK.getHash(content); + if (hash === oldestKnownHash) { + found = true; + } + messageBuffer.push(parsed); + }, function (err) { + cb(err, messageBuffer); + }); +}; + const COMMANDS = { COMPUTE_INDEX: computeIndex, COMPUTE_METADATA: computeMetadata, + GET_OLDER_HISTORY: getOlderHistory, }; process.on('message', function (data) { From 4ba36a9173a3b8ff7c3ee28a8214f535b2a4d3e8 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 25 Mar 2020 11:39:14 -0400 Subject: [PATCH 06/22] load user pins in the database worker --- lib/commands/pin-rpc.js | 26 ++++++-------------- lib/historyKeeper.js | 2 ++ lib/hk-util.js | 11 +++++++++ lib/workers/compute-index.js | 47 ++++++++++++++++++++++++++++-------- 4 files changed, 58 insertions(+), 28 deletions(-) diff --git a/lib/commands/pin-rpc.js b/lib/commands/pin-rpc.js index cda482d6b..b831dbb37 100644 --- a/lib/commands/pin-rpc.js +++ b/lib/commands/pin-rpc.js @@ -156,7 +156,6 @@ var getMultipleFileSize = function (Env, channels, cb) { }); }; -const batchUserPins = BatchRead("LOAD_USER_PINS"); var loadUserPins = function (Env, safeKey, cb) { var session = Core.getSession(Env.Sessions, safeKey); @@ -164,23 +163,14 @@ var loadUserPins = function (Env, safeKey, cb) { return cb(session.channels); } - batchUserPins(safeKey, cb, function (done) { - var ref = {}; - var lineHandler = Pins.createLineHandler(ref, function (label, data) { - Env.Log.error(label, { - log: safeKey, - data: data, - }); - }); - - // if channels aren't in memory. load them from disk - // TODO replace with readMessagesBin - Env.pinStore.getMessages(safeKey, lineHandler, function () { - // no more messages - - // only put this into the cache if it completes - session.channels = ref.pins; - done(ref.pins); // FIXME no error handling? + Env.batchUserPins(safeKey, cb, function (done) { + Env.getPinState(safeKey, function (err, value) { + if (!err) { + // only put this into the cache if it completes + session.channels = value; + } + session.channels = value; + done(value); }); }); }; diff --git a/lib/historyKeeper.js b/lib/historyKeeper.js index c8356b908..13be09bd1 100644 --- a/lib/historyKeeper.js +++ b/lib/historyKeeper.js @@ -42,6 +42,7 @@ module.exports.create = function (config, cb) { batchMetadata: BatchRead('GET_METADATA'), batchRegisteredUsers: BatchRead("GET_REGISTERED_USERS"), batchDiskUsage: BatchRead('GET_DISK_USAGE'), + batchUserPins: BatchRead('LOAD_USER_PINS'), //historyKeeper: config.historyKeeper, intervals: config.intervals || {}, @@ -242,6 +243,7 @@ module.exports.create = function (config, cb) { })); }).nThen(function (w) { HK.initializeIndexWorkers(Env, { + pinPath: pinPath, filePath: config.filePath, archivePath: config.archivePath, channelExpirationMs: config.channelExpirationMs, diff --git a/lib/hk-util.js b/lib/hk-util.js index 0fafcdb91..d17cf778b 100644 --- a/lib/hk-util.js +++ b/lib/hk-util.js @@ -625,6 +625,8 @@ const handleGetHistoryRange = function (Env, Server, seq, userId, parsed) { Env.Log.error("HK_GET_OLDER_HISTORY", err); } + if (!Array.isArray(messages)) { messages = []; } + var toSend = []; if (typeof (desiredMessages) === "number") { toSend = messages.slice(-desiredMessages); @@ -886,6 +888,15 @@ HK.initializeIndexWorkers = function (Env, config, _cb) { }); }; + Env.getPinState = function (safeKey, cb) { + Env.pinStore.getWeakLock(safeKey, function (next) { + sendCommand({ + key: safeKey, + command: 'GET_PIN_STATE', + }, Util.both(next, cb)); + }); + }; + //console.log("index workers ready"); cb(void 0); }); diff --git a/lib/workers/compute-index.js b/lib/workers/compute-index.js index e46e40bcc..dd3798aa6 100644 --- a/lib/workers/compute-index.js +++ b/lib/workers/compute-index.js @@ -6,19 +6,37 @@ const Store = require("../storage/file"); const Util = require("../common-util"); const nThen = require("nthen"); const Meta = require("../metadata"); +const Pins = require("../pins"); const Env = {}; var ready = false; var store; -const init = function (config, cb) { +var pinStore; +const init = function (config, _cb) { + const cb = Util.once(Util.mkAsync(_cb)); if (!config) { return void cb('E_INVALID_CONFIG'); } - Store.create(config, function (err, _store) { - if (err) { return void cb(err); } - store = _store; + nThen(function (w) { + Store.create(config, w(function (err, _store) { + if (err) { + w.abort(); + return void cb(err); + } + store = _store; + })); + Store.create({ + filePath: config.pinPath, + }, w(function (err, _pinStore) { + if (err) { + w.abort(); + return void cb(err); + } + pinStore = _pinStore; + })); + }).nThen(function () { cb(); }); }; @@ -187,10 +205,24 @@ const getOlderHistory = function (data, cb) { }); }; +const getPinState = function (data, cb, errorHandler) { + const safeKey = data.key; + + var ref = {}; + var lineHandler = Pins.createLineHandler(ref, errorHandler); + + // if channels aren't in memory. load them from disk + // TODO replace with readMessagesBin + pinStore.getMessages(safeKey, lineHandler, function () { + cb(void 0, ref.pins); // FIXME no error handling? + }); +}; + const COMMANDS = { COMPUTE_INDEX: computeIndex, COMPUTE_METADATA: computeMetadata, GET_OLDER_HISTORY: getOlderHistory, + GET_PIN_STATE: getPinState, }; process.on('message', function (data) { @@ -201,13 +233,8 @@ process.on('message', function (data) { } const cb = function (err, value) { - if (err) { - return void process.send({ - txid: data.txid, - error: err, - }); - } process.send({ + error: err, txid: data.txid, value: value, }); From bc13a21796fb1a4a8db2e2803dbbf44308ea1f44 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 25 Mar 2020 11:50:45 -0400 Subject: [PATCH 07/22] give fileStreams a little bit more time before closing them --- lib/storage/file.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/storage/file.js b/lib/storage/file.js index 669ff900b..994680218 100644 --- a/lib/storage/file.js +++ b/lib/storage/file.js @@ -64,7 +64,7 @@ const destroyStream = function (stream) { try { stream.close(); } catch (err) { console.error(err); } setTimeout(function () { try { stream.destroy(); } catch (err) { console.error(err); } - }, 5000); + }, 15000); }; const ensureStreamCloses = function (stream, id, ms) { @@ -729,7 +729,7 @@ var getChannel = function (env, id, _callback) { delete env.channels[id]; destroyStream(channel.writeStream, path); //console.log("closing writestream"); - }, 30000); + }, 120000); channel.delayClose(); env.channels[id] = channel; done(void 0, channel); From 454d9516215d133edab8d10977b7967aa8bd4ccb Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 25 Mar 2020 17:12:05 +0100 Subject: [PATCH 08/22] Translated using Weblate (German) Currently translated at 100.0% (1241 of 1241 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/de/ --- www/common/translations/messages.de.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/translations/messages.de.json b/www/common/translations/messages.de.json index ce1c916dd..13959d261 100644 --- a/www/common/translations/messages.de.json +++ b/www/common/translations/messages.de.json @@ -575,7 +575,7 @@ "mdToolbar_button": "Die Markdown-Werkzeugleiste anzeigen oder verbergen", "mdToolbar_defaultText": "Dein Text hier", "mdToolbar_help": "Hilfe", - "mdToolbar_tutorial": "http://www.markdowntutorial.com/", + "mdToolbar_tutorial": "https://www.markdowntutorial.com/", "mdToolbar_bold": "Fett", "mdToolbar_italic": "Kursiv", "mdToolbar_strikethrough": "Durchgestrichen", From 4add6759214506514b183db708400e808b13f075 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 25 Mar 2020 17:12:05 +0100 Subject: [PATCH 09/22] Translated using Weblate (Italian) Currently translated at 70.6% (876 of 1241 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/it/ --- www/common/translations/messages.it.json | 51 +++++++++++++++++------- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/www/common/translations/messages.it.json b/www/common/translations/messages.it.json index 7e7d8a01f..fe9e1df04 100644 --- a/www/common/translations/messages.it.json +++ b/www/common/translations/messages.it.json @@ -1,5 +1,5 @@ { - "main_title": "CryptPad: Editor zero knowledge collaborativo in tempo reale", + "main_title": "CryptPad: Editor Zero Knowledge collaborativo in tempo reale", "type": { "pad": "Testo", "code": "Codice", @@ -13,7 +13,7 @@ "todo": "Promemoria", "contacts": "Contatti", "sheet": "Fogli", - "teams": "Team" + "teams": "Teams" }, "button_newpad": "Nuovo pad di Testo", "button_newcode": "Nuovo pad di Codice", @@ -25,14 +25,14 @@ "common_connectionLost": "Connessione al server persa
Rimarrai in modalità solo lettura finché la connessione non sarà ripristinata.", "websocketError": "Impossibile connettersi al WebSocket server...", "typeError": "Questo pad non è compatibile con l'applicazione selezionata", - "onLogout": "Sei logged out, {0}Click qui{1} per fare il log in
o premi Esc per accedere il tuo pad in modalità solo lettura.", - "wrongApp": "Impossibile mostrare il contenuto di quella sessione in tempo reale nel tuo browser. Per favore, prova a ricaricare la pagina.", - "padNotPinned": "Questo pad scadrà dopo 3 mesi di inattività, {0}login{1} o {2}registrati{3} per mantenerlo permanentemente.", - "anonymousStoreDisabled": "Il webmaster di questa istanza di CryptPad ha disabilitato il drive per gli utenti anonimi. Devi eseguire il login per poter usare CryptDrive.", + "onLogout": "Sei uscito, {0}Clicca qui{1} per entrare
o premi Esc per accedere al tuo pad in modalità solo lettura.", + "wrongApp": "Impossibile mostrare il contenuto di quella sessione in tempo reale nel tuo browser. Per favore, prova a ricaricare quella pagina.", + "padNotPinned": "Questo pad scadrà dopo 3 mesi di inattività, {0}accedi{1} o {2}registrati{3} per conservarlo.", + "anonymousStoreDisabled": "Il webmaster di questa istanza di CryptPad ha disabilitato il drive per gli utenti anonimi. Devi accedere per poter usare CryptDrive.", "expiredError": "Questo pad ha raggiunto la sua data di scadenza e non è più disponibile.", "deletedError": "Questo pad è stato cancellato dal suo autore e non è più disponibile.", "inactiveError": "Questo pad è stato cancellato per inattività. Premi Esc per creare un nuovo pad.", - "chainpadError": "Si è verificato un errore critico nell'aggiornamento del tuo contenuto. Questa pagina è in modalità solo lettura per assicurarci che non perderai il tuo lavoro..
Premi Esc per continuare a visualizzare questo pad, o ricarica la pagina per provare a modificarlo di nuovo.", + "chainpadError": "Si è verificato un errore critico nell'aggiornamento del tuo contenuto. Questa pagina è in modalità solo lettura per assicurarci che non perderai il tuo lavoro.
Premi Esc per continuare a visualizzare questo pad, o ricarica la pagina per provare a modificarlo di nuovo.", "invalidHashError": "Il documento richiesto ha un URL non valido.", "errorCopy": " Puoi ancora accedere al contenuto premendo Esc.
Una volta chiusa questa finestra, non sarà possibile accedere di nuovo.", "errorRedirectToHome": "Premi Esc per essere reindirizzato al tuo CryptDrive.", @@ -549,16 +549,33 @@ "why": { "q": "Perché dovrei usare CryptPad?" }, - "title": "Sicurezza" + "title": "Sicurezza", + "proof": { + "q": "Come utilizzate le Zero Knowledge Proofs?" + } }, "privacy": { "register": { - "a": "nome utente" + "a": "nome utente", + "q": "Il server mi conosce di più se mi registro?" }, "policy": { - "a": "Sì! È disponibile qui." + "a": "Sì! È disponibile qui.", + "q": "Avete una politica di privacy dei dati?" + }, + "title": "Privacy", + "anonymous": { + "q": "CryptPad mi rende anonimo?" + }, + "other": { + "q": "Cosa possono conoscere di me gli altri collaboratori?" }, - "title": "Privacy" + "me": { + "q": "Che informazioni ha il server su di me?" + }, + "different": { + "q": "In cosa è diverso CryptPad dagli altri servizi Pad?" + } }, "other": { "jobs": { @@ -583,13 +600,19 @@ }, "expiring": { "q": "Cos'è un pad effimero?", - "a": "Un expiring pad è un pad creato con una scadenza, raggiunta il pad verrà automaticamente cancellato dal server. Gli expiring pad possono essere configurati per durare da un minimo di un'ora ad un massimo di 100 mesi. Il pad e tutta la sua cronologia diventeranno permanentemente non disponibili anche se vengono modificati nel momento in cui scadono.

Se un pad è impostato con una scadenza, puoi controllare il suo tempo di durata visualizzando le sue proprietà , sia facendo clic con il tasto destro del mouse sul pad in CryptDrive, sia usando la proprietà -menu dalla barra degli strumenti di un'applicazione." + "a": "Un pad effimero è un pad creato con una scadenza, raggiunta la quale il pad verrà automaticamente cancellato dal server. I pad effimeri possono essere configurati per durare da un minimo di un'ora ad un massimo di 100 mesi. Il pad e tutta la sua cronologia diventeranno permanentemente non disponibili anche se vengono modificati nel momento in cui scadono.

Se un pad è impostato con una scadenza, puoi controllare il suo tempo di durata visualizzando le sue proprietà , sia facendo clic con il tasto destro del mouse sul pad nel tuo CryptDrive, sia usando le proprietà sub-menu dalla barra degli strumenti di un'applicazione." }, "owned": { "a": "Un pad di proprietà è un pad creato da un esplicito proprietario, identificato dal server dalla sua chiave di crittografia pubblica. Il proprietario di un pad può scegliere di cancellare i suoi pad dal server, rendendoli invalidi per gli altri collaboratori nel futuro, sia che essi li avessero oppure no nei loro Cryptdrive.", "q": "Cos'è un Pad di proprietà?" }, - "title": "Parole chiave" + "title": "Parole chiave", + "abandoned": { + "q": "Cos'è un pad abbandonato?" + }, + "template": { + "q": "Cos'è un modello?" + } } }, "whatis_zeroknowledge_p2": "Quando ti registri e accedi, il tuo nome utente e la tua password vengono computati in una chiave segreta utilizzando la funzione di derivazione scrypt. Né questa chiave, né il tuo nome utente o la tua password vengono inviati al server. Infatti sono usati soltanto dal lato client per decriptare il contenuto del tuo CryptDrive, che contiene le chiavi per tutti i pad a cui hai accesso.", @@ -635,7 +658,7 @@ "mdToolbar_link": "Link", "mdToolbar_italic": "Corsivo", "mdToolbar_bold": "Grassetto", - "mdToolbar_tutorial": "http://www.markdowntutorial.com/", + "mdToolbar_tutorial": "https://www.markdowntutorial.com/", "mdToolbar_help": "Aiuto", "pad_hideToolbar": "Nascondi barra degli strumenti", "pad_showToolbar": "Mostra barra degli strumenti", From 008bc42a63507ccf0e0d77fe7b1f84ca4a21fd2f Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 25 Mar 2020 17:12:06 +0100 Subject: [PATCH 10/22] Translated using Weblate (Japanese) Currently translated at 13.6% (169 of 1241 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ --- www/common/translations/messages.ja.json | 157 ++++++++++++++++++++++- 1 file changed, 152 insertions(+), 5 deletions(-) diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json index 4d71dcfc7..feceb792f 100644 --- a/www/common/translations/messages.ja.json +++ b/www/common/translations/messages.ja.json @@ -2,7 +2,7 @@ "websocketError": "ウェブソケットサーバーとの接続ができません。", "common_connectionLost": "サーバーとの接続が切断しました。\nサーバーと再接続するまで閲覧モードになります。", "button_newsheet": "新規スプレッドシート", - "button_newkanban": "新規カンバン", + "button_newkanban": "新規看板", "button_newwhiteboard": "新規ホワイトボード", "button_newslide": "新規プレゼンテーション", "button_newpoll": "新規投票・アンケート", @@ -15,12 +15,159 @@ "media": "メディア", "file": "ファイル", "whiteboard": "ホワイトボード", - "drive": "ドライブ", + "drive": "CryptDrive", "slide": "プレゼン", "kanban": "看板", - "poll": "投票・アンケート", + "poll": "投票", "code": "コード", - "pad": "リッチテキスト" + "pad": "リッチテキスト", + "sheet": "シート" }, - "main_title": " CryptPad - それは直感的なリアルタイム同期編集エディター -" + "main_title": "CryptPad - 安全にリアルタイム編集可能なコラボレーションツール", + "support_formButton": "送信", + "support_formMessage": "メッセージを入力...", + "support_formContentError": "エラー:内容が空です", + "support_formTitleError": "エラー:件名が空です", + "support_formTitle": "チケットの件名", + "support_cat_new": "新しいチケット", + "support_answer": "返信", + "support_remove": "チケットを削除", + "support_close": "チケットを閉じる", + "notifications_cat_all": "全て", + "openNotificationsApp": "通知パネルを開く", + "notificationsPage": "通知", + "notifications_empty": "通知がありません", + "copy_title": "{0} (コピー)", + "access_main": "アクセス", + "allow_disabled": "無効", + "allow_enabled": "有効", + "logoutEverywhere": "全ての場所でログアウト", + "settings_logoutEverywhereButton": "ログアウト", + "cancelButton": "キャンセル (Esc)", + "fm_recentPadsName": "最近使用したパッド", + "drive_active28Days": "最近4週間", + "drive_active7Days": "最近7日間", + "drive_active1Day": "最近24時間", + "fm_viewGridButton": "グリッド表示", + "fm_viewListButton": "一覧表示", + "fc_open": "開く", + "fc_newsharedfolder": "新しい共有フォルダ", + "fc_newfolder": "新しいフォルダ", + "fm_tags_name": "タグ名", + "fm_prop_tagsList": "タグ", + "fm_numberOfFiles": "ファイル数", + "fm_numberOfFolders": "フォルダ数", + "fm_folder": "フォルダ", + "fm_folderName": "フォルダ名", + "fm_fileName": "ファイル名", + "crowdfunding_button2": "CryptPad を助ける", + "fm_padIsOwned": "あなたはこのパッドの所有者です", + "creation_expiration": "有効期限", + "owner_removeText": "所有者", + "creation_owners": "所有者", + "download_mt_button": "ダウンロード", + "fc_rename": "名前を変更", + "forgotten": "ごみ箱へ移動", + "filePicker_close": "閉じる", + "upload_size": "容量", + "propertiesButton": "プロパティ", + "fm_creation": "作成日時", + "fm_lastAccess": "最終アクセス日時", + "fm_type": "種類", + "team_inviteLinkLoading": "あなたのリンクを生成中", + "loading_drive_3": "データの整合性を検証中", + "loading_drive_2": "データの形式を更新中", + "loading_drive_1": "データを読み込み中", + "loading_pad_2": "パッドの内容を読み込み中", + "download_step1": "ダウンロード中", + "loading": "読み込み中...", + "upload_type": "種類", + "fm_searchPlaceholder": "検索...", + "fm_searchName": "検索", + "fm_templateName": "テンプレート", + "fc_empty": "ごみ箱を空にする", + "fm_emptyTrashDialog": "ごみ箱を空にしてよろしいですか?", + "fm_trashName": "ごみ箱", + "settings_trimHistoryTitle": "履歴の削除", + "trimHistory_success": "履歴を削除しました", + "trimHistory_button": "履歴を削除", + "storageStatus": "ストレージ使用量:
{1} の内 {0}", + "formattedKB": "{0} KB", + "formattedGB": "{0} GB", + "formattedMB": "{0} MB", + "KB": "KB", + "GB": "GB", + "MB": "MB", + "upgradeAccount": "アカウントをアップグレード", + "upgrade": "アップグレード", + "settings_deleteButton": "アカウントを削除", + "settings_deleteTitle": "アカウントの削除", + "settings_changePasswordNewConfirm": "新しいパスワードの確認", + "settings_changePasswordNew": "新しいパスワード", + "settings_changePasswordCurrent": "現在のパスワード", + "settings_changePasswordButton": "パスワードを変更", + "settings_changePasswordHint": "アカウントのパスワードを変更します。「現在のパスワード」と、「新しいパスワード」および「新しいパスワードの確認」を入力してください。
あなたがパスワードを忘れた場合、パスワードをリセットする方法はありません。細心の注意を払って、パスワードを安全に管理してください。", + "settings_changePasswordTitle": "パスワードの変更", + "languageButton": "言語", + "language": "言語", + "settings_publicSigningKey": "公開署名鍵", + "user_accountName": "アカウント名", + "settings_restore": "復元", + "settings_backupCategory": "バックアップ", + "settings_backup": "バックアップ", + "settings_title": "設定", + "settings_cat_subscription": "サブスクリプション", + "settings_cat_drive": "CryptDrive", + "settings_cat_account": "アカウント", + "settings_cat_creation": "新しいパッド", + "settings_save": "保存", + "slideOptionsButton": "保存 (Enter)", + "profile_viewMyProfile": "自分のプロフィールを表示", + "clickToEdit": "クリックして編集", + "profile_addLink": "あなたのウェブサイトへのリンクを追加", + "shareSuccess": "リンクをクリップボードにコピーしました", + "shareButton": "共有", + "login_hashing": "パスワードをハッシュ化しています、この処理には時間がかかる場合があります。", + "login_invalPass": "パスワードを入力してください", + "login_invalUser": "ユーザー名を入力してください", + "register_importRecent": "匿名セッション中のパッドをインポート", + "importButton": "インポート", + "policy_title": "CryptPad プライバシーポリシー", + "main_catch_phrase": "ゼロ知識クラウド", + "tos_3rdparties": "私たちは、法律で義務付けられている場合を除き、個別のデータを第三者に提供しません。", + "tos_logs": "あなたのブラウザからサーバーに送信されたメタデータは、サービスを維持するために記録される場合があります。", + "tos_availability": "私たちはこのサービスがあなたの役に立つことを願っていますが、可用性や性能は保証できません。定期的にデータをエクスポートしてください。", + "tos_legal": "悪意ある行為、乱用する行為、または何らかの違法な行為を行わないでください。", + "tos_title": "CryptPad サービス利用規約", + "whatis_title": "CryptPad とは何か", + "topbar_whatIsCryptpad": "CryptPad とは何か", + "faq_title": "よくある質問", + "faq_link": "よくある質問", + "footer_tos": "利用規約", + "footer_donate": "寄付", + "footer_legal": "法的情報", + "footer_aboutUs": "私たちについて", + "pricing": "料金", + "contact": "連絡先", + "privacy": "プライバシー", + "blog": "ブログ", + "driveReadmeTitle": "CryptPad とは何ですか?", + "readme_welcome": "CryptPad へようこそ!", + "register_header": "CryptPad へようこそ", + "login_confirm": "パスワードの確認", + "login_register": "新規登録", + "login_username": "ユーザー名", + "login_password": "パスワード", + "settingsButton": "設定", + "logoutButton": "ログアウト", + "login_login": "ログイン", + "autostore_hide": "保存しない", + "autostore_store": "保存する", + "autostore_notstored": "この {0} は、あなたの CryptDrive に保存されていません。今すぐ保存しますか?", + "user_displayName": "表示名", + "exportButton": "エクスポート", + "user_rename": "表示名を変更", + "users": "ユーザー", + "saved": "保存しました", + "error": "エラー" } From 0453ec60e8a47ed968a45aecc06c90b73d756f78 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 25 Mar 2020 17:12:06 +0100 Subject: [PATCH 11/22] Translated using Weblate (Swedish) Currently translated at 13.2% (164 of 1241 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/sv/ --- www/common/translations/messages.sv.json | 168 ++++++++++++++++++++++- 1 file changed, 166 insertions(+), 2 deletions(-) diff --git a/www/common/translations/messages.sv.json b/www/common/translations/messages.sv.json index f727905a1..9ba84d691 100644 --- a/www/common/translations/messages.sv.json +++ b/www/common/translations/messages.sv.json @@ -8,7 +8,171 @@ "slide": "Presentation", "poll": "Röstning", "code": "Kod", - "todo": "Att-göra" + "todo": "Att-göra", + "teams": "Teams", + "sheet": "Kalkylark", + "pad": "Rik text", + "kanban": "Kanban" }, - "main_title": "CryptPad: Nollkunskap, samarbete i realtid" + "main_title": "CryptPad: Nollkunskap, samarbete i realtid", + "fileEmbedScript": "För att bädda in denna fil, inkludera detta skript en gång på din sida för att ladda Media Tag:", + "fileEmbedTitle": "Bädda in filen i en extern sida", + "viewEmbedTag": "Bädda in detta dokument, inkludera denna iframe i din sida var du vill. Du kan anpassa den genom CSS- eller HTML-attribut.", + "getEmbedCode": "Visa inbäddningskod", + "fileShare": "Kopiera länk", + "viewOpenTitle": "Öppna detta dokument i skrivskyddat läge i en ny flik", + "viewOpen": "Öppna skrivskyddad länk i ny flik", + "viewShareTitle": "Kopiera skrivskyddad länk", + "viewShare": "Skrivskyddad länk", + "editOpenTitle": "Öppna detta dokument i redigeringsläge i en ny flik", + "editShareTitle": "Kopiera länk", + "editShare": "Redigerar länk", + "themeButtonTitle": "Välj färgtema för användning när du redigerar kod och presentationer", + "themeButton": "Tema", + "languageButtonTitle": "Välj språk för användning vid syntaxmarkering", + "languageButton": "Språk", + "slide_invalidLess": "Ogiltig anpassad stil", + "slideOptionsButton": "Spara (Enter)", + "slideOptionsTitle": "Anpassa dina bilder", + "slideOptionsText": "Alternativ", + "tags_noentry": "Du kan inte tagga ett raderat dokument!", + "tags_duplicate": "Duplicera tagg: {0}", + "tags_notShared": "Dina taggar är inte delade med andra användare", + "tags_searchHint": "Påbörja en sökning med # i din CryptDrive för att hitta dina taggade dokument.", + "tags_add": "Uppdatera taggar för denna sida", + "tags_title": "Taggar (endast för dig)", + "or": "eller", + "filePicker_filter": "Filtrera filer efter namn", + "filePicker_description": "Välj en fil från din CryptDrive för att bädda in den eller ladda upp en ny", + "filePicker_close": "Stäng", + "filePickerButton": "Bädda in en fil lagrad i CryptDrive", + "printBackgroundRemove": "Ta bort denna bakgrundsbild", + "printBackgroundNoValue": "Ingen bakgrundsbild vald", + "printBackgroundValue": "Nuvarande bakgrund: {0}", + "printBackgroundButton": "Välj en bild", + "printBackground": "Använd som bakgrundsbild", + "printTransition": "Aktivera övergångsanimationer", + "printCSS": "Anpassade stilregler (CSS):", + "printTitle": "Visa dokumenttiteln", + "printDate": "Visa datumet", + "printSlideNumber": "Visa sidnumret", + "printOptions": "Layout-alternativ", + "printButtonTitle2": "Skriv ut dokumentet eller exportera det som en PDF-fil", + "printButton": "Skriv ut (enter)", + "printText": "Skriv ut", + "propertiesButtonTitle": "Visa dokumentegenskaper", + "propertiesButton": "Egenskaper", + "colorButtonTitle": "Ändra textfärgen i presentationsläge", + "useTemplateCancel": "Starta tomt (Esc)", + "pinLimitReachedAlert": "Du har nått din lagringsgräns. Nya dokument kommer inte lagras i din CryptDrive.
Du kan antingen ta bort dokument från din CryptDrive eller eller prenumerera på premium för att öka din lagringsgräns.", + "lag": "Fördröjning", + "anonymousStoreDisabled": "Administratören för denna CryptPad-instans har avaktiverat anonyma användare. Du måste logga in för att kunna använda CryptDrive.", + "wrongApp": "Kan inte visa innehållet av realtidssessionen i din webbläsare. Vänligen försök ladda om sidan.", + "common_connectionLost": "Serveranslutning tappad
Du är nu i skrivskyddat läge tills anslutningen är tillbaka.", + "button_newcode": "Nytt kod-dokument", + "backgroundButtonTitle": "Ändra bakgrundfärgen i presentationen", + "presentButtonTitle": "Gå in i presentationsläge", + "previewButtonTitle": "Visa eller dölj Markdown förhandsvisning", + "template_empty": "Ingen mall tillgänglig", + "template_import": "Importera en mall", + "useTemplateOK": "Välj en mall (Enter)", + "useTemplate": "Vill du starta från en mall?", + "selectTemplate": "Välj en mall och tryck escape", + "templateSaved": "Mall sparad!", + "saveTemplatePrompt": "Välj ett namn på mallen", + "saveTemplateButton": "Spara som mall", + "uploadButtonTitle": "Ladda upp en ny fil till den nuvarande mappen", + "uploadFolderButton": "Ladda upp mapp", + "uploadButton": "Ladda upp filer", + "newButtonTitle": "Skapa ett dokument", + "newButton": "Ny", + "userAccountButton": "Ditt konto", + "chatButton": "Chatt", + "userListButton": "Användarlista", + "shareSuccess": "Länken är kopierad", + "shareButton": "Dela", + "movedToTrash": "Dokumentet har flyttats till papperskorgen.
Gå till min Drive", + "forgetPrompt": "Om du klickar OK flyttas detta dokument till papperskorgen. Är du säker?", + "forgetButtonTitle": "Flytta dokumentet till papperskorgen", + "forgetButton": "Radera", + "saveTitle": "Spara titeln (enter)", + "clickToEdit": "Klicka för att redigera", + "user_accountName": "Kontonamn", + "user_displayName": "Visningsnamn", + "user_rename": "Ändra ditt visningsnamn", + "changeNamePrompt": "Ändra ditt namn (lämna tomt för att vara anonym): ", + "exportPrompt": "Vad vill du kalla din fil?", + "exportButtonTitle": "Exportera detta dokument till en fil på din enhet", + "exportButton": "Exportera", + "importButtonTitle": "Importera ett dokument från en fil på din enhet", + "importButton": "Importera", + "moreActions": "Fler åtgärder", + "pinLimitDrive": "Du har nått din lagringsgräns.
Du kan inte skapa nya dokument.", + "pinLimitNotPinned": "Du har nått din lagringsgräns.
Detta dokument är inte lagrat i din CryptDrive.", + "pinLimitReachedAlertNoAccounts": "Du har nått din lagringsgräns", + "pinLimitReached": "Du har nått din lagringsgräns", + "redLight": "Du är frånkopplad från sessionen", + "orangeLight": "Din långsamma anslutning kan påverka din upplevelse", + "greenLight": "Allt fungerar fint", + "formattedKB": "{0} KB", + "formattedGB": "{0} GB", + "formattedMB": "{0} MB", + "supportCryptpad": "Stötta CryptPad", + "KB": "KB", + "GB": "GB", + "MB": "MB", + "storageStatus": "Lagring:
{0} använd av {1}", + "upgradeAccount": "Uppgradera konto", + "upgradeTitle": "Uppgradera ditt konto för att öka din lagringsgräns", + "upgrade": "Uppgradera", + "newVersion": "CryptPad har uppdaterats!
Se vad som är nytt i den senaste versionen:
Release notes för CryptPad {0}", + "comingSoon": "Kommer snart...", + "language": "Språk", + "userlist_offline": "Du är för närvarande offline, användarlistan är inte tillgänglig.", + "editors": "redigerare", + "editor": "redigerare", + "viewers": "läsare", + "viewer": "läsare", + "and": "Och", + "users": "Användare", + "anonymousUser": "anonym redaktör", + "anonymousUsers": "anonyma redigerare", + "yourself": "Dig själv", + "anonymous": "Anonym", + "readonly": "Skrivskyddat", + "errorState": "Kritiskt fel: {0}", + "forgotten": "Flyttad till papperskorgen", + "initializing": "Initialiserar...", + "typing": "Redigerar", + "reconnecting": "Återuppkopplar", + "synchronizing": "Synkroniserar", + "disconnected": "Frånkopplad", + "realtime_unrecoverableError": "Ett oåterkalleligt fel har uppstått. Klicka OK för att ladda om.", + "disabledApp": "Programmet har blivit avaktiverat. Kontakta administratören av denna CryptPad för mer information.", + "mustLogin": "Du måste vara inloggad för att ha tillgång till denna sida", + "deletedFromServer": "Dokumentet är borttaget från servern", + "deleted": "Raderad", + "synced": "Allting är sparat", + "saved": "Sparad", + "error": "Fel", + "loading": "Laddar...", + "newVersionError": "En ny version av CryptPad är tillgänglig.
Ladda om för att använda den nya versionen, eller tryck Esc för att nå ditt innehåll i offline-läge.", + "errorRedirectToHome": "Tryck Esc för att bli omdirigerad till din CryptDrive.", + "errorCopy": " Du kan fortfarande nå innehållet genom att trycka Esc.
När du stänger detta fönster kommer du inte längre ha tillgång till det.", + "invalidHashError": "Dokumentet du har begärt har en felaktig URL.", + "chainpadError": "Ett kritiskt fel har uppstått när ditt innehåll uppdaterades. Denna sida är i skrivskyddat läge för att säkerställa att du inte förlorar ditt arbete.
Tryck Esc för att fortsätta visa detta dokument, eller ladda om och försök redigera igen.", + "inactiveError": "Detta dokument har tagits bort på grund av inaktivitet. Vänligen tryck Esc för att skapa ett nytt dokument.", + "deletedError": "Detta dokument har tagits bort av sin ägare och är inte längre tillgängligt.", + "expiredError": "Detta dokument har nått sitt utgångsdatum och är inte längre tillgängligt.", + "padNotPinnedVariable": "Detta dokument kommer gå ut efter {4} dagar av inaktivitet, {0}logga in{1} eller {2}registrera{3} för att bevara det.", + "padNotPinned": "Detta dokument kommer automatiskt gå ut efter 3 månader av inaktivitet, {0}logga in{1} eller {2}registrera{3} för att bevara det.", + "onLogout": "Du är utloggad, {0}klicka här{1} för att logga in
eller tryck Escape för att öppna ditt dokument i skrivskyddat läge.", + "typeError": "Detta dokument är inte kompatibelt med det valda programmet", + "websocketError": "Kan inte ansluta till websocket-servern...", + "button_newsheet": "Nytt kalkylark", + "button_newkanban": "Ny Kanban", + "button_newwhiteboard": "Ny whiteboard", + "button_newslide": "Ny presentation", + "button_newpoll": "Ny votering", + "button_newpad": "Nytt textdokument" } From 9521b9dd3713c46818d21f3d312b629aac127990 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 25 Mar 2020 17:15:37 +0100 Subject: [PATCH 12/22] Translated using Weblate (English) Currently translated at 100.0% (1244 of 1244 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1243 of 1243 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1242 of 1242 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ --- www/common/translations/messages.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json index f10288dc1..ed44f9a3f 100644 --- a/www/common/translations/messages.json +++ b/www/common/translations/messages.json @@ -1337,5 +1337,8 @@ "kanban_clearFilter": "Clear filter", "kanban_editCard": "Edit this card", "kanban_editBoard": "Edit this board", - "oo_isLocked": "syncing changes, please wait" + "oo_isLocked": "syncing changes, please wait", + "profile_copyKey": "Copy public key", + "admin_openFilesTitle": "Open Files", + "admin_openFilesHint": "Number of file descriptors currently open on the server." } From 67c933622ddf04fca42acd7c5a73933b05cf9635 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 25 Mar 2020 17:15:37 +0100 Subject: [PATCH 13/22] Translated using Weblate (French) Currently translated at 100.0% (1244 of 1244 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/fr/ --- www/common/translations/messages.fr.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.fr.json b/www/common/translations/messages.fr.json index 39a26fdf0..c641bd8de 100644 --- a/www/common/translations/messages.fr.json +++ b/www/common/translations/messages.fr.json @@ -1337,5 +1337,8 @@ "kanban_color": "Couleur", "kanban_body": "Contenu", "kanban_title": "Titre", - "oo_isLocked": "Synchronisation, veuillez patienter" + "oo_isLocked": "Synchronisation, veuillez patienter", + "admin_openFilesHint": "Nombre de descripteurs de fichiers actuellement ouverts sur le serveur.", + "admin_openFilesTitle": "Fichiers Ouverts", + "profile_copyKey": "Copier la clé publique" } From b20beee2dcbf10117b4dbdcf43aaace52277beb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Benqu=C3=A9?= Date: Wed, 25 Mar 2020 16:40:41 +0000 Subject: [PATCH 14/22] remove // XXX related to translation keys --- www/admin/inner.js | 2 +- www/profile/inner.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/www/admin/inner.js b/www/admin/inner.js index acc789784..8a9c2d4f4 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -121,7 +121,7 @@ define([ return $div; }; create['open-files'] = function () { - var key = 'open-files'; // XXX + var key = 'open-files'; var $div = makeBlock(key); sFrameChan.query('Q_ADMIN_RPC', { cmd: 'GET_FILE_DESCRIPTOR_COUNT', diff --git a/www/profile/inner.js b/www/profile/inner.js index 5c31e95d7..c97521407 100644 --- a/www/profile/inner.js +++ b/www/profile/inner.js @@ -459,7 +459,7 @@ define([ var addPublicKey = function ($container) { if (!APP.readOnly) { return; } - if (!Messages.profile_copyKey) { return; } // XXX + if (!Messages.profile_copyKey) { return; } var $div = $(h('div.cp-sidebarlayout-element')).appendTo($container); APP.$edPublic = $('