1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-08-30 20:39:46 +02:00

Compare commits

...

53 Commits

Author SHA1 Message Date
Laurent Cozic
07c6347014 Android v0.10.74 2018-01-15 18:40:44 +00:00
Laurent Cozic
b10999e83e All: Update French translation 2018-01-15 18:35:39 +00:00
Laurent Cozic
961b5bfd25 All: Fixes #85: Don't record deleted_items entries for folders deleted via sync 2018-01-15 18:10:14 +00:00
Laurent Cozic
d1f1d1068a Electron release v0.10.46 2018-01-15 12:29:58 +00:00
Laurent Cozic
faade0afe2 All: Fixed model ID issue 2018-01-14 17:11:44 +00:00
Laurent Cozic
a442a49e2f Electron release v0.10.45 2018-01-15 12:27:10 +00:00
Laurent Cozic
7d3fbbcaba Updated translations 2018-01-14 17:07:34 +00:00
Laurent Cozic
d9bb7c3271 Android v0.10.73 2018-01-14 17:05:59 +00:00
Laurent Cozic
4d1dd17fa2 All: Fixed issue with timestamp when saving notes 2018-01-14 17:01:22 +00:00
Laurent Cozic
c5c6c777be Electron release v0.10.44 2018-01-12 18:11:39 +01:00
Laurent Cozic
1fd1a73fda Electron: Improved the way new note are created, and automatically add a title. Made saving and loading notes more reliable. 2018-01-12 19:58:01 +00:00
Laurent Cozic
feeb498a79 All: Fixed OneDrive sync when resync is requested 2018-01-12 19:01:34 +00:00
Laurent Cozic
1d7f30d441 Electron: Fixed logic to save, and make sure scheduled save always happen even when changing note 2018-01-11 21:05:34 +01:00
Laurent Cozic
424443a2d8 CLI: Display arrays and objects in settings 2018-01-09 21:25:31 +01:00
Laurent Cozic
08b58f0e4c All: Fixed table font size and family 2018-01-09 21:09:49 +01:00
Laurent Cozic
c2a0d8600f Electron: Move prompt to top to avoid issue with date picker being hidden 2018-01-09 21:06:47 +01:00
Laurent Cozic
ede3c2ce2f Electron: Fixed display of too long notebook titles 2018-01-09 19:34:06 +01:00
Laurent Cozic
0b93515711 Electron: Display URL for links 2018-01-09 19:26:46 +01:00
Laurent Cozic
2f13e689b9 Electron: Don't scroll back to top when note is reloaded via sync 2018-01-09 20:26:20 +00:00
Laurent Cozic
ea135a0d28 Electron: Fixed logic of what note is used when right-clicking one or more notes 2018-01-09 20:16:09 +00:00
Laurent Cozic
f67e4a03e4 CLI: Detect installed Node version 2018-01-09 19:56:38 +00:00
Laurent Cozic
e9268edeff All: Fixes #150: Extra comma causes crash 2018-01-09 19:45:08 +00:00
Laurent Cozic
a8576a55d6 CLI v0.10.87 2018-01-09 09:31:03 +01:00
Laurent Cozic
eb500cdf9e All: Display sync items being fetched 2018-01-08 21:36:00 +01:00
Laurent Cozic
7b9dc66121 All: Schedule sync after enabling or disabling encryption 2018-01-08 21:25:38 +01:00
Laurent Cozic
bba2c68c6f All: Schedule sync only after 30 seconds 2018-01-08 21:05:08 +01:00
Laurent Cozic
c70d8bea78 All: Fixes #129: Tags are case insensitive 2018-01-08 21:04:44 +01:00
Laurent Cozic
176bda66ad Merge branch 'master' of github.com:laurent22/joplin 2018-01-08 20:09:12 +01:00
Laurent Cozic
78ce10ddf0 All: Fixed race condition when a note is being uploaded while it's being modified in the text editor 2018-01-08 20:09:01 +01:00
Laurent Cozic
29f14681a8 Mobile: Fixed mix of tabs and spaces 2018-01-08 19:31:04 +00:00
Laurent Cozic
aaf617e41c iOS v0.10.9 2018-01-08 18:26:30 +01:00
Laurent Cozic
b99146ed7f Merge pull request #111 from marcosvega91/fix_scroll_note_keyboard
Fix scroll note keyboard on IOS
2018-01-08 16:45:58 +00:00
Laurent Cozic
d136161650 Android v0.10.71 2018-01-07 19:29:57 +00:00
Laurent Cozic
39051a27a1 Update website 2018-01-08 11:12:22 +01:00
Laurent Cozic
30bc9dd551 Electron release v0.10.43 2018-01-08 10:57:36 +01:00
Laurent Cozic
cc2f665313 Electron: Undone tests 2018-01-08 10:57:29 +01:00
Laurent Cozic
37c989ed28 Electron release v0.10.42 2018-01-08 10:27:02 +01:00
Laurent Cozic
adc5885980 All: Better handling of null values in settings 2018-01-07 19:20:10 +00:00
Laurent Cozic
8de5b4219d All: Updated translations 2018-01-06 21:05:34 +01:00
Laurent Cozic
e096ddebd4 Merge branch 'master' of github.com:laurent22/joplin 2018-01-06 20:40:47 +01:00
Laurent Cozic
83398dd0bc Mobile: Fixes #139: Crash when creating new notebook 2018-01-06 20:37:42 +01:00
Laurent Cozic
ddc78ebb41 Merge pull request #138 from rtmkrlv/russian-locale
Updated Russian translation
2018-01-06 19:34:02 +00:00
rtmkrlv
70b69eb31e Merge branch 'master' into russian-locale 2018-01-06 14:59:28 +02:00
rtmkrlv
3fa891e136 Merge branch 'master' into russian-locale 2018-01-06 14:54:46 +02:00
rtmkrlv
6f7a9f3295 Updated Russian translation
Added translation of new strings and small corrections
2018-01-06 14:45:30 +02:00
Laurent Cozic
8e8793943b Update README.md 2018-01-06 10:19:50 +01:00
Laurent Cozic
83d9faf2fe Create PULL_REQUEST_TEMPLATE 2018-01-06 10:17:14 +01:00
Laurent Cozic
f45a4fff8b Mobile: Fixes #136, fixes #137: styling issues on E2EE 2018-01-06 10:06:41 +01:00
Laurent Cozic
1e02aa3120 Update website 2018-01-05 21:38:37 +01:00
Laurent Cozic
77fec75f23 CLI v0.10.86 2018-01-05 21:02:23 +01:00
marcosvega91
277ad90f72 Indent with tab 2017-12-19 21:14:40 +01:00
marcosvega91
f2e3bedde6 Fix scroll
After fixing the issue on ios, it caused an issue on android that I solved with this commit
2017-12-19 10:28:52 +01:00
marcosvega91
98c0f2315a Fix scroll
Fixed the issue that not permit to view edited text when the keyboard is shown.
2017-12-19 10:08:22 +01:00
72 changed files with 1734 additions and 489 deletions

View File

@@ -28,6 +28,8 @@ yarn dist
If there's an error `while loading shared libraries: libgconf-2.so.4: cannot open shared object file: No such file or directory`, run `sudo apt-get install libgconf-2-4`
For node-gyp to work, you might need to install the `windows-build-tools` using `npm install --global windows-build-tools`.
That will create the executable file in the `dist` directory.
From `/ElectronClient` you can also run `run.sh` to run the app for testing.

View File

