From dbb5599b0fd8e9cb5ed0071e3e1b1658c3c77d33 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Tue, 14 Nov 2017 18:02:58 +0000 Subject: [PATCH] Save window state --- CliClient/locales/en_GB.po | 6 +- CliClient/locales/fr_FR.po | 7 +- CliClient/locales/joplin.pot | 6 +- ElectronClient/app/ElectronAppWrapper.js | 20 +++- ElectronClient/app/app.js | 32 ++++-- ElectronClient/app/bridge.js | 11 ++ ElectronClient/app/gui/NoteList.jsx | 4 +- ElectronClient/app/gui/NoteList.min.js | 4 +- ElectronClient/app/gui/Root.jsx | 6 +- ElectronClient/app/gui/Root.min.js | 6 +- ElectronClient/app/lib/models/setting.js | 13 ++- ElectronClient/app/lib/shim.js | 126 +++++++++++++---------- ElectronClient/app/locales/en_GB.json | 2 +- ElectronClient/app/locales/fr_FR.json | 2 +- ElectronClient/app/package-lock.json | 27 ++++- ElectronClient/app/package.json | 1 + ReactNativeClient/lib/models/setting.js | 13 ++- ReactNativeClient/lib/shim.js | 126 +++++++++++++---------- linkToLocal.sh | 6 ++ 19 files changed, 275 insertions(+), 143 deletions(-) create mode 100644 linkToLocal.sh diff --git a/CliClient/locales/en_GB.po b/CliClient/locales/en_GB.po index 253db9f94..4cc900fb5 100644 --- a/CliClient/locales/en_GB.po +++ b/CliClient/locales/en_GB.po @@ -499,12 +499,16 @@ msgstr "" msgid "Help" msgstr "" -msgid "Documentation" +msgid "Website and documentation" msgstr "" msgid "About Joplin" msgstr "" +#, javascript-format +msgid "%s %s (%s, %s)" +msgstr "" + msgid "OK" msgstr "" diff --git a/CliClient/locales/fr_FR.po b/CliClient/locales/fr_FR.po index 0917b7e7f..b223aacbe 100644 --- a/CliClient/locales/fr_FR.po +++ b/CliClient/locales/fr_FR.po @@ -550,12 +550,17 @@ msgstr "Options" msgid "Help" msgstr "Aide" -msgid "Documentation" +#, fuzzy +msgid "Website and documentation" msgstr "Documentation" msgid "About Joplin" msgstr "A props de Joplin" +#, fuzzy, javascript-format +msgid "%s %s (%s, %s)" +msgstr "%s %s (%s)" + msgid "OK" msgstr "OK" diff --git a/CliClient/locales/joplin.pot b/CliClient/locales/joplin.pot index 253db9f94..4cc900fb5 100644 --- a/CliClient/locales/joplin.pot +++ b/CliClient/locales/joplin.pot @@ -499,12 +499,16 @@ msgstr "" msgid "Help" msgstr "" -msgid "Documentation" +msgid "Website and documentation" msgstr "" msgid "About Joplin" msgstr "" +#, javascript-format +msgid "%s %s (%s, %s)" +msgstr "" + msgid "OK" msgstr "" diff --git a/ElectronClient/app/ElectronAppWrapper.js b/ElectronClient/app/ElectronAppWrapper.js index 7527d9430..de75a4e3e 100644 --- a/ElectronClient/app/ElectronAppWrapper.js +++ b/ElectronClient/app/ElectronAppWrapper.js @@ -29,7 +29,20 @@ class ElectronAppWrapper { } createWindow() { - this.win_ = new BrowserWindow({width: 800, height: 600}) + const windowStateKeeper = require('electron-window-state'); + + // Load the previous state with fallback to defaults + const windowState = windowStateKeeper({ + defaultWidth: 800, + defaultHeight: 600, + }); + + this.win_ = new BrowserWindow({ + 'x': windowState.x, + 'y': windowState.y, + 'width': windowState.width, + 'height': windowState.height + }) this.win_.loadURL(url.format({ pathname: path.join(__dirname, 'index.html'), @@ -42,6 +55,11 @@ class ElectronAppWrapper { this.win_.on('closed', () => { this.win_ = null }) + + // Let us register listeners on the window, so we can update the state + // automatically (the listeners will be removed when the window is closed) + // and restore the maximized or full screen state + windowState.manage(this.win_); } async waitForElectronAppReady() { diff --git a/ElectronClient/app/app.js b/ElectronClient/app/app.js index a4d3c8d47..4ae3e1d36 100644 --- a/ElectronClient/app/app.js +++ b/ElectronClient/app/app.js @@ -3,6 +3,7 @@ require('app-module-path').addPath(__dirname); const { BaseApplication } = require('lib/BaseApplication'); const { FoldersScreenUtils } = require('lib/folders-screen-utils.js'); const { Setting } = require('lib/models/setting.js'); +const { shim } = require('lib/shim.js'); const { BaseModel } = require('lib/base-model.js'); const { _, setLocale } = require('lib/locale.js'); const os = require('os'); @@ -30,6 +31,7 @@ const appDefaultState = Object.assign({}, defaultState, { fileToImport: null, windowCommand: null, noteVisiblePanes: ['editor', 'viewer'], + windowContentSize: bridge().windowContentSize(), }); class Application extends BaseApplication { @@ -231,7 +233,7 @@ class Application extends BaseApplication { }, { label: _('Help'), submenu: [{ - label: _('Documentation'), + label: _('Website and documentation'), accelerator: 'F1', click () { bridge().openExternal('http://joplin.cozic.net') } }, { @@ -242,7 +244,7 @@ class Application extends BaseApplication { p.description, '', 'Copyright © 2016-2017', - _('%s %s (%s)', p.name, p.version, Setting.value('env')), + _('%s %s (%s, %s)', p.name, p.version, Setting.value('env'), process.platform), ]; bridge().showMessageBox({ message: message.join('\n'), @@ -278,6 +280,16 @@ class Application extends BaseApplication { this.initRedux(); + // const windowSize = Setting.value('windowSize'); + // const width = windowSize && windowSize.width ? windowSize.width : 800; + // const height = windowSize && windowSize.height ? windowSize.height : 800; + // bridge().windowSetSize(width, height); + + // this.store().dispatch({ + // type: 'WINDOW_CONTENT_SIZE_SET', + // size: bridge().windowContentSize(), + // }); + // Since the settings need to be loaded before the store is created, it will never // receive the SETTING_UPDATE_ALL even, which mean state.settings will not be // initialised. So we manually call dispatchUpdateAll() to force an update. @@ -297,13 +309,17 @@ class Application extends BaseApplication { id: Setting.value('activeFolderId'), }); - const runAutoUpdateCheck = function() { - bridge().checkForUpdatesAndNotify(Setting.value('profileDir') + '/log-autoupdater.txt'); + // Note: Auto-update currently doesn't work in Linux: it downloads the update + // but then doesn't install it on exit. + if (shim.isWindows() || shim.isMac()) { + const runAutoUpdateCheck = function() { + bridge().checkForUpdatesAndNotify(Setting.value('profileDir') + '/log-autoupdater.txt'); + } + + setTimeout(() => { runAutoUpdateCheck() }, 5000); + // For those who leave the app always open + setInterval(() => { runAutoUpdateCheck() }, 2 * 60 * 60 * 1000); } - - setTimeout(() => { runAutoUpdateCheck() }, 5000); - // For those who leave the app always open - setInterval(() => { runAutoUpdateCheck() }, 2 * 60 * 60 * 1000); } } diff --git a/ElectronClient/app/bridge.js b/ElectronClient/app/bridge.js index fe6672ca2..6dd5b356d 100644 --- a/ElectronClient/app/bridge.js +++ b/ElectronClient/app/bridge.js @@ -25,6 +25,17 @@ class Bridge { return { width: s[0], height: s[1] }; } + windowSize() { + if (!this.window()) return { width: 0, height: 0 }; + const s = this.window().getSize(); + return { width: s[0], height: s[1] }; + } + + windowSetSize(width, height) { + if (!this.window()) return; + return this.window().setSize(width, height); + } + showOpenDialog(options) { const {dialog} = require('electron'); return dialog.showOpenDialog(options); diff --git a/ElectronClient/app/gui/NoteList.jsx b/ElectronClient/app/gui/NoteList.jsx index edde65824..5266b1f40 100644 --- a/ElectronClient/app/gui/NoteList.jsx +++ b/ElectronClient/app/gui/NoteList.jsx @@ -113,7 +113,9 @@ class NoteListComponent extends React.Component { listItemTitleStyle.paddingLeft = !checkbox ? hPadding : 4; if (item.is_todo && !!item.todo_completed) listItemTitleStyle = Object.assign(listItemTitleStyle, this.style().listItemTitleCompleted); - return
+ // Need to include "todo_completed" in key so that checkbox is updated when + // item is changed via sync. + return
{checkbox} ' + value); - c.value = this.formatValue(key, value); + c.value = value; this.dispatch({ type: 'SETTING_UPDATE_ONE', @@ -143,6 +143,7 @@ class Setting extends BaseModel { if (md.type == Setting.TYPE_INT) return value.toFixed(0); 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; } @@ -162,11 +163,19 @@ class Setting extends BaseModel { } if (md.type === Setting.TYPE_ARRAY) { + if (!value) return []; if (Array.isArray(value)) return value; if (typeof value === 'string') return JSON.parse(value); return []; } + if (md.type === Setting.TYPE_OBJECT) { + if (!value) return {}; + if (typeof value === 'object') return value; + if (typeof value === 'string') return JSON.parse(value); + return {}; + } + return value; } @@ -308,6 +317,7 @@ class Setting extends BaseModel { if (typeId === Setting.TYPE_STRING) return 'string'; if (typeId === Setting.TYPE_BOOL) return 'bool'; if (typeId === Setting.TYPE_ARRAY) return 'array'; + if (typeId === Setting.TYPE_OBJECT) return 'object'; } } @@ -320,6 +330,7 @@ Setting.TYPE_INT = 1; Setting.TYPE_STRING = 2; Setting.TYPE_BOOL = 3; Setting.TYPE_ARRAY = 4; +Setting.TYPE_OBJECT = 5; Setting.THEME_LIGHT = 1; Setting.THEME_DARK = 2; diff --git a/ElectronClient/app/lib/shim.js b/ElectronClient/app/lib/shim.js index f24c9357e..322d0acf7 100644 --- a/ElectronClient/app/lib/shim.js +++ b/ElectronClient/app/lib/shim.js @@ -10,86 +10,98 @@ shim.isReactNative = () => { return !shim.isNode(); }; +shim.isLinux = () => { + return process && process.platform === 'linux'; +} + +shim.isWindows = () => { + return process && process.platform === 'win32'; +} + +shim.isMac = () => { + return process && process.platform === 'darwin'; +} + // https://github.com/cheton/is-electron shim.isElectron = () => { - // Renderer process - if (typeof window !== 'undefined' && typeof window.process === 'object' && window.process.type === 'renderer') { - return true; - } + // Renderer process + if (typeof window !== 'undefined' && typeof window.process === 'object' && window.process.type === 'renderer') { + return true; + } - // Main process - if (typeof process !== 'undefined' && typeof process.versions === 'object' && !!process.versions.electron) { - return true; - } + // Main process + if (typeof process !== 'undefined' && typeof process.versions === 'object' && !!process.versions.electron) { + return true; + } - // Detect the user agent when the `nodeIntegration` option is set to true - if (typeof navigator === 'object' && typeof navigator.userAgent === 'string' && navigator.userAgent.indexOf('Electron') >= 0) { - return true; - } + // Detect the user agent when the `nodeIntegration` option is set to true + if (typeof navigator === 'object' && typeof navigator.userAgent === 'string' && navigator.userAgent.indexOf('Electron') >= 0) { + return true; + } - return false; + return false; } // Node requests can go wrong is so many different ways and with so // many different error messages... This handler inspects the error // and decides whether the request can safely be repeated or not. function fetchRequestCanBeRetried(error) { - if (!error) return false; + if (!error) return false; - // Unfortunately the error 'Network request failed' doesn't have a type - // or error code, so hopefully that message won't change and is not localized - if (error.message == 'Network request failed') return true; + // Unfortunately the error 'Network request failed' doesn't have a type + // or error code, so hopefully that message won't change and is not localized + if (error.message == 'Network request failed') return true; - // request to https://public-ch3302....1fab24cb1bd5f.md failed, reason: socket hang up" - if (error.code == 'ECONNRESET') return true; + // request to https://public-ch3302....1fab24cb1bd5f.md failed, reason: socket hang up" + if (error.code == 'ECONNRESET') return true; - // OneDrive (or Node?) sometimes sends back a "not found" error for resources - // that definitely exist and in this case repeating the request works. - // Error is: - // request to https://graph.microsoft.com/v1.0/drive/special/approot failed, reason: getaddrinfo ENOTFOUND graph.microsoft.com graph.microsoft.com:443 - if (error.code == 'ENOTFOUND') return true; + // OneDrive (or Node?) sometimes sends back a "not found" error for resources + // that definitely exist and in this case repeating the request works. + // Error is: + // request to https://graph.microsoft.com/v1.0/drive/special/approot failed, reason: getaddrinfo ENOTFOUND graph.microsoft.com graph.microsoft.com:443 + if (error.code == 'ENOTFOUND') return true; - // network timeout at: https://public-ch3302...859f9b0e3ab.md - if (error.message && error.message.indexOf('network timeout') === 0) return true; + // network timeout at: https://public-ch3302...859f9b0e3ab.md + if (error.message && error.message.indexOf('network timeout') === 0) return true; - // name: 'FetchError', - // message: 'request to https://api.ipify.org/?format=json failed, reason: getaddrinfo EAI_AGAIN api.ipify.org:443', - // type: 'system', - // errno: 'EAI_AGAIN', - // code: 'EAI_AGAIN' } } reason: { FetchError: request to https://api.ipify.org/?format=json failed, reason: getaddrinfo EAI_AGAIN api.ipify.org:443 - // - // It's a Microsoft error: "A temporary failure in name resolution occurred." - if (error.code == 'EAI_AGAIN') return true; + // name: 'FetchError', + // message: 'request to https://api.ipify.org/?format=json failed, reason: getaddrinfo EAI_AGAIN api.ipify.org:443', + // type: 'system', + // errno: 'EAI_AGAIN', + // code: 'EAI_AGAIN' } } reason: { FetchError: request to https://api.ipify.org/?format=json failed, reason: getaddrinfo EAI_AGAIN api.ipify.org:443 + // + // It's a Microsoft error: "A temporary failure in name resolution occurred." + if (error.code == 'EAI_AGAIN') return true; - // request to https://public-...8fd8bc6bb68e9c4d17a.md failed, reason: connect ETIMEDOUT 204.79.197.213:443 - // Code: ETIMEDOUT - if (error.code === 'ETIMEDOUT') return true; + // request to https://public-...8fd8bc6bb68e9c4d17a.md failed, reason: connect ETIMEDOUT 204.79.197.213:443 + // Code: ETIMEDOUT + if (error.code === 'ETIMEDOUT') return true; - return false; + return false; } shim.fetchWithRetry = async function(fetchFn, options = null) { - const { time } = require('lib/time-utils.js'); + const { time } = require('lib/time-utils.js'); - if (!options) options = {}; - if (!options.timeout) options.timeout = 1000 * 120; // ms - if (!('maxRetry' in options)) options.maxRetry = 5; + if (!options) options = {}; + if (!options.timeout) options.timeout = 1000 * 120; // ms + if (!('maxRetry' in options)) options.maxRetry = 5; - let retryCount = 0; - while (true) { - try { - const response = await fetchFn(); - return response; - } catch (error) { - if (fetchRequestCanBeRetried(error)) { - retryCount++; - if (retryCount > options.maxRetry) throw error; - await time.sleep(retryCount * 3); - } else { - throw error; - } - } - } + let retryCount = 0; + while (true) { + try { + const response = await fetchFn(); + return response; + } catch (error) { + if (fetchRequestCanBeRetried(error)) { + retryCount++; + if (retryCount > options.maxRetry) throw error; + await time.sleep(retryCount * 3); + } else { + throw error; + } + } + } } shim.nativeFetch_ = typeof fetch !== 'undefined' ? fetch : null; diff --git a/ElectronClient/app/locales/en_GB.json b/ElectronClient/app/locales/en_GB.json index 7300fcbcf..41a5aa7a6 100644 --- a/ElectronClient/app/locales/en_GB.json +++ b/ElectronClient/app/locales/en_GB.json @@ -1 +1 @@ -{"Give focus to next pane":"","Give focus to previous pane":"","Enter command line mode":"","Exit command line mode":"","Edit the selected note":"","Cancel the current command.":"","Exit the application.":"","Delete the currently selected note or notebook.":"","To delete a tag, untag the associated notes.":"","Please select the note or notebook to be deleted first.":"","Set a to-do as completed / not completed":"","[t]oggle [c]onsole between maximized/minimized/hidden/visible.":"","Search":"","[t]oggle note [m]etadata.":"","[M]ake a new [n]ote":"","[M]ake a new [t]odo":"","[M]ake a new note[b]ook":"","Copy ([Y]ank) the [n]ote to a notebook.":"","Move the note to a notebook.":"","Press Ctrl+D or type \"exit\" to exit the application":"","More than one item match \"%s\". Please narrow down your query.":"","No notebook selected.":"","No notebook has been specified.":"","Y":"","n":"","N":"","y":"","Cancelling background synchronisation... Please wait.":"","The command \"%s\" is only available in GUI mode":"","Missing required argument: %s":"","%s: %s":"","Your choice: ":"","Invalid answer: %s":"","Attaches the given file to the note.":"","Cannot find \"%s\".":"","Displays the given note.":"","Displays the complete information about note.":"","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"","Also displays unset and hidden config variables.":"","%s = %s (%s)":"","%s = %s":"","Duplicates the notes matching to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"","Marks a to-do as done.":"","Note is not a to-do: \"%s\"":"","Edit note.":"","No text editor is defined. Please set it using `config editor `":"","No active notebook.":"","Note does not exist: \"%s\". Create it?":"","Starting to edit note. Close the editor to get back to the prompt.":"","Note has been saved.":"","Exits the application.":"","Exports Joplin data to the given directory. By default, it will export the complete database including notebooks, notes, tags and resources.":"","Exports only the given note.":"","Exports only the given notebook.":"","Displays a geolocation URL for the note.":"","Displays usage information.":"","Shortcuts are not available in CLI mode.":"","Type `help [command]` for more information about a command.":"","The possible commands are:":"","In any command, a note or notebook can be refered to by title or ID, or using the shortcuts `$n` or `$b` for, respectively, the currently selected note or notebook. `$c` can be used to refer to the currently selected item.":"","To move from one pane to another, press Tab or Shift+Tab.":"","Use the arrows and page up/down to scroll the lists and text areas (including this console).":"","To maximise/minimise the console, press \"TC\".":"","To enter command line mode, press \":\"":"","To exit command line mode, press ESCAPE":"","For the complete list of available keyboard shortcuts, type `help shortcuts`":"","Imports an Evernote notebook file (.enex file).":"","Do not ask for confirmation.":"","File \"%s\" will be imported into existing notebook \"%s\". Continue?":"","New notebook \"%s\" will be created and file \"%s\" will be imported into it. Continue?":"","Found: %d.":"","Created: %d.":"","Updated: %d.":"","Skipped: %d.":"","Resources: %d.":"","Tagged: %d.":"","Importing notes...":"","The notes have been imported: %s":"","Displays the notes in the current notebook. Use `ls /` to display the list of notebooks.":"","Displays only the first top notes.":"","Sorts the item by (eg. title, updated_time, created_time).":"","Reverses the sorting order.":"","Displays only the items of the specific type(s). Can be `n` for notes, `t` for to-dos, or `nt` for notes and to-dos (eg. `-tt` would display only the to-dos, while `-ttd` would display notes and to-dos.":"","Either \"text\" or \"json\"":"","Use long list format. Format is ID, NOTE_COUNT (for notebook), DATE, TODO_CHECKED (for to-dos), TITLE":"","Please select a notebook first.":"","Creates a new notebook.":"","Creates a new note.":"","Notes can only be created within a notebook.":"","Creates a new to-do.":"","Moves the notes matching to [notebook].":"","Renames the given (note or notebook) to .":"","Deletes the given notebook.":"","Deletes the notebook without asking for confirmation.":"","Delete notebook \"%s\"?":"","Deletes the notes matching .":"","Deletes the notes without asking for confirmation.":"","%d notes match this pattern. Delete them?":"","Delete note?":"","Searches for the given in all the notes.":"","Sets the property of the given to the given [value].":"","Displays summary about the notes and notebooks.":"","Synchronises with remote storage.":"","Sync to provided target (defaults to sync.target config value)":"","Synchronisation is already in progress.":"","Lock file is already being hold. If you know that no synchronisation is taking place, you may delete the lock file at \"%s\" and resume the operation.":"","Authentication was not completed (did not receive an authentication token).":"","Synchronisation target: %s (%s)":"","Cannot initialize synchroniser.":"","Starting synchronisation...":"","Cancelling... Please wait.":""," can be \"add\", \"remove\" or \"list\" to assign or remove [tag] from [note], or to list the notes associated with [tag]. The command `tag list` can be used to list all the tags.":"","Invalid command: \"%s\"":""," can either be \"toggle\" or \"clear\". Use \"toggle\" to toggle the given to-do between completed and uncompleted state (If the target is a regular note it will be converted to a to-do). Use \"clear\" to convert the to-do back to a regular note.":"","Marks a to-do as non-completed.":"","Switches to [notebook] - all further operations will happen within this notebook.":"","Displays version information":"","%s %s (%s)":"","Enum":"","Type: %s.":"","Possible values: %s.":"","Default: %s":"","Possible keys/values:":"","Fatal error:":"","The application has been authorised - you may now close this browser tab.":"","The application has been successfully authorised.":"","Please open the following URL in your browser to authenticate the application. The application will create a directory in \"Apps/Joplin\" and will only read and write files in this directory. It will have no access to any files outside this directory nor to any other personal data. No data will be shared with any third party.":"","Search:":"","File":"","New note":"","New to-do":"","New notebook":"","Import Evernote notes":"","Evernote Export Files":"","Quit":"","Tools":"","Options":"","Help":"","Documentation":"","About Joplin":"","OK":"","Cancel":"","Back":"","New notebook \"%s\" will be created and file \"%s\" will be imported into it":"","Please create a notebook first.":"","Note title:":"","Please create a notebook first":"","To-do title:":"","Notebook title:":"","Add or remove tags:":"","Separate each tag by a comma.":"","Layout":"","Add or remove tags":"","Switch between note and to-do":"","Delete":"","No notes in here. Create one by clicking on \"New note\".":"","Unsupported link or message: %s":"","Attach file":"","Refresh":"","OneDrive Login":"","Import":"","Configuration":"","Delete notebook?":"","Remove this tag from all the notes?":"","Notebooks":"","Tags":"","Synchronise":"","Usage: %s":"","Unknown flag: %s":"","Unknown log level: %s":"","Unknown level ID: %s":"","Cannot refresh token: authentication data is missing. Starting the synchronisation again may fix the problem.":"","Please set the \"sync.2.path\" config value to the desired synchronisation destination.":"","Cannot access %s":"","Created local items: %d.":"","Updated local items: %d.":"","Created remote items: %d.":"","Updated remote items: %d.":"","Deleted local items: %d.":"","Deleted remote items: %d.":"","State: \"%s\".":"","Cancelling...":"","Completed: %s":"","Synchronisation is already in progress. State: %s":"","Conflicts":"","A notebook with this title already exists: \"%s\"":"","Notebooks cannot be named \"%s\", which is a reserved title.":"","Untitled":"","This note does not have geolocation information.":"","Cannot copy note to \"%s\" notebook":"","Cannot move note to \"%s\" notebook":"","Invalid option value: \"%s\". Possible values are: %s.":"","File system synchronisation target directory":"","The path to synchronise with when file system synchronisation is enabled. See `sync.target`.":"","Synchronisation target":"","The target to synchonise to. If synchronising with the file system, set `sync.2.path` to specify the target directory.":"","File system":"","OneDrive":"","Text editor":"","The editor that will be used to open a note. If none is provided it will try to auto-detect the default editor.":"","Language":"","Theme":"","Light":"","Dark":"","Show uncompleted todos on top of the lists":"","Save geo-location with notes":"","Synchronisation interval":"","Disabled":"","%d minutes":"","%d hour":"","%d hours":"","Show advanced options":"","Sync status (synced items / total items)":"","%s: %d/%d":"","Total: %d/%d":"","Conflicted: %d":"","To delete: %d":"","Folders":"","%s: %d notes":"","There are currently no notes. Create one by clicking on the (+) button.":"","Log":"","Status":"","Cancel synchronisation":"","The notebook could not be saved: %s":"","Edit notebook":"","This note has been modified:":"","Save changes":"","Discard changes":"","Delete note":"","Convert to regular note":"","Convert to todo":"","Hide metadata":"","Show metadata":"","View location on map":"","Edit":"","Delete notebook":"","Login with OneDrive":"","Click on the (+) button to create a new note or notebook. Click on the side menu to access your existing notebooks.":"","You currently have no notebook. Create one by clicking on (+) button.":"","Welcome":""} \ No newline at end of file +{"Give focus to next pane":"","Give focus to previous pane":"","Enter command line mode":"","Exit command line mode":"","Edit the selected note":"","Cancel the current command.":"","Exit the application.":"","Delete the currently selected note or notebook.":"","To delete a tag, untag the associated notes.":"","Please select the note or notebook to be deleted first.":"","Set a to-do as completed / not completed":"","[t]oggle [c]onsole between maximized/minimized/hidden/visible.":"","Search":"","[t]oggle note [m]etadata.":"","[M]ake a new [n]ote":"","[M]ake a new [t]odo":"","[M]ake a new note[b]ook":"","Copy ([Y]ank) the [n]ote to a notebook.":"","Move the note to a notebook.":"","Press Ctrl+D or type \"exit\" to exit the application":"","More than one item match \"%s\". Please narrow down your query.":"","No notebook selected.":"","No notebook has been specified.":"","Y":"","n":"","N":"","y":"","Cancelling background synchronisation... Please wait.":"","The command \"%s\" is only available in GUI mode":"","Missing required argument: %s":"","%s: %s":"","Your choice: ":"","Invalid answer: %s":"","Attaches the given file to the note.":"","Cannot find \"%s\".":"","Displays the given note.":"","Displays the complete information about note.":"","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"","Also displays unset and hidden config variables.":"","%s = %s (%s)":"","%s = %s":"","Duplicates the notes matching to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"","Marks a to-do as done.":"","Note is not a to-do: \"%s\"":"","Edit note.":"","No text editor is defined. Please set it using `config editor `":"","No active notebook.":"","Note does not exist: \"%s\". Create it?":"","Starting to edit note. Close the editor to get back to the prompt.":"","Note has been saved.":"","Exits the application.":"","Exports Joplin data to the given directory. By default, it will export the complete database including notebooks, notes, tags and resources.":"","Exports only the given note.":"","Exports only the given notebook.":"","Displays a geolocation URL for the note.":"","Displays usage information.":"","Shortcuts are not available in CLI mode.":"","Type `help [command]` for more information about a command.":"","The possible commands are:":"","In any command, a note or notebook can be refered to by title or ID, or using the shortcuts `$n` or `$b` for, respectively, the currently selected note or notebook. `$c` can be used to refer to the currently selected item.":"","To move from one pane to another, press Tab or Shift+Tab.":"","Use the arrows and page up/down to scroll the lists and text areas (including this console).":"","To maximise/minimise the console, press \"TC\".":"","To enter command line mode, press \":\"":"","To exit command line mode, press ESCAPE":"","For the complete list of available keyboard shortcuts, type `help shortcuts`":"","Imports an Evernote notebook file (.enex file).":"","Do not ask for confirmation.":"","File \"%s\" will be imported into existing notebook \"%s\". Continue?":"","New notebook \"%s\" will be created and file \"%s\" will be imported into it. Continue?":"","Found: %d.":"","Created: %d.":"","Updated: %d.":"","Skipped: %d.":"","Resources: %d.":"","Tagged: %d.":"","Importing notes...":"","The notes have been imported: %s":"","Displays the notes in the current notebook. Use `ls /` to display the list of notebooks.":"","Displays only the first top notes.":"","Sorts the item by (eg. title, updated_time, created_time).":"","Reverses the sorting order.":"","Displays only the items of the specific type(s). Can be `n` for notes, `t` for to-dos, or `nt` for notes and to-dos (eg. `-tt` would display only the to-dos, while `-ttd` would display notes and to-dos.":"","Either \"text\" or \"json\"":"","Use long list format. Format is ID, NOTE_COUNT (for notebook), DATE, TODO_CHECKED (for to-dos), TITLE":"","Please select a notebook first.":"","Creates a new notebook.":"","Creates a new note.":"","Notes can only be created within a notebook.":"","Creates a new to-do.":"","Moves the notes matching to [notebook].":"","Renames the given (note or notebook) to .":"","Deletes the given notebook.":"","Deletes the notebook without asking for confirmation.":"","Delete notebook \"%s\"?":"","Deletes the notes matching .":"","Deletes the notes without asking for confirmation.":"","%d notes match this pattern. Delete them?":"","Delete note?":"","Searches for the given in all the notes.":"","Sets the property of the given to the given [value].":"","Displays summary about the notes and notebooks.":"","Synchronises with remote storage.":"","Sync to provided target (defaults to sync.target config value)":"","Synchronisation is already in progress.":"","Lock file is already being hold. If you know that no synchronisation is taking place, you may delete the lock file at \"%s\" and resume the operation.":"","Authentication was not completed (did not receive an authentication token).":"","Synchronisation target: %s (%s)":"","Cannot initialize synchroniser.":"","Starting synchronisation...":"","Cancelling... Please wait.":""," can be \"add\", \"remove\" or \"list\" to assign or remove [tag] from [note], or to list the notes associated with [tag]. The command `tag list` can be used to list all the tags.":"","Invalid command: \"%s\"":""," can either be \"toggle\" or \"clear\". Use \"toggle\" to toggle the given to-do between completed and uncompleted state (If the target is a regular note it will be converted to a to-do). Use \"clear\" to convert the to-do back to a regular note.":"","Marks a to-do as non-completed.":"","Switches to [notebook] - all further operations will happen within this notebook.":"","Displays version information":"","%s %s (%s)":"","Enum":"","Type: %s.":"","Possible values: %s.":"","Default: %s":"","Possible keys/values:":"","Fatal error:":"","The application has been authorised - you may now close this browser tab.":"","The application has been successfully authorised.":"","Please open the following URL in your browser to authenticate the application. The application will create a directory in \"Apps/Joplin\" and will only read and write files in this directory. It will have no access to any files outside this directory nor to any other personal data. No data will be shared with any third party.":"","Search:":"","File":"","New note":"","New to-do":"","New notebook":"","Import Evernote notes":"","Evernote Export Files":"","Quit":"","Tools":"","Options":"","Help":"","Website and documentation":"","About Joplin":"","%s %s (%s, %s)":"","OK":"","Cancel":"","Back":"","New notebook \"%s\" will be created and file \"%s\" will be imported into it":"","Please create a notebook first.":"","Note title:":"","Please create a notebook first":"","To-do title:":"","Notebook title:":"","Add or remove tags:":"","Separate each tag by a comma.":"","Layout":"","Add or remove tags":"","Switch between note and to-do":"","Delete":"","No notes in here. Create one by clicking on \"New note\".":"","Unsupported link or message: %s":"","Attach file":"","Refresh":"","OneDrive Login":"","Import":"","Configuration":"","Delete notebook?":"","Remove this tag from all the notes?":"","Notebooks":"","Tags":"","Synchronise":"","Usage: %s":"","Unknown flag: %s":"","Unknown log level: %s":"","Unknown level ID: %s":"","Cannot refresh token: authentication data is missing. Starting the synchronisation again may fix the problem.":"","Please set the \"sync.2.path\" config value to the desired synchronisation destination.":"","Cannot access %s":"","Created local items: %d.":"","Updated local items: %d.":"","Created remote items: %d.":"","Updated remote items: %d.":"","Deleted local items: %d.":"","Deleted remote items: %d.":"","State: \"%s\".":"","Cancelling...":"","Completed: %s":"","Synchronisation is already in progress. State: %s":"","Conflicts":"","A notebook with this title already exists: \"%s\"":"","Notebooks cannot be named \"%s\", which is a reserved title.":"","Untitled":"","This note does not have geolocation information.":"","Cannot copy note to \"%s\" notebook":"","Cannot move note to \"%s\" notebook":"","Invalid option value: \"%s\". Possible values are: %s.":"","File system synchronisation target directory":"","The path to synchronise with when file system synchronisation is enabled. See `sync.target`.":"","Synchronisation target":"","The target to synchonise to. If synchronising with the file system, set `sync.2.path` to specify the target directory.":"","File system":"","OneDrive":"","Text editor":"","The editor that will be used to open a note. If none is provided it will try to auto-detect the default editor.":"","Language":"","Theme":"","Light":"","Dark":"","Show uncompleted todos on top of the lists":"","Save geo-location with notes":"","Synchronisation interval":"","Disabled":"","%d minutes":"","%d hour":"","%d hours":"","Show advanced options":"","Sync status (synced items / total items)":"","%s: %d/%d":"","Total: %d/%d":"","Conflicted: %d":"","To delete: %d":"","Folders":"","%s: %d notes":"","There are currently no notes. Create one by clicking on the (+) button.":"","Log":"","Status":"","Cancel synchronisation":"","The notebook could not be saved: %s":"","Edit notebook":"","This note has been modified:":"","Save changes":"","Discard changes":"","Delete note":"","Convert to regular note":"","Convert to todo":"","Hide metadata":"","Show metadata":"","View location on map":"","Edit":"","Delete notebook":"","Login with OneDrive":"","Click on the (+) button to create a new note or notebook. Click on the side menu to access your existing notebooks.":"","You currently have no notebook. Create one by clicking on (+) button.":"","Welcome":""} \ No newline at end of file diff --git a/ElectronClient/app/locales/fr_FR.json b/ElectronClient/app/locales/fr_FR.json index 51ffe41dd..c145703d5 100644 --- a/ElectronClient/app/locales/fr_FR.json +++ b/ElectronClient/app/locales/fr_FR.json @@ -1 +1 @@ -{"Give focus to next pane":"Activer le volet suivant","Give focus to previous pane":"Activer le volet précédent","Enter command line mode":"Démarrer le mode de ligne de commande","Exit command line mode":"Sortir du mode de ligne de commande","Edit the selected note":"Editer la note sélectionnée","Cancel the current command.":"Annuler la commande en cours.","Exit the application.":"Quitter le logiciel.","Delete the currently selected note or notebook.":"Supprimer la note ou carnet sélectionné.","To delete a tag, untag the associated notes.":"Pour supprimer une vignette, enlever là des notes associées.","Please select the note or notebook to be deleted first.":"Veuillez d'abord sélectionner un carnet.","Set a to-do as completed / not completed":"Marquer une tâches comme complétée / non-complétée","[t]oggle [c]onsole between maximized/minimized/hidden/visible.":"Maximiser, minimiser, cacher ou rendre visible la console.","Search":"Chercher","[t]oggle note [m]etadata.":"Afficher/Cacher les métadonnées des notes.","[M]ake a new [n]ote":"Créer une nouvelle note","[M]ake a new [t]odo":"Créer une nouvelle tâche","[M]ake a new note[b]ook":"Créer un nouveau carnet","Copy ([Y]ank) the [n]ote to a notebook.":"Copier la note dans un autre carnet.","Move the note to a notebook.":"Déplacer la note vers un carnet.","Press Ctrl+D or type \"exit\" to exit the application":"Appuyez sur Ctrl+D ou tapez \"exit\" pour sortir du logiciel","More than one item match \"%s\". Please narrow down your query.":"Plus d'un objet correspond à \"%s\". Veuillez préciser votre requête.","No notebook selected.":"Aucun carnet n'est sélectionné.","No notebook has been specified.":"Aucun carnet n'est spécifié.","Y":"O","n":"n","N":"N","y":"o","Cancelling background synchronisation... Please wait.":"Annulation de la synchronisation... Veuillez patienter.","The command \"%s\" is only available in GUI mode":"La commande \"%s\" est disponible uniquement en mode d'interface graphique","Missing required argument: %s":"Paramètre requis manquant : %s","%s: %s":"%s : %s","Your choice: ":"Votre choix :","Invalid answer: %s":"Réponse invalide : %s","Attaches the given file to the note.":"Joindre le fichier fourni à la note.","Cannot find \"%s\".":"Impossible de trouver \"%s\".","Displays the given note.":"Affiche la note.","Displays the complete information about note.":"Affiche tous les détails de la note.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Obtient ou modifie une valeur de configuration. Si la [valeur] n'est pas fournie, la valeur de [nom] est affichée. Si ni le [nom] ni la [valeur] ne sont fournis, la configuration complète est affichée.","Also displays unset and hidden config variables.":"Afficher également les variables cachées.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"Copie les notes correspondant à vers [carnet]. Si aucun carnet n'est spécifié, la note est dupliquée sur place.","Marks a to-do as done.":"Marquer la tâche comme complétée.","Note is not a to-do: \"%s\"":"La note n'est pas une tâche : \"%s\"","Edit note.":"Editer la note.","No text editor is defined. Please set it using `config editor `":"Aucun éditeur de texte n'est défini. Veuillez le définir en utilisant la commande `config editor `","No active notebook.":"Aucun carnet actif.","Note does not exist: \"%s\". Create it?":"Cette note n'existe pas : \"%s\". La créer ?","Starting to edit note. Close the editor to get back to the prompt.":"Edition de la note en cours. Fermez l'éditeur de texte pour retourner à l'invite de commande.","Note has been saved.":"La note a été enregistrée.","Exits the application.":"Quitter le logiciel.","Exports Joplin data to the given directory. By default, it will export the complete database including notebooks, notes, tags and resources.":"Exporter les données de Joplin vers le dossier fourni. Par défaut, la base de donnée complète sera exportée, y compris les carnets, notes, tags et resources.","Exports only the given note.":"Exporter uniquement la note spécifiée.","Exports only the given notebook.":"Exporter uniquement le carnet spécifié.","Displays a geolocation URL for the note.":"Afficher l'URL de l'emplacement de la note.","Displays usage information.":"Affiche les informations d'utilisation.","Shortcuts are not available in CLI mode.":"Les raccourcis ne sont pas disponible en mode de ligne de commande.","Type `help [command]` for more information about a command.":"Tapez `help [command]` pour plus d'information sur une commande.","The possible commands are:":"Les commandes possibles sont :","In any command, a note or notebook can be refered to by title or ID, or using the shortcuts `$n` or `$b` for, respectively, the currently selected note or notebook. `$c` can be used to refer to the currently selected item.":"Dans n'importe quelle commande, une note ou carnet peut être référé par titre ou identifiant, ou en utilisant les raccourcis `$n` et `$b` pour, respectivement, la note sélectionnée et le carnet sélectionné. `$c` peut être utilisé pour faire référence à l'objet sélectionné en cours.","To move from one pane to another, press Tab or Shift+Tab.":"Pour aller d'un volet à l'autre, pressez Tab ou Maj+Tab.","Use the arrows and page up/down to scroll the lists and text areas (including this console).":"Utilisez les touches fléchées et page précédente/suivante pour faire défiler les listes et zones de texte (y compris cette console).","To maximise/minimise the console, press \"TC\".":"Pour maximiser ou minimiser la console, pressez \"TC\".","To enter command line mode, press \":\"":"Pour démarrer le mode ligne de commande, pressez \":\"","To exit command line mode, press ESCAPE":"Pour sortir du mode ligne de commande, pressez ECHAP","For the complete list of available keyboard shortcuts, type `help shortcuts`":"Pour la liste complète des raccourcis disponibles, tapez `help shortcuts`","Imports an Evernote notebook file (.enex file).":"Importer un carnet Evernote (fichier .enex).","Do not ask for confirmation.":"Ne pas demander de confirmation.","File \"%s\" will be imported into existing notebook \"%s\". Continue?":"Le fichier \"%s\" va être importé dans le carnet existant \"%s\". Continuer ?","New notebook \"%s\" will be created and file \"%s\" will be imported into it. Continue?":"Un nouveau carnet \"%s\" va être créé et le fichier \"%s\" va être importé dedans. Continuer ?","Found: %d.":"Trouvés : %d.","Created: %d.":"Créés : %d.","Updated: %d.":"Mise à jour : %d.","Skipped: %d.":"Ignorés : %d.","Resources: %d.":"Ressources : %d.","Tagged: %d.":"Etiquettes : %d.","Importing notes...":"Importation des notes...","The notes have been imported: %s":"Les notes ont été importées : %s","Displays the notes in the current notebook. Use `ls /` to display the list of notebooks.":"Affiche les notes dans le carnet. Utilisez `ls /` pour afficher la liste des carnets.","Displays only the first top notes.":"Affiche uniquement les premières notes.","Sorts the item by (eg. title, updated_time, created_time).":"Trier les notes par (par exemple, title, updated_time, created_time).","Reverses the sorting order.":"Inverser l'ordre.","Displays only the items of the specific type(s). Can be `n` for notes, `t` for to-dos, or `nt` for notes and to-dos (eg. `-tt` would display only the to-dos, while `-ttd` would display notes and to-dos.":"Affiche uniquement les notes du ou des types spécifiés. Le type peut-être `n` pour les notes, `t` pour les tâches (par exemple, `-tt` affiche uniquement les tâches, tandis que `-ttd` affiche les notes et les tâches).","Either \"text\" or \"json\"":"Soit \"text\" soit \"json\"","Use long list format. Format is ID, NOTE_COUNT (for notebook), DATE, TODO_CHECKED (for to-dos), TITLE":"Utilise le format de liste longue. Le format est ID, NOMBRE_DE_NOTES (pour les carnets), DATE, TACHE_TERMINE (pour les tâches), TITRE","Please select a notebook first.":"Veuillez d'abord sélectionner un carnet.","Creates a new notebook.":"Créer un carnet.","Creates a new note.":"Créer une note.","Notes can only be created within a notebook.":"Les notes ne peuvent être créées que dans un carnet.","Creates a new to-do.":"Créer une nouvelle tâche.","Moves the notes matching to [notebook].":"Déplacer les notes correspondant à vers [notebook].","Renames the given (note or notebook) to .":"Renommer l'objet (note ou carnet) en .","Deletes the given notebook.":"Supprimer le carnet.","Deletes the notebook without asking for confirmation.":"Supprimer le carnet sans demander la confirmation.","Delete notebook \"%s\"?":"Supprimer le carnet \"%s\" ?","Deletes the notes matching .":"Supprimer les notes correspondants à .","Deletes the notes without asking for confirmation.":"Supprimer les notes sans demander la confirmation.","%d notes match this pattern. Delete them?":"%d notes correspondent à ce motif. Les supprimer ?","Delete note?":"Supprimer la note ?","Searches for the given in all the notes.":"Chercher le motif dans toutes les notes.","Sets the property of the given to the given [value].":"Assigner la valeur [value] à la propriété de la donnée.","Displays summary about the notes and notebooks.":"Afficher un résumé des notes et carnets.","Synchronises with remote storage.":"Synchroniser les notes et carnets.","Sync to provided target (defaults to sync.target config value)":"Synchroniser avec la cible donnée (par défaut, la valeur de configuration `sync.target`).","Synchronisation is already in progress.":"La synchronisation est déjà en cours.","Lock file is already being hold. If you know that no synchronisation is taking place, you may delete the lock file at \"%s\" and resume the operation.":"La synchronisation est déjà en cours ou ne s'est pas interrompue correctement. Si vous savez qu'aucune autre synchronisation est en cours, vous pouvez supprimer le fichier \"%s\" pour reprendre l'opération.","Authentication was not completed (did not receive an authentication token).":"Impossible d'autoriser le logiciel (jeton d'identification non-reçu).","Synchronisation target: %s (%s)":"Cible de la synchronisation : %s (%s)","Cannot initialize synchroniser.":"Impossible d'initialiser la synchronisation.","Starting synchronisation...":"Commencement de la synchronisation...","Cancelling... Please wait.":"Annulation... Veuillez attendre."," can be \"add\", \"remove\" or \"list\" to assign or remove [tag] from [note], or to list the notes associated with [tag]. The command `tag list` can be used to list all the tags.":" peut être \"add\", \"remove\" ou \"list\" pour assigner ou enlever l'étiquette [tag] de la [note], our pour lister les notes associées avec l'étiquette [tag]. La commande `tag list` peut être utilisée pour lister les étiquettes.","Invalid command: \"%s\"":"Commande invalide : \"%s\""," can either be \"toggle\" or \"clear\". Use \"toggle\" to toggle the given to-do between completed and uncompleted state (If the target is a regular note it will be converted to a to-do). Use \"clear\" to convert the to-do back to a regular note.":"Gère le status des tâches. peut être \"toggle\" ou \"clear\". Utilisez \"toggle\" pour basculer la tâche entre le status terminé et non-terminé (Si la cible est une note, elle sera convertie en tâche). Utilisez \"clear\" pour convertir la tâche en note.","Marks a to-do as non-completed.":"Marquer une tâche comme non-complétée.","Switches to [notebook] - all further operations will happen within this notebook.":"Changer de carnet - toutes les opérations à venir se feront dans ce carnet.","Displays version information":"Affiche les informations de version","%s %s (%s)":"%s %s (%s)","Enum":"Enum","Type: %s.":"Type : %s.","Possible values: %s.":"Valeurs possibles : %s.","Default: %s":"Défaut : %s","Possible keys/values:":"Clefs/Valeurs possibles :","Fatal error:":"Erreur fatale :","The application has been authorised - you may now close this browser tab.":"Le logiciel a été autorisé. Vous pouvez maintenant fermer cet onglet.","The application has been successfully authorised.":"Le logiciel a été autorisé.","Please open the following URL in your browser to authenticate the application. The application will create a directory in \"Apps/Joplin\" and will only read and write files in this directory. It will have no access to any files outside this directory nor to any other personal data. No data will be shared with any third party.":"Veuillez ouvrir le lien ci-dessous dans votre browser pour authentifier le logiciel. Joplin va créer un répertoire \"Apps/Joplin\" et lire/écrira des fichiers uniquement dans ce répertoire. Le logiciel n'aura pas d'accès à aucun fichier en dehors de ce répertoire, ni à d'autres données personnelles. Aucune donnée ne sera partagé avec aucun tier.","Search:":"Search:","File":"","New note":"Nouvelle note","New to-do":"Nouvelle tâche","New notebook":"Nouveau carnet","Import Evernote notes":"Importer notes d'Evernotes","Evernote Export Files":"Fichiers d'export Evernote","Quit":"Quitter","Tools":"Outils","Options":"Options","Help":"Aide","Documentation":"Documentation","About Joplin":"A props de Joplin","OK":"OK","Cancel":"Annulation","Back":"Retour","New notebook \"%s\" will be created and file \"%s\" will be imported into it":"New notebook \"%s\" will be created and file \"%s\" will be imported into it","Please create a notebook first.":"Please create a notebook first.","Note title:":"Note title:","Please create a notebook first":"Please create a notebook first","To-do title:":"To-do title:","Notebook title:":"Notebook title:","Add or remove tags:":"Modifier les étiquettes","Separate each tag by a comma.":"","Layout":"","Add or remove tags":"","Switch between note and to-do":"","Delete":"Delete","No notes in here. Create one by clicking on \"New note\".":"No notes in here. Create one by clicking on \"New note\".","Unsupported link or message: %s":"","Attach file":"Attacher un fichier","Refresh":"Rafraîchir","OneDrive Login":"OneDrive Login","Import":"Import","Configuration":"Configuration","Delete notebook?":"Supprimer le carnet ?","Remove this tag from all the notes?":"","Notebooks":"Notebooks","Tags":"","Synchronise":"Synchroniser","Usage: %s":"Utilisation : %s","Unknown flag: %s":"Paramètre inconnu : %s","Unknown log level: %s":"Paramètre inconnu : %s","Unknown level ID: %s":"Paramètre inconnu : %s","Cannot refresh token: authentication data is missing. Starting the synchronisation again may fix the problem.":"Impossible de rafraîchir la connection à OneDrive. Démarrez la synchronisation à nouveau pour corriger le problème.","Please set the \"sync.2.path\" config value to the desired synchronisation destination.":"Veuillez attribuer une valeur au paramètre de configuration \"sync.2.path\" pour indiquer le dossier où devra se faire la synchronisation.","Cannot access %s":"Impossible d'accéder à %s","Created local items: %d.":"Objets créés localement : %d.","Updated local items: %d.":"Objets mis à jour localement : %d.","Created remote items: %d.":"Objets distants créés : %d.","Updated remote items: %d.":"Objets distants mis à jour : %d.","Deleted local items: %d.":"Objets supprimés localement : %d.","Deleted remote items: %d.":"Objets distants supprimés : %d.","State: \"%s\".":"Etat : \"%s\".","Cancelling...":"Annulation...","Completed: %s":"Terminé : %s","Synchronisation is already in progress. State: %s":"La synchronisation est déjà en cours. Etat : %s","Conflicts":"Conflits","A notebook with this title already exists: \"%s\"":"Un carnet avec ce titre existe déjà : \"%s\"","Notebooks cannot be named \"%s\", which is a reserved title.":"Les carnets ne peuvent être nommés \"%s\" car c'est un nom réservé.","Untitled":"Sans titre","This note does not have geolocation information.":"Cette note n'a pas d'information d'emplacement.","Cannot copy note to \"%s\" notebook":"Impossible de copier la note vers le carnet \"%s\"","Cannot move note to \"%s\" notebook":"Impossible de déplacer la note vers le carnet \"%s\"","Invalid option value: \"%s\". Possible values are: %s.":"Option invalide: \"%s\". Les valeurs possibles sont : %s.","File system synchronisation target directory":"Cible de la synchronisation sur le disque dur","The path to synchronise with when file system synchronisation is enabled. See `sync.target`.":"Le chemin du répertoire avec lequel synchroniser lorsque la synchronisation par système de fichier est activée. Voir `sync.target`.","Synchronisation target":"Cible de la synchronisation","The target to synchonise to. If synchronising with the file system, set `sync.2.path` to specify the target directory.":"La cible avec laquelle synchroniser. Pour synchroniser avec le système de fichier, veuillez spécifier le répertoire avec `sync.2.path`.","File system":"Système de fichier","OneDrive":"OneDrive","Text editor":"Editeur de texte","The editor that will be used to open a note. If none is provided it will try to auto-detect the default editor.":"L'éditeur de texte pour ouvrir et modifier les notes. Si aucun n'est spécifié, il sera détecté automatiquement.","Language":"Langue","Theme":"Apparence","Light":"Clair","Dark":"Sombre","Show uncompleted todos on top of the lists":"Tâches non-terminées en haut des listes","Save geo-location with notes":"Enregistrer l'emplacement avec les notes","Synchronisation interval":"Interval de synchronisation","Disabled":"Désactivé","%d minutes":"%d minutes","%d hour":"%d heure","%d hours":"%d heures","Show advanced options":"Montrer les options avancées","Sync status (synced items / total items)":"Status de la synchronisation (objets synchro. / total)","%s: %d/%d":"%s: %d/%d","Total: %d/%d":"Total : %d/%d","Conflicted: %d":"Conflits : %d","To delete: %d":"A supprimer : %d","Folders":"Carnets","%s: %d notes":"%s : %d notes","There are currently no notes. Create one by clicking on the (+) button.":"Ce carnet ne contient aucune note. Créez-en une en appuyant sur le bouton (+).","Log":"Journal","Status":"Etat","Cancel synchronisation":"Annuler synchronisation","The notebook could not be saved: %s":"Ce carnet n'a pas pu être sauvegardé : %s","Edit notebook":"Editer le carnet","This note has been modified:":"Cette note a été modifiée :","Save changes":"Enregistrer les changements","Discard changes":"Ignorer les changements","Delete note":"Supprimer la note","Convert to regular note":"Convertir en note","Convert to todo":"Convertir en tâche","Hide metadata":"Cacher les métadonnées","Show metadata":"Afficher les métadonnées","View location on map":"Voir l'emplacement sur la carte","Edit":"Editer","Delete notebook":"Supprimer le carnet","Login with OneDrive":"Se connecter avec OneDrive","Click on the (+) button to create a new note or notebook. Click on the side menu to access your existing notebooks.":"Appuyez sur le bouton (+) pour créer une nouvelle note ou carnet. Ouvrez le menu latéral pour accéder à vos carnets.","You currently have no notebook. Create one by clicking on (+) button.":"Vous n'avez pour l'instant pas de carnets. Créez-en un en pressant le bouton (+).","Welcome":"Bienvenue"} \ No newline at end of file +{"Give focus to next pane":"Activer le volet suivant","Give focus to previous pane":"Activer le volet précédent","Enter command line mode":"Démarrer le mode de ligne de commande","Exit command line mode":"Sortir du mode de ligne de commande","Edit the selected note":"Editer la note sélectionnée","Cancel the current command.":"Annuler la commande en cours.","Exit the application.":"Quitter le logiciel.","Delete the currently selected note or notebook.":"Supprimer la note ou carnet sélectionné.","To delete a tag, untag the associated notes.":"Pour supprimer une vignette, enlever là des notes associées.","Please select the note or notebook to be deleted first.":"Veuillez d'abord sélectionner un carnet.","Set a to-do as completed / not completed":"Marquer une tâches comme complétée / non-complétée","[t]oggle [c]onsole between maximized/minimized/hidden/visible.":"Maximiser, minimiser, cacher ou rendre visible la console.","Search":"Chercher","[t]oggle note [m]etadata.":"Afficher/Cacher les métadonnées des notes.","[M]ake a new [n]ote":"Créer une nouvelle note","[M]ake a new [t]odo":"Créer une nouvelle tâche","[M]ake a new note[b]ook":"Créer un nouveau carnet","Copy ([Y]ank) the [n]ote to a notebook.":"Copier la note dans un autre carnet.","Move the note to a notebook.":"Déplacer la note vers un carnet.","Press Ctrl+D or type \"exit\" to exit the application":"Appuyez sur Ctrl+D ou tapez \"exit\" pour sortir du logiciel","More than one item match \"%s\". Please narrow down your query.":"Plus d'un objet correspond à \"%s\". Veuillez préciser votre requête.","No notebook selected.":"Aucun carnet n'est sélectionné.","No notebook has been specified.":"Aucun carnet n'est spécifié.","Y":"O","n":"n","N":"N","y":"o","Cancelling background synchronisation... Please wait.":"Annulation de la synchronisation... Veuillez patienter.","The command \"%s\" is only available in GUI mode":"La commande \"%s\" est disponible uniquement en mode d'interface graphique","Missing required argument: %s":"Paramètre requis manquant : %s","%s: %s":"%s : %s","Your choice: ":"Votre choix :","Invalid answer: %s":"Réponse invalide : %s","Attaches the given file to the note.":"Joindre le fichier fourni à la note.","Cannot find \"%s\".":"Impossible de trouver \"%s\".","Displays the given note.":"Affiche la note.","Displays the complete information about note.":"Affiche tous les détails de la note.","Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.":"Obtient ou modifie une valeur de configuration. Si la [valeur] n'est pas fournie, la valeur de [nom] est affichée. Si ni le [nom] ni la [valeur] ne sont fournis, la configuration complète est affichée.","Also displays unset and hidden config variables.":"Afficher également les variables cachées.","%s = %s (%s)":"%s = %s (%s)","%s = %s":"%s = %s","Duplicates the notes matching to [notebook]. If no notebook is specified the note is duplicated in the current notebook.":"Copie les notes correspondant à vers [carnet]. Si aucun carnet n'est spécifié, la note est dupliquée sur place.","Marks a to-do as done.":"Marquer la tâche comme complétée.","Note is not a to-do: \"%s\"":"La note n'est pas une tâche : \"%s\"","Edit note.":"Editer la note.","No text editor is defined. Please set it using `config editor `":"Aucun éditeur de texte n'est défini. Veuillez le définir en utilisant la commande `config editor `","No active notebook.":"Aucun carnet actif.","Note does not exist: \"%s\". Create it?":"Cette note n'existe pas : \"%s\". La créer ?","Starting to edit note. Close the editor to get back to the prompt.":"Edition de la note en cours. Fermez l'éditeur de texte pour retourner à l'invite de commande.","Note has been saved.":"La note a été enregistrée.","Exits the application.":"Quitter le logiciel.","Exports Joplin data to the given directory. By default, it will export the complete database including notebooks, notes, tags and resources.":"Exporter les données de Joplin vers le dossier fourni. Par défaut, la base de donnée complète sera exportée, y compris les carnets, notes, tags et resources.","Exports only the given note.":"Exporter uniquement la note spécifiée.","Exports only the given notebook.":"Exporter uniquement le carnet spécifié.","Displays a geolocation URL for the note.":"Afficher l'URL de l'emplacement de la note.","Displays usage information.":"Affiche les informations d'utilisation.","Shortcuts are not available in CLI mode.":"Les raccourcis ne sont pas disponible en mode de ligne de commande.","Type `help [command]` for more information about a command.":"Tapez `help [command]` pour plus d'information sur une commande.","The possible commands are:":"Les commandes possibles sont :","In any command, a note or notebook can be refered to by title or ID, or using the shortcuts `$n` or `$b` for, respectively, the currently selected note or notebook. `$c` can be used to refer to the currently selected item.":"Dans n'importe quelle commande, une note ou carnet peut être référé par titre ou identifiant, ou en utilisant les raccourcis `$n` et `$b` pour, respectivement, la note sélectionnée et le carnet sélectionné. `$c` peut être utilisé pour faire référence à l'objet sélectionné en cours.","To move from one pane to another, press Tab or Shift+Tab.":"Pour aller d'un volet à l'autre, pressez Tab ou Maj+Tab.","Use the arrows and page up/down to scroll the lists and text areas (including this console).":"Utilisez les touches fléchées et page précédente/suivante pour faire défiler les listes et zones de texte (y compris cette console).","To maximise/minimise the console, press \"TC\".":"Pour maximiser ou minimiser la console, pressez \"TC\".","To enter command line mode, press \":\"":"Pour démarrer le mode ligne de commande, pressez \":\"","To exit command line mode, press ESCAPE":"Pour sortir du mode ligne de commande, pressez ECHAP","For the complete list of available keyboard shortcuts, type `help shortcuts`":"Pour la liste complète des raccourcis disponibles, tapez `help shortcuts`","Imports an Evernote notebook file (.enex file).":"Importer un carnet Evernote (fichier .enex).","Do not ask for confirmation.":"Ne pas demander de confirmation.","File \"%s\" will be imported into existing notebook \"%s\". Continue?":"Le fichier \"%s\" va être importé dans le carnet existant \"%s\". Continuer ?","New notebook \"%s\" will be created and file \"%s\" will be imported into it. Continue?":"Un nouveau carnet \"%s\" va être créé et le fichier \"%s\" va être importé dedans. Continuer ?","Found: %d.":"Trouvés : %d.","Created: %d.":"Créés : %d.","Updated: %d.":"Mise à jour : %d.","Skipped: %d.":"Ignorés : %d.","Resources: %d.":"Ressources : %d.","Tagged: %d.":"Etiquettes : %d.","Importing notes...":"Importation des notes...","The notes have been imported: %s":"Les notes ont été importées : %s","Displays the notes in the current notebook. Use `ls /` to display the list of notebooks.":"Affiche les notes dans le carnet. Utilisez `ls /` pour afficher la liste des carnets.","Displays only the first top notes.":"Affiche uniquement les premières notes.","Sorts the item by (eg. title, updated_time, created_time).":"Trier les notes par (par exemple, title, updated_time, created_time).","Reverses the sorting order.":"Inverser l'ordre.","Displays only the items of the specific type(s). Can be `n` for notes, `t` for to-dos, or `nt` for notes and to-dos (eg. `-tt` would display only the to-dos, while `-ttd` would display notes and to-dos.":"Affiche uniquement les notes du ou des types spécifiés. Le type peut-être `n` pour les notes, `t` pour les tâches (par exemple, `-tt` affiche uniquement les tâches, tandis que `-ttd` affiche les notes et les tâches).","Either \"text\" or \"json\"":"Soit \"text\" soit \"json\"","Use long list format. Format is ID, NOTE_COUNT (for notebook), DATE, TODO_CHECKED (for to-dos), TITLE":"Utilise le format de liste longue. Le format est ID, NOMBRE_DE_NOTES (pour les carnets), DATE, TACHE_TERMINE (pour les tâches), TITRE","Please select a notebook first.":"Veuillez d'abord sélectionner un carnet.","Creates a new notebook.":"Créer un carnet.","Creates a new note.":"Créer une note.","Notes can only be created within a notebook.":"Les notes ne peuvent être créées que dans un carnet.","Creates a new to-do.":"Créer une nouvelle tâche.","Moves the notes matching to [notebook].":"Déplacer les notes correspondant à vers [notebook].","Renames the given (note or notebook) to .":"Renommer l'objet (note ou carnet) en .","Deletes the given notebook.":"Supprimer le carnet.","Deletes the notebook without asking for confirmation.":"Supprimer le carnet sans demander la confirmation.","Delete notebook \"%s\"?":"Supprimer le carnet \"%s\" ?","Deletes the notes matching .":"Supprimer les notes correspondants à .","Deletes the notes without asking for confirmation.":"Supprimer les notes sans demander la confirmation.","%d notes match this pattern. Delete them?":"%d notes correspondent à ce motif. Les supprimer ?","Delete note?":"Supprimer la note ?","Searches for the given in all the notes.":"Chercher le motif dans toutes les notes.","Sets the property of the given to the given [value].":"Assigner la valeur [value] à la propriété de la donnée.","Displays summary about the notes and notebooks.":"Afficher un résumé des notes et carnets.","Synchronises with remote storage.":"Synchroniser les notes et carnets.","Sync to provided target (defaults to sync.target config value)":"Synchroniser avec la cible donnée (par défaut, la valeur de configuration `sync.target`).","Synchronisation is already in progress.":"La synchronisation est déjà en cours.","Lock file is already being hold. If you know that no synchronisation is taking place, you may delete the lock file at \"%s\" and resume the operation.":"La synchronisation est déjà en cours ou ne s'est pas interrompue correctement. Si vous savez qu'aucune autre synchronisation est en cours, vous pouvez supprimer le fichier \"%s\" pour reprendre l'opération.","Authentication was not completed (did not receive an authentication token).":"Impossible d'autoriser le logiciel (jeton d'identification non-reçu).","Synchronisation target: %s (%s)":"Cible de la synchronisation : %s (%s)","Cannot initialize synchroniser.":"Impossible d'initialiser la synchronisation.","Starting synchronisation...":"Commencement de la synchronisation...","Cancelling... Please wait.":"Annulation... Veuillez attendre."," can be \"add\", \"remove\" or \"list\" to assign or remove [tag] from [note], or to list the notes associated with [tag]. The command `tag list` can be used to list all the tags.":" peut être \"add\", \"remove\" ou \"list\" pour assigner ou enlever l'étiquette [tag] de la [note], our pour lister les notes associées avec l'étiquette [tag]. La commande `tag list` peut être utilisée pour lister les étiquettes.","Invalid command: \"%s\"":"Commande invalide : \"%s\""," can either be \"toggle\" or \"clear\". Use \"toggle\" to toggle the given to-do between completed and uncompleted state (If the target is a regular note it will be converted to a to-do). Use \"clear\" to convert the to-do back to a regular note.":"Gère le status des tâches. peut être \"toggle\" ou \"clear\". Utilisez \"toggle\" pour basculer la tâche entre le status terminé et non-terminé (Si la cible est une note, elle sera convertie en tâche). Utilisez \"clear\" pour convertir la tâche en note.","Marks a to-do as non-completed.":"Marquer une tâche comme non-complétée.","Switches to [notebook] - all further operations will happen within this notebook.":"Changer de carnet - toutes les opérations à venir se feront dans ce carnet.","Displays version information":"Affiche les informations de version","%s %s (%s)":"%s %s (%s)","Enum":"Enum","Type: %s.":"Type : %s.","Possible values: %s.":"Valeurs possibles : %s.","Default: %s":"Défaut : %s","Possible keys/values:":"Clefs/Valeurs possibles :","Fatal error:":"Erreur fatale :","The application has been authorised - you may now close this browser tab.":"Le logiciel a été autorisé. Vous pouvez maintenant fermer cet onglet.","The application has been successfully authorised.":"Le logiciel a été autorisé.","Please open the following URL in your browser to authenticate the application. The application will create a directory in \"Apps/Joplin\" and will only read and write files in this directory. It will have no access to any files outside this directory nor to any other personal data. No data will be shared with any third party.":"Veuillez ouvrir le lien ci-dessous dans votre browser pour authentifier le logiciel. Joplin va créer un répertoire \"Apps/Joplin\" et lire/écrira des fichiers uniquement dans ce répertoire. Le logiciel n'aura pas d'accès à aucun fichier en dehors de ce répertoire, ni à d'autres données personnelles. Aucune donnée ne sera partagé avec aucun tier.","Search:":"Search:","File":"","New note":"Nouvelle note","New to-do":"Nouvelle tâche","New notebook":"Nouveau carnet","Import Evernote notes":"Importer notes d'Evernotes","Evernote Export Files":"Fichiers d'export Evernote","Quit":"Quitter","Tools":"Outils","Options":"Options","Help":"Aide","Website and documentation":"Website and documentation","About Joplin":"A props de Joplin","%s %s (%s, %s)":"%s %s (%s, %s)","OK":"OK","Cancel":"Annulation","Back":"Retour","New notebook \"%s\" will be created and file \"%s\" will be imported into it":"New notebook \"%s\" will be created and file \"%s\" will be imported into it","Please create a notebook first.":"Please create a notebook first.","Note title:":"Note title:","Please create a notebook first":"Please create a notebook first","To-do title:":"To-do title:","Notebook title:":"Notebook title:","Add or remove tags:":"Modifier les étiquettes","Separate each tag by a comma.":"","Layout":"","Add or remove tags":"","Switch between note and to-do":"","Delete":"Delete","No notes in here. Create one by clicking on \"New note\".":"No notes in here. Create one by clicking on \"New note\".","Unsupported link or message: %s":"","Attach file":"Attacher un fichier","Refresh":"Rafraîchir","OneDrive Login":"OneDrive Login","Import":"Import","Configuration":"Configuration","Delete notebook?":"Supprimer le carnet ?","Remove this tag from all the notes?":"","Notebooks":"Notebooks","Tags":"","Synchronise":"Synchroniser","Usage: %s":"Utilisation : %s","Unknown flag: %s":"Paramètre inconnu : %s","Unknown log level: %s":"Paramètre inconnu : %s","Unknown level ID: %s":"Paramètre inconnu : %s","Cannot refresh token: authentication data is missing. Starting the synchronisation again may fix the problem.":"Impossible de rafraîchir la connection à OneDrive. Démarrez la synchronisation à nouveau pour corriger le problème.","Please set the \"sync.2.path\" config value to the desired synchronisation destination.":"Veuillez attribuer une valeur au paramètre de configuration \"sync.2.path\" pour indiquer le dossier où devra se faire la synchronisation.","Cannot access %s":"Impossible d'accéder à %s","Created local items: %d.":"Objets créés localement : %d.","Updated local items: %d.":"Objets mis à jour localement : %d.","Created remote items: %d.":"Objets distants créés : %d.","Updated remote items: %d.":"Objets distants mis à jour : %d.","Deleted local items: %d.":"Objets supprimés localement : %d.","Deleted remote items: %d.":"Objets distants supprimés : %d.","State: \"%s\".":"Etat : \"%s\".","Cancelling...":"Annulation...","Completed: %s":"Terminé : %s","Synchronisation is already in progress. State: %s":"La synchronisation est déjà en cours. Etat : %s","Conflicts":"Conflits","A notebook with this title already exists: \"%s\"":"Un carnet avec ce titre existe déjà : \"%s\"","Notebooks cannot be named \"%s\", which is a reserved title.":"Les carnets ne peuvent être nommés \"%s\" car c'est un nom réservé.","Untitled":"Sans titre","This note does not have geolocation information.":"Cette note n'a pas d'information d'emplacement.","Cannot copy note to \"%s\" notebook":"Impossible de copier la note vers le carnet \"%s\"","Cannot move note to \"%s\" notebook":"Impossible de déplacer la note vers le carnet \"%s\"","Invalid option value: \"%s\". Possible values are: %s.":"Option invalide: \"%s\". Les valeurs possibles sont : %s.","File system synchronisation target directory":"Cible de la synchronisation sur le disque dur","The path to synchronise with when file system synchronisation is enabled. See `sync.target`.":"Le chemin du répertoire avec lequel synchroniser lorsque la synchronisation par système de fichier est activée. Voir `sync.target`.","Synchronisation target":"Cible de la synchronisation","The target to synchonise to. If synchronising with the file system, set `sync.2.path` to specify the target directory.":"La cible avec laquelle synchroniser. Pour synchroniser avec le système de fichier, veuillez spécifier le répertoire avec `sync.2.path`.","File system":"Système de fichier","OneDrive":"OneDrive","Text editor":"Editeur de texte","The editor that will be used to open a note. If none is provided it will try to auto-detect the default editor.":"L'éditeur de texte pour ouvrir et modifier les notes. Si aucun n'est spécifié, il sera détecté automatiquement.","Language":"Langue","Theme":"Apparence","Light":"Clair","Dark":"Sombre","Show uncompleted todos on top of the lists":"Tâches non-terminées en haut des listes","Save geo-location with notes":"Enregistrer l'emplacement avec les notes","Synchronisation interval":"Interval de synchronisation","Disabled":"Désactivé","%d minutes":"%d minutes","%d hour":"%d heure","%d hours":"%d heures","Show advanced options":"Montrer les options avancées","Sync status (synced items / total items)":"Status de la synchronisation (objets synchro. / total)","%s: %d/%d":"%s: %d/%d","Total: %d/%d":"Total : %d/%d","Conflicted: %d":"Conflits : %d","To delete: %d":"A supprimer : %d","Folders":"Carnets","%s: %d notes":"%s : %d notes","There are currently no notes. Create one by clicking on the (+) button.":"Ce carnet ne contient aucune note. Créez-en une en appuyant sur le bouton (+).","Log":"Journal","Status":"Etat","Cancel synchronisation":"Annuler synchronisation","The notebook could not be saved: %s":"Ce carnet n'a pas pu être sauvegardé : %s","Edit notebook":"Editer le carnet","This note has been modified:":"Cette note a été modifiée :","Save changes":"Enregistrer les changements","Discard changes":"Ignorer les changements","Delete note":"Supprimer la note","Convert to regular note":"Convertir en note","Convert to todo":"Convertir en tâche","Hide metadata":"Cacher les métadonnées","Show metadata":"Afficher les métadonnées","View location on map":"Voir l'emplacement sur la carte","Edit":"Editer","Delete notebook":"Supprimer le carnet","Login with OneDrive":"Se connecter avec OneDrive","Click on the (+) button to create a new note or notebook. Click on the side menu to access your existing notebooks.":"Appuyez sur le bouton (+) pour créer une nouvelle note ou carnet. Ouvrez le menu latéral pour accéder à vos carnets.","You currently have no notebook. Create one by clicking on (+) button.":"Vous n'avez pour l'instant pas de carnets. Créez-en un en pressant le bouton (+).","Welcome":"Bienvenue"} \ No newline at end of file diff --git a/ElectronClient/app/package-lock.json b/ElectronClient/app/package-lock.json index a8363f0a7..495ff5f9e 100644 --- a/ElectronClient/app/package-lock.json +++ b/ElectronClient/app/package-lock.json @@ -1,6 +1,6 @@ { "name": "Joplin", - "version": "0.10.0", + "version": "0.10.5", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1168,6 +1168,11 @@ "mimic-response": "1.0.0" } }, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=" + }, "deep-extend": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", @@ -1612,6 +1617,26 @@ } } }, + "electron-window-state": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/electron-window-state/-/electron-window-state-4.1.1.tgz", + "integrity": "sha1-azT9wxs4UU3+yLfI97XUrdtnYy0=", + "requires": { + "deep-equal": "1.0.1", + "jsonfile": "2.4.0", + "mkdirp": "0.5.1" + }, + "dependencies": { + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "requires": { + "graceful-fs": "4.1.11" + } + } + } + }, "encoding": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", diff --git a/ElectronClient/app/package.json b/ElectronClient/app/package.json index 270003c1b..a5b55aca6 100644 --- a/ElectronClient/app/package.json +++ b/ElectronClient/app/package.json @@ -43,6 +43,7 @@ "electron-context-menu": "^0.9.1", "electron-log": "^2.2.11", "electron-updater": "^2.16.1", + "electron-window-state": "^4.1.1", "follow-redirects": "^1.2.5", "form-data": "^2.3.1", "fs-extra": "^4.0.2", diff --git a/ReactNativeClient/lib/models/setting.js b/ReactNativeClient/lib/models/setting.js index 59d421d14..09f3e282d 100644 --- a/ReactNativeClient/lib/models/setting.js +++ b/ReactNativeClient/lib/models/setting.js @@ -110,7 +110,7 @@ class Setting extends BaseModel { this.logger().info('Setting: ' + key + ' = ' + c.value + ' => ' + value); - c.value = this.formatValue(key, value); + c.value = value; this.dispatch({ type: 'SETTING_UPDATE_ONE', @@ -143,6 +143,7 @@ class Setting extends BaseModel { if (md.type == Setting.TYPE_INT) return value.toFixed(0); 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; } @@ -162,11 +163,19 @@ class Setting extends BaseModel { } if (md.type === Setting.TYPE_ARRAY) { + if (!value) return []; if (Array.isArray(value)) return value; if (typeof value === 'string') return JSON.parse(value); return []; } + if (md.type === Setting.TYPE_OBJECT) { + if (!value) return {}; + if (typeof value === 'object') return value; + if (typeof value === 'string') return JSON.parse(value); + return {}; + } + return value; } @@ -308,6 +317,7 @@ class Setting extends BaseModel { if (typeId === Setting.TYPE_STRING) return 'string'; if (typeId === Setting.TYPE_BOOL) return 'bool'; if (typeId === Setting.TYPE_ARRAY) return 'array'; + if (typeId === Setting.TYPE_OBJECT) return 'object'; } } @@ -320,6 +330,7 @@ Setting.TYPE_INT = 1; Setting.TYPE_STRING = 2; Setting.TYPE_BOOL = 3; Setting.TYPE_ARRAY = 4; +Setting.TYPE_OBJECT = 5; Setting.THEME_LIGHT = 1; Setting.THEME_DARK = 2; diff --git a/ReactNativeClient/lib/shim.js b/ReactNativeClient/lib/shim.js index f24c9357e..322d0acf7 100644 --- a/ReactNativeClient/lib/shim.js +++ b/ReactNativeClient/lib/shim.js @@ -10,86 +10,98 @@ shim.isReactNative = () => { return !shim.isNode(); }; +shim.isLinux = () => { + return process && process.platform === 'linux'; +} + +shim.isWindows = () => { + return process && process.platform === 'win32'; +} + +shim.isMac = () => { + return process && process.platform === 'darwin'; +} + // https://github.com/cheton/is-electron shim.isElectron = () => { - // Renderer process - if (typeof window !== 'undefined' && typeof window.process === 'object' && window.process.type === 'renderer') { - return true; - } + // Renderer process + if (typeof window !== 'undefined' && typeof window.process === 'object' && window.process.type === 'renderer') { + return true; + } - // Main process - if (typeof process !== 'undefined' && typeof process.versions === 'object' && !!process.versions.electron) { - return true; - } + // Main process + if (typeof process !== 'undefined' && typeof process.versions === 'object' && !!process.versions.electron) { + return true; + } - // Detect the user agent when the `nodeIntegration` option is set to true - if (typeof navigator === 'object' && typeof navigator.userAgent === 'string' && navigator.userAgent.indexOf('Electron') >= 0) { - return true; - } + // Detect the user agent when the `nodeIntegration` option is set to true + if (typeof navigator === 'object' && typeof navigator.userAgent === 'string' && navigator.userAgent.indexOf('Electron') >= 0) { + return true; + } - return false; + return false; } // Node requests can go wrong is so many different ways and with so // many different error messages... This handler inspects the error // and decides whether the request can safely be repeated or not. function fetchRequestCanBeRetried(error) { - if (!error) return false; + if (!error) return false; - // Unfortunately the error 'Network request failed' doesn't have a type - // or error code, so hopefully that message won't change and is not localized - if (error.message == 'Network request failed') return true; + // Unfortunately the error 'Network request failed' doesn't have a type + // or error code, so hopefully that message won't change and is not localized + if (error.message == 'Network request failed') return true; - // request to https://public-ch3302....1fab24cb1bd5f.md failed, reason: socket hang up" - if (error.code == 'ECONNRESET') return true; + // request to https://public-ch3302....1fab24cb1bd5f.md failed, reason: socket hang up" + if (error.code == 'ECONNRESET') return true; - // OneDrive (or Node?) sometimes sends back a "not found" error for resources - // that definitely exist and in this case repeating the request works. - // Error is: - // request to https://graph.microsoft.com/v1.0/drive/special/approot failed, reason: getaddrinfo ENOTFOUND graph.microsoft.com graph.microsoft.com:443 - if (error.code == 'ENOTFOUND') return true; + // OneDrive (or Node?) sometimes sends back a "not found" error for resources + // that definitely exist and in this case repeating the request works. + // Error is: + // request to https://graph.microsoft.com/v1.0/drive/special/approot failed, reason: getaddrinfo ENOTFOUND graph.microsoft.com graph.microsoft.com:443 + if (error.code == 'ENOTFOUND') return true; - // network timeout at: https://public-ch3302...859f9b0e3ab.md - if (error.message && error.message.indexOf('network timeout') === 0) return true; + // network timeout at: https://public-ch3302...859f9b0e3ab.md + if (error.message && error.message.indexOf('network timeout') === 0) return true; - // name: 'FetchError', - // message: 'request to https://api.ipify.org/?format=json failed, reason: getaddrinfo EAI_AGAIN api.ipify.org:443', - // type: 'system', - // errno: 'EAI_AGAIN', - // code: 'EAI_AGAIN' } } reason: { FetchError: request to https://api.ipify.org/?format=json failed, reason: getaddrinfo EAI_AGAIN api.ipify.org:443 - // - // It's a Microsoft error: "A temporary failure in name resolution occurred." - if (error.code == 'EAI_AGAIN') return true; + // name: 'FetchError', + // message: 'request to https://api.ipify.org/?format=json failed, reason: getaddrinfo EAI_AGAIN api.ipify.org:443', + // type: 'system', + // errno: 'EAI_AGAIN', + // code: 'EAI_AGAIN' } } reason: { FetchError: request to https://api.ipify.org/?format=json failed, reason: getaddrinfo EAI_AGAIN api.ipify.org:443 + // + // It's a Microsoft error: "A temporary failure in name resolution occurred." + if (error.code == 'EAI_AGAIN') return true; - // request to https://public-...8fd8bc6bb68e9c4d17a.md failed, reason: connect ETIMEDOUT 204.79.197.213:443 - // Code: ETIMEDOUT - if (error.code === 'ETIMEDOUT') return true; + // request to https://public-...8fd8bc6bb68e9c4d17a.md failed, reason: connect ETIMEDOUT 204.79.197.213:443 + // Code: ETIMEDOUT + if (error.code === 'ETIMEDOUT') return true; - return false; + return false; } shim.fetchWithRetry = async function(fetchFn, options = null) { - const { time } = require('lib/time-utils.js'); + const { time } = require('lib/time-utils.js'); - if (!options) options = {}; - if (!options.timeout) options.timeout = 1000 * 120; // ms - if (!('maxRetry' in options)) options.maxRetry = 5; + if (!options) options = {}; + if (!options.timeout) options.timeout = 1000 * 120; // ms + if (!('maxRetry' in options)) options.maxRetry = 5; - let retryCount = 0; - while (true) { - try { - const response = await fetchFn(); - return response; - } catch (error) { - if (fetchRequestCanBeRetried(error)) { - retryCount++; - if (retryCount > options.maxRetry) throw error; - await time.sleep(retryCount * 3); - } else { - throw error; - } - } - } + let retryCount = 0; + while (true) { + try { + const response = await fetchFn(); + return response; + } catch (error) { + if (fetchRequestCanBeRetried(error)) { + retryCount++; + if (retryCount > options.maxRetry) throw error; + await time.sleep(retryCount * 3); + } else { + throw error; + } + } + } } shim.nativeFetch_ = typeof fetch !== 'undefined' ? fetch : null; diff --git a/linkToLocal.sh b/linkToLocal.sh new file mode 100644 index 000000000..a396696cc --- /dev/null +++ b/linkToLocal.sh @@ -0,0 +1,6 @@ +#!/bin/bash +ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +cd "$ROOT_DIR/CliClient/node_modules" +rm -rf tkwidgets +ln -s /mnt/d/Docs/PROGS/Node/tkwidgets/src tkwidgets \ No newline at end of file