diff --git a/.jshintignore b/.jshintignore index c2037807f..45011b5dc 100644 --- a/.jshintignore +++ b/.jshintignore @@ -1,16 +1,11 @@ node_modules/ www/bower_components/ -www/code/codemirror* -www/common/chainpad.js -storage/kad.js -www/common/otaml.js +www/common/pdfjs/ server.js -NetFluxWebsocketSrv.js -NetFluxWebsocketServer.js -WebRTCSrv.js www/common/media-tag.js www/scratch www/common/toolbar.js www/common/hyperscript.js +www/common/tippy.min.js diff --git a/config.example.js b/config.example.js index da000a519..081f2a04b 100644 --- a/config.example.js +++ b/config.example.js @@ -25,7 +25,7 @@ module.exports = { "default-src 'none'", "style-src 'unsafe-inline' 'self'", "script-src 'self'", - "font-src 'self'", + "font-src 'self' data:", /* child-src is used to restrict iframes to a set of allowed domains. * connect-src is used to restrict what domains can connect to the websocket. @@ -67,7 +67,7 @@ module.exports = { "connect-src 'self' ws: wss:", // (insecure remote) images are included by users of the wysiwyg who embed photos in their pads - "img-src *", + "img-src * blob:", ].join('; '), httpPort: 3000, diff --git a/customize.dist/about.html b/customize.dist/about.html index 5593e41b9..03032969b 100644 --- a/customize.dist/about.html +++ b/customize.dist/about.html @@ -2,7 +2,7 @@
-',
'Esto es CryptPad, el editor collaborativo en tiempo real Zero Knowledge. Todo está guardado cuando escribes.',
'
',
- 'Comparte el enlace a este pad para editar con amigos o utiliza el botón Compartir para obtener un enlace solo lectura que permite leer pero no escribir.',
+ 'Comparte el enlace a este pad para editar con amigos o utiliza el botón para obtener un enlace solo lectura que permite leer pero no escribir.',
'
',
@@ -485,5 +485,62 @@ define(function () {
out.canvas_opacityLabel = "Opacidad: {0}";
out.canvas_widthLabel = "Talla: {0}";
+ // 1.10.0 - Kraken
+
+ out.moreActions = "Más acciones";
+ out.importButton = "Importar";
+ out.exportButton = "Exportar";
+ out.saveTitle = "Guardar título (enter)";
+ out.forgetButton = "Eliminar";
+ out.printText = "Imprimir";
+ out.slideOptionsText = "Opciones";
+ out.historyText = "Historial";
+ out.openLinkInNewTab = "Abrir enlace en pestaña nueva";
+ out.profileButton = "Perfíl";
+ out.profile_urlPlaceholder = "URL";
+ out.profile_namePlaceholder = "Nombre mostrado en su perfíl";
+ out.profile_avatar = "Imágen";
+ out.profile_upload = "Subir una imágen";
+ out.profile_error = "Error al crear tu perfíl: {0}";
+ out.profile_register = "Tienes que registrarte para crear perfíl";
+ out.profile_create = "Crear perfíl";
+ out.profile_description = "Descripción";
+ out.profile_fieldSaved = "Guardado: {0}";
+ out.download_mt_button = "Descargar";
+ out.updated_0_header_logoTitle = "Volver a tu CryptDrive";
+ out.header_logoTitle = out.updated_0_header_logoTitle;
+
+ // 1.11.0 - Lutin
+
+ out.realtime_unrecoverableError = "El motor de tiempo real a encontrado un error. Haga clic en OK para recargar la página.";
+ out.typing = "Escribiendo";
+ out.profile_inviteButton = "Connectar";
+ out.profile_inviteButtonTitle = "Crear un enlace de invitación para este usuario.";
+ out.profile_inviteExplanation = "Hacer clic en OK creará un enlace de mensaje seguro que sólo {0} podrá ver. ',
'Voici CryptPad, l\'éditeur collaboratif en temps-réel Zero Knowledge. Tout est sauvegardé dés que vous le tapez.',
' ',
'',
diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js
index 86ce50f9d..eff1c1eda 100644
--- a/customize.dist/translations/messages.js
+++ b/customize.dist/translations/messages.js
@@ -9,10 +9,11 @@ define(function () {
out.type.code = 'Code';
out.type.poll = 'Poll';
out.type.slide = 'Presentation';
- out.type.drive = 'Drive';
+ out.type.drive = 'CryptDrive';
out.type.whiteboard = 'Whiteboard';
out.type.file = 'File';
out.type.media = 'Media';
+ out.type.contacts = 'Contacts';
out.button_newpad = 'New Rich Text pad';
out.button_newcode = 'New Code pad';
@@ -36,9 +37,12 @@ define(function () {
out.synced = "Everything is saved";
out.deleted = "Pad deleted from your CryptDrive";
+ out.realtime_unrecoverableError = "The realtime engine has encountered an unrecoverable error. Click OK to reload.";
+
out.disconnected = 'Disconnected';
out.synchronizing = 'Synchronizing';
out.reconnecting = 'Reconnecting...';
+ out.typing = "Typing";
out.lag = 'Lag';
out.readonly = 'Read only';
out.anonymous = "Anonymous";
@@ -254,6 +258,30 @@ define(function () {
out.profile_description = "Description";
out.profile_fieldSaved = 'New value saved: {0}';
+ out.profile_inviteButton = "Connect";
+ out.profile_inviteButtonTitle ='Create a link that will invite this user to connect with you.';
+ out.profile_inviteExplanation = "Clicking OK will create a link to a secure messaging session that only {0} will be able to redeem. ',
'This is CryptPad, the Zero Knowledge realtime collaborative editor. Everything is saved as you type.',
' ',
diff --git a/customize.dist/translations/messages.ro.js b/customize.dist/translations/messages.ro.js
index c921581b4..0eeb8f7f2 100644
--- a/customize.dist/translations/messages.ro.js
+++ b/customize.dist/translations/messages.ro.js
@@ -331,7 +331,7 @@ define(function () {
out.header_france = "With from by ";
out.header_support = " ";
out.header_logoTitle = "Mergi la pagina principală";
- out.initialState = " Acesta este CryptPad, editorul colaborativ bazat pe tehnologia Zero Knowledge în timp real. Totul este salvat pe măsură ce scrii. Îndrăznește, începe să scrii... Acesta este CryptPad, editorul colaborativ bazat pe tehnologia Zero Knowledge în timp real. Totul este salvat pe măsură ce scrii. Îndrăznește, începe să scrii... ',
'這是 CryptPad, 零知識即時協作編輯平台,當你輸入時一切已即存好。',
' ',
diff --git a/package.json b/package.json
index ed0f25695..02b26fc7d 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "cryptpad",
"description": "realtime collaborative visual editor with zero knowlege server",
- "version": "1.10.0",
+ "version": "1.11.0",
"dependencies": {
"chainpad-server": "^1.0.1",
"express": "~4.10.1",
diff --git a/readme.md b/readme.md
index 2c5b6e895..220891324 100644
--- a/readme.md
+++ b/readme.md
@@ -129,7 +129,7 @@ Still there are other low-lives in the world so using CryptPad over HTTPS is pro
## Setup using Docker
-See [Cryptpad-Docker](cryptpad-docker.md)
+See [Cryptpad-Docker](docs/cryptpad-docker.md)
## Translations
diff --git a/rpc.js b/rpc.js
index 5b5d058b9..73fb43736 100644
--- a/rpc.js
+++ b/rpc.js
@@ -28,8 +28,8 @@ var WARN = function (e, output) {
};
var isValidId = function (chan) {
- return chan && chan.length && /^[a-fA-F0-9]/.test(chan) ||
- [32, 48].indexOf(chan.length) !== -1;
+ return chan && chan.length && /^[a-fA-F0-9]/.test(chan) &&
+ [32, 48].indexOf(chan.length) > -1;
};
var uint8ArrayToHex = function (a) {
@@ -113,15 +113,21 @@ var isTooOld = function (time, now) {
return (now - time) > 300000;
};
+var expireSession = function (Sessions, key) {
+ var session = Sessions[key];
+ if (!session) { return; }
+ if (session.blobstage) {
+ session.blobstage.close();
+ }
+ delete Sessions[key];
+};
+
var expireSessions = function (Sessions) {
var now = +new Date();
Object.keys(Sessions).forEach(function (key) {
var session = Sessions[key];
- if (isTooOld(Sessions[key].atime, now)) {
- if (session.blobstage) {
- session.blobstage.close();
- }
- delete Sessions[key];
+ if (session && isTooOld(session.atime, now)) {
+ expireSession(Sessions, key);
}
});
};
@@ -670,6 +676,29 @@ var makeFileStream = function (root, id, cb) {
});
};
+var clearOwnedChannel = function (Env, channelId, unsafeKey, cb) {
+ if (typeof(channelId) !== 'string' || channelId.length !== 32) {
+ return cb('INVALID_ARGUMENTS');
+ }
+
+ if (!(Env.msgStore && Env.msgStore.getChannelMetadata)) {
+ return cb('E_NOT_IMPLEMENTED');
+ }
+
+ Env.msgStore.getChannelMetadata(channelId, function (e, metadata) {
+ if (e) { return cb(e); }
+ if (!(metadata && Array.isArray(metadata.owners))) { return void cb('E_NO_OWNERS'); }
+ // Confirm that the channel is owned by the user is question
+ if (metadata.owners.indexOf(unsafeKey) === -1) {
+ return void cb('INSUFFICIENT_PERMISSIONS');
+ }
+
+ return void Env.msgStore.clearChannel(channelId, function (e) {
+ cb(e);
+ });
+ });
+};
+
var upload = function (Env, publicKey, content, cb) {
var paths = Env.paths;
var dec;
@@ -846,6 +875,7 @@ var isAuthenticatedCall = function (call) {
'GET_LIMIT',
'UPLOAD_COMPLETE',
'UPLOAD_CANCEL',
+ 'EXPIRE_SESSION',
].indexOf(call) !== -1;
};
@@ -1046,7 +1076,16 @@ RPC.create = function (config /*:typeof(ConfigType)*/, cb /*:(?Error, ?Function)
}
Respond(void 0, dict);
});
-
+ case 'EXPIRE_SESSION':
+ return void setTimeout(function () {
+ expireSession(Sessions, safeKey);
+ Respond(void 0, "OK");
+ });
+ case 'CLEAR_OWNED_CHANNEL':
+ return void clearOwnedChannel(Env, msg[1], publicKey, function (e, response) {
+ if (e) { return void Respond(e); }
+ Respond(void 0, response);
+ });
// restricted to privileged users...
case 'UPLOAD':
if (!privileged) { return deny(); }
diff --git a/storage/file.js b/storage/file.js
index 857f147f4..31b58aa94 100644
--- a/storage/file.js
+++ b/storage/file.js
@@ -6,6 +6,85 @@ var mkPath = function (env, channelId) {
return Path.join(env.root, channelId.slice(0, 2), channelId) + '.ndjson';
};
+var getMetadataAtPath = function (Env, path, cb) {
+ var remainder = '';
+ var stream = Fs.createReadStream(path, 'utf8');
+ var complete = function (err, data) {
+ var _cb = cb;
+ cb = undefined;
+ if (_cb) { _cb(err, data); }
+ };
+ stream.on('data', function (chunk) {
+ if (!/\n/.test(chunk)) {
+ remainder += chunk;
+ return;
+ }
+ stream.close();
+ var metadata = chunk.split('\n')[0];
+
+ var parsed = null;
+ try {
+ parsed = JSON.parse(metadata);
+ complete(void 0, parsed);
+ }
+ catch (e) {
+ console.log();
+ console.error(e);
+ complete('INVALID_METADATA');
+ }
+ });
+ stream.on('end', function () {
+ complete(null);
+ });
+ stream.on('error', function (e) { complete(e); });
+};
+
+var getChannelMetadata = function (Env, channelId, cb) {
+ var path = mkPath(Env, channelId);
+ getMetadataAtPath(Env, path, cb);
+};
+
+var closeChannel = function (env, channelName, cb) {
+ if (!env.channels[channelName]) { return; }
+ try {
+ env.channels[channelName].writeStream.close();
+ delete env.channels[channelName];
+ env.openFiles--;
+ cb();
+ } catch (err) {
+ cb(err);
+ }
+};
+
+var clearChannel = function (env, channelId, cb) {
+ var path = mkPath(env, channelId);
+ getMetadataAtPath(env, path, function (e, metadata) {
+ if (e) { return cb(e); }
+ if (!metadata) {
+ return void Fs.truncate(path, 0, function (err) {
+ if (err) {
+ return cb(err);
+ }
+ cb(void 0);
+ });
+ }
+
+ var len = JSON.stringify(metadata).length + 1;
+
+ // as long as closeChannel is synchronous, this should not cause
+ // any race conditions. truncate ought to return faster than a channel
+ // can be opened and read by another user. if that turns out not to be
+ // the case, we'll need to implement locking.
+ closeChannel(env, channelId, function (err) {
+ if (err) { cb(err); }
+ Fs.truncate(path, len, function (err) {
+ if (err) { return cb(err); }
+ cb();
+ });
+ });
+ });
+};
+
var readMessages = function (path, msgHandler, cb) {
var remainder = '';
var stream = Fs.createReadStream(path, 'utf8');
@@ -49,22 +128,10 @@ var checkPath = function (path, callback) {
};
var removeChannel = function (env, channelName, cb) {
- var filename = Path.join(env.root, channelName.slice(0, 2), channelName + '.ndjson');
+ var filename = mkPath(env, channelName);
Fs.unlink(filename, cb);
};
-var closeChannel = function (env, channelName, cb) {
- if (!env.channels[channelName]) { return; }
- try {
- env.channels[channelName].writeStream.close();
- delete env.channels[channelName];
- env.openFiles--;
- cb();
- } catch (err) {
- cb(err);
- }
-};
-
var flushUnusedChannels = function (env, cb, frame) {
var currentTime = +new Date();
@@ -260,6 +327,12 @@ module.exports.create = function (conf, cb) {
getChannelSize: function (chanName, cb) {
channelBytes(env, chanName, cb);
},
+ getChannelMetadata: function (channelName, cb) {
+ getChannelMetadata(env, channelName, cb);
+ },
+ clearChannel: function (channelName, cb) {
+ clearChannel(env, channelName, cb);
+ },
});
});
setInterval(function () {
diff --git a/www/code/inner.js b/www/code/inner.js
index 57d154950..fa3a41f6f 100644
--- a/www/code/inner.js
+++ b/www/code/inner.js
@@ -6,6 +6,8 @@ define([
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
'less!/code/code.less',
'less!/customize/src/less/toolbar.less',
+ 'less!/customize/src/less/cryptpad.less',
+
'css!cm/lib/codemirror.css',
'css!cm/addon/dialog/dialog.css',
'css!cm/addon/fold/foldgutter.css',
diff --git a/www/code/main.js b/www/code/main.js
index 68d9c68bc..1b6cb8997 100644
--- a/www/code/main.js
+++ b/www/code/main.js
@@ -364,6 +364,21 @@ define([
return;
}
UserList.getLastName(toolbar.$userNameButton, isNew);
+ var fmConfig = {
+ dropArea: $iframe.find('.CodeMirror'),
+ body: $iframe.find('body'),
+ onUploaded: function (ev, data) {
+ //var cursor = editor.getCursor();
+ //var cleanName = data.name.replace(/[\[\]]/g, '');
+ //var text = '!['+cleanName+']('+data.url+')';
+ var parsed = Cryptpad.parsePadUrl(data.url);
+ var hexFileName = Cryptpad.base64ToHex(parsed.hashData.channel);
+ var src = '/blob/' + hexFileName.slice(0,2) + '/' + hexFileName;
+ var mt = '
El enlace será copiado a tu portapapeles y puede ser compartido publicamente.";
+ out.profile_viewMyProfile = "Ver mi perfíl";
+ out.userlist_addAsFriendTitle = 'Agregar "{0}" como contacto';
+ out.userlist_thisIsYou = 'Tú mismo ("{0}")';
+ out.contacts_title = "Contactos";
+ out.contacts_addError = "Error al agregar este contacto a la lista";
+ out.contacts_added = "Invitación acceptada";
+ out.contacts_rejected = "Invitación denegada";
+ out.contacts_request = "{0} quiere agregarte como contacto. Acceptar?";
+ out.contacts_send = "Enviar";
+ out.contacts_remove = "Eliminar este contacto";
+ out.contacts_confirmRemove = "Estás seguro que quieres eliminar {0} de tus contactos?";
+ out.contacts_info1 = "Estos son tus contactos. De aquí, puedes:";
+ out.contacts_info2 = "Hacer clic en el icono de tu contacto para chatear";
+ out.contacts_info3 = "Hacer doble-clic para ver su perfil";
+ out.contacts_info4 = "Cualquier participante puede eliminar definitivamente el historial de chat";
+ out.settings_cat_account = "Cuenta";
+ out.settings_cat_drive = "CryptDrive";
+ out.settings_backupCategory = "Copia de seguridad";
+ out.settings_resetNewTitle = "Limpiar CryptDrive";
+ out.settings_resetButton = "Eliminar";
+ out.settings_resetTipsAction = "Reiniciar";
+ out.settings_userFeedbackTitle = "Feedback";
+ out.settings_logoutEverywhereButton = "Cerar sesión";
+ out.upload_title = "Subir archivo";
+
return out;
});
diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js
index bca33cb26..1effcfca7 100644
--- a/customize.dist/translations/messages.fr.js
+++ b/customize.dist/translations/messages.fr.js
@@ -9,10 +9,11 @@ define(function () {
out.type.code = 'Code';
out.type.poll = 'Sondage';
out.type.slide = 'Présentation';
- out.type.drive = 'Drive';
+ out.type.drive = 'CryptDrive';
out.type.whiteboard = "Tableau Blanc";
out.type.file = "Fichier";
out.type.media = "Média";
+ out.type.contacts = "Contacts";
out.button_newpad = 'Nouveau document texte';
out.button_newcode = 'Nouvelle page de code';
@@ -34,9 +35,12 @@ define(function () {
out.synced = "Tout est enregistré";
out.deleted = "Pad supprimé de votre CryptDrive";
+ out.realtime_unrecoverableError = "Le moteur temps-réel a rencontré une erreur critique. Cliquez sur OK pour recharger la page.";
+
out.disconnected = 'Déconnecté';
out.synchronizing = 'Synchronisation';
out.reconnecting = 'Reconnexion...';
+ out.typing = "Édition";
out.lag = 'Latence';
out.readonly = 'Lecture seule';
out.anonymous = "Anonyme";
@@ -252,6 +256,28 @@ define(function () {
out.profile_description = "Description";
out.profile_fieldSaved = 'Nouvelle valeur enregistrée: {0}';
+ out.profile_viewMyProfile = "Voir mon profil";
+
+ // contacts/userlist
+ out.userlist_addAsFriendTitle = 'Ajouter "{0}" comme contact';
+ out.userlist_thisIsYou = 'Vous ("{0}")';
+ out.userlist_pending = "En attente...";
+ out.contacts_title = "Contacts";
+ out.contacts_addError = "Erreur lors de l'ajout de ce contact dans votre liste";
+ out.contacts_added = 'Invitation de contact acceptée';
+ out.contacts_rejected = 'Invitation de contact rejetée';
+ out.contacts_request = '{0} souhaite vous ajouter en tant que contact. Accepter ?';
+ out.contacts_send = 'Envoyer';
+ out.contacts_remove = 'Supprimer ce contact';
+ out.contacts_confirmRemove = 'Êtes-vous sûr de voulour supprimer {0} de vos contacts ?';
+ out.contacts_typeHere = "Entrez un message ici...";
+
+
+ out.contacts_info1 = "Voici vos contacts. Ici, vous pouvez :";
+ out.contacts_info2 = "Cliquer sur le nom d'un contact pour discuter avec lui";
+ out.contacts_info3 = "Double-cliquer sur son nom pour voir son profil";
+ out.contacts_info4 = "Chaque participant peut nettoyer définitivement l'historique d'une discussion";
+
// File manager
out.fm_rootName = "Documents";
@@ -294,7 +320,7 @@ define(function () {
out.updated_0_fm_info_trash = "Vider la corbeille permet de libérer de l'espace dans votre CryptDrive";
out.fm_info_trash = out.updated_0_fm_info_trash;
out.fm_info_allFiles = 'Contient tous les fichiers de "Documents", "Fichiers non triés" et "Corbeille". Vous ne pouvez pas supprimer ou déplacer des fichiers depuis cet endroit.'; // Same here
- out.fm_info_anonymous = 'Vous n\'êtes pas connectés, ces pads risquent donc d\'être supprimés (découvrez pourquoi). ' +
+ out.fm_info_anonymous = 'Vous n\'êtes pas connecté, ces pads risquent donc d\'être supprimés (découvrez pourquoi). ' +
'Inscrivez-vous ou connectez-vous pour les maintenir en vie.';
out.fm_alert_backupUrl = "Lien de secours pour ce CryptDrive.
" +
"Il est fortement recommandé de garder ce lien pour vous-même.
" +
@@ -375,28 +401,37 @@ define(function () {
];
// Settings
+ out.settings_cat_account = "Compte";
+ out.settings_cat_drive = "CryptDrive";
out.settings_title = "Préférences";
out.settings_save = "Sauver";
+
+ out.settings_backupCategory = "Sauvegarde";
out.settings_backupTitle = "Créer ou restaurer une sauvegarde de vos données";
- out.settings_backup = "Créer une sauvegarde";
- out.settings_restore = "Restaurer une sauvegarde";
- out.settings_resetTitle = "Vider votre drive";
+ out.settings_backup = "Sauvegarder";
+ out.settings_restore = "Restaurer";
+
+ out.settings_resetNewTitle = "Vider CryptDrive";
+ out.settings_resetButton = "Supprimer";
out.settings_reset = "Supprimer tous les fichiers et dossiers de votre CryptDrive";
out.settings_resetPrompt = "Cette action va supprimer tous les pads de votre drive.
"+
"Êtes-vous sûr de vouloir continuer ?
" +
"Tapez “I love CryptPad” pour confirmer.";
out.settings_resetDone = "Votre drive est désormais vide!";
out.settings_resetError = "Texte de vérification incorrect. Votre CryptDrive n'a pas été modifié.";
- out.settings_resetTips = "Astuces et informations dans CryptDrive";
+
+ out.settings_resetTipsAction ="Réinitialiser";
+ out.settings_resetTips = "Astuces";
out.settings_resetTipsButton = "Réinitialiser les astuces visibles dans CryptDrive";
out.settings_resetTipsDone = "Toutes les astuces sont de nouveau visibles.";
- out.settings_importTitle = "Importer les pads récents de ce navigateur dans mon CryptDrive";
+ out.settings_importTitle = "Importer les pads récents de ce navigateur dans votre CryptDrive";
out.settings_import = "Importer";
out.settings_importConfirm = "Êtes-vous sûr de vouloir importer les pads récents de ce navigateur dans le CryptDrive de votre compte utilisateur ?";
out.settings_importDone = "Importation terminée";
- out.settings_userFeedbackHint1 = "CryptPad peut envoyer des retours d'expérience très limités vers le serveur, de manière à nous permettre d'améliorer l'expérience des utilisateurs.";
+ out.settings_userFeedbackTitle = "Retour d'expérience";
+ out.settings_userFeedbackHint1 = "CryptPad peut envoyer des retours d'expérience très limités vers le serveur, de manière à nous permettre d'améliorer l'expérience des utilisateurs. ";
out.settings_userFeedbackHint2 = "Le contenu de vos pads et les clés de déchiffrement ne seront jamais partagés avec le serveur.";
out.settings_userFeedback = "Activer l'envoi de retours d'expérience";
@@ -409,10 +444,12 @@ define(function () {
out.settings_pinningError = "Un problème est survenu";
out.settings_usageAmount = "Vos pads épinglés occupent {0} Mo";
+ out.settings_logoutEverywhereButton = "Se déconnecter";
out.settings_logoutEverywhereTitle = "Se déconnecter partout";
- out.settings_logoutEverywhere = "Se déconnecter de toutes les autres sessions.";
+ out.settings_logoutEverywhere = "Se déconnecter de force de toutes les autres sessions.";
out.settings_logoutEverywhereConfirm = "Êtes-vous sûr ? Vous devrez vous reconnecter sur tous vos autres appareils.";
+ out.upload_title = "Hébergement de fichiers";
out.upload_serverError = "Erreur interne: impossible d'importer le fichier pour l'instant.";
out.upload_uploadPending = "Vous avez déjà un fichier en cours d'importation. Souhaitez-vous l'annuler et importer ce nouveau fichier ?";
out.upload_success = "Votre fichier ({0}) a été importé avec succès et ajouté à votre CryptDrive.";
@@ -518,7 +555,7 @@ define(function () {
'
',
- 'Partagez le lien vers ce pad avec des amis ou utilisez le bouton Partager pour obtenir le lien de lecture-seule, qui permet la lecture mais non la modification.',
+ 'Partagez le lien vers ce pad avec des amis ou utilisez le bouton pour obtenir le lien de lecture-seule, qui permet la lecture mais non la modification.',
'
The link will be copied to your clipboard and can be shared publicly.";
+ out.profile_viewMyProfile = "View my profile";
+
+ // contacts/userlist
+ out.userlist_addAsFriendTitle = 'Add "{0}" as a contact';
+ out.userlist_thisIsYou = 'This is you ("{0}")';
+ out.userlist_pending = "Pending...";
+ out.contacts_title = "Contacts";
+ out.contacts_addError = 'Error while adding that contact to the list';
+ out.contacts_added = 'Contact invite accepted.';
+ out.contacts_rejected = 'Contact invite rejected';
+ out.contacts_request = '{0} would like to add you as a contact. Accept?';
+ out.contacts_send = 'Send';
+ out.contacts_remove = 'Remove this contact';
+ out.contacts_confirmRemove = 'Are you sure you want to remove {0} from your contacts?';
+ out.contacts_typeHere = "Type a message here...";
+
+ out.contacts_info1 = "These are your contacts. From here, you can:";
+ out.contacts_info2 = "Click your contact's icon to chat with them";
+ out.contacts_info3 = "Double-click their icon to view their profile";
+ out.contacts_info4 = "Either participant can clear permanently a chat history";
+
// File manager
out.fm_rootName = "Documents";
@@ -380,28 +408,37 @@ define(function () {
out.register_alreadyRegistered = "This user already exists, do you want to log in?";
// Settings
+ out.settings_cat_account = "Account";
+ out.settings_cat_drive = "CryptDrive";
out.settings_title = "Settings";
out.settings_save = "Save";
+
+ out.settings_backupCategory = "Backup";
out.settings_backupTitle = "Backup or restore all your data";
out.settings_backup = "Backup";
out.settings_restore = "Restore";
- out.settings_resetTitle = "Clean your drive";
+
+ out.settings_resetNewTitle = "Clean CryptDrive";
+ out.settings_resetButton = "Remove";
out.settings_reset = "Remove all the files and folders from your CryptDrive";
out.settings_resetPrompt = "This action will remove all the pads from your drive.
"+
"Are you sure you want to continue?
" +
"Type “I love CryptPad” to confirm.";
out.settings_resetDone = "Your drive is now empty!";
out.settings_resetError = "Incorrect verification text. Your CryptDrive has not been changed.";
- out.settings_resetTips = "Tips in CryptDrive";
+
+ out.settings_resetTipsAction = "Reset";
+ out.settings_resetTips = "Tips";
out.settings_resetTipsButton = "Reset the available tips in CryptDrive";
out.settings_resetTipsDone = "All the tips are now visible again.";
- out.settings_importTitle = "Import this browser's recent pads in my CryptDrive";
+ out.settings_importTitle = "Import this browser's recent pads in your CryptDrive";
out.settings_import = "Import";
out.settings_importConfirm = "Are you sure you want to import recent pads from this browser to your user account's CryptDrive?";
out.settings_importDone = "Import completed";
- out.settings_userFeedbackHint1 = "CryptPad provides some very basic feedback to the server, to let us know how to improve your experience.";
+ out.settings_userFeedbackTitle = "Feedback";
+ out.settings_userFeedbackHint1 = "CryptPad provides some very basic feedback to the server, to let us know how to improve your experience. ";
out.settings_userFeedbackHint2 = "Your pad's content will never be shared with the server.";
out.settings_userFeedback = "Enable user feedback";
@@ -414,10 +451,12 @@ define(function () {
out.settings_pinningError = "Something went wrong";
out.settings_usageAmount = "Your pinned pads occupy {0}MB";
+ out.settings_logoutEverywhereButton = "Log out";
out.settings_logoutEverywhereTitle = "Log out everywhere";
- out.settings_logoutEverywhere = "Log out of all other web sessions";
+ out.settings_logoutEverywhere = "Force log out of all other web sessions";
out.settings_logoutEverywhereConfirm = "Are you sure? You will need to log in with all your devices.";
+ out.upload_title = "File upload";
out.upload_serverError = "Server Error: unable to upload your file at this time.";
out.upload_uploadPending = "You already have an upload in progress. Cancel it and upload your new file?";
out.upload_success = "Your file ({0}) has been successfully uploaded and added to your drive.";
@@ -528,7 +567,7 @@ define(function () {
'
',
- 'Share the link to this pad to edit with friends or use the Share button to share a read-only link which allows viewing but not editing.',
+ 'Share the link to this pad to edit with friends or use the button to share a read-only link which allows viewing but not editing.',
'
Partajează link-ul către acest pad pentru a edita cu prieteni sau folosește Share butonul pentru a partaja read-only link permițând vizualizarea dar nu și editarea.
Partajează link-ul către acest pad pentru a edita cu prieteni sau folosește Share butonul pentru a partaja read-only link permițând vizualizarea dar nu și editarea.
',
- '分享這個工作檔案的網址連結給友人或是使用、 分享 按鈕分享唯讀的連結 其只能看不能編寫。',
+ '分享這個工作檔案的網址連結給友人或是使用、 按鈕分享唯讀的連結 其只能看不能編寫。',
'