@@ -23,7 +23,8 @@ class Command extends BaseCommand {
const verbose = args.options.verbose;
const renderKeyValue = (name) => {
const value = Setting.value(name);
let value = Setting.value(name);
if (typeof value === 'object' || Array.isArray(value)) value = JSON.stringify(value);
if (Setting.isEnum(name)) {
return _('%s = %s (%s)', name, value, Setting.enumOptionsDoc(name));
} else {

View File

@@ -3,6 +3,13 @@
// Make it possible to require("/lib/...") without specifying full path
require('app-module-path').addPath(__dirname);
const compareVersion = require('compare-version');
const nodeVersion = process && process.versions && process.versions.node ? process.versions.node : '0.0.0';
if (compareVersion(nodeVersion, '8.0.0') < 0) {
console.error('Joplin requires Node 8+. Detected version ' + nodeVersion);
process.exit(1);
}
const { app } = require('./app.js');
const Folder = require('lib/models/Folder.js');
const Resource = require('lib/models/Resource.js');

View File

@@ -2,7 +2,7 @@
# Copyright (C) YEAR Laurent Cozic
# This file is distributed under the same license as the Joplin-CLI package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#
msgid ""
msgstr ""
"Project-Id-Version: Joplin-CLI 1.0.0\n"
@@ -116,6 +116,9 @@ msgstr "Ungültiger Befehl: %s"
msgid "The command \"%s\" is only available in GUI mode"
msgstr "Der Befehl \"%s\" ist nur im GUI Modus verfügbar"
msgid "Cannot change encrypted item"
msgstr ""
#, javascript-format
msgid "Missing required argument: %s"
msgstr "Fehlendes benötigtes Argument: %s"
@@ -180,6 +183,36 @@ msgstr "Markiert ein To-Do als abgeschlossen."
msgid "Note is not a to-do: \"%s\""
msgstr "Notiz ist kein To-Do: \"%s\""
msgid ""
"Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, "
"`status` and `target-status`."
msgstr ""
msgid "Enter master password:"
msgstr ""
msgid "Operation cancelled"
msgstr ""
msgid ""
"Starting decryption... Please wait as it may take several minutes depending "
"on how much there is to decrypt."
msgstr ""
msgid "Completed decryption."
msgstr ""
#, fuzzy
msgid "Enabled"
msgstr "Deaktiviert"
msgid "Disabled"
msgstr "Deaktiviert"
#, javascript-format
msgid "Encryption is: %s"
msgstr ""
msgid "Edit note."
msgstr "Notiz bearbeiten."
@@ -573,6 +606,13 @@ msgstr ""
"Um zum Beispiel ein Notizbuch zu erstellen, drücke `mb`; um eine Notiz zu "
"erstellen drücke `mn`."
msgid ""
"One or more items are currently encrypted and you may need to supply a "
"master password. To do so please type `e2ee decrypt`. If you have already "
"supplied the password, the encrypted items are being decrypted in the "
"background and will be available soon."
msgstr ""
msgid "File"
msgstr "Datei"
@@ -615,7 +655,11 @@ msgstr "Werkzeuge"
msgid "Synchronisation status"
msgstr "Status der Synchronisation"
msgid "Options"
msgid "Encryption options"
msgstr ""
#, fuzzy
msgid "General Options"
msgstr "Optionen"
msgid "Help"
@@ -703,13 +747,6 @@ msgstr "Status"
msgid "Encryption is:"
msgstr ""
#, fuzzy
msgid "Enabled"
msgstr "Deaktiviert"
msgid "Disabled"
msgstr "Deaktiviert"
msgid "Back"
msgstr "Zurück"
@@ -723,15 +760,9 @@ msgstr ""
msgid "Please create a notebook first."
msgstr "Bitte erstelle zuerst ein Notizbuch."
msgid "Note title:"
msgstr "Notizen Titel:"
msgid "Please create a notebook first"
msgstr "Bitte erstelle zuerst ein Notizbuch"
msgid "To-do title:"
msgstr "To-Do Titel:"
msgid "Notebook title:"
msgstr "Notizbuch Titel:"
@@ -808,6 +839,9 @@ msgstr "OneDrive Login"
msgid "Import"
msgstr "Importieren"
msgid "Options"
msgstr "Optionen"
msgid "Synchronisation Status"
msgstr "Synchronisations Status"
@@ -914,6 +948,10 @@ msgstr "Lokale Objekte gelöscht: %d."
msgid "Deleted remote items: %d."
msgstr "Remote Objekte gelöscht: %d."
#, fuzzy, javascript-format
msgid "Fetched items: %d/%d."
msgstr "Lokale Objekte erstellt: %d."
#, javascript-format
msgid "State: \"%s\"."
msgstr "Status: \"%s\"."
@@ -929,6 +967,13 @@ msgstr "Abgeschlossen: %s"
msgid "Synchronisation is already in progress. State: %s"
msgstr "Synchronisation ist bereits im Gange. Status: %s"
msgid "Encrypted"
msgstr ""
#, fuzzy
msgid "Encrypted items cannot be modified"
msgstr "Manche Objekte können nicht synchronisiert werden."
msgid "Conflicts"
msgstr "Konflikte"
@@ -1039,9 +1084,15 @@ msgstr "Ungültiger Optionswert: \"%s\". Mögliche Werte sind: %s."
msgid "Items that cannot be synchronised"
msgstr "Objekte können nicht synchronisiert werden"
#, javascript-format
msgid "\"%s\": \"%s\""
msgstr "\"%s\": \"%s\""
#, fuzzy, javascript-format
msgid "%s (%s): %s"
msgstr "%s %s (%s)"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
"target. In order to find these items, either search for the title or the ID "
"(which is displayed in brackets above)."
msgstr ""
msgid "Sync status (synced items / total items)"
msgstr "Synchronisationsstatus (synchronisierte Objekte / gesamte Objekte)"
@@ -1090,6 +1141,9 @@ msgstr "Log"
msgid "Export Debug Report"
msgstr "Fehlerbreicht exportieren"
msgid "Encryption Config"
msgstr ""
msgid "Configuration"
msgstr "Konfiguration"
@@ -1100,6 +1154,9 @@ msgstr "In Notizbuch verschieben..."
msgid "Move %d notes to notebook \"%s\"?"
msgstr "%d Notizen in das Notizbuch \"%s\" verschieben?"
msgid "Press to set the decryption password."
msgstr ""
msgid "Select date"
msgstr "Datum auswählen"
@@ -1109,6 +1166,25 @@ msgstr "Bestätigen"
msgid "Cancel synchronisation"
msgstr "Synchronisation abbrechen"
#, javascript-format
msgid "Master Key %s"
msgstr ""
#, fuzzy, javascript-format
msgid "Created: %s"
msgstr "Erstellt: %d."
#, fuzzy
msgid "Password:"
msgstr "Passwort"
msgid "Password cannot be empty"
msgstr ""
#, fuzzy
msgid "Enable"
msgstr "Deaktiviert"
#, javascript-format
msgid "The notebook could not be saved: %s"
msgstr "Dieses Notizbuch konnte nicht gespeichert werden: %s"
@@ -1172,6 +1248,15 @@ msgstr ""
msgid "Welcome"
msgstr "Willkommen"
#~ msgid "Note title:"
#~ msgstr "Notizen Titel:"
#~ msgid "To-do title:"
#~ msgstr "To-Do Titel:"
#~ msgid "\"%s\": \"%s\""
#~ msgstr "\"%s\": \"%s\""
#~ msgid "Delete notebook?"
#~ msgstr "Notizbuch löschen?"

View File

@@ -108,6 +108,9 @@ msgstr ""
msgid "The command \"%s\" is only available in GUI mode"
msgstr ""
msgid "Cannot change encrypted item"
msgstr ""
#, javascript-format
msgid "Missing required argument: %s"
msgstr ""
@@ -165,6 +168,35 @@ msgstr ""
msgid "Note is not a to-do: \"%s\""
msgstr ""
msgid ""
"Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, "
"`status` and `target-status`."
msgstr ""
msgid "Enter master password:"
msgstr ""
msgid "Operation cancelled"
msgstr ""
msgid ""
"Starting decryption... Please wait as it may take several minutes depending "
"on how much there is to decrypt."
msgstr ""
msgid "Completed decryption."
msgstr ""
msgid "Enabled"
msgstr ""
msgid "Disabled"
msgstr ""
#, javascript-format
msgid "Encryption is: %s"
msgstr ""
msgid "Edit note."
msgstr ""
@@ -488,6 +520,13 @@ msgid ""
"For example, to create a notebook press `mb`; to create a note press `mn`."
msgstr ""
msgid ""
"One or more items are currently encrypted and you may need to supply a "
"master password. To do so please type `e2ee decrypt`. If you have already "
"supplied the password, the encrypted items are being decrypted in the "
"background and will be available soon."
msgstr ""
msgid "File"
msgstr ""
@@ -530,7 +569,10 @@ msgstr ""
msgid "Synchronisation status"
msgstr ""
msgid "Options"
msgid "Encryption options"
msgstr ""
msgid "General Options"
msgstr ""
msgid "Help"
@@ -614,12 +656,6 @@ msgstr ""
msgid "Encryption is:"
msgstr ""
msgid "Enabled"
msgstr ""
msgid "Disabled"
msgstr ""
msgid "Back"
msgstr ""
@@ -631,15 +667,9 @@ msgstr ""
msgid "Please create a notebook first."
msgstr ""
msgid "Note title:"
msgstr ""
msgid "Please create a notebook first"
msgstr ""
msgid "To-do title:"
msgstr ""
msgid "Notebook title:"
msgstr ""
@@ -711,6 +741,9 @@ msgstr ""
msgid "Import"
msgstr ""
msgid "Options"
msgstr ""
msgid "Synchronisation Status"
msgstr ""
@@ -808,6 +841,10 @@ msgstr ""
msgid "Deleted remote items: %d."
msgstr ""
#, javascript-format
msgid "Fetched items: %d/%d."
msgstr ""
#, javascript-format
msgid "State: \"%s\"."
msgstr ""
@@ -823,6 +860,12 @@ msgstr ""
msgid "Synchronisation is already in progress. State: %s"
msgstr ""
msgid "Encrypted"
msgstr ""
msgid "Encrypted items cannot be modified"
msgstr ""
msgid "Conflicts"
msgstr ""
@@ -925,7 +968,13 @@ msgid "Items that cannot be synchronised"
msgstr ""
#, javascript-format
msgid "\"%s\": \"%s\""
msgid "%s (%s): %s"
msgstr ""
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
"target. In order to find these items, either search for the title or the ID "
"(which is displayed in brackets above)."
msgstr ""
msgid "Sync status (synced items / total items)"
@@ -973,6 +1022,9 @@ msgstr ""
msgid "Export Debug Report"
msgstr ""
msgid "Encryption Config"
msgstr ""
msgid "Configuration"
msgstr ""
@@ -983,6 +1035,9 @@ msgstr ""
msgid "Move %d notes to notebook \"%s\"?"
msgstr ""
msgid "Press to set the decryption password."
msgstr ""
msgid "Select date"
msgstr ""
@@ -992,6 +1047,23 @@ msgstr ""
msgid "Cancel synchronisation"
msgstr ""
#, javascript-format
msgid "Master Key %s"
msgstr ""
#, javascript-format
msgid "Created: %s"
msgstr ""
msgid "Password:"
msgstr ""
msgid "Password cannot be empty"
msgstr ""
msgid "Enable"
msgstr ""
#, javascript-format
msgid "The notebook could not be saved: %s"
msgstr ""

View File

@@ -110,6 +110,9 @@ msgstr "Comando inválido: \"%s\""
msgid "The command \"%s\" is only available in GUI mode"
msgstr "El comando \"%s\" unicamente disponible en modo GUI"
msgid "Cannot change encrypted item"
msgstr ""
#, javascript-format
msgid "Missing required argument: %s"
msgstr "Falta un argumento requerido: %s"
@@ -172,6 +175,36 @@ msgstr "Marca una tarea como hecha."
msgid "Note is not a to-do: \"%s\""
msgstr "Una nota no es una tarea: \"%s\""
msgid ""
"Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, "
"`status` and `target-status`."
msgstr ""
msgid "Enter master password:"
msgstr ""
msgid "Operation cancelled"
msgstr ""
msgid ""
"Starting decryption... Please wait as it may take several minutes depending "
"on how much there is to decrypt."
msgstr ""
msgid "Completed decryption."
msgstr ""
#, fuzzy
msgid "Enabled"
msgstr "Deshabilitado"
msgid "Disabled"
msgstr "Deshabilitado"
#, javascript-format
msgid "Encryption is: %s"
msgstr ""
msgid "Edit note."
msgstr "Editar una nota."
@@ -543,6 +576,13 @@ msgid ""
"For example, to create a notebook press `mb`; to create a note press `mn`."
msgstr ""
msgid ""
"One or more items are currently encrypted and you may need to supply a "
"master password. To do so please type `e2ee decrypt`. If you have already "
"supplied the password, the encrypted items are being decrypted in the "
"background and will be available soon."
msgstr ""
msgid "File"
msgstr "Archivo"
@@ -586,7 +626,11 @@ msgstr "Herramientas"
msgid "Synchronisation status"
msgstr "Sincronización de objetivo"
msgid "Options"
msgid "Encryption options"
msgstr ""
#, fuzzy
msgid "General Options"
msgstr "Opciones"
msgid "Help"
@@ -672,13 +716,6 @@ msgstr "Estatus"
msgid "Encryption is:"
msgstr ""
#, fuzzy
msgid "Enabled"
msgstr "Deshabilitado"
msgid "Disabled"
msgstr "Deshabilitado"
#, fuzzy
msgid "Back"
msgstr "Retroceder"
@@ -692,15 +729,9 @@ msgstr ""
msgid "Please create a notebook first."
msgstr "Por favor crea una libreta primero."
msgid "Note title:"
msgstr "Título de nota:"
msgid "Please create a notebook first"
msgstr "Por favor crea una libreta primero"
msgid "To-do title:"
msgstr "Títuto de lista de tareas:"
msgid "Notebook title:"
msgstr "Título de libreta:"
@@ -777,6 +808,9 @@ msgstr "Inicio de sesión de OneDrive"
msgid "Import"
msgstr "Importar"
msgid "Options"
msgstr "Opciones"
#, fuzzy
msgid "Synchronisation Status"
msgstr "Sincronización de objetivo"
@@ -887,6 +921,10 @@ msgstr "Artículos locales borrados: %d."
msgid "Deleted remote items: %d."
msgstr "Artículos remotos borrados: %d."
#, fuzzy, javascript-format
msgid "Fetched items: %d/%d."
msgstr "Artículos locales creados: %d."
#, javascript-format
msgid "State: \"%s\"."
msgstr "Estado: \"%s\"."
@@ -902,6 +940,13 @@ msgstr "Completado: %s"
msgid "Synchronisation is already in progress. State: %s"
msgstr "La sincronizacion ya esta en progreso. Estod: %s"
msgid "Encrypted"
msgstr ""
#, fuzzy
msgid "Encrypted items cannot be modified"
msgstr "No se puede inicializar sincronizador."
msgid "Conflicts"
msgstr "Conflictos"
@@ -1013,8 +1058,14 @@ msgstr "Valor inválido de opción: \"%s\". Los válores inválidos son: %s."
msgid "Items that cannot be synchronised"
msgstr ""
#, javascript-format
msgid "\"%s\": \"%s\""
#, fuzzy, javascript-format
msgid "%s (%s): %s"
msgstr "%s %s (%s)"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
"target. In order to find these items, either search for the title or the ID "
"(which is displayed in brackets above)."
msgstr ""
msgid "Sync status (synced items / total items)"
@@ -1067,6 +1118,9 @@ msgstr "Log"
msgid "Export Debug Report"
msgstr "Exportar reporte depuracion"
msgid "Encryption Config"
msgstr ""
msgid "Configuration"
msgstr "Configuracion"
@@ -1077,6 +1131,9 @@ msgstr "Mover a libreta...."
msgid "Move %d notes to notebook \"%s\"?"
msgstr "Mover %d notas a libreta \"%s\"?"
msgid "Press to set the decryption password."
msgstr ""
msgid "Select date"
msgstr "Seleccionar fecha"
@@ -1086,6 +1143,24 @@ msgstr "Confirmar"
msgid "Cancel synchronisation"
msgstr "Sincronizacion cancelada"
#, javascript-format
msgid "Master Key %s"
msgstr ""
#, fuzzy, javascript-format
msgid "Created: %s"
msgstr "Creado: %d."
msgid "Password:"
msgstr ""
msgid "Password cannot be empty"
msgstr ""
#, fuzzy
msgid "Enable"
msgstr "Deshabilitado"
#, javascript-format
msgid "The notebook could not be saved: %s"
msgstr "Esta libreta no pudo ser guardada: %s"
@@ -1150,6 +1225,12 @@ msgstr ""
msgid "Welcome"
msgstr "Bienvenido"
#~ msgid "Note title:"
#~ msgstr "Título de nota:"
#~ msgid "To-do title:"
#~ msgstr "Títuto de lista de tareas:"
#~ msgid "Delete notebook?"
#~ msgstr "Eliminar libreta?"

View File

@@ -111,6 +111,9 @@ msgstr "El comando no existe: %s"
msgid "The command \"%s\" is only available in GUI mode"
msgstr "El comando «%s» solamente está disponible en modo GUI"
msgid "Cannot change encrypted item"
msgstr ""
#, javascript-format
msgid "Missing required argument: %s"
msgstr "Falta un argumento requerido: %s"
@@ -173,6 +176,36 @@ msgstr "Marca una tarea como hecha."
msgid "Note is not a to-do: \"%s\""
msgstr "Una nota no es una tarea: \"%s\""
msgid ""
"Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, "
"`status` and `target-status`."
msgstr ""
msgid "Enter master password:"
msgstr ""
msgid "Operation cancelled"
msgstr ""
msgid ""
"Starting decryption... Please wait as it may take several minutes depending "
"on how much there is to decrypt."
msgstr ""
msgid "Completed decryption."
msgstr ""
#, fuzzy
msgid "Enabled"
msgstr "Deshabilitado"
msgid "Disabled"
msgstr "Deshabilitado"
#, javascript-format
msgid "Encryption is: %s"
msgstr ""
msgid "Edit note."
msgstr "Editar una nota."
@@ -558,6 +591,13 @@ msgstr ""
"Por ejemplo, para crear una libreta escriba «mb», para crear una nota "
"escriba «mn»."
msgid ""
"One or more items are currently encrypted and you may need to supply a "
"master password. To do so please type `e2ee decrypt`. If you have already "
"supplied the password, the encrypted items are being decrypted in the "
"background and will be available soon."
msgstr ""
msgid "File"
msgstr "Archivo"
@@ -600,7 +640,11 @@ msgstr "Herramientas"
msgid "Synchronisation status"
msgstr "Estado de la sincronización"
msgid "Options"
msgid "Encryption options"
msgstr ""
#, fuzzy
msgid "General Options"
msgstr "Opciones"
msgid "Help"
@@ -684,13 +728,6 @@ msgstr "Estado"
msgid "Encryption is:"
msgstr ""
#, fuzzy
msgid "Enabled"
msgstr "Deshabilitado"
msgid "Disabled"
msgstr "Deshabilitado"
msgid "Back"
msgstr "Atrás"
@@ -702,15 +739,9 @@ msgstr "Se creará la nueva libreta «%s» y se importará en ella el archivo «
msgid "Please create a notebook first."
msgstr "Cree primero una libreta."
msgid "Note title:"
msgstr "Título de la nota:"
msgid "Please create a notebook first"
msgstr "Por favor crea una libreta primero"
msgid "To-do title:"
msgstr "Títuto de lista de tareas:"
msgid "Notebook title:"
msgstr "Título de libreta:"
@@ -783,6 +814,9 @@ msgstr "Inicio de sesión de OneDrive"
msgid "Import"
msgstr "Importar"
msgid "Options"
msgstr "Opciones"
msgid "Synchronisation Status"
msgstr "Estado de la sincronización"
@@ -888,6 +922,10 @@ msgstr "Elementos locales borrados: %d."
msgid "Deleted remote items: %d."
msgstr "Elementos remotos borrados: %d."
#, fuzzy, javascript-format
msgid "Fetched items: %d/%d."
msgstr "Elementos locales creados: %d."
#, javascript-format
msgid "State: \"%s\"."
msgstr "Estado: «%s»."
@@ -903,6 +941,13 @@ msgstr "Completado: %s"
msgid "Synchronisation is already in progress. State: %s"
msgstr "La sincronización ya está en progreso. Estado: %s"
msgid "Encrypted"
msgstr ""
#, fuzzy
msgid "Encrypted items cannot be modified"
msgstr "No se han podido sincronizar algunos de los elementos."
msgid "Conflicts"
msgstr "Conflictos"
@@ -1011,9 +1056,15 @@ msgstr "Opción inválida: «%s». Los valores posibles son: %s."
msgid "Items that cannot be synchronised"
msgstr "Elementos que no se pueden sincronizar"
#, javascript-format
msgid "\"%s\": \"%s\""
msgstr "«%s»: «%s»"
#, fuzzy, javascript-format
msgid "%s (%s): %s"
msgstr "%s %s (%s)"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
"target. In order to find these items, either search for the title or the ID "
"(which is displayed in brackets above)."
msgstr ""
msgid "Sync status (synced items / total items)"
msgstr "Estado de sincronización (elementos sincronizados/elementos totales)"
@@ -1060,6 +1111,9 @@ msgstr "Log"
msgid "Export Debug Report"
msgstr "Exportar informe de depuración"
msgid "Encryption Config"
msgstr ""
msgid "Configuration"
msgstr "Configuración"
@@ -1070,6 +1124,9 @@ msgstr "Mover a la libreta..."
msgid "Move %d notes to notebook \"%s\"?"
msgstr "¿Desea mover %d notas a libreta «%s»?"
msgid "Press to set the decryption password."
msgstr ""
msgid "Select date"
msgstr "Seleccione fecha"
@@ -1079,6 +1136,24 @@ msgstr "Confirmar"
msgid "Cancel synchronisation"
msgstr "Cancelar sincronización"
#, javascript-format
msgid "Master Key %s"
msgstr ""
#, fuzzy, javascript-format
msgid "Created: %s"
msgstr "Creado: %d."
msgid "Password:"
msgstr ""
msgid "Password cannot be empty"
msgstr ""
#, fuzzy
msgid "Enable"
msgstr "Deshabilitado"
#, javascript-format
msgid "The notebook could not be saved: %s"
msgstr "No se ha podido guardar esta libreta: %s"
@@ -1140,6 +1215,15 @@ msgstr ""
msgid "Welcome"
msgstr "Bienvenido"
#~ msgid "Note title:"
#~ msgstr "Título de la nota:"
#~ msgid "To-do title:"
#~ msgstr "Títuto de lista de tareas:"
#~ msgid "\"%s\": \"%s\""
#~ msgstr "«%s»: «%s»"
#~ msgid "Delete notebook?"
#~ msgstr "Eliminar libreta?"

View File

@@ -100,15 +100,18 @@ msgstr "o"
msgid "Cancelling background synchronisation... Please wait."
msgstr "Annulation de la synchronisation... Veuillez patienter."
#, fuzzy, javascript-format
#, javascript-format
msgid "No such command: %s"
msgstr "Commande invalide : \"%s\""
msgstr "Commande invalide : %s"
#, javascript-format
msgid "The command \"%s\" is only available in GUI mode"
msgstr ""
"La commande \"%s\" est disponible uniquement en mode d'interface graphique"
msgid "Cannot change encrypted item"
msgstr "Un objet crypté ne peut pas être modifié"
#, javascript-format
msgid "Missing required argument: %s"
msgstr "Paramètre requis manquant : %s"
@@ -171,6 +174,39 @@ msgstr "Marquer la tâche comme complétée."
msgid "Note is not a to-do: \"%s\""
msgstr "La note n'est pas une tâche : \"%s\""
msgid ""
"Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, "
"`status` and `target-status`."
msgstr ""
"Gérer la configuration E2EE (Cryptage de bout à bout). Les commandes sont "
"`enable`, `disable`, `decrypt` et `status` et `target-status`."
msgid "Enter master password:"
msgstr "Entrer le mot de passe maître :"
msgid "Operation cancelled"
msgstr "Opération annulée"
msgid ""
"Starting decryption... Please wait as it may take several minutes depending "
"on how much there is to decrypt."
msgstr ""
"Démarrage du décryptage... Veuillez patienter car cela pourrait prendre "
"plusieurs minutes selon le nombre d'objets à décrypter."
msgid "Completed decryption."
msgstr "Décryptage complété."
msgid "Enabled"
msgstr "Activé"
msgid "Disabled"
msgstr "Désactivé"
#, javascript-format
msgid "Encryption is: %s"
msgstr "Le cryptage est : %s"
msgid "Edit note."
msgstr "Éditer la note."
@@ -221,11 +257,12 @@ msgstr "Affiche les informations d'utilisation."
msgid "Shortcuts are not available in CLI mode."
msgstr "Les raccourcis ne sont pas disponible en mode de ligne de commande."
#, fuzzy
msgid ""
"Type `help [command]` for more information about a command; or type `help "
"all` for the complete usage information."
msgstr "Tapez `help [command]` pour plus d'information sur une commande."
msgstr ""
"Tapez `help [command]` pour plus d'information sur une commande ; ou tapez "
"`help all` pour l'aide complète."
msgid "The possible commands are:"
msgstr "Les commandes possibles sont :"
@@ -379,6 +416,8 @@ msgstr "Supprimer le carnet sans demander la confirmation."
msgid "Delete notebook? All notes within this notebook will also be deleted."
msgstr ""
"Effacer le carnet ? Toutes les notes dans ce carnet seront également "
"effacées."
msgid "Deletes the notes matching <note-pattern>."
msgstr "Supprimer les notes correspondants à <note-pattern>."
@@ -396,13 +435,17 @@ msgstr "Supprimer la note ?"
msgid "Searches for the given <pattern> in all the notes."
msgstr "Chercher le motif <pattern> dans toutes les notes."
#, fuzzy, javascript-format
#, javascript-format
msgid ""
"Sets the property <name> of the given <note> to the given [value]. Possible "
"properties are:\n"
"\n"
"%s"
msgstr "Assigner la valeur [value] à la propriété <name> de la <note> donnée."
msgstr ""
"Assigner la valeur [value] à la propriété <name> de la <note> donnée. Les "
"valeurs possibles sont :\n"
"\n"
"%s"
msgid "Displays summary about the notes and notebooks."
msgstr "Afficher un résumé des notes et carnets."
@@ -538,6 +581,24 @@ msgid ""
"\n"
"For example, to create a notebook press `mb`; to create a note press `mn`."
msgstr ""
"Bienvenue dans Joplin!\n"
"\n"
"Tapez `:help shortcuts` pour la liste des raccourcis claviers, ou simplement "
"`:help` pour une vue d'ensemble.\n"
"\n"
"Par exemple, pour créer un carnet, pressez `mb` ; pour créer une note "
"pressed `mn`."
msgid ""
"One or more items are currently encrypted and you may need to supply a "
"master password. To do so please type `e2ee decrypt`. If you have already "
"supplied the password, the encrypted items are being decrypted in the "
"background and will be available soon."
msgstr ""
"Au moins un objet est actuellement crypté et il se peut que vous deviez "
"fournir votre mot de passe maître. Pour se faire, veuillez taper `e2ee "
"decrypt`. Si vous avez déjà fourni ce mot de passe, les objets cryptés vont "
"être décrypté en tâche de fond et seront disponible prochainement."
msgid "File"
msgstr "Fichier"
@@ -578,12 +639,14 @@ msgstr "Chercher dans toutes les notes"
msgid "Tools"
msgstr "Outils"
#, fuzzy
msgid "Synchronisation status"
msgstr "Cible de la synchronisation"
msgstr "État de la synchronisation"
msgid "Options"
msgstr "Options"
msgid "Encryption options"
msgstr "Options de cryptage"
msgid "General Options"
msgstr "Options générales"
msgid "Help"
msgstr "Aide"
@@ -606,16 +669,19 @@ msgstr "Annulation"
#, javascript-format
msgid "Notes and settings are stored in: %s"
msgstr ""
msgstr "Les notes et paramètres se trouve dans : %s"
msgid "Save"
msgstr ""
msgstr "Enregistrer"
msgid ""
"Disabling encryption means *all* your notes and attachments are going to be "
"re-synchronised and sent unencrypted to the sync target. Do you wish to "
"continue?"
msgstr ""
"Désactiver le cryptage signifie que *toutes* les notes et fichiers vont être "
"re-synchronisés et envoyés décryptés sur la cible de la synchronisation. "
"Souhaitez vous continuer ?"
msgid ""
"Enabling encryption means *all* your notes and attachments are going to be "
@@ -623,57 +689,57 @@ msgid ""
"password as, for security purposes, this will be the *only* way to decrypt "
"the data! To enable encryption, please enter your password below."
msgstr ""
"Activer le cryptage signifie que *toutes* les notes et fichiers vont être re-"
"synchronisés et envoyés cryptés vers la cible de la synchronisation. Ne "
"perdez pas votre mot de passe car, pour des raisons de sécurité, ce sera la "
"*seule* façon de décrypter les données ! Pour activer le cryptage, veuillez "
"entrer votre mot de passe ci-dessous."
msgid "Disable encryption"
msgstr ""
msgstr "Désactiver le cryptage"
msgid "Enable encryption"
msgstr ""
msgstr "Activer le cryptage"
msgid "Master Keys"
msgstr ""
msgstr "Clefs maître"
msgid "Active"
msgstr ""
msgstr "Actif"
msgid "ID"
msgstr ""
msgstr "ID"
msgid "Source"
msgstr ""
msgstr "Source"
#, fuzzy
msgid "Created"
msgstr "Créés : %d."
msgstr "Créé"
#, fuzzy
msgid "Updated"
msgstr "Mis à jour : %d."
msgstr "Mis à jour"
msgid "Password"
msgstr ""
msgstr "Mot de passe"
msgid "Password OK"
msgstr ""
msgstr "Mot de passe OK"
msgid ""
"Note: Only one master key is going to be used for encryption (the one marked "
"as \"active\"). Any of the keys might be used for decryption, depending on "
"how the notes or notebooks were originally encrypted."
msgstr ""
"Note : seule une clef maître va être utilisée pour le cryptage (celle "
"marquée comme \"actif\" ci-dessus). N'importe quel clef peut-être utilisée "
"pour le décryptage, selon la façon dont les notes ou carnets étaient cryptés "
"à l'origine."
msgid "Status"
msgstr "État"
msgid "Encryption is:"
msgstr ""
#, fuzzy
msgid "Enabled"
msgstr "Désactivé"
msgid "Disabled"
msgstr "Désactivé"
msgstr "Le cryptage est :"
msgid "Back"
msgstr "Retour"
@@ -688,15 +754,9 @@ msgstr ""
msgid "Please create a notebook first."
msgstr "Veuillez d'abord sélectionner un carnet."
msgid "Note title:"
msgstr "Titre de la note :"
msgid "Please create a notebook first"
msgstr "Veuillez d'abord créer un carnet d'abord"
msgid "To-do title:"
msgstr "Titre de la tâche :"
msgid "Notebook title:"
msgstr "Titre du carnet :"
@@ -709,26 +769,23 @@ msgstr "Séparez chaque étiquette par une virgule."
msgid "Rename notebook:"
msgstr "Renommer le carnet :"
#, fuzzy
msgid "Set alarm:"
msgstr "Définir ou modifier alarme"
msgstr "Définir ou modifier alarme :"
msgid "Layout"
msgstr "Disposition"
#, fuzzy
msgid "Some items cannot be synchronised."
msgstr "Impossible d'initialiser la synchronisation."
msgstr "Certains objets ne peuvent être synchronisés."
msgid "View them now"
msgstr ""
msgstr "Les voir maintenant"
#, fuzzy
msgid "Some items cannot be decrypted."
msgstr "Impossible d'initialiser la synchronisation."
msgstr "Certains objets ne peuvent être décryptés."
msgid "Set the password"
msgstr ""
msgstr "Définir le mot de passe"
msgid "Add or remove tags"
msgstr "Gérer les étiquettes"
@@ -746,12 +803,11 @@ msgid "No notes in here. Create one by clicking on \"New note\"."
msgstr ""
"Pas de notes ici. Créez-en une en pressant le bouton \"Nouvelle note\"."
#, fuzzy
msgid ""
"There is currently no notebook. Create one by clicking on \"New notebook\"."
msgstr ""
"Il n'y a pour l'instant aucun carnet. Créez-en un en cliquant sur le bouton "
"(+)"
"Il n'y a pour l'instant aucun carnet. Créez-en un en cliquant sur \"Nouveau "
"carnet\"."
#, javascript-format
msgid "Unsupported link or message: %s"
@@ -760,7 +816,6 @@ msgstr "Lien ou message non géré : %s"
msgid "Attach file"
msgstr "Attacher un fichier"
#, fuzzy
msgid "Set alarm"
msgstr "Définir ou modifier alarme"
@@ -776,12 +831,14 @@ msgstr "Connexion OneDrive"
msgid "Import"
msgstr "Importer"
#, fuzzy
msgid "Options"
msgstr "Options"
msgid "Synchronisation Status"
msgstr "Cible de la synchronisation"
msgstr "État de la synchronisation"
msgid "Encryption Options"
msgstr ""
msgstr "Options de cryptage"
msgid "Remove this tag from all the notes?"
msgstr "Enlever cette étiquette de toutes les notes ?"
@@ -804,9 +861,9 @@ msgstr "Étiquettes"
msgid "Searches"
msgstr "Recherches"
#, fuzzy
msgid "Please select where the sync status should be exported to"
msgstr "Veuillez d'abord sélectionner un carnet."
msgstr ""
"Veuillez sélectionner un répertoire ou exporter l'état de la synchronisation"
#, javascript-format
msgid "Usage: %s"
@@ -848,6 +905,12 @@ msgid ""
"\n"
"Please consider using a regular OneDrive account."
msgstr ""
"Impossible de synchroniser avec OneDrive.\n"
"\n"
"Cette erreur se produit lors de l'utilisation de OneDrive for Business, qui "
"malheureusement n'est pas compatible.\n"
"\n"
"Veuillez utiliser à la place un compte OneDrive normal."
#, javascript-format
msgid "Cannot access %s"
@@ -877,6 +940,10 @@ msgstr "Objets supprimés localement : %d."
msgid "Deleted remote items: %d."
msgstr "Objets distants supprimés : %d."
#, javascript-format
msgid "Fetched items: %d/%d."
msgstr "Téléchargés : %d/%d."
#, javascript-format
msgid "State: \"%s\"."
msgstr "État : \"%s\"."
@@ -892,6 +959,12 @@ msgstr "Terminé : %s"
msgid "Synchronisation is already in progress. State: %s"
msgstr "La synchronisation est déjà en cours. État : %s"
msgid "Encrypted"
msgstr "Crypté"
msgid "Encrypted items cannot be modified"
msgstr "Les objets cryptés ne peuvent être modifiés"
msgid "Conflicts"
msgstr "Conflits"
@@ -983,7 +1056,7 @@ msgstr ""
"fichier, veuillez spécifier le répertoire avec `sync.2.path`."
msgid "Directory to synchronise with (absolute path)"
msgstr ""
msgstr "Répertoire avec lequel synchroniser (chemin absolu)"
msgid ""
"The path to synchronise with when file system synchronisation is enabled. "
@@ -997,11 +1070,20 @@ msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Option invalide: \"%s\". Les valeurs possibles sont : %s."
msgid "Items that cannot be synchronised"
msgstr ""
msgstr "Objets qui ne peuvent pas être synchronisés"
#, javascript-format
msgid "\"%s\": \"%s\""
msgid "%s (%s): %s"
msgstr "%s (%s) : %s"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
"target. In order to find these items, either search for the title or the ID "
"(which is displayed in brackets above)."
msgstr ""
"Ces objets resteront sur l'appareil mais ne seront pas envoyé sur la cible "
"de la synchronisation. Pour trouver ces objets, faite une recherche sur le "
"titre ou l'identifiant de l'objet (affiché ci-dessus entre parenthèses)."
msgid "Sync status (synced items / total items)"
msgstr "Status de la synchronisation (objets synchro. / total)"
@@ -1050,6 +1132,9 @@ msgstr "Journal"
msgid "Export Debug Report"
msgstr "Exporter rapport de débogage"
msgid "Encryption Config"
msgstr "Config cryptage"
msgid "Configuration"
msgstr "Configuration"
@@ -1060,6 +1145,9 @@ msgstr "Déplacer la note vers carnet..."
msgid "Move %d notes to notebook \"%s\"?"
msgstr "Déplacer %d notes vers carnet \"%s\" ?"
msgid "Press to set the decryption password."
msgstr "Définir mot de passe de synchronisation."
msgid "Select date"
msgstr "Sélectionner date"
@@ -1069,6 +1157,23 @@ msgstr "Confirmer"
msgid "Cancel synchronisation"
msgstr "Annuler synchronisation"
#, javascript-format
msgid "Master Key %s"
msgstr "Clef maître %s"
#, javascript-format
msgid "Created: %s"
msgstr "Créé : %s"
msgid "Password:"
msgstr "Mot de passe :"
msgid "Password cannot be empty"
msgstr "Mot de passe ne peut être vide"
msgid "Enable"
msgstr "Activer"
#, javascript-format
msgid "The notebook could not be saved: %s"
msgstr "Ce carnet n'a pas pu être sauvegardé : %s"
@@ -1105,10 +1210,10 @@ msgid "Hide metadata"
msgstr "Cacher les métadonnées"
msgid "Show metadata"
msgstr "Afficher les métadonnées"
msgstr "Voir métadonnées"
msgid "View on map"
msgstr "Voir emplacement sur carte"
msgstr "Voir sur carte"
msgid "Delete notebook"
msgstr "Supprimer le carnet"
@@ -1131,6 +1236,12 @@ msgstr ""
msgid "Welcome"
msgstr "Bienvenue"
#~ msgid "Note title:"
#~ msgstr "Titre de la note :"
#~ msgid "To-do title:"
#~ msgstr "Titre de la tâche :"
#~ msgid "Delete notebook?"
#~ msgstr "Supprimer le carnet ?"
@@ -1205,9 +1316,6 @@ msgstr "Bienvenue"
#~ msgid "Delete a note"
#~ msgstr "Supprimer la note"
#~ msgid "%s (%s)"
#~ msgstr "%s (%s)"
#, fuzzy
#~ msgid "Show/Hide the console"
#~ msgstr "Quitter le logiciel."

View File

@@ -116,6 +116,9 @@ msgstr "Ne postoji naredba: %s"
msgid "The command \"%s\" is only available in GUI mode"
msgstr "Naredba \"%s\" postoji samo u inačici s grafičkim sučeljem"
msgid "Cannot change encrypted item"
msgstr ""
#, javascript-format
msgid "Missing required argument: %s"
msgstr "Nedostaje obavezni argument: %s"
@@ -180,6 +183,36 @@ msgstr "Označava zadatak završenim."
msgid "Note is not a to-do: \"%s\""
msgstr "Bilješka nije zadatak: \"%s\""
msgid ""
"Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, "
"`status` and `target-status`."
msgstr ""
msgid "Enter master password:"
msgstr ""
msgid "Operation cancelled"
msgstr ""
msgid ""
"Starting decryption... Please wait as it may take several minutes depending "
"on how much there is to decrypt."
msgstr ""
msgid "Completed decryption."
msgstr ""
#, fuzzy
msgid "Enabled"
msgstr "Onemogućeno"
msgid "Disabled"
msgstr "Onemogućeno"
#, javascript-format
msgid "Encryption is: %s"
msgstr ""
msgid "Edit note."
msgstr "Uredi bilješku."
@@ -566,6 +599,13 @@ msgstr ""
"\n"
"For example, to create a notebook press `mb`; to create a note press `mn`."
msgid ""
"One or more items are currently encrypted and you may need to supply a "
"master password. To do so please type `e2ee decrypt`. If you have already "
"supplied the password, the encrypted items are being decrypted in the "
"background and will be available soon."
msgstr ""
msgid "File"
msgstr "Datoteka"
@@ -608,7 +648,11 @@ msgstr "Alati"
msgid "Synchronisation status"
msgstr "Status sinkronizacije"
msgid "Options"
msgid "Encryption options"
msgstr ""
#, fuzzy
msgid "General Options"
msgstr "Opcije"
msgid "Help"
@@ -692,13 +736,6 @@ msgstr "Status"
msgid "Encryption is:"
msgstr ""
#, fuzzy
msgid "Enabled"
msgstr "Onemogućeno"
msgid "Disabled"
msgstr "Onemogućeno"
msgid "Back"
msgstr "Natrag"
@@ -712,15 +749,9 @@ msgstr ""
msgid "Please create a notebook first."
msgstr "Prvo stvori bilježnicu."
msgid "Note title:"
msgstr "Naslov bilješke:"
msgid "Please create a notebook first"
msgstr "Prvo stvori bilježnicu"
msgid "To-do title:"
msgstr "Naslov zadatka:"
msgid "Notebook title:"
msgstr "Naslov bilježnice:"
@@ -793,6 +824,9 @@ msgstr "OneDrive Login"
msgid "Import"
msgstr "Uvoz"
msgid "Options"
msgstr "Opcije"
msgid "Synchronisation Status"
msgstr "Status Sinkronizacije"
@@ -896,6 +930,10 @@ msgstr "Obrisane lokalne stavke: %d."
msgid "Deleted remote items: %d."
msgstr "Obrisane udaljene stavke: %d."
#, fuzzy, javascript-format
msgid "Fetched items: %d/%d."
msgstr "Stvorene lokalne stavke: %d."
#, javascript-format
msgid "State: \"%s\"."
msgstr "Stanje: \"%s\"."
@@ -911,6 +949,13 @@ msgstr "Dovršeno: %s"
msgid "Synchronisation is already in progress. State: %s"
msgstr "Sinkronizacija je već u toku. Stanje: %s"
msgid "Encrypted"
msgstr ""
#, fuzzy
msgid "Encrypted items cannot be modified"
msgstr "Neke stavke se ne mogu sinkronizirati."
msgid "Conflicts"
msgstr "Sukobi"
@@ -1018,9 +1063,15 @@ msgstr "Nevažeća vrijednost: \"%s\". Moguće vrijednosti su: %s."
msgid "Items that cannot be synchronised"
msgstr "Stavke koje se ne mogu sinkronizirati"
#, javascript-format
msgid "\"%s\": \"%s\""
msgstr "\"%s\": \"%s\""
#, fuzzy, javascript-format
msgid "%s (%s): %s"
msgstr "%s %s (%s)"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
"target. In order to find these items, either search for the title or the ID "
"(which is displayed in brackets above)."
msgstr ""
msgid "Sync status (synced items / total items)"
msgstr "Status (sinkronizirane stavke / ukupni broj stavki)"
@@ -1067,6 +1118,9 @@ msgstr "Log"
msgid "Export Debug Report"
msgstr "Izvezi Debug izvještaj"
msgid "Encryption Config"
msgstr ""
msgid "Configuration"
msgstr "Konfiguracija"
@@ -1077,6 +1131,9 @@ msgstr "Premjesti u bilježnicu..."
msgid "Move %d notes to notebook \"%s\"?"
msgstr "Premjesti %d bilješke u bilježnicu \"%s\"?"
msgid "Press to set the decryption password."
msgstr ""
msgid "Select date"
msgstr "Odaberi datum"
@@ -1086,6 +1143,24 @@ msgstr "Potvrdi"
msgid "Cancel synchronisation"
msgstr "Prekini sinkronizaciju"
#, javascript-format
msgid "Master Key %s"
msgstr ""
#, fuzzy, javascript-format
msgid "Created: %s"
msgstr "Stvoreno: %d."
msgid "Password:"
msgstr ""
msgid "Password cannot be empty"
msgstr ""
#, fuzzy
msgid "Enable"
msgstr "Onemogućeno"
#, javascript-format
msgid "The notebook could not be saved: %s"
msgstr "Bilježnicu nije moguće snimiti: %s"
@@ -1145,3 +1220,12 @@ msgstr "Trenutno nemaš nijednu bilježnicu. Stvori novu klikom na (+) gumb."
msgid "Welcome"
msgstr "Dobro došli"
#~ msgid "Note title:"
#~ msgstr "Naslov bilješke:"
#~ msgid "To-do title:"
#~ msgstr "Naslov zadatka:"
#~ msgid "\"%s\": \"%s\""
#~ msgstr "\"%s\": \"%s\""

View File

@@ -112,6 +112,9 @@ msgstr "Nessun comando: %s"
msgid "The command \"%s\" is only available in GUI mode"
msgstr "Il comando \"%s\" è disponibile solo nella modalità grafica"
msgid "Cannot change encrypted item"
msgstr ""
#, javascript-format
msgid "Missing required argument: %s"
msgstr "Argomento richiesto mancante: %s"
@@ -174,6 +177,36 @@ msgstr "Segna un'attività come completata."
msgid "Note is not a to-do: \"%s\""
msgstr "La nota non è un'attività: \"%s\""
msgid ""
"Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, "
"`status` and `target-status`."
msgstr ""
msgid "Enter master password:"
msgstr ""
msgid "Operation cancelled"
msgstr ""
msgid ""
"Starting decryption... Please wait as it may take several minutes depending "
"on how much there is to decrypt."
msgstr ""
msgid "Completed decryption."
msgstr ""
#, fuzzy
msgid "Enabled"
msgstr "Disabilitato"
msgid "Disabled"
msgstr "Disabilitato"
#, javascript-format
msgid "Encryption is: %s"
msgstr ""
msgid "Edit note."
msgstr "Modifica nota."
@@ -544,6 +577,13 @@ msgid ""
"For example, to create a notebook press `mb`; to create a note press `mn`."
msgstr ""
msgid ""
"One or more items are currently encrypted and you may need to supply a "
"master password. To do so please type `e2ee decrypt`. If you have already "
"supplied the password, the encrypted items are being decrypted in the "
"background and will be available soon."
msgstr ""
msgid "File"
msgstr "File"
@@ -586,7 +626,11 @@ msgstr "Strumenti"
msgid "Synchronisation status"
msgstr "Stato di sincronizzazione"
msgid "Options"
msgid "Encryption options"
msgstr ""
#, fuzzy
msgid "General Options"
msgstr "Opzioni"
msgid "Help"
@@ -672,13 +716,6 @@ msgstr "Stato"
msgid "Encryption is:"
msgstr ""
#, fuzzy
msgid "Enabled"
msgstr "Disabilitato"
msgid "Disabled"
msgstr "Disabilitato"
msgid "Back"
msgstr "Indietro"
@@ -690,15 +727,9 @@ msgstr "Il nuovo blocco note \"%s\" verrà creato e \"%s\" vi verrà importato"
msgid "Please create a notebook first."
msgstr "Per favore prima crea un blocco note."
msgid "Note title:"
msgstr "Titolo della Nota:"
msgid "Please create a notebook first"
msgstr "Per favore prima crea un blocco note"
msgid "To-do title:"
msgstr "Titolo dell'attività:"
msgid "Notebook title:"
msgstr "Titolo del blocco note:"
@@ -772,6 +803,9 @@ msgstr "Login OneDrive"
msgid "Import"
msgstr "Importa"
msgid "Options"
msgstr "Opzioni"
msgid "Synchronisation Status"
msgstr "Stato della Sincronizzazione"
@@ -878,6 +912,10 @@ msgstr "Elementi locali eliminati: %d."
msgid "Deleted remote items: %d."
msgstr "Elementi remoti eliminati: %d."
#, fuzzy, javascript-format
msgid "Fetched items: %d/%d."
msgstr "Elementi locali creati: %d."
#, javascript-format
msgid "State: \"%s\"."
msgstr "Stato: \"%s\"."
@@ -893,6 +931,13 @@ msgstr "Completata: %s"
msgid "Synchronisation is already in progress. State: %s"
msgstr "La sincronizzazione è già in corso. Stato: %s"
msgid "Encrypted"
msgstr ""
#, fuzzy
msgid "Encrypted items cannot be modified"
msgstr "Alcuni elementi non possono essere sincronizzati."
msgid "Conflicts"
msgstr "Conflitti"
@@ -1001,9 +1046,15 @@ msgstr "Oprione non valida: \"%s\". I valori possibili sono: %s."
msgid "Items that cannot be synchronised"
msgstr "Elementi che non possono essere sincronizzati"
#, javascript-format
msgid "\"%s\": \"%s\""
msgstr "\"%s\": \"%s\""
#, fuzzy, javascript-format
msgid "%s (%s): %s"
msgstr "%s %s (%s)"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
"target. In order to find these items, either search for the title or the ID "
"(which is displayed in brackets above)."
msgstr ""
msgid "Sync status (synced items / total items)"
msgstr "Stato di sincronizzazione (Elementi sincronizzati / Elementi totali)"
@@ -1050,6 +1101,9 @@ msgstr "Log"
msgid "Export Debug Report"
msgstr "Esporta il Report di Debug"
msgid "Encryption Config"
msgstr ""
msgid "Configuration"
msgstr "Configurazione"
@@ -1060,6 +1114,9 @@ msgstr "Sposta sul blocco note..."
msgid "Move %d notes to notebook \"%s\"?"
msgstr "Spostare le note %d sul blocco note \"%s\"?"
msgid "Press to set the decryption password."
msgstr ""
msgid "Select date"
msgstr "Seleziona la data"
@@ -1069,6 +1126,24 @@ msgstr "Conferma"
msgid "Cancel synchronisation"
msgstr "Cancella la sincronizzazione"
#, javascript-format
msgid "Master Key %s"
msgstr ""
#, fuzzy, javascript-format
msgid "Created: %s"
msgstr "Creato: %d."
msgid "Password:"
msgstr ""
msgid "Password cannot be empty"
msgstr ""
#, fuzzy
msgid "Enable"
msgstr "Disabilitato"
#, javascript-format
msgid "The notebook could not be saved: %s"
msgstr "Il blocco note non può essere salvato: %s"
@@ -1131,6 +1206,15 @@ msgstr ""
msgid "Welcome"
msgstr "Benvenuto"
#~ msgid "Note title:"
#~ msgstr "Titolo della Nota:"
#~ msgid "To-do title:"
#~ msgstr "Titolo dell'attività:"
#~ msgid "\"%s\": \"%s\""
#~ msgstr "\"%s\": \"%s\""
#~ msgid "Delete notebook?"
#~ msgstr "Eliminare il blocco note?"

View File

@@ -110,6 +110,9 @@ msgstr "コマンドが違います:%s"
msgid "The command \"%s\" is only available in GUI mode"
msgstr "コマンド \"%s\"は、GUIのみで有効です。"
msgid "Cannot change encrypted item"
msgstr ""
#, javascript-format
msgid "Missing required argument: %s"
msgstr "引数が足りません:%s"
@@ -171,6 +174,36 @@ msgstr "ToDoを完了として"
msgid "Note is not a to-do: \"%s\""
msgstr "ノートはToDoリストではありません:\"%s\""
msgid ""
"Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, "
"`status` and `target-status`."
msgstr ""
msgid "Enter master password:"
msgstr ""
msgid "Operation cancelled"
msgstr ""
msgid ""
"Starting decryption... Please wait as it may take several minutes depending "
"on how much there is to decrypt."
msgstr ""
msgid "Completed decryption."
msgstr ""
#, fuzzy
msgid "Enabled"
msgstr "無効"
msgid "Disabled"
msgstr "無効"
#, javascript-format
msgid "Encryption is: %s"
msgstr ""
msgid "Edit note."
msgstr "ノートを編集する。"
@@ -543,6 +576,13 @@ msgstr ""
"例えば、ノートブックの作成には`mb`で出来、ノートの作成は`mn`で行うことが出来"
"ます。"
msgid ""
"One or more items are currently encrypted and you may need to supply a "
"master password. To do so please type `e2ee decrypt`. If you have already "
"supplied the password, the encrypted items are being decrypted in the "
"background and will be available soon."
msgstr ""
msgid "File"
msgstr "ファイル"
@@ -585,7 +625,11 @@ msgstr "ツール"
msgid "Synchronisation status"
msgstr "同期状況"
msgid "Options"
msgid "Encryption options"
msgstr ""
#, fuzzy
msgid "General Options"
msgstr "オプション"
msgid "Help"
@@ -673,13 +717,6 @@ msgstr "状態"
msgid "Encryption is:"
msgstr ""
#, fuzzy
msgid "Enabled"
msgstr "無効"
msgid "Disabled"
msgstr "無効"
msgid "Back"
msgstr "戻る"
@@ -693,15 +730,9 @@ msgstr ""
msgid "Please create a notebook first."
msgstr "ますはノートブックを作成して下さい。"
msgid "Note title:"
msgstr "ノートの題名:"
msgid "Please create a notebook first"
msgstr "ますはノートブックを作成して下さい。"
msgid "To-do title:"
msgstr "ToDoの題名:"
msgid "Notebook title:"
msgstr "ノートブックの題名:"
@@ -774,6 +805,9 @@ msgstr "OneDriveログイン"
msgid "Import"
msgstr "インポート"
msgid "Options"
msgstr "オプション"
msgid "Synchronisation Status"
msgstr "同期状況"
@@ -879,6 +913,10 @@ msgstr "ローカルアイテムの削除: %d."
msgid "Deleted remote items: %d."
msgstr "リモートアイテムの削除: %d."
#, fuzzy, javascript-format
msgid "Fetched items: %d/%d."
msgstr "ローカルアイテムの作成: %d."
#, javascript-format
msgid "State: \"%s\"."
msgstr "状態: \"%s\"。"
@@ -894,6 +932,13 @@ msgstr "完了: %s"
msgid "Synchronisation is already in progress. State: %s"
msgstr "同期作業はすでに実行中です。状態: %s"
msgid "Encrypted"
msgstr ""
#, fuzzy
msgid "Encrypted items cannot be modified"
msgstr "いくつかの項目は同期されませんでした。"
msgid "Conflicts"
msgstr "衝突"
@@ -1004,7 +1049,13 @@ msgid "Items that cannot be synchronised"
msgstr "同期が出来なかったアイテム"
#, javascript-format
msgid "\"%s\": \"%s\""
msgid "%s (%s): %s"
msgstr ""
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
"target. In order to find these items, either search for the title or the ID "
"(which is displayed in brackets above)."
msgstr ""
msgid "Sync status (synced items / total items)"
@@ -1052,6 +1103,9 @@ msgstr "ログ"
msgid "Export Debug Report"
msgstr "デバッグレポートの出力"
msgid "Encryption Config"
msgstr ""
msgid "Configuration"
msgstr "設定"
@@ -1062,6 +1116,9 @@ msgstr "ノートブックへ移動..."
msgid "Move %d notes to notebook \"%s\"?"
msgstr "%d個のノートを\"%s\"に移動しますか?"
msgid "Press to set the decryption password."
msgstr ""
msgid "Select date"
msgstr "日付の選択"
@@ -1071,6 +1128,24 @@ msgstr "確認"
msgid "Cancel synchronisation"
msgstr "同期の中止"
#, javascript-format
msgid "Master Key %s"
msgstr ""
#, fuzzy, javascript-format
msgid "Created: %s"
msgstr "作成しました:%d"
msgid "Password:"
msgstr ""
msgid "Password cannot be empty"
msgstr ""
#, fuzzy
msgid "Enable"
msgstr "無効"
#, javascript-format
msgid "The notebook could not be saved: %s"
msgstr "ノートブックは保存できませんでした:%s"
@@ -1132,3 +1207,9 @@ msgstr ""
msgid "Welcome"
msgstr "ようこそ"
#~ msgid "Note title:"
#~ msgstr "ノートの題名:"
#~ msgid "To-do title:"
#~ msgstr "ToDoの題名:"

View File

@@ -108,6 +108,9 @@ msgstr ""
msgid "The command \"%s\" is only available in GUI mode"
msgstr ""
msgid "Cannot change encrypted item"
msgstr ""
#, javascript-format
msgid "Missing required argument: %s"
msgstr ""
@@ -165,6 +168,35 @@ msgstr ""
msgid "Note is not a to-do: \"%s\""
msgstr ""
msgid ""
"Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, "
"`status` and `target-status`."
msgstr ""
msgid "Enter master password:"
msgstr ""
msgid "Operation cancelled"
msgstr ""
msgid ""
"Starting decryption... Please wait as it may take several minutes depending "
"on how much there is to decrypt."
msgstr ""
msgid "Completed decryption."
msgstr ""
msgid "Enabled"
msgstr ""
msgid "Disabled"
msgstr ""
#, javascript-format
msgid "Encryption is: %s"
msgstr ""
msgid "Edit note."
msgstr ""
@@ -488,6 +520,13 @@ msgid ""
"For example, to create a notebook press `mb`; to create a note press `mn`."
msgstr ""
msgid ""
"One or more items are currently encrypted and you may need to supply a "
"master password. To do so please type `e2ee decrypt`. If you have already "
"supplied the password, the encrypted items are being decrypted in the "
"background and will be available soon."
msgstr ""
msgid "File"
msgstr ""
@@ -530,7 +569,10 @@ msgstr ""
msgid "Synchronisation status"
msgstr ""
msgid "Options"
msgid "Encryption options"
msgstr ""
msgid "General Options"
msgstr ""
msgid "Help"
@@ -614,12 +656,6 @@ msgstr ""
msgid "Encryption is:"
msgstr ""
msgid "Enabled"
msgstr ""
msgid "Disabled"
msgstr ""
msgid "Back"
msgstr ""
@@ -631,15 +667,9 @@ msgstr ""
msgid "Please create a notebook first."
msgstr ""
msgid "Note title:"
msgstr ""
msgid "Please create a notebook first"
msgstr ""
msgid "To-do title:"
msgstr ""
msgid "Notebook title:"
msgstr ""
@@ -711,6 +741,9 @@ msgstr ""
msgid "Import"
msgstr ""
msgid "Options"
msgstr ""
msgid "Synchronisation Status"
msgstr ""
@@ -808,6 +841,10 @@ msgstr ""
msgid "Deleted remote items: %d."
msgstr ""
#, javascript-format
msgid "Fetched items: %d/%d."
msgstr ""
#, javascript-format
msgid "State: \"%s\"."
msgstr ""
@@ -823,6 +860,12 @@ msgstr ""
msgid "Synchronisation is already in progress. State: %s"
msgstr ""
msgid "Encrypted"
msgstr ""
msgid "Encrypted items cannot be modified"
msgstr ""
msgid "Conflicts"
msgstr ""
@@ -925,7 +968,13 @@ msgid "Items that cannot be synchronised"
msgstr ""
#, javascript-format
msgid "\"%s\": \"%s\""
msgid "%s (%s): %s"
msgstr ""
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
"target. In order to find these items, either search for the title or the ID "
"(which is displayed in brackets above)."
msgstr ""
msgid "Sync status (synced items / total items)"
@@ -973,6 +1022,9 @@ msgstr ""
msgid "Export Debug Report"
msgstr ""
msgid "Encryption Config"
msgstr ""
msgid "Configuration"
msgstr ""
@@ -983,6 +1035,9 @@ msgstr ""
msgid "Move %d notes to notebook \"%s\"?"
msgstr ""
msgid "Press to set the decryption password."
msgstr ""
msgid "Select date"
msgstr ""
@@ -992,6 +1047,23 @@ msgstr ""
msgid "Cancel synchronisation"
msgstr ""
#, javascript-format
msgid "Master Key %s"
msgstr ""
#, javascript-format
msgid "Created: %s"
msgstr ""
msgid "Password:"
msgstr ""
msgid "Password cannot be empty"
msgstr ""
msgid "Enable"
msgstr ""
#, javascript-format
msgid "The notebook could not be saved: %s"
msgstr ""

View File

@@ -109,6 +109,9 @@ msgstr "Comando inválido: \"%s\""
msgid "The command \"%s\" is only available in GUI mode"
msgstr "O comando \"%s\" está disponível somente em modo gráfico"
msgid "Cannot change encrypted item"
msgstr ""
#, javascript-format
msgid "Missing required argument: %s"
msgstr "Argumento requerido faltando: %s"
@@ -171,6 +174,36 @@ msgstr "Marca uma tarefa como feita."
msgid "Note is not a to-do: \"%s\""
msgstr "Nota não é uma tarefa: \"%s\""
msgid ""
"Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, "
"`status` and `target-status`."
msgstr ""
msgid "Enter master password:"
msgstr ""
msgid "Operation cancelled"
msgstr ""
msgid ""
"Starting decryption... Please wait as it may take several minutes depending "
"on how much there is to decrypt."
msgstr ""
msgid "Completed decryption."
msgstr ""
#, fuzzy
msgid "Enabled"
msgstr "Desabilitado"
msgid "Disabled"
msgstr "Desabilitado"
#, javascript-format
msgid "Encryption is: %s"
msgstr ""
msgid "Edit note."
msgstr "Editar nota."
@@ -538,6 +571,13 @@ msgid ""
"For example, to create a notebook press `mb`; to create a note press `mn`."
msgstr ""
msgid ""
"One or more items are currently encrypted and you may need to supply a "
"master password. To do so please type `e2ee decrypt`. If you have already "
"supplied the password, the encrypted items are being decrypted in the "
"background and will be available soon."
msgstr ""
msgid "File"
msgstr "Arquivo"
@@ -581,7 +621,11 @@ msgstr "Ferramentas"
msgid "Synchronisation status"
msgstr "Alvo de sincronização"
msgid "Options"
msgid "Encryption options"
msgstr ""
#, fuzzy
msgid "General Options"
msgstr "Opções"
msgid "Help"
@@ -667,13 +711,6 @@ msgstr "Status"
msgid "Encryption is:"
msgstr ""
#, fuzzy
msgid "Enabled"
msgstr "Desabilitado"
msgid "Disabled"
msgstr "Desabilitado"
msgid "Back"
msgstr "Voltar"
@@ -686,15 +723,9 @@ msgstr ""
msgid "Please create a notebook first."
msgstr "Primeiro, crie um caderno."
msgid "Note title:"
msgstr "Título da nota:"
msgid "Please create a notebook first"
msgstr "Primeiro, crie um caderno"
msgid "To-do title:"
msgstr "Título da tarefa:"
msgid "Notebook title:"
msgstr "Título do caderno:"
@@ -769,6 +800,9 @@ msgstr "Login no OneDrive"
msgid "Import"
msgstr "Importar"
msgid "Options"
msgstr "Opções"
#, fuzzy
msgid "Synchronisation Status"
msgstr "Alvo de sincronização"
@@ -876,6 +910,10 @@ msgstr "Itens locais excluídos: %d."
msgid "Deleted remote items: %d."
msgstr "Itens remotos excluídos: %d."
#, fuzzy, javascript-format
msgid "Fetched items: %d/%d."
msgstr "Itens locais criados: %d."
#, javascript-format
msgid "State: \"%s\"."
msgstr "Estado: \"%s\"."
@@ -891,6 +929,13 @@ msgstr "Completado: %s"
msgid "Synchronisation is already in progress. State: %s"
msgstr "Sincronização já em andamento. Estado: %s"
msgid "Encrypted"
msgstr ""
#, fuzzy
msgid "Encrypted items cannot be modified"
msgstr "Não é possível inicializar o sincronizador."
msgid "Conflicts"
msgstr "Conflitos"
@@ -999,8 +1044,14 @@ msgstr "Valor da opção inválida: \"%s\". Os valores possíveis são: %s."
msgid "Items that cannot be synchronised"
msgstr ""
#, javascript-format
msgid "\"%s\": \"%s\""
#, fuzzy, javascript-format
msgid "%s (%s): %s"
msgstr "%s %s (%s)"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
"target. In order to find these items, either search for the title or the ID "
"(which is displayed in brackets above)."
msgstr ""
msgid "Sync status (synced items / total items)"
@@ -1048,6 +1099,9 @@ msgstr "Log"
msgid "Export Debug Report"
msgstr "Exportar Relatório de Debug"
msgid "Encryption Config"
msgstr ""
msgid "Configuration"
msgstr "Configuração"
@@ -1058,6 +1112,9 @@ msgstr "Mover para o caderno..."
msgid "Move %d notes to notebook \"%s\"?"
msgstr "Mover %d notas para o caderno \"%s\"?"
msgid "Press to set the decryption password."
msgstr ""
msgid "Select date"
msgstr "Selecionar data"
@@ -1067,6 +1124,24 @@ msgstr "Confirmar"
msgid "Cancel synchronisation"
msgstr "Cancelar sincronização"
#, javascript-format
msgid "Master Key %s"
msgstr ""
#, fuzzy, javascript-format
msgid "Created: %s"
msgstr "Criado: %d."
msgid "Password:"
msgstr ""
msgid "Password cannot be empty"
msgstr ""
#, fuzzy
msgid "Enable"
msgstr "Desabilitado"
#, javascript-format
msgid "The notebook could not be saved: %s"
msgstr "O caderno não pôde ser salvo: %s"
@@ -1127,6 +1202,12 @@ msgstr "Você não possui cadernos. Crie um clicando no botão (+)."
msgid "Welcome"
msgstr "Bem-vindo"
#~ msgid "Note title:"
#~ msgstr "Título da nota:"
#~ msgid "To-do title:"
#~ msgstr "Título da tarefa:"
#~ msgid "Delete notebook?"
#~ msgstr "Excluir caderno?"

View File

@@ -13,7 +13,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 2.0.4\n"
"X-Generator: Poedit 2.0.5\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
@@ -111,6 +111,9 @@ msgstr "Нет такой команды: %s"
msgid "The command \"%s\" is only available in GUI mode"
msgstr "Команда «%s» доступна только в режиме GUI"
msgid "Cannot change encrypted item"
msgstr ""
#, javascript-format
msgid "Missing required argument: %s"
msgstr "Отсутствует требуемый аргумент: %s"
@@ -173,6 +176,37 @@ msgstr "Отмечает задачу как завершённую."
msgid "Note is not a to-do: \"%s\""
msgstr "Заметка не является задачей: «%s»"
msgid ""
"Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, "
"`status` and `target-status`."
msgstr ""
#, fuzzy
msgid "Enter master password:"
msgstr "Установить пароль"
msgid "Operation cancelled"
msgstr ""
msgid ""
"Starting decryption... Please wait as it may take several minutes depending "
"on how much there is to decrypt."
msgstr ""
#, fuzzy
msgid "Completed decryption."
msgstr "Включить шифрование"
msgid "Enabled"
msgstr "Включено"
msgid "Disabled"
msgstr "Отключено"
#, fuzzy, javascript-format
msgid "Encryption is: %s"
msgstr "Шифрование:"
msgid "Edit note."
msgstr "Редактировать заметку."
@@ -553,6 +587,13 @@ msgstr ""
"Например, для создания блокнота нужно ввести `mb`, для создания заметки — "
"`mn`."
msgid ""
"One or more items are currently encrypted and you may need to supply a "
"master password. To do so please type `e2ee decrypt`. If you have already "
"supplied the password, the encrypted items are being decrypted in the "
"background and will be available soon."
msgstr ""
msgid "File"
msgstr "Файл"
@@ -575,7 +616,7 @@ msgid "Quit"
msgstr "Выход"
msgid "Edit"
msgstr "Редактировать"
msgstr "Правка"
msgid "Copy"
msgstr "Копировать"
@@ -595,7 +636,12 @@ msgstr "Инструменты"
msgid "Synchronisation status"
msgstr "Статус синхронизации"
msgid "Options"
#, fuzzy
msgid "Encryption options"
msgstr "Настройки шифрования"
#, fuzzy
msgid "General Options"
msgstr "Настройки"
msgid "Help"
@@ -629,6 +675,9 @@ msgid ""
"re-synchronised and sent unencrypted to the sync target. Do you wish to "
"continue?"
msgstr ""
"Отключение шифрования означает, что *все* ваши заметки и вложения будут "
"пересинхронизированы и отправлены в расшифрованном виде к цели "
"синхронизации. Желаете продолжить?"
msgid ""
"Enabling encryption means *all* your notes and attachments are going to be "
@@ -636,18 +685,23 @@ msgid ""
"password as, for security purposes, this will be the *only* way to decrypt "
"the data! To enable encryption, please enter your password below."
msgstr ""
"Включение шифрования означает, что *все* ваши заметки и вложения будут "
"пересинхронизированы и отправлены в зашифрованном виде к цели синхронизации. "
"Не теряйте пароль, так как в целях безопасности *только* с его помощью можно "
"будет расшифровать данные! Чтобы включить шифрование, введите ваш пароль "
"ниже."
msgid "Disable encryption"
msgstr ""
msgstr "Отключить шифрование"
msgid "Enable encryption"
msgstr ""
msgstr "Включить шифрование"
msgid "Master Keys"
msgstr ""
msgstr "Мастер-ключи"
msgid "Active"
msgstr ""
msgstr "Активен"
msgid "ID"
msgstr "ID"
@@ -656,35 +710,32 @@ msgid "Source"
msgstr "Источник"
msgid "Created"
msgstr "Создана"
msgstr "Создан"
msgid "Updated"
msgstr "Обновлена"
msgstr "Обновлён"
msgid "Password"
msgstr ""
msgstr "Пароль"
msgid "Password OK"
msgstr ""
msgstr "Пароль OK"
msgid ""
"Note: Only one master key is going to be used for encryption (the one marked "
"as \"active\"). Any of the keys might be used for decryption, depending on "
"how the notes or notebooks were originally encrypted."
msgstr ""
"Внимание: Для шифрования может быть использован только один мастер-ключ "
"(отмеченный как «активный»). Для расшифровки может использоваться любой из "
"ключей, в зависимости от того, как изначально были зашифрованы заметки или "
"блокноты."
msgid "Status"
msgstr "Статус"
msgid "Encryption is:"
msgstr ""
#, fuzzy
msgid "Enabled"
msgstr "Отключена"
msgid "Disabled"
msgstr "Отключена"
msgstr "Шифрование:"
msgid "Back"
msgstr "Назад"
@@ -697,15 +748,9 @@ msgstr "Будет создан новый блокнот «%s» и в него
msgid "Please create a notebook first."
msgstr "Сначала создайте блокнот."
msgid "Note title:"
msgstr "Название заметки:"
msgid "Please create a notebook first"
msgstr "Сначала создайте блокнот"
msgid "To-do title:"
msgstr "Название задачи:"
msgid "Notebook title:"
msgstr "Название блокнота:"
@@ -730,12 +775,11 @@ msgstr "Некоторые элементы не могут быть синхр
msgid "View them now"
msgstr "Просмотреть их сейчас"
#, fuzzy
msgid "Some items cannot be decrypted."
msgstr "Некоторые элементы не могут быть синхронизированы."
msgstr "Некоторые элементы не могут быть расшифрованы."
msgid "Set the password"
msgstr ""
msgstr "Установить пароль"
msgid "Add or remove tags"
msgstr "Добавить или удалить теги"
@@ -778,11 +822,14 @@ msgstr "Вход в OneDrive"
msgid "Import"
msgstr "Импорт"
msgid "Options"
msgstr "Настройки"
msgid "Synchronisation Status"
msgstr "Статус синхронизации"
msgid "Encryption Options"
msgstr ""
msgstr "Настройки шифрования"
msgid "Remove this tag from all the notes?"
msgstr "Убрать этот тег со всех заметок?"
@@ -883,6 +930,10 @@ msgstr "Удалено локальных элементов: %d."
msgid "Deleted remote items: %d."
msgstr "Удалено удалённых элементов: %d."
#, fuzzy, javascript-format
msgid "Fetched items: %d/%d."
msgstr "Создано локальных элементов: %d."
#, javascript-format
msgid "State: \"%s\"."
msgstr "Статус: «%s»."
@@ -898,6 +949,14 @@ msgstr "Завершено: %s"
msgid "Synchronisation is already in progress. State: %s"
msgstr "Синхронизация уже выполняется. Статус: %s"
#, fuzzy
msgid "Encrypted"
msgstr "Шифрование:"
#, fuzzy
msgid "Encrypted items cannot be modified"
msgstr "Некоторые элементы не могут быть синхронизированы."
msgid "Conflicts"
msgstr "Конфликты"
@@ -1005,9 +1064,15 @@ msgstr "Неверное значение параметра: «%s». Досту
msgid "Items that cannot be synchronised"
msgstr "Элементы, которые не могут быть синхронизированы"
#, javascript-format
msgid "\"%s\": \"%s\""
msgstr "«%s»: «%s»"
#, fuzzy, javascript-format
msgid "%s (%s): %s"
msgstr "%s %s (%s)"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
"target. In order to find these items, either search for the title or the ID "
"(which is displayed in brackets above)."
msgstr ""
msgid "Sync status (synced items / total items)"
msgstr "Статус синхронизации (элементов синхронизировано/всего)"
@@ -1054,6 +1119,10 @@ msgstr "Лог"
msgid "Export Debug Report"
msgstr "Экспортировать отладочный отчёт"
#, fuzzy
msgid "Encryption Config"
msgstr "Шифрование:"
msgid "Configuration"
msgstr "Конфигурация"
@@ -1064,6 +1133,9 @@ msgstr "Переместить в блокнот..."
msgid "Move %d notes to notebook \"%s\"?"
msgstr "Переместить %d заметок в блокнот «%s»?"
msgid "Press to set the decryption password."
msgstr ""
msgid "Select date"
msgstr "Выбрать дату"
@@ -1073,6 +1145,25 @@ msgstr "Подтвердить"
msgid "Cancel synchronisation"
msgstr "Отменить синхронизацию"
#, fuzzy, javascript-format
msgid "Master Key %s"
msgstr "Мастер-ключи"
#, fuzzy, javascript-format
msgid "Created: %s"
msgstr "Создано: %d."
#, fuzzy
msgid "Password:"
msgstr "Пароль"
msgid "Password cannot be empty"
msgstr ""
#, fuzzy
msgid "Enable"
msgstr "Включено"
#, javascript-format
msgid "The notebook could not be saved: %s"
msgstr "Не удалось сохранить блокнот: %s"
@@ -1132,3 +1223,12 @@ msgstr "У вас сейчас нет блокнота. Создайте его
msgid "Welcome"
msgstr "Добро пожаловать"
#~ msgid "Note title:"
#~ msgstr "Название заметки:"
#~ msgid "To-do title:"
#~ msgstr "Название задачи:"
#~ msgid "\"%s\": \"%s\""
#~ msgstr "«%s»: «%s»"

View File

@@ -2,7 +2,7 @@
# Copyright (C) YEAR Laurent Cozic
# This file is distributed under the same license as the Joplin-CLI package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#
#, fuzzy
msgid ""
msgstr ""
@@ -108,6 +108,9 @@ msgstr "无以下命令:%s"
msgid "The command \"%s\" is only available in GUI mode"
msgstr "命令\"%s\"仅在GUI模式下可用"
msgid "Cannot change encrypted item"
msgstr ""
#, javascript-format
msgid "Missing required argument: %s"
msgstr "缺失所需参数:%s"
@@ -168,6 +171,36 @@ msgstr "标记待办事项为完成。"
msgid "Note is not a to-do: \"%s\""
msgstr "笔记非待办事项:\"%s\""
msgid ""
"Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, "
"`status` and `target-status`."
msgstr ""
msgid "Enter master password:"
msgstr ""
msgid "Operation cancelled"
msgstr ""
msgid ""
"Starting decryption... Please wait as it may take several minutes depending "
"on how much there is to decrypt."
msgstr ""
msgid "Completed decryption."
msgstr ""
#, fuzzy
msgid "Enabled"
msgstr "已禁止"
msgid "Disabled"
msgstr "已禁止"
#, javascript-format
msgid "Encryption is: %s"
msgstr ""
msgid "Edit note."
msgstr "编辑笔记。"
@@ -510,6 +543,13 @@ msgid ""
"For example, to create a notebook press `mb`; to create a note press `mn`."
msgstr ""
msgid ""
"One or more items are currently encrypted and you may need to supply a "
"master password. To do so please type `e2ee decrypt`. If you have already "
"supplied the password, the encrypted items are being decrypted in the "
"background and will be available soon."
msgstr ""
msgid "File"
msgstr "文件"
@@ -552,7 +592,11 @@ msgstr "工具"
msgid "Synchronisation status"
msgstr "同步状态"
msgid "Options"
msgid "Encryption options"
msgstr ""
#, fuzzy
msgid "General Options"
msgstr "选项"
msgid "Help"
@@ -638,13 +682,6 @@ msgstr "状态"
msgid "Encryption is:"
msgstr ""
#, fuzzy
msgid "Enabled"
msgstr "已禁止"
msgid "Disabled"
msgstr "已禁止"
msgid "Back"
msgstr "返回"
@@ -656,15 +693,9 @@ msgstr "将创建新笔记本\"%s\"并将文件\"%s\"导入至其中"
msgid "Please create a notebook first."
msgstr "请先创建笔记本。"
msgid "Note title:"
msgstr "笔记标题:"
msgid "Please create a notebook first"
msgstr "请先创建笔记本"
msgid "To-do title:"
msgstr "待办事项标题:"
msgid "Notebook title:"
msgstr "笔记本标题:"
@@ -738,6 +769,9 @@ msgstr "登陆OneDrive"
msgid "Import"
msgstr "导入"
msgid "Options"
msgstr "选项"
msgid "Synchronisation Status"
msgstr "同步状态"
@@ -841,6 +875,10 @@ msgstr "已删除本地项目: %d。"
msgid "Deleted remote items: %d."
msgstr "已删除远程项目: %d。"
#, fuzzy, javascript-format
msgid "Fetched items: %d/%d."
msgstr "已新建本地项目: %d。"
#, javascript-format
msgid "State: \"%s\"."
msgstr "状态:\"%s\"。"
@@ -856,6 +894,13 @@ msgstr "已完成:\"%s\""
msgid "Synchronisation is already in progress. State: %s"
msgstr "同步正在进行中。状态:%s"
msgid "Encrypted"
msgstr ""
#, fuzzy
msgid "Encrypted items cannot be modified"
msgstr "一些项目无法被同步。"
msgid "Conflicts"
msgstr "冲突"
@@ -957,9 +1002,15 @@ msgstr "无效的选项值:\"%s\"。可用值为:%s。"
msgid "Items that cannot be synchronised"
msgstr "项目无法被同步。"
#, javascript-format
msgid "\"%s\": \"%s\""
msgstr "\"%s\": \"%s\""
#, fuzzy, javascript-format
msgid "%s (%s): %s"
msgstr "%s %s (%s)"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
"target. In order to find these items, either search for the title or the ID "
"(which is displayed in brackets above)."
msgstr ""
msgid "Sync status (synced items / total items)"
msgstr "同步状态(已同步项目/项目总数)"
@@ -1006,6 +1057,9 @@ msgstr "日志"
msgid "Export Debug Report"
msgstr "导出调试报告"
msgid "Encryption Config"
msgstr ""
msgid "Configuration"
msgstr "配置"
@@ -1016,6 +1070,9 @@ msgstr "移动至笔记本..."
msgid "Move %d notes to notebook \"%s\"?"
msgstr "移动%d条笔记至笔记本\"%s\"?"
msgid "Press to set the decryption password."
msgstr ""
msgid "Select date"
msgstr "选择日期"
@@ -1025,6 +1082,24 @@ msgstr "确认"
msgid "Cancel synchronisation"
msgstr "取消同步"
#, javascript-format
msgid "Master Key %s"
msgstr ""
#, fuzzy, javascript-format
msgid "Created: %s"
msgstr "已创建:%d条。"
msgid "Password:"
msgstr ""
msgid "Password cannot be empty"
msgstr ""
#, fuzzy
msgid "Enable"
msgstr "已禁止"
#, javascript-format
msgid "The notebook could not be saved: %s"
msgstr "此笔记本无法保存:%s"
@@ -1083,6 +1158,15 @@ msgstr "您当前没有任何笔记本。点击(+)按钮创建新笔记本。"
msgid "Welcome"
msgstr "欢迎"
#~ msgid "Note title:"
#~ msgstr "笔记标题:"
#~ msgid "To-do title:"
#~ msgstr "待办事项标题:"
#~ msgid "\"%s\": \"%s\""
#~ msgstr "\"%s\": \"%s\""
#~ msgid "Delete notebook \"%s\"?"
#~ msgstr "删除笔记本\"%s\"?"

View File

@@ -1,6 +1,6 @@
{
"name": "joplin",
"version": "0.10.85",
"version": "0.10.87",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -197,6 +197,11 @@
"delayed-stream": "1.0.0"
}
},
"compare-version": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz",
"integrity": "sha1-AWLsLZNR9d3VmpICy6k1NmpyUIA="
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",

View File

@@ -19,7 +19,7 @@
],
"owner": "Laurent Cozic"
},
"version": "0.10.85",
"version": "0.10.87",
"bin": {
"joplin": "./main.js"
},
@@ -28,6 +28,7 @@
},
"dependencies": {
"app-module-path": "^2.2.0",
"compare-version": "^0.1.2",
"follow-redirects": "^1.2.4",
"form-data": "^2.1.4",
"fs-extra": "^5.0.0",

View File

@@ -9,4 +9,10 @@ bash $SCRIPT_DIR/build.sh
cp "$SCRIPT_DIR/package.json" build/
cp "$SCRIPT_DIR/../README.md" build/
cd "$SCRIPT_DIR/build"
npm publish
npm publish
NEW_VERSION=$("cat package.json | jq -r .version")
git add -A
git commit -m "CLI v$NEW_VERSION"
git tag "cli-v$NEW_VERSION"
git push && git push --tags

View File

@@ -268,6 +268,24 @@ describe('Synchronizer', function() {
expect(deletedItems.length).toBe(0);
}));
it('should not created deleted_items entries for items deleted via sync', asyncTest(async () => {
let folder1 = await Folder.save({ title: "folder1" });
let note1 = await Note.save({ title: "un", parent_id: folder1.id });
await synchronizer().start();
await switchClient(2);
await synchronizer().start();
await Folder.delete(folder1.id);
await synchronizer().start();
await switchClient(1);
await synchronizer().start();
let deletedItems = await BaseItem.deletedItems(syncTargetId());
expect(deletedItems.length).toBe(0);
}));
it('should delete local notes', asyncTest(async () => {
let folder1 = await Folder.save({ title: "folder1" });
let note1 = await Note.save({ title: "un", parent_id: folder1.id });
@@ -830,6 +848,8 @@ describe('Synchronizer', function() {
}));
it('should sync resources', asyncTest(async () => {
while (insideBeforeEach) await time.msleep(100);
let folder1 = await Folder.save({ title: "folder1" });
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');

View File

@@ -44,16 +44,14 @@ class MainScreenComponent extends React.Component {
const folderId = Setting.value('activeFolderId');
if (!folderId) return;
const note = await Note.save({
title: title,
const newNote = {
parent_id: folderId,
is_todo: isTodo ? 1 : 0,
});
Note.updateGeolocation(note.id);
};
this.props.dispatch({
type: 'NOTE_SELECT',
id: note.id,
type: 'NOTE_SET_NEW_ONE',
item: newNote,
});
}
@@ -65,30 +63,14 @@ class MainScreenComponent extends React.Component {
return;
}
this.setState({
promptOptions: {
label: _('Note title:'),
onClose: async (answer) => {
if (answer) await createNewNote(answer, false);
this.setState({ promptOptions: null });
}
},
});
await createNewNote(null, false);
} else if (command.name === 'newTodo') {
if (!this.props.folders.length) {
bridge().showErrorMessageBox(_('Please create a notebook first'));
return;
}
this.setState({
promptOptions: {
label: _('To-do title:'),
onClose: async (answer) => {
if (answer) await createNewNote(answer, true);
this.setState({ promptOptions: null });
}
},
});
await createNewNote(null, true);
} else if (command.name === 'newNotebook') {
this.setState({
promptOptions: {

View File

@@ -54,7 +54,16 @@ class NoteListComponent extends React.Component {
}
itemContextMenu(event) {
const noteIds = this.props.selectedNoteIds;
const currentItemId = event.currentTarget.getAttribute('data-id');
if (!currentItemId) return;
let noteIds = [];
if (this.props.selectedNoteIds.indexOf(currentItemId) < 0) {
noteIds = [currentItemId];
} else {
noteIds = this.props.selectedNoteIds;
}
if (!noteIds.length) return;
const notes = noteIds.map((id) => BaseModel.byId(this.props.notes, id));
@@ -137,7 +146,10 @@ class NoteListComponent extends React.Component {
const hPadding = 10;
let style = Object.assign({ width: width }, this.style().listItem);
if (this.props.selectedNoteIds.indexOf(item.id) >= 0) style = Object.assign(style, this.style().listItemSelected);
if (this.props.selectedNoteIds.indexOf(item.id) >= 0) {
style = Object.assign(style, this.style().listItemSelected);
}
// Setting marginBottom = 1 because it makes the checkbox looks more centered, at least on Windows
// but don't know how it will look in other OSes.
@@ -163,6 +175,7 @@ class NoteListComponent extends React.Component {
style={listItemTitleStyle}
onClick={(event) => { onTitleClick(event, item) }}
onDragStart={(event) => onDragStart(event) }
data-id={item.id}
>
{Note.displayTitle(item)}
</a>
@@ -172,8 +185,9 @@ class NoteListComponent extends React.Component {
render() {
const theme = themeStyle(this.props.theme);
const style = this.props.style;
let notes = this.props.notes.slice();
if (!this.props.notes.length) {
if (!notes.length) {
const padding = 10;
const emptyDivStyle = Object.assign({
padding: padding + 'px',
@@ -192,7 +206,7 @@ class NoteListComponent extends React.Component {
itemHeight={this.style().listItem.height}
style={style}
className={"note-list"}
items={this.props.notes}
items={notes}
itemRenderer={ (item) => { return this.itemRenderer(item, theme, style.width) } }
></ItemList>
);

View File

@@ -36,7 +36,13 @@ class NoteTextComponent extends React.Component {
isLoading: true,
webviewReady: false,
scrollHeight: null,
editorScrollTop: 0
editorScrollTop: 0,
newNote: null,
// If the current note was just created, and the title has never been
// changed by the user, this variable contains that note ID. Used
// to automatically set the title.
newAndNoTitleChangeNoteId: null,
};
this.lastLoadedNoteId_ = null;
@@ -75,7 +81,10 @@ class NoteTextComponent extends React.Component {
async componentWillMount() {
let note = null;
if (this.props.noteId) {
if (this.props.newNote) {
note = Object.assign({}, this.props.newNote);
} else if (this.props.noteId) {
note = await Note.load(this.props.noteId);
}
@@ -114,7 +123,14 @@ class NoteTextComponent extends React.Component {
}
async saveOneProperty(name, value) {
await shared.saveOneProperty(this, name, value);
if (this.state.note && !this.state.note.id) {
const note = Object.assign({}, this.state.note);
note[name] = value;
this.setState({ note: note });
this.scheduleSave();
} else {
await shared.saveOneProperty(this, name, value);
}
}
scheduleSave() {
@@ -128,17 +144,32 @@ class NoteTextComponent extends React.Component {
if (!options) options = {};
if (!('noReloadIfLocalChanges' in options)) options.noReloadIfLocalChanges = false;
const noteId = props.noteId;
this.lastLoadedNoteId_ = noteId;
const note = noteId ? await Note.load(noteId) : null;
if (noteId !== this.lastLoadedNoteId_) return; // Race condition - current note was changed while this one was loading
if (!options.noReloadIfLocalChanges && this.isModified()) return;
await this.saveIfNeeded();
// If the note hasn't been changed, exit now
if (this.state.note && note) {
let diff = Note.diffObjects(this.state.note, note);
delete diff.type_;
if (!Object.getOwnPropertyNames(diff).length) return;
const previousNote = this.state.note ? Object.assign({}, this.state.note) : null;
const stateNoteId = this.state.note ? this.state.note.id : null;
let noteId = null;
let note = null;
let loadingNewNote = true;
if (props.newNote) {
note = Object.assign({}, props.newNote);
this.lastLoadedNoteId_ = null;
} else {
noteId = props.noteId;
loadingNewNote = stateNoteId !== noteId;
this.lastLoadedNoteId_ = noteId;
note = noteId ? await Note.load(noteId) : null;
if (noteId !== this.lastLoadedNoteId_) return; // Race condition - current note was changed while this one was loading
if (options.noReloadIfLocalChanges && this.isModified()) return;
// If the note hasn't been changed, exit now
if (this.state.note && note) {
let diff = Note.diffObjects(this.state.note, note);
delete diff.type_;
if (!Object.getOwnPropertyNames(diff).length) return;
}
}
this.mdToHtml_ = null;
@@ -146,35 +177,53 @@ class NoteTextComponent extends React.Component {
// If we are loading nothing (noteId == null), make sure to
// set webviewReady to false too because the webview component
// is going to be removed in render().
const webviewReady = this.webview_ && this.state.webviewReady && noteId;
const webviewReady = this.webview_ && this.state.webviewReady && (noteId || props.newNote);
this.editorMaxScrollTop_ = 0;
// Scroll back to top when loading new note
if (loadingNewNote) {
this.editorMaxScrollTop_ = 0;
// HACK: To go around a bug in Ace editor, we first set the scroll position to 1
// and then (in the renderer callback) to the value we actually need. The first
// operation helps clear the scroll position cache. See:
// https://github.com/ajaxorg/ace/issues/2195
this.editorSetScrollTop(1);
this.restoreScrollTop_ = 0;
// HACK: To go around a bug in Ace editor, we first set the scroll position to 1
// and then (in the renderer callback) to the value we actually need. The first
// operation helps clear the scroll position cache. See:
// https://github.com/ajaxorg/ace/issues/2195
this.editorSetScrollTop(1);
this.restoreScrollTop_ = 0;
this.setState({
note: note,
lastSavedNote: Object.assign({}, note),
webviewReady: webviewReady,
});
}
async componentWillReceiveProps(nextProps) {
if ('noteId' in nextProps && nextProps.noteId !== this.props.noteId) {
await this.reloadNote(nextProps);
if(this.editor_){
if (this.editor_) {
const session = this.editor_.editor.getSession();
const undoManager = session.getUndoManager();
undoManager.reset();
session.setUndoManager(undoManager);
this.editor_.editor.focus();
this.editor_.editor.clearSelection();
this.editor_.editor.moveCursorTo(0,0);
}
}
let newState = {
note: note,
lastSavedNote: Object.assign({}, note),
webviewReady: webviewReady,
};
if (!note) {
newState.newAndNoTitleChangeNoteId = null;
} else if (note.id !== this.state.newAndNoTitleChangeNoteId) {
newState.newAndNoTitleChangeNoteId = null;
}
this.setState(newState);
}
async componentWillReceiveProps(nextProps) {
if (nextProps.newNote) {
await this.reloadNote(nextProps);
} else if ('noteId' in nextProps && nextProps.noteId !== this.props.noteId) {
await this.reloadNote(nextProps);
}
if ('syncStarted' in nextProps && !nextProps.syncStarted && !this.isModified()) {
await this.reloadNote(nextProps, { noReloadIfLocalChanges: true });
}
@@ -190,6 +239,7 @@ class NoteTextComponent extends React.Component {
title_changeText(event) {
shared.noteComponent_change(this, 'title', event.target.value);
this.setState({ newAndNoTitleChangeNoteId: null });
this.scheduleSave();
}
@@ -397,20 +447,10 @@ class NoteTextComponent extends React.Component {
menu.popup(bridge().window());
}
// shouldComponentUpdate(nextProps, nextState) {
// //console.info('NEXT PROPS', JSON.stringify(nextProps));
// console.info('NEXT STATE ====================');
// for (var n in nextProps) {
// if (!nextProps.hasOwnProperty(n)) continue;
// console.info(n + ' = ' + (nextProps[n] === this.props[n]));
// }
// return true;
// }
render() {
const style = this.props.style;
const note = this.state.note;
const body = note ? note.body : '';
const body = note && note.body ? note.body : '';
const theme = themeStyle(this.props.theme);
const visiblePanes = this.props.visiblePanes || ['editor', 'viewer'];
@@ -537,7 +577,7 @@ class NoteTextComponent extends React.Component {
const titleEditor = <input
type="text"
style={titleEditorStyle}
value={note ? note.title : ''}
value={note && note.title ? note.title : ''}
onChange={(event) => { this.title_changeText(event); }}
/>
@@ -605,6 +645,7 @@ const mapStateToProps = (state) => {
theme: state.settings.theme,
showAdvancedOptions: state.settings.showAdvancedOptions,
syncStarted: state.syncStarted,
newNote: state.newNote,
};
};

View File

@@ -42,17 +42,20 @@ class PromptDialog extends React.Component {
this.styles_ = {};
const paddingTop = 20;
this.styles_.modalLayer = {
zIndex: 9999,
position: 'absolute',
top: 0,
left: 0,
width: width,
height: height,
height: height - paddingTop,
backgroundColor: 'rgba(0,0,0,0.6)',
display: visible ? 'flex' : 'none',
alignItems: 'center',
alignItems: 'flex-start',
justifyContent: 'center',
paddingTop: paddingTop + 'px',
};
this.styles_.promptDialog = {
@@ -88,24 +91,6 @@ class PromptDialog extends React.Component {
return this.styles_;
}
// shouldComponentUpdate(nextProps, nextState) {
// console.info(JSON.stringify(nextProps)+JSON.stringify(nextState));
// console.info('NEXT PROPS ====================');
// for (var n in nextProps) {
// if (!nextProps.hasOwnProperty(n)) continue;
// console.info(n + ' = ' + (nextProps[n] === this.props[n]));
// }
// console.info('NEXT STATE ====================');
// for (var n in nextState) {
// if (!nextState.hasOwnProperty(n)) continue;
// console.info(n + ' = ' + (nextState[n] === this.state[n]));
// }
// return true;
// }
render() {
const style = this.props.style;
const theme = themeStyle(this.props.theme);

View File

@@ -35,6 +35,7 @@ class SideBarComponent extends React.Component {
alignItems: 'center',
cursor: 'default',
opacity: 0.8,
whiteSpace: 'nowrap',
},
listItemSelected: {
backgroundColor: theme.selectedColor2,

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
{
"name": "Joplin",
"version": "0.10.41",
"version": "0.10.46",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "Joplin",
"version": "0.10.41",
"version": "0.10.46",
"description": "Joplin for Desktop",
"main": "main.js",
"scripts": {

View File

@@ -18,9 +18,9 @@ Three types of applications are available: for the **desktop** (Windows, macOS a
Operating System | Download
-----------------|--------
Windows | <a href='https://github.com/laurent22/joplin/releases/download/v0.10.40/Joplin-Setup-0.10.40.exe'><img alt='Get it on Windows' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/BadgeWindows.png'/></a>
macOS | <a href='https://github.com/laurent22/joplin/releases/download/v0.10.40/Joplin-0.10.40.dmg'><img alt='Get it on macOS' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/BadgeMacOS.png'/></a>
Linux | <a href='https://github.com/laurent22/joplin/releases/download/v0.10.40/Joplin-0.10.40-x86_64.AppImage'><img alt='Get it on macOS' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/BadgeLinux.png'/></a>
Windows | <a href='https://github.com/laurent22/joplin/releases/download/v0.10.43/Joplin-Setup-0.10.43.exe'><img alt='Get it on Windows' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/BadgeWindows.png'/></a>
macOS | <a href='https://github.com/laurent22/joplin/releases/download/v0.10.43/Joplin-0.10.43.dmg'><img alt='Get it on macOS' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/BadgeMacOS.png'/></a>
Linux | <a href='https://github.com/laurent22/joplin/releases/download/v0.10.43/Joplin-0.10.43-x86_64.AppImage'><img alt='Get it on macOS' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/BadgeLinux.png'/></a>
## Mobile applications
@@ -124,6 +124,10 @@ Joplin is currently available in English, French, Spanish, German, Portuguese, C
This translation will apply to the three applications - desktop, mobile and terminal.
# Contributing
Please see the guide for information on how to contribute to the development of Joplin: https://github.com/laurent22/joplin/blob/master/CONTRIBUTING.md
# Coming features
- NextCloud support

View File

@@ -90,8 +90,8 @@ android {
applicationId "net.cozic.joplin"
minSdkVersion 16
targetSdkVersion 22
versionCode 84
versionName "0.10.69"
versionCode 89
versionName "0.10.74"
ndk {
abiFilters "armeabi-v7a", "x86"
}

View File

@@ -5,6 +5,7 @@
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; };
00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; };
@@ -41,8 +42,8 @@
E8DD8252C0DD4CF1B53590E9 /* SimpleLineIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 69B8EE98BFBC4AABA4885BB0 /* SimpleLineIcons.ttf */; };
EA501DCDCF4745E9B63ECE98 /* Octicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7D46CBDF8846409890AD7A84 /* Octicons.ttf */; };
EC11356C90E9419799A2626F /* EvilIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 51BCEC3BC28046C8BB19531F /* EvilIcons.ttf */; };
FBF57CE2F0F448FA9A8985E2 /* libsqlite3.0.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 0EB8BCAEA9AA41CAAE460443 /* libsqlite3.0.tbd */; };
F3D0BB525E6C490294D73075 /* libRNSecureRandom.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 22647ACF9A4C45918C44C599 /* libRNSecureRandom.a */; };
FBF57CE2F0F448FA9A8985E2 /* libsqlite3.0.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 0EB8BCAEA9AA41CAAE460443 /* libsqlite3.0.tbd */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -123,6 +124,13 @@
remoteGlobalIDString = 3D3CD90B1DE5FBD600167DC4;
remoteInfo = jschelpers;
};
4D2A44E7200015A2001CA388 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 252BD7B86BF7435B960DA901 /* RNSecureRandom.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 134814201AA4EA6300B7C361;
remoteInfo = RNSecureRandom;
};
4D2A85A91FBCE3AC0028537D /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
@@ -370,6 +378,8 @@
146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = "<group>"; };
15FD7D2C8F0A445BBA807A9D /* MaterialIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = MaterialIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/MaterialIcons.ttf"; sourceTree = "<group>"; };
1F79F2CD7CED446B986A6252 /* Entypo.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Entypo.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Entypo.ttf"; sourceTree = "<group>"; };
22647ACF9A4C45918C44C599 /* libRNSecureRandom.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNSecureRandom.a; sourceTree = "<group>"; };
252BD7B86BF7435B960DA901 /* RNSecureRandom.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNSecureRandom.xcodeproj; path = "../node_modules/react-native-securerandom/ios/RNSecureRandom.xcodeproj"; sourceTree = "<group>"; };
381C047F2739439CB3E6452A /* libRNVectorIcons.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNVectorIcons.a; sourceTree = "<group>"; };
3FFC0F5EFDC54862B1F998DD /* Foundation.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Foundation.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Foundation.ttf"; sourceTree = "<group>"; };
44A39642217548C8ADA91CBA /* libRNImagePicker.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNImagePicker.a; sourceTree = "<group>"; };
@@ -398,8 +408,6 @@
F5E37D05726A4A08B2EE323A /* libRNFetchBlob.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNFetchBlob.a; sourceTree = "<group>"; };
FD370E24D76E461D960DD85D /* Feather.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Feather.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Feather.ttf"; sourceTree = "<group>"; };
FF411B45E68B4A8CBCC35777 /* Ionicons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Ionicons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Ionicons.ttf"; sourceTree = "<group>"; };
252BD7B86BF7435B960DA901 /* RNSecureRandom.xcodeproj */ = {isa = PBXFileReference; name = "RNSecureRandom.xcodeproj"; path = "../node_modules/react-native-securerandom/ios/RNSecureRandom.xcodeproj"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; };
22647ACF9A4C45918C44C599 /* libRNSecureRandom.a */ = {isa = PBXFileReference; name = "libRNSecureRandom.a"; path = "libRNSecureRandom.a"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -540,6 +548,14 @@
name = Products;
sourceTree = "<group>";
};
4D2A44E4200015A2001CA388 /* Products */ = {
isa = PBXGroup;
children = (
4D2A44E8200015A2001CA388 /* libRNSecureRandom.a */,
);
name = Products;
sourceTree = "<group>";
};
4D2A85911FBCE3950028537D /* Recovered References */ = {
isa = PBXGroup;
children = (
@@ -550,6 +566,7 @@
87BABCF4ED0A406B9546CCE9 /* libSQLite.a */,
381C047F2739439CB3E6452A /* libRNVectorIcons.a */,
44A39642217548C8ADA91CBA /* libRNImagePicker.a */,
22647ACF9A4C45918C44C599 /* libRNSecureRandom.a */,
);
name = "Recovered References";
sourceTree = "<group>";
@@ -853,6 +870,10 @@
ProductGroup = 4DA7F8091FC1DA9C00353191 /* Products */;
ProjectRef = A4716DB8654B431D894F89E1 /* RNImagePicker.xcodeproj */;
},
{
ProductGroup = 4D2A44E4200015A2001CA388 /* Products */;
ProjectRef = 252BD7B86BF7435B960DA901 /* RNSecureRandom.xcodeproj */;
},
{
ProductGroup = 4D2A85B71FBCE3AC0028537D /* Products */;
ProjectRef = 711CBD21F0894B83A2D8E234 /* RNVectorIcons.xcodeproj */;
@@ -947,6 +968,13 @@
remoteRef = 3DAD3EAC1DF850E9000B6D8A /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
4D2A44E8200015A2001CA388 /* libRNSecureRandom.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRNSecureRandom.a;
remoteRef = 4D2A44E7200015A2001CA388 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
4D2A85AA1FBCE3AC0028537D /* libfishhook.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
@@ -1257,10 +1285,14 @@
"$(SRCROOT)/../node_modules/react-native-sqlite-storage/src/ios",
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
"$(SRCROOT)..\node_modules\neact-native-image-pickerios",
"$(SRCROOT)\..\node_modules\react-native-securerandom\ios",
"$(SRCROOT)..\node_modules\neact-native-securerandomios",
);
INFOPLIST_FILE = Joplin/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/Joplin\"",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -1272,10 +1304,6 @@
PROVISIONING_PROFILE_SPECIFIER = "";
TARGETED_DEVICE_FAMILY = 1;
VERSIONING_SYSTEM = "apple-generic";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/Joplin\"",
);
};
name = Debug;
};
@@ -1297,10 +1325,14 @@
"$(SRCROOT)/../node_modules/react-native-sqlite-storage/src/ios",
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
"$(SRCROOT)..\node_modules\neact-native-image-pickerios",
"$(SRCROOT)\..\node_modules\react-native-securerandom\ios",
"$(SRCROOT)..\node_modules\neact-native-securerandomios",
);
INFOPLIST_FILE = Joplin/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/Joplin\"",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -1312,10 +1344,6 @@
PROVISIONING_PROFILE_SPECIFIER = "";
TARGETED_DEVICE_FAMILY = 1;
VERSIONING_SYSTEM = "apple-generic";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/Joplin\"",
);
};
name = Release;
};

View File

@@ -17,11 +17,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.10.6</string>
<string>0.10.9</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>6</string>
<string>9</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>

View File

@@ -277,6 +277,10 @@ class BaseApplication {
type: 'MASTERKEY_REMOVE_NOT_LOADED',
ids: loadedMasterKeyIds,
});
// Schedule a sync operation so that items that need to be encrypted
// are sent to sync target.
reg.scheduleSync();
}
}

View File

@@ -193,8 +193,12 @@ class BaseModel {
});
}
static loadByField(fieldName, fieldValue) {
return this.modelSelectOne('SELECT * FROM `' + this.tableName() + '` WHERE `' + fieldName + '` = ?', [fieldValue]);
static loadByField(fieldName, fieldValue, options = null) {
if (!options) options = {};
if (!('caseInsensitive' in options)) options.caseInsensitive = false;
let sql = 'SELECT * FROM `' + this.tableName() + '` WHERE `' + fieldName + '` = ?';
if (options.caseInsensitive) sql += ' COLLATE NOCASE';
return this.modelSelectOne(sql, [fieldValue]);
}
static loadByTitle(fieldValue) {
@@ -250,10 +254,25 @@ class BaseModel {
let n = fieldNames[i];
if (n in o) temp[n] = o[n];
}
// Remove fields that are not in the `fields` list, if provided.
// Note that things like update_time, user_update_time will still
// be part of the final list of fields if autoTimestamp is on.
// id also will stay.
if (!options.isNew && options.fields) {
const filtered = {};
for (let k in temp) {
if (!temp.hasOwnProperty(k)) continue;
if (k !== 'id' && options.fields.indexOf(k) < 0) continue;
filtered[k] = temp[k];
}
temp = filtered;
}
o = temp;
let modelId = temp.id;
let query = {};
let modelId = o.id;
const timeNow = time.unixMs();
@@ -292,15 +311,6 @@ class BaseModel {
let temp = Object.assign({}, o);
delete temp.id;
if (options.fields) {
let filtered = {};
for (let i = 0; i < options.fields.length; i++) {
const f = options.fields[i];
filtered[f] = o[f];
}
temp = filtered;
}
query = Database.updateQuery(this.tableName(), temp, where);
}

View File

@@ -125,9 +125,9 @@ class MdToHtml {
renderOpenLink_(attrs, options) {
let href = this.getAttr_(attrs, 'href');
const title = this.getAttr_(attrs, 'title');
const text = this.getAttr_(attrs, 'text');
const isResourceUrl = Resource.isResourceUrl(href);
const title = isResourceUrl ? this.getAttr_(attrs, 'title') : href;
if (isResourceUrl && !this.supportsResourceLinks_) {
// In mobile, links to local resources, such as PDF, etc. currently aren't supported.
@@ -305,13 +305,15 @@ class MdToHtml {
b,strong{font-weight:bolder}small{font-size:80%}img{border-style:none}
`;
const fontFamily = 'sans-serif';
const css = `
body {
font-size: ` + style.htmlFontSize + `;
color: ` + style.htmlColor + `;
line-height: ` + style.htmlLineHeight + `;
background-color: ` + style.htmlBackgroundColor + `;
font-family: sans-serif;
font-family: ` + fontFamily + `;
padding-bottom: ` + options.paddingBottom + `;
}
p, h1, h2, h3, h4, h5, h6, ul, table {
@@ -359,6 +361,10 @@ class MdToHtml {
td, th {
border: 1px solid silver;
padding: .5em 1em .5em 1em;
font-size: ` + style.htmlFontSize + `;
color: ` + style.htmlColor + `;
background-color: ` + style.htmlBackgroundColor + `;
font-family: ` + fontFamily + `;
}
hr {
border: none;

View File

@@ -77,10 +77,12 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
paddingBottom: 5,
marginTop: theme.marginTop,
marginBottom: 5,
color: theme.color,
},
normalText: {
flex: 1,
fontSize: theme.fontSize,
color: theme.color,
},
container: {
flex: 1,
@@ -112,9 +114,9 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
<Text style={this.styles().titleText}>{_('Master Key %s', mk.id.substr(0,6))}</Text>
<Text style={this.styles().normalText}>{_('Created: %s', time.formatMsToLocal(mk.created_time))}</Text>
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<Text style={{flex:0, fontSize: theme.fontSize, marginRight: 10}}>{_('Password:')}</Text>
<TextInput secureTextEntry={true} value={password} onChangeText={(text) => onPasswordChange(text)} style={{flex:1, marginRight: 10}}></TextInput>
<Text style={{fontSize: theme.fontSize, marginRight: 10}}>{passwordOk}</Text>
<Text style={{flex:0, fontSize: theme.fontSize, marginRight: 10, color: theme.color}}>{_('Password:')}</Text>
<TextInput secureTextEntry={true} value={password} onChangeText={(text) => onPasswordChange(text)} style={{flex:1, marginRight: 10, color: theme.color}}></TextInput>
<Text style={{fontSize: theme.fontSize, marginRight: 10, color: theme.color}}>{passwordOk}</Text>
<Button title={_('Save')} onPress={() => onSaveClick()}></Button>
</View>
</View>
@@ -137,8 +139,8 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
return (
<View style={{flex:1, borderColor: theme.dividerColor, borderWidth: 1, padding: 10, marginTop: 10, marginBottom: 10}}>
<Text style={{fontSize: theme.fontSize}}>{_('Enabling encryption means *all* your notes and attachments are going to be re-synchronised and sent encrypted to the sync target. Do not lose the password as, for security purposes, this will be the *only* way to decrypt the data! To enable encryption, please enter your password below.')}</Text>
<TextInput secureTextEntry={true} value={this.state.passwordPromptAnswer} onChangeText={(text) => { this.setState({ passwordPromptAnswer: text }) }}></TextInput>
<Text style={{fontSize: theme.fontSize, color: theme.color}}>{_('Enabling encryption means *all* your notes and attachments are going to be re-synchronised and sent encrypted to the sync target. Do not lose the password as, for security purposes, this will be the *only* way to decrypt the data! To enable encryption, please enter your password below.')}</Text>
<TextInput style={{margin: 10, color: theme.color, borderWidth: 1, borderColor: theme.dividerColor }} secureTextEntry={true} value={this.state.passwordPromptAnswer} onChangeText={(text) => { this.setState({ passwordPromptAnswer: text }) }}></TextInput>
<View style={{flexDirection: 'row'}}>
<View style={{flex:1 , marginRight:10}} >
<Button title={_('Enable')} onPress={() => { onEnableClick() }}></Button>

View File

@@ -1,5 +1,5 @@
const React = require('react'); const Component = React.Component;
const { Platform, Keyboard, BackHandler, View, Button, TextInput, WebView, Text, StyleSheet, Linking, Image } = require('react-native');
const { Platform, Keyboard, BackHandler, View, Button, TextInput, WebView, Text, StyleSheet, Linking, Image, KeyboardAvoidingView } = require('react-native');
const { connect } = require('react-redux');
const { uuid } = require('lib/uuid.js');
const { Log } = require('lib/log.js');
@@ -34,7 +34,7 @@ const AlarmService = require('lib/services/AlarmService.js');
const { SelectDateTimeDialog } = require('lib/components/select-date-time-dialog.js');
class NoteScreenComponent extends BaseScreenComponent {
static navigationOptions(options) {
return { header: null };
}
@@ -51,11 +51,12 @@ class NoteScreenComponent extends BaseScreenComponent {
isLoading: true,
titleTextInputHeight: 20,
alarmDialogShown: false,
heightBumpView:0
};
// iOS doesn't support multiline text fields properly so disable it
this.enableMultilineTitle_ = Platform.OS !== 'ios';
this.saveButtonHasBeenShown_ = false;
this.styles_ = {};
@@ -148,6 +149,12 @@ class NoteScreenComponent extends BaseScreenComponent {
await shared.initState(this);
this.refreshNoteMetadata();
if (Platform.OS === 'ios') {
this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this._keyboardDidShow.bind(this));
this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this._keyboardDidHide.bind(this));
}
}
refreshNoteMetadata(force = null) {
@@ -156,6 +163,19 @@ class NoteScreenComponent extends BaseScreenComponent {
componentWillUnmount() {
BackButtonService.removeHandler(this.backHandler);
if (Platform.OS === 'ios'){
this.keyboardDidShowListener.remove();
this.keyboardDidHideListener.remove();
}
}
_keyboardDidShow () {
this.setState({ heightBumpView:30 })
}
_keyboardDidHide () {
this.setState({ heightBumpView:0 })
}
title_changeText(text) {
@@ -241,13 +261,13 @@ class NoteScreenComponent extends BaseScreenComponent {
const format = mimeType == 'image/png' ? 'PNG' : 'JPEG';
reg.logger().info('Resizing image ' + localFilePath);
const resizedImage = await ImageResizer.createResizedImage(localFilePath, dimensions.width, dimensions.height, format, 85); //, 0, targetPath);
const resizedImagePath = resizedImage.uri;
reg.logger().info('Resized image ', resizedImagePath);
reg.logger().info('Moving ' + resizedImagePath + ' => ' + targetPath);
await RNFS.copyFile(resizedImagePath, targetPath);
try {
await RNFS.unlink(resizedImagePath);
} catch (error) {
@@ -522,7 +542,7 @@ class NoteScreenComponent extends BaseScreenComponent {
);
return (
<View style={this.rootStyle(this.props.theme).root}>
<KeyboardAvoidingView behavior= {(Platform.OS === 'ios')? "padding" : null} style={this.rootStyle(this.props.theme).root}>
<ScreenHeader
folderPickerOptions={{
enabled: true,
@@ -558,7 +578,8 @@ class NoteScreenComponent extends BaseScreenComponent {
/>
<DialogBox ref={dialogbox => { this.dialogbox = dialogbox }}/>
</View>
<View style={{ height: this.state.heightBumpView }} />
</KeyboardAvoidingView>
);
}

View File

@@ -96,6 +96,7 @@ class NotesScreenComponent extends BaseScreenComponent {
if (this.props.selectedFolderId == Folder.conflictFolderId()) return [];
const folder = this.parentItem();
if (!folder) return [];
let output = [];
if (!folder.encryption_applied) output.push({ title: _('Edit notebook'), onPress: () => { this.editFolder_onPress(this.props.selectedFolderId); } });

View File

@@ -17,49 +17,36 @@ shared.saveNoteButton_press = async function(comp) {
// just save a new note by clearing the note ID.
if (note.id && !(await shared.noteExists(note.id))) delete note.id;
// reg.logger().info('Saving note: ', note);
if (!note.parent_id) {
let folder = await Folder.defaultFolder();
if (!folder) {
//Log.warn('Cannot save note without a notebook');
return;
}
if (!folder) return;
note.parent_id = folder.id;
}
let isNew = !note.id;
let titleWasAutoAssigned = false;
if (isNew && !note.title) {
note.title = Note.defaultTitle(note);
titleWasAutoAssigned = true;
}
// Save only the properties that have changed
// let diff = null;
// if (!isNew) {
// diff = BaseModel.diffObjects(comp.state.lastSavedNote, note);
// diff.type_ = note.type_;
// diff.id = note.id;
// } else {
// diff = Object.assign({}, note);
// }
// const savedNote = await Note.save(diff);
let options = {};
let options = { userSideValidation: true };
if (!isNew) {
options.fields = BaseModel.diffObjectsFields(comp.state.lastSavedNote, note);
}
const savedNote = ('fields' in options) && !options.fields.length ? Object.assign({}, note) : await Note.save(note, { userSideValidation: true });
const hasAutoTitle = comp.state.newAndNoTitleChangeNoteId || (isNew && !note.title);
if (hasAutoTitle) {
note.title = Note.defaultTitle(note);
if (options.fields && options.fields.indexOf('title') < 0) options.fields.push('title');
}
const savedNote = ('fields' in options) && !options.fields.length ? Object.assign({}, note) : await Note.save(note, options);
const stateNote = comp.state.note;
// Note was reloaded while being saved.
if (!isNew && (!stateNote || stateNote.id !== savedNote.id)) return;
// Re-assign any property that might have changed during saving (updated_time, etc.)
note = Object.assign(note, savedNote);
if (stateNote) {
if (stateNote.id === note.id) {
// But we preserve the current title and body because
// the user might have changed them between the time
// saveNoteButton_press was called and the note was
@@ -67,17 +54,30 @@ shared.saveNoteButton_press = async function(comp) {
//
// If the title was auto-assigned above, we don't restore
// it from the state because it will be empty there.
if (!titleWasAutoAssigned) note.title = stateNote.title;
if (!hasAutoTitle) note.title = stateNote.title;
note.body = stateNote.body;
}
comp.setState({
let newState = {
lastSavedNote: Object.assign({}, note),
note: note,
});
};
if (isNew) newState.newAndNoTitleChangeNoteId = note.id;
comp.setState(newState);
if (isNew) Note.updateGeolocation(note.id);
comp.refreshNoteMetadata();
if (isNew) {
// Clear the newNote item now that the note has been saved, and
// make sure that the note we're editing is selected.
comp.props.dispatch({
type: 'NOTE_SELECT',
id: savedNote.id,
});
}
}
shared.saveOneProperty = async function(comp, name, value) {
@@ -106,9 +106,13 @@ shared.saveOneProperty = async function(comp, name, value) {
}
shared.noteComponent_change = function(comp, propName, propValue) {
let newState = {}
let note = Object.assign({}, comp.state.note);
note[propName] = propValue;
comp.setState({ note: note });
newState.note = note;
comp.setState(newState);
}
shared.refreshNoteMetadata = async function(comp, force = null) {
@@ -120,7 +124,7 @@ shared.refreshNoteMetadata = async function(comp, force = null) {
shared.isModified = function(comp) {
if (!comp.state.note || !comp.state.lastSavedNote) return false;
let diff = BaseModel.diffObjects(comp.state.note, comp.state.lastSavedNote);
let diff = BaseModel.diffObjects(comp.state.lastSavedNote, comp.state.note);
delete diff.type_;
return !!Object.getOwnPropertyNames(diff).length;
}

View File

@@ -196,17 +196,24 @@ class FileApiDriverOneDrive {
items: [],
};
const freshStartDelta = () => {
const url = this.makePath_(path) + ':/delta';
const query = this.itemFilter_();
query.select += ',deleted';
return { url: url, query: query };
}
const pathDetails = await this.pathDetails_(path);
const pathId = pathDetails.id;
const pathId = pathDetails.id;
let context = options ? options.context : null;
let url = context ? context.nextLink : null;
let query = null;
if (!url) {
url = this.makePath_(path) + ':/delta';
const query = this.itemFilter_();
query.select += ',deleted';
const info = freshStartDelta();
url = info.url;
query = info.query;
}
let response = null;
@@ -218,18 +225,18 @@ class FileApiDriverOneDrive {
// Code: resyncRequired
// Request: GET https://graph.microsoft.com/v1.0/drive/root:/Apps/JoplinDev:/delta?select=...
// The delta token has expired or is invalid and so a full resync is required.
// It is an error that is hard to replicate and it's not entirely clear what
// URL is in the Location header. What might happen is that:
// - OneDrive will get all the latest changes (since delta is done at the
// end of the sync process)
// - Client will get all the new files and updates from OneDrive
// This is unknown:
// - Will the files that have been deleted on OneDrive be part of the this
// URL in the Location header?
//
// The delta token has expired or is invalid and so a full resync is required. This happens for example when all the items
// on the OneDrive App folder are manually deleted. In this case, instead of sending the list of deleted items in the delta
// call, OneDrive simply request the client to re-sync everything.
// OneDrive provides a URL to resume syncing from but it does not appear to work so below we simply start over from
// the beginning. The synchronizer will ensure that no duplicate are created and conflicts will be resolved.
// More info there: https://stackoverflow.com/q/46941371/561309
url = error.headers.get('location');
const info = freshStartDelta();
url = info.url;
query = info.query;
response = await this.api_.execJson('GET', url, query);
} else {
throw error;

View File

@@ -174,6 +174,15 @@ class BaseItem extends BaseModel {
}
}
// Note: Currently, once a deleted_items entry has been processed, it is removed from the database. In practice it means that
// the following case will not work as expected:
// - Client 1 creates a note and sync with target 1 and 2
// - Client 2 sync with target 1
// - Client 2 deletes note and sync with target 1
// - Client 1 syncs with target 1 only (note is deleted from local machine, as expected)
// - Client 1 syncs with target 2 only => the note is *not* deleted from target 2 because no information
// that it was previously deleted exist (deleted_items entry has been deleted).
// The solution would be to permanently store the list of deleted items on each client.
static deletedItems(syncTarget) {
return this.db().selectAll('SELECT * FROM deleted_items WHERE sync_target = ?', [syncTarget]);
}
@@ -611,7 +620,7 @@ class BaseItem extends BaseModel {
SELECT id
FROM %s
WHERE encryption_applied = 0`,
this.db().escapeField(ItemClass.tableName()),
this.db().escapeField(ItemClass.tableName())
);
const items = await ItemClass.modelSelectAll(sql);

View File

@@ -69,8 +69,6 @@ class Note extends BaseItem {
}
static defaultTitle(note) {
if (note.title && note.title.length) return note.title;
if (note.body && note.body.length) {
const lines = note.body.trim().split("\n");
return lines[0].trim().substr(0, 80).trim();

View File

@@ -242,13 +242,15 @@ class Setting extends BaseModel {
if (md.type == Setting.TYPE_BOOL) return value ? '1' : '0';
if (md.type == Setting.TYPE_ARRAY) return value ? JSON.stringify(value) : '[]';
if (md.type == Setting.TYPE_OBJECT) return value ? JSON.stringify(value) : '{}';
return value;
if (md.type == Setting.TYPE_STRING) return value ? value + '' : '';
throw new Error('Unhandled value type: ' + md.type);
}
static formatValue(key, value) {
const md = this.settingMetadata(key);
if (md.type == Setting.TYPE_INT) return Math.floor(Number(value));
if (md.type == Setting.TYPE_INT) return !value ? 0 : Math.floor(Number(value));
if (md.type == Setting.TYPE_BOOL) {
if (typeof value === 'string') {
@@ -274,7 +276,12 @@ class Setting extends BaseModel {
return {};
}
return value;
if (md.type === Setting.TYPE_STRING) {
if (!value) return '';
return value + '';
}
throw new Error('Unhandled value type: ' + md.type);
}
static value(key) {
@@ -283,6 +290,7 @@ class Setting extends BaseModel {
// and object and change a key, the objects will be detected as equal. By returning a copy
// we avoid this problem.
function copyIfNeeded(value) {
if (value === null || value === undefined) return value;
if (Array.isArray(value)) return value.slice();
if (typeof value === 'object') return Object.assign({}, value);
return value;

View File

@@ -109,7 +109,7 @@ class Tag extends BaseItem {
for (let i = 0; i < tagTitles.length; i++) {
const title = tagTitles[i].trim().toLowerCase();
if (!title) continue;
let tag = await this.loadByField('title', title);
let tag = await this.loadByField('title', title, { caseInsensitive: true });
if (!tag) tag = await Tag.save({ title: title }, { userSideValidation: true });
await this.addNote(tag.id, noteId);
addedTitles.push(title);

View File

@@ -29,6 +29,7 @@ const defaultState = {
appState: 'starting',
//windowContentSize: { width: 0, height: 0 },
hasDisabledSyncItems: false,
newNote: null,
};
function arrayHasEncryptedItems(array) {
@@ -144,12 +145,14 @@ function changeSelectedNotes(state, action) {
if (action.type === 'NOTE_SELECT') {
newState.selectedNoteIds = noteIds;
newState.newNote = null;
return newState;
}
if (action.type === 'NOTE_SELECT_ADD') {
if (!noteIds.length) return state;
newState.selectedNoteIds = ArrayUtils.unique(newState.selectedNoteIds.concat(noteIds));
newState.newNote = null;
return newState;
}
@@ -164,6 +167,7 @@ function changeSelectedNotes(state, action) {
newSelectedNoteIds.push(id);
}
newState.selectedNoteIds = newSelectedNoteIds;
newState.newNote = null;
return newState;
}
@@ -177,6 +181,8 @@ function changeSelectedNotes(state, action) {
newState = changeSelectedNotes(state, { type: 'NOTE_SELECT_ADD', id: noteIds[0] });
}
newState.newNote = null;
return newState;
}
@@ -455,6 +461,12 @@ const reducer = (state = defaultState, action) => {
newState.hasDisabledSyncItems = true;
break;
case 'NOTE_SET_NEW_ONE':
newState = Object.assign({}, state);
newState.newNote = action.item;
break;
}
} catch (error) {
error.message = 'In reducer: ' + error.message + ' Action: ' + JSON.stringify(action);

View File

@@ -44,7 +44,7 @@ reg.syncTarget = (syncTargetId = null) => {
}
reg.scheduleSync = async (delay = null) => {
if (delay === null) delay = 1000 * 3;
if (delay === null) delay = 1000 * 30;
let promiseResolve = null;
const promise = new Promise((resolve, reject) => {
@@ -80,7 +80,17 @@ reg.scheduleSync = async (delay = null) => {
const contextKey = 'sync.' + syncTargetId + '.context';
let context = Setting.value(contextKey);
context = context ? JSON.parse(context) : {};
try {
context = context ? JSON.parse(context) : {};
} catch (error) {
// Clearing the context is inefficient since it means all items are going to be re-downloaded
// however it won't result in duplicate items since the synchroniser is going to compare each
// item to the current state.
reg.logger().warn('Could not parse JSON sync context ' + contextKey + ':', context);
reg.logger().info('Clearing context and starting from scratch');
context = null;
}
try {
reg.logger().info('Starting scheduled sync');
let newContext = await sync.start({ context: context });

View File

@@ -83,6 +83,7 @@ class DecryptionWorker {
});
continue;
}
this.logger().warn('DecryptionWorker: error for: ' + item.id + ' (' + ItemClass.tableName() + ')');
throw error;
}
}

View File

@@ -71,6 +71,7 @@ class Synchronizer {
if (report.updateRemote) lines.push(_('Updated remote items: %d.', report.updateRemote));
if (report.deleteLocal) lines.push(_('Deleted local items: %d.', report.deleteLocal));
if (report.deleteRemote) lines.push(_('Deleted remote items: %d.', report.deleteRemote));
if (report.fetchingTotal && report.fetchingProcessed) lines.push(_('Fetched items: %d/%d.', report.fetchingProcessed, report.fetchingTotal));
if (!report.completedTime && report.state) lines.push(_('State: "%s".', report.state));
if (report.cancelling && !report.completedTime) lines.push(_('Cancelling...'));
if (report.completedTime) lines.push(_('Completed: %s', time.unixMsToLocalDateTime(report.completedTime)));
@@ -78,7 +79,7 @@ class Synchronizer {
return lines;
}
logSyncOperation(action, local = null, remote = null, message = null) {
logSyncOperation(action, local = null, remote = null, message = null, actionCount = 1) {
let line = ['Sync'];
line.push(action);
if (message) line.push(message);
@@ -105,7 +106,7 @@ class Synchronizer {
this.logger().debug(line.join(': '));
if (!this.progressReport_[action]) this.progressReport_[action] = 0;
this.progressReport_[action]++;
this.progressReport_[action] += actionCount;
this.progressReport_.state = this.state();
this.onProgress_(this.progressReport_);
@@ -166,7 +167,6 @@ class Synchronizer {
let error = new Error(_('Synchronisation is already in progress. State: %s', this.state()));
error.code = 'alreadyStarted';
throw error;
return;
}
this.state_ = 'in_progress';
@@ -321,9 +321,23 @@ class Synchronizer {
}
}
// Note: Currently, we set sync_time to update_time, which should work fine given that the resolution is the millisecond.
// In theory though, this could happen:
//
// 1. t0: Editor: Note is modified
// 2. t0: Sync: Found that note was modified so start uploading it
// 3. t0: Editor: Note is modified again
// 4. t1: Sync: Note has finished uploading, set sync_time to t0
//
// Later any attempt to sync will not detect that note was modified in (3) (within the same millisecond as it was being uploaded)
// because sync_time will be t0 too.
//
// The solution would be to use something like an etag (a simple counter incremented on every change) to make sure each
// change is uniquely identified. Leaving it like this for now.
if (canSync) {
await this.api().setTimestamp(path, local.updated_time);
await ItemClass.saveSyncTime(syncTargetId, local, time.unixMs());
await ItemClass.saveSyncTime(syncTargetId, local, local.updated_time);
}
} else if (action == 'itemConflict') {
@@ -433,12 +447,17 @@ class Synchronizer {
});
let remotes = listResult.items;
this.logSyncOperation('fetchingTotal', null, null, 'Fetching delta items from sync target', remotes.length);
for (let i = 0; i < remotes.length; i++) {
if (this.cancelling() || this.debugFlags_.indexOf('cancelDeltaLoop2') >= 0) {
hasCancelled = true;
break;
}
this.logSyncOperation('fetchingProcessed', null, null, 'Processing fetched item');
let remote = remotes[i];
if (!BaseItem.isSystemPath(remote.path)) continue; // The delta API might return things like the .sync, .resource or the root folder
@@ -566,7 +585,7 @@ class Synchronizer {
if (noteIds.length) { // CONFLICT
await Folder.markNotesAsConflict(item.id);
}
await Folder.delete(item.id, { deleteChildren: false });
await Folder.delete(item.id, { deleteChildren: false, trackDeleted: false });
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -97,6 +97,10 @@ const generalMiddleware = store => next => async (action) => {
type: 'MASTERKEY_REMOVE_NOT_LOADED',
ids: loadedMasterKeyIds,
});
// Schedule a sync operation so that items that need to be encrypted
// are sent to sync target.
reg.scheduleSync();
}
if (action.type == 'NAV_GO' && action.routeName == 'Notes') {

View File

@@ -28,7 +28,7 @@ toolUtils.downloadFile = function(url, targetPath) {
if (response.statusCode !== 200) reject(new Error('HTTP error ' + response.statusCode));
response.pipe(file);
file.on('finish', function() {
file.close();
//file.close();
resolve();
});
}).on('error', (error) => {

View File

@@ -0,0 +1,14 @@
<!--
# Adding new features
If you want to add a new feature, consider asking about it before implementing it to
make sure it is within the scope of the project. Of course you are free to create the
pull request directly but it is not guaranteed it is going to be accepted.
# Style
- Only use tabs for indentation, not spaces.
- Do not remove or add optional characters from other lines (such as colons or new line
characters) as it can make the commit needlessly big, and create conflicts with other
changes.
-->

View File

@@ -218,15 +218,15 @@
<tbody>
<tr>
<td>Windows</td>
<td><a href='https://github.com/laurent22/joplin/releases/download/v0.10.40/Joplin-Setup-0.10.40.exe'><img alt='Get it on Windows' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/BadgeWindows.png'/></a></td>
<td><a href='https://github.com/laurent22/joplin/releases/download/v0.10.43/Joplin-Setup-0.10.43.exe'><img alt='Get it on Windows' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/BadgeWindows.png'/></a></td>
</tr>
<tr>
<td>macOS</td>
<td><a href='https://github.com/laurent22/joplin/releases/download/v0.10.40/Joplin-0.10.40.dmg'><img alt='Get it on macOS' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/BadgeMacOS.png'/></a></td>
<td><a href='https://github.com/laurent22/joplin/releases/download/v0.10.43/Joplin-0.10.43.dmg'><img alt='Get it on macOS' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/BadgeMacOS.png'/></a></td>
</tr>
<tr>
<td>Linux</td>
<td><a href='https://github.com/laurent22/joplin/releases/download/v0.10.40/Joplin-0.10.40-x86_64.AppImage'><img alt='Get it on macOS' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/BadgeLinux.png'/></a></td>
<td><a href='https://github.com/laurent22/joplin/releases/download/v0.10.43/Joplin-0.10.43-x86_64.AppImage'><img alt='Get it on macOS' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/BadgeLinux.png'/></a></td>
</tr>
</tbody>
</table>
@@ -317,6 +317,8 @@ sudo ln -s ~/.joplin-bin/bin/joplin /usr/bin/joplin
<li>From then you can translate the file. Once it is done, please either <a href="https://github.com/laurent22/joplin/pulls">open a pull request</a> or send the file to <a href="https://raw.githubusercontent.com/laurent22/joplin/master/Assets/Adresse.png">this address</a>.</li>
</ul>
<p>This translation will apply to the three applications - desktop, mobile and terminal.</p>
<h1 id="contributing">Contributing</h1>
<p>Please see the guide for information on how to contribute to the development of Joplin: <a href="https://github.com/laurent22/joplin/blob/master/CONTRIBUTING.md">https://github.com/laurent22/joplin/blob/master/CONTRIBUTING.md</a></p>
<h1 id="coming-features">Coming features</h1>
<ul>
<li>NextCloud support</li>