1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-09-05 20:56:22 +02:00

Compare commits

...

207 Commits

Author SHA1 Message Date
Laurent Cozic
613041b806 Electron release v1.0.155 2019-05-24 14:47:35 +01:00
Laurent Cozic
ff1d01a864 Merge branch 'master' of github.com:laurent22/joplin 2019-05-24 14:47:30 +01:00
Laurent Cozic
bcbbe10bf8 Electron release v1.0.154 2019-05-24 14:47:12 +01:00
Laurent Cozic
3de0abfc84 Update FUNDING.yml 2019-05-24 09:57:53 +01:00
Laurent Cozic
133fd03469 Update FUNDING.yml 2019-05-24 09:55:29 +01:00
Laurent Cozic
4f97c5c017 Update FUNDING.yml 2019-05-24 09:55:07 +01:00
Laurent Cozic
2d8fbac58c Create FUNDING.yml 2019-05-24 09:53:31 +01:00
Laurent Cozic
95f7ac4a4a Merge branch 'master' of github.com:laurent22/joplin 2019-05-24 09:07:11 +01:00
Laurent Cozic
6a56a6ccf0 Doc: Added more technical info for revision history 2019-05-24 09:05:16 +01:00
Luis Orozco
1eb8df9fa6 Desktop: Fixes #1186, #1354: Clears search when clicking on a notebook. (#1504)
* Fixes #1186, #1354. Clears search when clicking on a notebook.

* use new resetSearch method where possible, replaced tabs with spaces

* replaced a couple more spaces with tabs
2019-05-24 08:13:01 +01:00
Helmut K. C. Tessarek
485b4baebb Update de_DE.po 2019-05-23 23:40:42 -04:00
Laurent Cozic
5590d887c9 Doc: Added note history info 2019-05-24 00:21:15 +01:00
Laurent Cozic
d00bfa997e Doc: Fixed more links 2019-05-22 16:57:45 +01:00
Laurent Cozic
1a8590e9b9 Update website 2019-05-22 16:49:57 +01:00
Laurent Cozic
5a978977df Fix Iran flag 2019-05-22 16:49:32 +01:00
Laurent Cozic
5d763c7e6c All: Remove tags from Welcome item due to issue with cleaning them up afterwards 2019-05-22 16:38:53 +01:00
Laurent Cozic
050b089e72 Update translations 2019-05-22 16:34:59 +01:00
Helmut K. C. Tessarek
733ea4027c Doc: use new forum link (#1545) 2019-05-22 16:20:10 +01:00
Helmut K. C. Tessarek
10500c78b1 All: Fix: Default sort order for notebooks should be title and ascending (#1541) 2019-05-22 16:18:16 +01:00
Caleb John
0040cc02a2 Only delete the .desktop file if it will be replaced by the script (#1537) 2019-05-22 16:16:41 +01:00
Luis Orozco
74afd20f0c Desktop: Fixes #1426: added backticks to auto-wrapping quotes. (#1534) 2019-05-22 16:16:03 +01:00
Luis Orozco
dc9bde2184 Github: updated Contributing.md (#1533)
* updated Contributing.md

- Added several guidelines
- Moved some rules to bulleted lists (for quicker reading).

* Replace links to old forum domain to new domain. Removed a word.
2019-05-22 16:14:59 +01:00
Mehrad Mahmoudian
5243ea7eb2 All: New: Added Persian translation (#1539)
* [init] the first version of the fa.po file

Providing translation for Persian language

* [fix] moved the fa.po file into correct path
2019-05-22 16:05:25 +01:00
水货
7d93492658 Update zh_CN.po (#1524) 2019-05-22 15:57:20 +01:00
Helmut K. C. Tessarek
c6b56345f5 add /%d to Fetching resources: %d (#1532) 2019-05-22 15:56:25 +01:00
Laurent Cozic
8a6fe20a69 All: Resolves #1481: New: Allow downloading attachments on demand or automatically (#1527)
* Allow downloading resources automatically, on demand, or when loading note

* Make needToBeFetched calls to return the right number of resources

* All: Improved handling of resource downloading and decryption

* Desktop: Click on resource to download it (and, optionally, to decrypt it)

* Desktop: Better handling of resource state (not downloaded, downloading, encrypted) in front end

* Renamed setting to sync.resourceDownloadMode

* Download resources when changing setting

* tweaks

* removed duplicate cs

* Better report resource download progress

* Make sure resource cache is properly cleared when needed

* Also handle manual download for non-image resources

* More improvements to logic when downloading and decrypting resources
2019-05-22 15:56:07 +01:00
Laurent Cozic
6bcbedd6a4 CLI v1.0.137 2019-05-19 12:05:02 +01:00
Laurent Cozic
4c935b78f9 Removed log statement 2019-05-19 12:04:09 +01:00
Laurent Cozic
94cddda6d0 Removed temp files 2019-05-19 11:22:00 +01:00
Laurent Cozic
1924ea062c CLI v1.0.136 2019-05-19 11:20:17 +01:00
Laurent Cozic
07e88b2eeb All: Handle missing resource blob when setting resource size 2019-05-19 11:18:44 +01:00
Laurent Cozic
e4a08c29d7 Desktop, Mobile: Improved: Gray out checkboxes that have been ticked inside notes 2019-05-17 22:41:30 +01:00
Laurent Cozic
d60afcaabe Fixed merge 2019-05-16 17:36:02 +00:00
Laurent Cozic
1a091460ca All: Fixed: Prevent app from trying to upload resource it has not downloaded yet 2019-05-16 17:34:16 +00:00
Laurent Cozic
8ebaa7f6eb All: Put back "Fetched items" message during sync 2019-05-15 08:14:36 +01:00
Laurent Cozic
e2a64e21a2 Electron release v1.0.153 2019-05-14 22:23:47 +01:00
Laurent Cozic
78ddd22f09 Log more revision information to allow debugging issues 2019-05-14 22:23:34 +01:00
Laurent Cozic
c546b7076a Fixed doc 2019-05-14 22:02:47 +01:00
Laurent Cozic
0e2bb5d784 Desktop: Improved: When opening a note using Goto Anything, open all its parent notebooks too 2019-05-14 00:11:27 +01:00
Laurent Cozic
5c069c38f5 CLI v1.0.135 2019-05-13 23:59:27 +01:00
Laurent Cozic
451b9c0ae9 CLI v1.0.133 2019-05-13 23:55:53 +01:00
Laurent Cozic
047897621a Fix CLI build script 2019-05-13 23:52:12 +01:00
Laurent Cozic
52e5cec585 Update website 2019-05-13 23:41:31 +01:00
Laurent Cozic
bc98b65efa Update website 2019-05-13 23:23:57 +01:00
Laurent Cozic
9250e77862 Added link to CLI changelog 2019-05-13 23:23:42 +01:00
Laurent Cozic
cd69e71945 Forgot to publish in publish script 2019-05-13 23:20:25 +01:00
Laurent Cozic
e705e6e990 CLI v1.0.129 2019-05-13 23:18:57 +01:00
Laurent Cozic
4638f11c5e Created CLI release script with changelog auto-generation 2019-05-13 23:18:44 +01:00
Laurent Cozic
9de7c15e93 CLI v1.0.128 2019-05-13 22:53:08 +01:00
Laurent Cozic
61736546b4 Updated translations 2019-05-13 22:52:42 +01:00
Laurent Cozic
82b6dd23a7 CLI v1.0.127 2019-05-13 10:11:10 +01:00
Laurent Cozic
64427f0160 iOS 10.0.34 2019-05-13 10:10:37 +01:00
Laurent Cozic
cbf47cb9ee Android release v1.0.252 2019-05-13 09:53:50 +01:00
Laurent Cozic
dba3e4202d Electron release v1.0.152 2019-05-13 09:51:04 +01:00
Laurent Cozic
173cd6de4d Fixed regression 2019-05-13 09:50:39 +01:00
Laurent Cozic
3d333bd8f2 Removed build files 2019-05-13 00:43:12 +01:00
Laurent Cozic
a82f8c7dd0 CLI v1.0.126 2019-05-13 00:42:16 +01:00
Helmut K. C. Tessarek
cde079e44e Clipper release v1.0.14 2019-05-12 17:52:20 -04:00
Laurent Cozic
f8d20b61ea Update website 2019-05-12 16:18:30 +01:00
Laurent Cozic
d279435502 Android release v1.0.251 2019-05-12 16:16:39 +01:00
Laurent Cozic
eb2065128e Electron release v1.0.151 2019-05-12 16:04:01 +01:00
Laurent Cozic
10e81aa476 Trying to fix iOS release issue 2019-05-12 16:03:22 +01:00
Laurent Cozic
3e808f05fd Improved logic to set resource file size 2019-05-12 15:53:42 +01:00
Laurent Cozic
e57bfad9b1 Android release v1.0.248 2019-05-12 11:50:21 +01:00
Laurent Cozic
5f344f07d4 Electron release v1.0.150 2019-05-12 11:41:35 +01:00
Laurent Cozic
e1b7b64e1b All: Make sure resource filesize is set in all cases 2019-05-12 11:41:07 +01:00
Laurent Cozic
ed3970be81 CLI: Fix: Do not resize images if they are already below the max dimensions 2019-05-12 11:38:33 +01:00
Laurent Cozic
c27861d40f Electron release v1.0.149 2019-05-12 01:22:02 +01:00
Laurent Cozic
565dfba8c9 All: Fixes #371 (sort of): Allow resources greater than 10 MB but they won't be synced on mobile 2019-05-12 01:15:52 +01:00
Laurent Cozic
553a26eb63 Desktop, CLI: Added option to disable creation of welcome items 2019-05-12 01:10:46 +01:00
Laurent Cozic
9c85bc2cd1 All: Save size of a resource to the database; and added mechanism to run non-database migrations 2019-05-11 17:55:40 +01:00
Laurent Cozic
e96bc9c48a All: Allow specifying the log level of a log target 2019-05-11 17:53:56 +01:00
Laurent Cozic
0d036d8183 Fixed regression following fix for #1425 2019-05-11 17:35:39 +01:00
Laurent Cozic
e5f2a7f2f5 Fixed regression caused by #1472 2019-05-11 17:34:45 +01:00
Laurent Cozic
016ce3dd61 Desktop: Resolves #1502: Improved note deletion dialog 2019-05-11 13:36:44 +01:00
Laurent Cozic
afb375955e Fixed regressions following fix for #1425 2019-05-11 12:08:28 +01:00
Laurent Cozic
b702b0b40c Desktop: Fixes #1425: Improved handling of images when using external editor, so that it works in Atom, VSCode and Typora 2019-05-11 11:46:13 +01:00
Laurent Cozic
91ecab51c5 Clipper: Fixed: Added Chrome workaround to prevent it from posting the same note twice 2019-05-11 11:18:09 +01:00
Laurent Cozic
7628506926 Merge branch 'master' of github.com:laurent22/joplin 2019-05-11 11:13:23 +01:00
Laurent Cozic
4e7f7c0c9c Clipper: Fixes #1510: Fixed display of some images in preview. Also display images at correct size inside preview. 2019-05-11 11:13:13 +01:00
Laurent Cozic
863f5bcf18 Desktop, Mobile: Fixed: Some images were not being displayed 2019-05-11 09:49:56 +01:00
Laurent Cozic
dccd489fcc Clipper: Fix: Fix handling of tables with empty headers 2019-05-11 09:23:31 +01:00
Helmut K. C. Tessarek
333c3f6369 added .gitignore to /Tools 2019-05-10 20:19:42 -04:00
Helmut K. C. Tessarek
808413d0bf remove section self-signed certs from FAQ for now - no Android rel available that has this feature yet 2019-05-10 03:19:47 -04:00
Helmut K. C. Tessarek
440be3d920 remove unintentionally committed files again 2019-05-09 23:01:49 -04:00
Helmut K. C. Tessarek
9b27a4f601 Update website 2019-05-09 22:58:56 -04:00
Don Bowman
6e36ca32b4 CLI: Fix: Bump sqlite3 to v4.0.7 for node12 support (#1508) 2019-05-10 01:18:04 +01:00
simonsan
85a9c303f2 Changed download links to v1.0.145 (#1507) 2019-05-10 01:17:08 +01:00
Krešimir Klas
7e9972d99f Android: Resolves #680: New: Allow self-signed certificates (#1466)
* Allow User-added CAs in Android

This will enable connecting to servers with self-signed certificates on
android as per issue #680.

Implemented as per:
- https://android-developers.googleblog.com/2016/07/changes-to-trusted-certificate.html
- https://github.com/facebook/react-native/issues/20488

* Allow User-added CAs in Android

This will enable connecting to servers with self-signed certificates on
android as per issue #680.

Implemented as per:
- https://android-developers.googleblog.com/2016/07/changes-to-trusted-certificate.html
- https://github.com/facebook/react-native/issues/20488
2019-05-10 01:15:13 +01:00
Laurent Cozic
771975cd35 Clipper: Fixes #1462: Allow importing images from local file with file:// URLs 2019-05-10 01:06:06 +01:00
Laurent Cozic
356f8e580b Clipper: Improved: Updated Readability library to improve Simplified Page clipping 2019-05-10 00:05:23 +01:00
Laurent Cozic
68268cb35d Merge branch 'master' of github.com:laurent22/joplin 2019-05-09 23:46:41 +01:00
Laurent Cozic
8e58ed12af Clipper: Resolves #1379: Improved: Display warning icon when a page might not render well in simplified mode 2019-05-09 23:41:52 +01:00
Laurent Cozic
beb428b246 Android release v1.0.246 2019-05-08 00:54:46 +01:00
Laurent Cozic
4d81caff0b Electron release v1.0.148 2019-05-08 00:52:20 +01:00
Laurent Cozic
78372c9bac All: Improved: Make sure a revision is saved a note has not been modified for over a week 2019-05-08 00:51:56 +01:00
Laurent Cozic
a4db1bc671 All: Improved: Do not save a revision if there is already a recent one that exists 2019-05-08 00:10:36 +01:00
Laurent Cozic
8ea1c373ed Fixed position of config button 2019-05-07 23:50:12 +01:00
Laurent Cozic
8ef27dfcdc Merge branch 'master' of github.com:laurent22/joplin 2019-05-07 23:43:40 +01:00
Laurent Cozic
23e43c7bc1 Desktop: Fix: Fixed note history sort order. 2019-05-07 23:42:46 +01:00
Helmut K. C. Tessarek
edb8f4c79f Merge pull request #1503 from ruzaq/master
CLI: CZech translation updated
2019-05-07 17:46:39 -04:00
Ruzicka Pavel
e115fa4bb3 CZech translation updated 2019-05-07 23:30:18 +02:00
Laurent Cozic
52a2daddbf All: Improved: Make sure user timestamp is preserved with revision information 2019-05-07 22:15:47 +01:00
Laurent Cozic
c400142996 All: Fix: Make sure a revision is not empty before saving it 2019-05-07 20:46:58 +01:00
Laurent Cozic
219171a18c Remove dependency to git2json and improved handling of new commit messages 2019-05-06 22:18:17 +01:00
Laurent Cozic
d7d573d9dd Android release v1.0.245 2019-05-06 21:51:42 +01:00
Laurent Cozic
c4b17f8919 Electron release v1.0.147 2019-05-06 21:48:50 +01:00
Laurent Cozic
da2f4b96c7 Electron release v1.0.146 2019-05-06 21:48:37 +01:00
Laurent Cozic
08af9de190 All: Resolves #712: New: Support for note history (#1415)
* Started revisions support

* More rev changes

* More rev changes

* More revs changes

* Fixed deletion algorithm

* More tests and moved updated time to separate field

* Display info when restoring note

* Better handling of existing notes

* wip

* Further improvements and fixed tests

* Better handling of changes created via sync

* Enable chokidar again

* Testing special case

* Further improved logic to handle notes that existed before the revision service

* Added tests

* Better handling of encrypted revisions

* Improved handling of deleted note revisions by moving logic to collectRevision

* Improved handling of old notes by moving logic to collectRevision()

* Handle case when deleting revisions while one is still encrypted

* UI tweaks

* Added revision service to mobile app

* Fixed config screens on mobile and desktop

* Enabled revisions on CLI app
2019-05-06 21:35:29 +01:00
Laurent Cozic
9e2982992a Merge branch 'master' of github.com:laurent22/joplin 2019-05-06 21:31:45 +01:00
Laurent Cozic
c03ac5c5f1 Make sure Appveyor only build tags 2019-05-06 21:31:37 +01:00
Luis Orozco
5934f2f08e Desktop: Fixes #355: Resets the undo manager when creating new notes (#1495) 2019-05-06 21:30:04 +01:00
Caleb John
f136f40fdc Doc: Update readme to warn about restarting the editor for userstyle (#1487) 2019-05-06 21:26:34 +01:00
Luis Orozco
d213e4ab57 All: Fixed: Prevents notes with no title to break after synchronize (#1472)
Tests to confirm serialize/unserialize don't change body and title

check if item title exists, otherwise display default title.

added test checking serializing/unserializing Folders don't modify data
2019-05-06 21:25:14 +01:00
Laurent Cozic
782aae4ddf Doc: Better handling of platform in changelog autogenerate 2019-05-03 15:02:32 +00:00
Laurent Cozic
4f47bd7bcd Android release v1.0.244 2019-05-03 00:22:11 +01:00
Laurent Cozic
4f76946140 Electron release v1.0.145 2019-05-03 00:20:01 +01:00
Laurent Cozic
aa60923cbd Doc: Better handling of platforms in changelog generation 2019-05-03 00:19:42 +01:00
doc75
7670ce32b1 removing sh in Linux installation command line as this is unnecessary (and failing on Ubuntu) (#1484) 2019-05-02 23:58:38 +01:00
Laurent Cozic
0b98632336 Update website 2019-05-02 23:54:52 +01:00
Laurent Cozic
49c998de83 Doc: Auto-generate anchors 2019-05-02 23:54:31 +01:00
Helmut K. C. Tessarek
da69d6b2c9 Desktop: Fix: Update chokidar to fix blank screen when returning from external editor (#1479) 2019-05-02 16:00:17 +01:00
Michael Schneider
a757aefce0 Remove separator between New Notebook and Close Window in File Menu (#1483) 2019-05-02 15:55:48 +01:00
Laurent Cozic
b2129cb8c4 Desktop, CLI: Fixes #1476: Import lists and sub-lists from Enex files with correct indentation 2019-05-01 18:06:37 +01:00
Laurent Cozic
27f14c175f Electron release v1.0.144 2019-04-30 23:42:42 +01:00
Laurent Cozic
aad49c520b All: Improved: Display better error message when trying to sync with a new sync target from an old version of Joplin 2019-04-30 23:42:06 +01:00
Michael Schneider
af794a16d6 Desktop (macOS): Add macOS "Close Window" menu item and add name to Quit menu (#1434)
* Add Close Window to macOS file menu

* Add Joplin to Quit menu item

On macOS the application name appears usually within the Quit menu item.

* Use performClose: selector for Close Window

* Revert Quit with name and add Quit string to translations

* Move Quit translation to joplin.pot

* Remove Quit string
2019-04-30 21:38:20 +01:00
Laurent Cozic
ca7266cd69 Fixing images 2019-04-30 19:04:24 +01:00
Laurent Cozic
fb758afc81 Update website 2019-04-30 18:58:35 +01:00
Laurent Cozic
b806f0da49 Removed dependency to unsafe and buggy marked 2019-04-30 18:58:19 +01:00
Laurent Cozic
4e3b1f3e13 Merge branch 'master' of github.com:laurent22/joplin 2019-04-30 18:29:46 +01:00
Laurent Cozic
475467c41c Update website 2019-04-30 18:29:43 +01:00
Caleb John
28e5039873 Update Joplin_install_and_update from #1422 and #1473 (#1475) 2019-04-30 18:28:36 +01:00
Laurent Cozic
1efc6e6151 Merge branch 'master' of github.com:laurent22/joplin 2019-04-30 18:27:08 +01:00
Laurent Cozic
e280a02643 Update doc 2019-04-30 18:26:58 +01:00
Christian Moritz
788dc42684 CLI: Improved: Update sharp (for node 12 compatibility) (#1471) 2019-04-30 17:32:51 +01:00
Laurent Cozic
01f2759a62 Added CLI changelog 2019-04-29 18:39:43 +01:00
Laurent Cozic
9419e3af9c CLI v1.0.125 2019-04-29 18:36:32 +01:00
Laurent Cozic
6d220005cc All: Fixes #1353: Remove message "Processing a path that has already been done" as this is not an error 2019-04-29 18:27:32 +01:00
Laurent Cozic
6d68e61bbd Exclude reverted commits from changelog 2019-04-29 07:42:40 +01:00
Laurent Cozic
29582623b0 Revert "Desktop: Improved: Removed gaps between note list and vertical resizers (#1464)"
This reverts commit d6e59c5238.
2019-04-29 07:28:16 +01:00
Laurent Cozic
4571e7853a Improved auto-generation of changelog 2019-04-28 15:09:07 +01:00
Luis Orozco
d6e59c5238 Desktop: Improved: Removed gaps between note list and vertical resizers (#1464) 2019-04-28 14:23:17 +01:00
Luis Orozco
6335cbedb8 Desktop: Improved: UI updates to sidebar and header, changing icon sizes and animations (#1463)
Added animation to icon in synchronize button

Moved sync report above button, which prevents the sync button from moving from its place when the report has text.

Added animation to icon in Toggle Sidebar button, using the css transition property.

Reduced font size for text and icons in header and sidebar

Changed theme color2 from white to a very light grey. It is barely
noticeable, but reduces contrast a bit, improving readability.
2019-04-28 14:20:18 +01:00
Laurent Cozic
f3344ce05d Removed "Demo" word from screenshot to comply with App Store 2019-04-28 13:11:15 +01:00
Laurent Cozic
155d38d24a Update website 2019-04-26 19:06:17 +01:00
Laurent Cozic
412f6d8316 Fixing Arabic flag 2019-04-26 18:58:40 +01:00
Laurent Cozic
d0f3ed80e0 Added new required iOS screenshots 2019-04-26 18:37:30 +01:00
Helmut K. C. Tessarek
b86f3b74bd build-translation.js: hack to show en_US as 100% (#1448) 2019-04-26 18:36:12 +01:00
Laurent Cozic
60054d1d8b ios-v10.0.31 2019-04-26 08:52:59 +01:00
Laurent Cozic
c40c6428d7 Merge branch 'master' of github.com:laurent22/joplin 2019-04-26 08:30:51 +01:00
Laurent Cozic
e708ecccee Updated FAQ 2019-04-26 08:30:40 +01:00
Helmut K. C. Tessarek
04f991d3bf Update website 2019-04-23 16:10:41 -04:00
Helmut K. C. Tessarek
d5d7368ba0 Merge pull request #1446 from Fvbor/patch-1
Readme: Change Download links from 1.0.142 to 1.0.143
2019-04-23 16:09:16 -04:00
Hagen Tasche
abff929d4e Change Download links from 1.0.142 to 1.0.143 2019-04-23 09:09:11 +02:00
Laurent Cozic
49edc82594 Tools: Allow auto-generating changelog from commit messages 2019-04-22 18:02:45 +00:00
Helmut K. C. Tessarek
7dd7d0ec17 Merge pull request #1439 from tessus/localization-de_DE
update localization de_DE.po
2019-04-22 00:01:34 -04:00
Helmut K. C. Tessarek
61aaf64f95 update localization de_DE.po 2019-04-22 00:00:54 -04:00
Helmut K. C. Tessarek
da35785951 Update website 2019-04-21 14:55:52 -04:00
Helmut K. C. Tessarek
e394034678 restore the content of API.md 2019-04-21 14:49:12 -04:00
Laurent Cozic
edf002ab32 Android release v1.0.243 2019-04-21 14:58:33 +01:00
Laurent Cozic
50f2076981 Electron release v1.0.143 2019-04-21 14:56:13 +01:00
Laurent Cozic
a9ae78bcde Updated translations 2019-04-21 14:55:12 +01:00
Laurent Cozic
0d7f9a2ab3 Merge branch 'master' of github.com:laurent22/joplin 2019-04-21 13:56:01 +01:00
Laurent Cozic
a5ee120281 All: Fixes #1433: Some resources could incorrectly be deleted even though they are still present in a note. Also added additional verifications before deleting a resource. 2019-04-21 13:49:40 +01:00
Helmut K. C. Tessarek
12ebf44e22 Desktop: add option to use soft breaks for markdown rendering (#1408)
* add option to use soft breaks for markdown rendering

* oops, I didn't use the British spelling

* moved setting to section Plugins

* change text -> Enable soft breaks
2019-04-21 10:03:10 +01:00
Laurent Cozic
220f5d0967 Desktop: Fixes #1425 (probably): Fix display of images when using VSCode as external editor 2019-04-20 21:12:19 +01:00
Laurent Cozic
4ef05272c4 Clipper: Fixes #1417: Sort the folders in the same order as the desktop app 2019-04-20 19:29:23 +01:00
Laurent Cozic
c3262aa5f8 Desktop: Allow CtrlCmd+G shortcut from text editor 2019-04-20 19:07:13 +01:00
Laurent Cozic
42119c8f42 All: Fixes #1427: Support checkoxes behind bullets 2019-04-20 19:00:22 +01:00
Laurent Cozic
27cce03968 Updated translations 2019-04-20 12:26:34 +01:00
Laurent Cozic
776aba1e49 Merge branch 'master' of github.com:laurent22/joplin 2019-04-20 12:23:55 +01:00
Laurent Cozic
9356841cfc Desktop: Fixes #423: Make sure links are clickable when exporting to PDF 2019-04-20 12:23:05 +01:00
Helmut K. C. Tessarek
7fc233e808 Desktop: change shortcuts for 'Print' and 'Goto Anything' (#1420)
Print            Command/Control + P
Goto Anything    Command/Control + G

closes #1413
2019-04-20 12:02:43 +01:00
Helmut K. C. Tessarek
7b2eac3abd add localization for English (United States) en_US (#1391) 2019-04-20 12:01:53 +01:00
Laurent Cozic
93323deea5 Desktop: Fix: Updated Electron and Chokidar to try to fix external editor crashing app 2019-04-20 12:00:42 +01:00
Laurent Cozic
e8fa399e9e Update website 2019-04-18 15:26:13 +01:00
Laurent Cozic
a974eb5d9f Fixing links 2019-04-18 15:11:56 +01:00
Laurent Cozic
6a3f04274d Update website 2019-04-18 15:00:32 +01:00
Laurent Cozic
f8e1395087 joplin.cozic.net => joplinapp.org 2019-04-18 14:59:17 +01:00
Laurent Cozic
82b5af51e5 Update CNAME 2019-04-18 14:06:15 +01:00
Laurent Cozic
cf40c14a86 All: Fixes #1405: Handle invalid resource tags that contain no data when importing ENEX 2019-04-12 01:43:15 +01:00
Laurent Cozic
be2b2b7836 Merge branch 'master' of github.com:laurent22/joplin 2019-04-04 08:14:36 +01:00
Laurent Cozic
0cebae8032 All: Allow longer folder paths 2019-04-04 08:01:16 +01:00
Laurent Cozic
6ebc77cbba Desktop: Fix: Goto Anything results were displayed lowercase 2019-04-04 07:53:20 +01:00
Tim Kilåker
542a5e88b7 All: 1383 Clear selected Notes when switching Notebook (#1387) 2019-04-04 07:48:33 +01:00
Laurent Cozic
72b36522e8 All: Improved support for Japanese, Chinese, Korean search queries (also applies to Goto Anything) 2019-04-03 07:46:41 +01:00
Laurent Cozic
252d937405 Update website 2019-04-02 17:46:39 +01:00
Laurent Cozic
a73b0309b9 Electron release v1.0.142 2019-04-02 17:27:52 +01:00
Laurent Cozic
c22283e799 Electron release v1.0.141 2019-04-02 17:27:39 +01:00
Laurent Cozic
1e51ab4a59 Updated translations 2019-04-02 17:27:19 +01:00
Caleb John
0c2f2667d3 All: Allow toggling markdown plugins and added several new plugins (#1347)
* Initial test of enabling plugins

* Added support for toggle-able plugins
- Also adds some new plugins

* Add instructions on adding toggle-plugins

* Fix subtle anchor bug
- webview was moving itself when scrolling to bottom anchors

* Moves the webview hack so that it only applies to anchors

* Add plugin descriptions to the README, also removed mermaid from README

* rename plugin.* to markdown.plugin.* to be more forward compatible
2019-04-02 17:14:48 +01:00
Laurent Cozic
496c9ddb91 Fixed tests to match new behaviour 2019-04-02 00:22:04 +01:00
Laurent Cozic
5ad0b2eed9 Clean up 2019-04-02 00:12:38 +01:00
Laurent Cozic
577d62e783 Updated translations 2019-04-02 00:11:40 +01:00
Laurent Cozic
dcb73c9916 Desktop: Fixed menu logic for non-macOS 2019-04-01 19:51:47 +00:00
Laurent Cozic
6b2910c3c7 Desktop: Added Goto Anything dialog and implemented basic plugin system 2019-04-01 19:43:13 +00:00
Helmut K. C. Tessarek
db04906416 Desktop: macOS: make the menu more like a macOS menu (#1348)
* macOS: make the menu more like a macOS menu

* remove duplcated code even more

* yep, I forgot to localize the new menu item

* more de-duplication, create File menu on macOS
2019-04-01 10:04:34 +01:00
s1nceri7y
54fceeb07d Update README.md (#1375)
added links to browser extensions
2019-03-31 18:27:36 +01:00
RaphaelKimmig
fa32678645 improve search bar text alignment (#1377) 2019-03-31 18:26:47 +01:00
RaphaelKimmig
ee1df1a396 fix sub pixel rendering for desktop (#1378) 2019-03-31 18:25:13 +01:00
Laurent Cozic
729be8767c Clipper release v1.0.13 2019-03-31 12:15:24 +01:00
Helmut K. C. Tessarek
8471f0d86d Merge pull request #1374 from s1nceri7y/patch-1
Update ru_RU.po
2019-03-30 16:34:43 -04:00
s1nceri7y
390b818d71 Update ru_RU.po
translation adjustments
2019-03-30 10:14:44 +00:00
Laurent Cozic
1a1c190ea3 Clipper: Move Confirm button up 2019-03-29 10:11:27 +00:00
Laurent Cozic
40d82b80f1 Clipper release v1.0.12 2019-03-29 09:45:19 +00:00
Laurent Cozic
7647ecbbc7 Clipper: Do not inline scripts to prevent CSP error 2019-03-29 09:44:56 +00:00
265 changed files with 16804 additions and 5920 deletions

5
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,5 @@
# These are supported funding model platforms
github: laurent22
patreon: joplin
custom: https://joplinapp.org/donate/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 335 KiB

After

Width:  |  Height:  |  Size: 336 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 254 KiB

After

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 KiB

View File

@@ -1,7 +1,8 @@
[![Travis Build Status](https://travis-ci.org/laurent22/joplin.svg?branch=master)](https://travis-ci.org/laurent22/joplin) [![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/github/laurent22/joplin?branch=master&passingText=master%20-%20OK&svg=true)](https://ci.appveyor.com/project/laurent22/joplin)
# General information
- All the applications share the same library, which, for historical reasons, is in ReactNativeClient/lib. This library is copied to the relevant directories when building each app.
- The translations are built by running CliClient/build-translation.sh. You normally don't need to run this if you haven't updated the translation since the compiled files are on the repository.
## macOS dependencies

View File

@@ -1,32 +1,42 @@
**IMPORTANT:** At the moment pull requests for new features are no longer being accepted. More info there: https://github.com/laurent22/joplin/issues/1112
* * *
# User support
For general discussion about Joplin, user support, software development questions, and to discuss new features, please go to the [Joplin Forum](https://discourse.joplin.cozic.net/). It is possible to login with your GitHub account.
The [Joplin Forum](https://discourse.joplinapp.org/) is the community driven place for user support, general discussion about Joplin, problems with installation, new features and software development questions. It is possible to login with your GitHub account.
# Reporting a bug
Please check first that it [has not already been reported](https://github.com/laurent22/joplin/issues?utf8=%E2%9C%93&q=is%3Aissue). Also consider [enabling debug mode](https://github.com/laurent22/joplin/blob/master/readme/debugging.md) before reporting the issue so that you can provide as much details as possible to help fix it.
File bugs in the [Github Issue Tracker](https://github.com/laurent22/joplin/issues?utf8=%E2%9C%93&q=is%3Aissue). Please follow these guidelines:
If possible, **please provide a screenshot**. A screenshot showing the problem is often more useful than a paragraph describing it as it can make it immediately clear what the issue is.
- Search existing issues first, make sure yours hasn't already been reported.
- Don't use the issue tracker for support questions.
- Consider [enabling debug mode](https://github.com/laurent22/joplin/blob/master/readme/debugging.md) so that you can provide as much details as possible when reporting the issue.
- Stay on topic, but describe the issue in detail so that others can reproduce it.
- **Provide a screenshot** if possible. A screenshot showing the problem is often more useful than a paragraph describing it.
# Feature requests
Again, please check that it has not already been requested. If it has, simply **up-vote the issue** - the ones with the most up-votes are likely to be implemented. "+1" comments are not tracked.
Please check that your request has not already been posted in the [Github Issue Tracker](https://github.com/laurent22/joplin/issues?utf8=%E2%9C%93&q=is%3Aissue). If it has, **up-voting the issue** increases the chances it'll be noticed and implemented in the future. "+1" comments are not tracked.
# Creating a pull request
As a general rule, suggestions to _improve Joplin_ should be posted first in the [Joplin Forum](https://discourse.joplinapp.org/) for discussion.
- If you want to add a new feature, consider asking about it before implementing it or checking existing discussions to make sure it is within the scope of the project. That scope, due to limited resources, might be narrower than you think. As a rule of thumb **if your change is likely to involve more than 50 lines of code, you should discuss it in the forum**, just so that you don't waste your time implementing something that might not be accepted.
Avoid listing multiple requests in one report in the [Github Issue Tracker](https://github.com/laurent22/joplin/issues?utf8=%E2%9C%93&q=is%3Aissue). One issue per request makes it easier to track and discuss it.
- Bug fixes have a very high chance of being accepted.
# Contribute to the project
- A pull request that is relevant to the current roadmap has a very high chance of being accepted.
## Contributing to Joplin's translation
Joplin is available in multiple languages thanks to the help of its users. You can help translate Joplin to your language or keep it up to date. Please read the documentation about [Localisation](https://github.com/laurent22/joplin#localisation).
## Contributing to Joplin's code
If you want to start contributing to the project's code, please follow these guidelines before creating a pull request:
- Bug fixes are always welcome. Start by reviewing the list of [essential issues](https://github.com/laurent22/joplin/issues?q=is%3Aissue+is%3Aopen+label%3Aessential)
- Before adding a new feature, ask about it in the [Github Issue Tracker](https://github.com/laurent22/joplin/issues?utf8=%E2%9C%93&q=is%3Aissue) or the [Joplin Forum](https://discourse.joplinapp.org/), or check if existing discussions exist to make sure the new functionality is desired.
- **Changes that will consist in more than 50 lines of code should be discussed the [Joplin Forum](https://discourse.joplinapp.org/)**, so that you don't spend too much time implementing something that might not be accepted.
Building the apps is relatively easy - please [see the build instructions](https://github.com/laurent22/joplin/blob/master/BUILD.md) for more details.
# Coding style
## Coding style
There are only two rules, but not following them means the pull request will not be accepted (it can be accepted once the issues are fixed):

View File

@@ -23,6 +23,7 @@ const fs = require('fs-extra');
const { cliUtils } = require('./cli-utils.js');
const Cache = require('lib/Cache');
const WelcomeUtils = require('lib/WelcomeUtils');
const RevisionService = require('lib/services/RevisionService');
class Application extends BaseApplication {
@@ -422,6 +423,8 @@ class Application extends BaseApplication {
const tags = await Tag.allWithNotes();
ResourceService.runInBackground();
RevisionService.instance().runInBackground();
this.dispatch({
type: 'TAG_UPDATE_ALL',

View File

@@ -102,7 +102,7 @@ function getFooter() {
output.push('WEBSITE');
output.push('');
output.push(INDENT + 'https://joplin.cozic.net');
output.push(INDENT + 'https://joplinapp.org');
output.push('');

View File

@@ -132,7 +132,7 @@ class Command extends BaseCommand {
lines.push('# Searching');
lines.push('');
lines.push('Call **GET /search?query=YOUR_QUERY** to search for notes. This end-point supports the `field` parameter which is recommended to use so that you only get the data that you need. The query syntax is as described in the main documentation: https://joplin.cozic.net/#searching');
lines.push('Call **GET /search?query=YOUR_QUERY** to search for notes. This end-point supports the `field` parameter which is recommended to use so that you only get the data that you need. The query syntax is as described in the main documentation: https://joplinapp.org/#searching');
lines.push('');
for (let i = 0; i < models.length; i++) {

View File

@@ -37,7 +37,7 @@ class Command extends BaseCommand {
const stdoutWidth = app().commandStdoutMaxWidth();
if (args.command === 'shortcuts' || args.command === 'keymap') {
this.stdout(_('For information on how to customise the shortcuts please visit %s', 'https://joplin.cozic.net/terminal/#shortcuts'));
this.stdout(_('For information on how to customise the shortcuts please visit %s', 'https://joplinapp.org/terminal/#shortcuts'));
this.stdout('');
if (app().gui().isDummy()) {

View File

@@ -22,6 +22,7 @@ const Tag = require('lib/models/Tag.js');
const NoteTag = require('lib/models/NoteTag.js');
const MasterKey = require('lib/models/MasterKey');
const Setting = require('lib/models/Setting.js');
const Revision = require('lib/models/Revision.js');
const { Logger } = require('lib/logger.js');
const { FsDriverNode } = require('lib/fs-driver-node.js');
const { shimInit } = require('lib/shim-init-node.js');
@@ -43,6 +44,7 @@ BaseItem.loadClass('Resource', Resource);
BaseItem.loadClass('Tag', Tag);
BaseItem.loadClass('NoteTag', NoteTag);
BaseItem.loadClass('MasterKey', MasterKey);
BaseItem.loadClass('Revision', Revision);
Setting.setConstant('appId', 'net.cozic.joplin-cli');
Setting.setConstant('appType', 'cli');

View File

@@ -587,8 +587,8 @@ msgstr "الاستيراد من \"%s\" بتنسيق \"%s\". فضلاً انتظ
msgid "PDF File"
msgstr "ملف PDF"
msgid "&File"
msgstr "&ملف"
msgid "Synchronisation status"
msgstr "حالة المزامنة"
msgid "New note"
msgstr "ملاحظة جديدة"
@@ -599,6 +599,34 @@ msgstr "قائمة جديدة للمهام"
msgid "New notebook"
msgstr "دفتر ملاحظات جديد"
msgid "Print"
msgstr "اطبع"
msgid "General Options"
msgstr "الخيارات العامة"
msgid "Encryption options"
msgstr "خيارات التشفير"
msgid "Web clipper options"
msgstr "خيارات Web clipper"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
msgid "&File"
msgstr "&ملف"
msgid "About Joplin"
msgstr "حول Joplin"
msgid "Preferences..."
msgstr ""
msgid "Check for updates..."
msgstr "البحث جارٍ عن تحديثات..."
msgid "Import"
msgstr "استيراد"
@@ -608,9 +636,6 @@ msgstr "تصدير"
msgid "Synchronise"
msgstr "زامِن"
msgid "Print"
msgstr "اطبع"
#, javascript-format
msgid "Hide %s"
msgstr "أخف %s"
@@ -618,6 +643,9 @@ msgstr "أخف %s"
msgid "Quit"
msgstr "إغلاق"
msgid "Close Window"
msgstr ""
msgid "&Edit"
msgstr "ت&حرير"
@@ -669,18 +697,6 @@ msgstr "تركيز"
msgid "&Tools"
msgstr "&أدوات"
msgid "Synchronisation status"
msgstr "حالة المزامنة"
msgid "Web clipper options"
msgstr "خيارات Web clipper"
msgid "Encryption options"
msgstr "خيارات التشفير"
msgid "General Options"
msgstr "الخيارات العامة"
msgid "&Help"
msgstr "م&ساعدة"
@@ -690,16 +706,6 @@ msgstr "موقع الويب و التوثيق"
msgid "Make a donation"
msgstr "تبرَّع"
msgid "Check for updates..."
msgstr "البحث جارٍ عن تحديثات..."
msgid "About Joplin"
msgstr "حول Joplin"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, javascript-format
msgid "Open %s"
msgstr "افتح %s"
@@ -806,12 +812,12 @@ msgstr ""
msgid "Notes and settings are stored in: %s"
msgstr "الملاحظات و الإعدادات مخزّنة في: %s"
msgid "Browse..."
msgstr "استعراض..."
msgid "Check synchronisation configuration"
msgstr "فحص ضبط المزامنة"
msgid "Browse..."
msgstr "استعراض..."
msgid "Apply"
msgstr "تطبيق"
@@ -971,9 +977,33 @@ msgstr "المكان"
msgid "URL"
msgstr "عنوان URL"
#, fuzzy
msgid "Note History"
msgstr "قائمة ملاحظات"
msgid "Previous versions of this note"
msgstr ""
msgid "Note properties"
msgstr "خصائص الملاحظة"
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr ""
#, fuzzy
msgid "This note has no history"
msgstr "جرى تعديل هذه الملاحظة:"
msgid "Restore"
msgstr ""
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
msgid "Open..."
msgstr "فتح..."
@@ -1124,15 +1154,12 @@ msgid "Decrypting items: %d/%d"
msgstr "فك تشفير العناصر: %d/%d"
#, javascript-format
msgid "Fetching resources: %d"
msgstr "جلب الموارد: %d"
msgid "Fetching resources: %d/%d"
msgstr "جلب الموارد: %d/%d"
msgid "Please select where the sync status should be exported to"
msgstr "فضلاً اختر أين سيتم تصدير حالة المزامنة"
msgid "Table of contents"
msgstr ""
msgid "Add or remove tags"
msgstr "إضافة أو حذف وسوم"
@@ -1163,6 +1190,14 @@ msgstr "حذف الملاحظة \"%s\" ؟"
msgid "Delete these %d notes?"
msgstr "حذف ملاحظات %d هذه ؟"
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
msgid "Goto Anything..."
msgstr ""
#, javascript-format
msgid "Usage: %s"
msgstr "الاستخدام : %s"
@@ -1275,6 +1310,10 @@ msgstr "قيد التقدم"
msgid "Synchronisation is already in progress. State: %s"
msgstr "المزامنة قيد التقدم بالفعل. الحال: %s"
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr ""
msgid "Encrypted"
msgstr "مشفّر"
@@ -1311,6 +1350,15 @@ msgstr "لا يمكن نسخ الملاحظة إلى دفتر الملاحظات
msgid "Cannot move note to \"%s\" notebook"
msgstr "لا يمكن نقل الملاحظة إلى دفتر الملاحظات \"%s\""
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
"تنبيه: إذا غيرت هذا المكان ، تأكد من نسخ كافة المحتويات لديك إليه قبل البدء "
"بالمزامنة ، وإلا فسيتم حذف كل الملفات! أنظر الأسئلة المتكررة لتفاصيل أكثر: %s"
msgid "Language"
msgstr "اللغة"
@@ -1360,6 +1408,43 @@ msgstr "التركيز على المتن"
msgid "When creating a new note:"
msgstr "عند إنشاء ملاحظة جديدة:"
msgid "Enable soft breaks"
msgstr ""
#, fuzzy
msgid "Enable math expressions"
msgstr "تفعيل التشفير"
msgid "Enable ==mark== syntax"
msgstr ""
msgid "Enable footnotes"
msgstr ""
msgid "Enable table of contents extension"
msgstr ""
msgid "Enable ~sub~ syntax"
msgstr ""
msgid "Enable ^sup^ syntax"
msgstr ""
msgid "Enable deflist syntax"
msgstr ""
msgid "Enable abbreviation syntax"
msgstr ""
msgid "Enable markdown emoji"
msgstr ""
msgid "Enable ++insert++ syntax"
msgstr ""
msgid "Enable multimarkdown table extension"
msgstr ""
msgid "Show tray icon"
msgstr "إظهار أيقونة لوحة النظام"
@@ -1441,28 +1526,30 @@ msgstr ""
"الوجهة المستهدفة المزامنة إليها. كل وجهة مزامنة مستهدفة قد يكون لها معلمات "
"إضافية تكون مسماة بـ `sync.NUM.NAME` (جميعها موثقة أدناه)."
msgid "Attachment download behaviour"
msgstr ""
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
msgid "Always"
msgstr ""
msgid "Manual"
msgstr ""
msgid "Auto"
msgstr ""
msgid "Directory to synchronise with (absolute path)"
msgstr "الدليل الذي تتم المزامنة معه (المسار المطلق)"
msgid ""
"The path to synchronise with when file system synchronisation is enabled. "
"See `sync.target`."
msgstr ""
"المسار الذي ستتم المزامنة معه عند تفعيل مزامنة نظام الملفات. أنظر `sync."
"target`."
msgid "Nextcloud WebDAV URL"
msgstr "عنوان URL لـ Nextcloud WebDAV"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
"تنبيه: إذا غيرت هذا المكان ، تأكد من نسخ كافة المحتويات لديك إليه قبل البدء "
"بالمزامنة ، وإلا فسيتم حذف كل الملفات! أنظر الأسئلة المتكررة لتفاصيل أكثر: %s"
msgid "Nextcloud username"
msgstr "اسم مستخدم Nextcloud"
@@ -1495,6 +1582,20 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr "تجاهل أخطاء شهادات TLS"
#, fuzzy
msgid "Enable note history"
msgstr "تفعيل التشفير"
msgid "days"
msgstr ""
#, javascript-format
msgid "%d days"
msgstr ""
msgid "Keep note history for"
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "قيمة خيار غير صحيحة: \"%s\". القيم الممكنة هي: %s."
@@ -1511,6 +1612,9 @@ msgstr "المظهر"
msgid "Note"
msgstr "ملاحظة"
msgid "Plugins"
msgstr ""
msgid "Application"
msgstr "التطبيق"
@@ -1561,12 +1665,19 @@ msgstr "لا يوجد بيانات للتصدير."
msgid "Please specify the notebook where the notes should be imported to."
msgstr "فضلاً حدّد دفتر الملاحظات الذي ترغب استيراد الملاحظات إليه."
msgid "Restored Notes"
msgstr ""
msgid "Items that cannot be synchronised"
msgstr "العناصر التي لا يمكن مزامنتها"
#, javascript-format
msgid "%s (%s): %s"
msgstr "%s (%s): %s"
#, fuzzy, javascript-format
msgid "%s (%s) could not be uploaded: %s"
msgstr "لم نتمكن من فتح هذا الملف: %s"
#, fuzzy, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr "لم نتمكن من فتح هذا الملف: %s"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
@@ -1839,6 +1950,16 @@ msgstr "ليس لديك دفاتر ملاحظات حالياً. أنشئ واح
msgid "Welcome"
msgstr "مرحباً"
#~ msgid "%s (%s): %s"
#~ msgstr "%s (%s): %s"
#~ msgid ""
#~ "The path to synchronise with when file system synchronisation is enabled. "
#~ "See `sync.target`."
#~ msgstr ""
#~ "المسار الذي ستتم المزامنة معه عند تفعيل مزامنة نظام الملفات. أنظر `sync."
#~ "target`."
#~ msgid "Remove?"
#~ msgstr "إزالة ؟"

View File

@@ -611,9 +611,8 @@ msgstr "S'està important des de «%s» com a format «%s». Espereu..."
msgid "PDF File"
msgstr "Fitxer PDF"
#, fuzzy
msgid "&File"
msgstr "Fitxer"
msgid "Synchronisation status"
msgstr "Estat de la sincronització"
msgid "New note"
msgstr "Nota nova"
@@ -624,6 +623,35 @@ msgstr "Llistat de tasques pendents nou"
msgid "New notebook"
msgstr "Bloc de notes nou"
msgid "Print"
msgstr "Imprimeix"
msgid "General Options"
msgstr "Opcions generals"
msgid "Encryption options"
msgstr "Opcions del xifratge"
msgid "Web clipper options"
msgstr "Opcions del desa-retalls de webs"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, fuzzy
msgid "&File"
msgstr "Fitxer"
msgid "About Joplin"
msgstr "Quant al Joplin"
msgid "Preferences..."
msgstr ""
msgid "Check for updates..."
msgstr "Comprova les actualitzacions..."
msgid "Import"
msgstr "Importació"
@@ -633,9 +661,6 @@ msgstr "Exportació"
msgid "Synchronise"
msgstr "Sincronitza"
msgid "Print"
msgstr "Imprimeix"
#, javascript-format
msgid "Hide %s"
msgstr "Amaga %s"
@@ -643,6 +668,9 @@ msgstr "Amaga %s"
msgid "Quit"
msgstr "Surt"
msgid "Close Window"
msgstr ""
#, fuzzy
msgid "&Edit"
msgstr "Edita"
@@ -700,18 +728,6 @@ msgstr "Vés al cos"
msgid "&Tools"
msgstr "Eines"
msgid "Synchronisation status"
msgstr "Estat de la sincronització"
msgid "Web clipper options"
msgstr "Opcions del desa-retalls de webs"
msgid "Encryption options"
msgstr "Opcions del xifratge"
msgid "General Options"
msgstr "Opcions generals"
#, fuzzy
msgid "&Help"
msgstr "Ajuda"
@@ -722,16 +738,6 @@ msgstr "Lloc web i documentació"
msgid "Make a donation"
msgstr "Donatius"
msgid "Check for updates..."
msgstr "Comprova les actualitzacions..."
msgid "About Joplin"
msgstr "Quant al Joplin"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, javascript-format
msgid "Open %s"
msgstr "Obre %s"
@@ -841,12 +847,12 @@ msgstr ""
msgid "Notes and settings are stored in: %s"
msgstr "Les notes i la configuració es desen a: %s"
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Comprova la configuració de la sincronització"
msgid "Browse..."
msgstr ""
msgid "Apply"
msgstr ""
@@ -1010,9 +1016,33 @@ msgstr ""
msgid "URL"
msgstr ""
#, fuzzy
msgid "Note History"
msgstr "Blocs de notes"
msgid "Previous versions of this note"
msgstr ""
msgid "Note properties"
msgstr ""
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr ""
#, fuzzy
msgid "This note has no history"
msgstr "Aquesta nota s'ha modificat:"
msgid "Restore"
msgstr ""
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
msgid "Open..."
msgstr "Obre..."
@@ -1161,18 +1191,15 @@ msgstr "Blocs de notes"
#, fuzzy, javascript-format
msgid "Decrypting items: %d/%d"
msgstr "Elements obtinguts: %d/%d."
msgstr "Elements obtinguts: %d/%d"
#, fuzzy, javascript-format
msgid "Fetching resources: %d"
msgstr "Recursos: %d."
msgid "Fetching resources: %d/%d"
msgstr "Recursos: %d/%d"
msgid "Please select where the sync status should be exported to"
msgstr "Seleccioneu on s'hauria d'exportar l'estat de la sincronització"
msgid "Table of contents"
msgstr ""
msgid "Add or remove tags"
msgstr "Afegeix o suprimeix etiquetes"
@@ -1206,6 +1233,14 @@ msgstr "Voleu suprimir les notes?"
msgid "Delete these %d notes?"
msgstr "Voleu suprimir aquestes notes?"
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
msgid "Goto Anything..."
msgstr ""
#, javascript-format
msgid "Usage: %s"
msgstr "Ús: %s"
@@ -1318,6 +1353,10 @@ msgstr "En progés"
msgid "Synchronisation is already in progress. State: %s"
msgstr "La sincronització ja és en procés. Estat: %s"
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr ""
msgid "Encrypted"
msgstr "Xifrat"
@@ -1354,6 +1393,13 @@ msgstr "No es pot copiar la nota al bloc de notes «%s»"
msgid "Cannot move note to \"%s\" notebook"
msgstr "No es pot moure la nota al bloc de notes «%s»"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
msgid "Language"
msgstr "Llengua"
@@ -1403,6 +1449,43 @@ msgstr "Vés al cos"
msgid "When creating a new note:"
msgstr "En crear una nota:"
msgid "Enable soft breaks"
msgstr ""
#, fuzzy
msgid "Enable math expressions"
msgstr "Activa el xifratge"
msgid "Enable ==mark== syntax"
msgstr ""
msgid "Enable footnotes"
msgstr ""
msgid "Enable table of contents extension"
msgstr ""
msgid "Enable ~sub~ syntax"
msgstr ""
msgid "Enable ^sup^ syntax"
msgstr ""
msgid "Enable deflist syntax"
msgstr ""
msgid "Enable abbreviation syntax"
msgstr ""
msgid "Enable markdown emoji"
msgstr ""
msgid "Enable ++insert++ syntax"
msgstr ""
msgid "Enable multimarkdown table extension"
msgstr ""
msgid "Show tray icon"
msgstr "Mostra la icona a la safata"
@@ -1486,26 +1569,30 @@ msgstr ""
"L'objectiu on se sincronitzarà. Cada objectiu pot tenir paràmetres "
"addicionals que s'anomenen com a «sync.NUM.NAME» (es documenten a sota)."
msgid "Attachment download behaviour"
msgstr ""
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
msgid "Always"
msgstr ""
msgid "Manual"
msgstr ""
msgid "Auto"
msgstr ""
msgid "Directory to synchronise with (absolute path)"
msgstr "Directori on es farà la sincronització (camí absolut)"
msgid ""
"The path to synchronise with when file system synchronisation is enabled. "
"See `sync.target`."
msgstr ""
"El camí on sincronitzar en activar la sincronització del sistema. Vegeu "
"«sync.target»."
msgid "Nextcloud WebDAV URL"
msgstr "URL del Nextcloud WebDAV"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
msgid "Nextcloud username"
msgstr "Nom d'usuari del Nextcloud"
@@ -1534,6 +1621,20 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr ""
#, fuzzy
msgid "Enable note history"
msgstr "Activa el xifratge"
msgid "days"
msgstr ""
#, javascript-format
msgid "%d days"
msgstr ""
msgid "Keep note history for"
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "El valor de l'opció no és vàlid: «%s». Els valors possibles són: %s."
@@ -1553,6 +1654,9 @@ msgstr ""
msgid "Note"
msgstr "Blocs de notes"
msgid "Plugins"
msgstr ""
#, fuzzy
msgid "Application"
msgstr "Surt de l'aplicació"
@@ -1605,12 +1709,19 @@ msgstr "No hi ha dades per exportar."
msgid "Please specify the notebook where the notes should be imported to."
msgstr "Indiqueu el bloc de notes on s'haurien d'importar les notes."
msgid "Restored Notes"
msgstr ""
msgid "Items that cannot be synchronised"
msgstr "Elements que no s'han pogut sincronitzar"
#, javascript-format
msgid "%s (%s): %s"
msgstr "%s (%s): %s"
#, fuzzy, javascript-format
msgid "%s (%s) could not be uploaded: %s"
msgstr "No s'ha pogut desar el bloc de notes: %s"
#, fuzzy, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr "No s'ha pogut desar el bloc de notes: %s"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
@@ -1889,6 +2000,16 @@ msgstr ""
msgid "Welcome"
msgstr "Benvingut"
#~ msgid "%s (%s): %s"
#~ msgstr "%s (%s): %s"
#~ msgid ""
#~ "The path to synchronise with when file system synchronisation is enabled. "
#~ "See `sync.target`."
#~ msgstr ""
#~ "El camí on sincronitzar en activar la sincronització del sistema. Vegeu "
#~ "«sync.target»."
#, fuzzy
#~ msgid "Joplin v%s"
#~ msgstr "Lloc web del Joplin"

File diff suppressed because it is too large Load Diff

View File

@@ -598,9 +598,8 @@ msgstr "Importerer fra \"%s\" som \"%s\"-format. Vent venligst..."
msgid "PDF File"
msgstr "PDF fil"
#, fuzzy
msgid "&File"
msgstr "Fil"
msgid "Synchronisation status"
msgstr "Synkroniserings status"
msgid "New note"
msgstr "Ny note"
@@ -611,6 +610,35 @@ msgstr "Ny opgave"
msgid "New notebook"
msgstr "Ny notesbog"
msgid "Print"
msgstr "Udskriv"
msgid "General Options"
msgstr "Generelle indstillinger"
msgid "Encryption options"
msgstr "Krypterings muligheder"
msgid "Web clipper options"
msgstr ""
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, fuzzy
msgid "&File"
msgstr "Fil"
msgid "About Joplin"
msgstr "Om Joplin"
msgid "Preferences..."
msgstr ""
msgid "Check for updates..."
msgstr "Checker om der er opdateringer.."
msgid "Import"
msgstr "Importer"
@@ -620,9 +648,6 @@ msgstr "Eksporter"
msgid "Synchronise"
msgstr "Synkroniser"
msgid "Print"
msgstr "Udskriv"
#, javascript-format
msgid "Hide %s"
msgstr "Skjul %s"
@@ -630,6 +655,9 @@ msgstr "Skjul %s"
msgid "Quit"
msgstr "Afslut"
msgid "Close Window"
msgstr ""
#, fuzzy
msgid "&Edit"
msgstr "Ret"
@@ -687,18 +715,6 @@ msgstr "Fokuser på brødtekst"
msgid "&Tools"
msgstr "Værktøjer"
msgid "Synchronisation status"
msgstr "Synkroniserings status"
msgid "Web clipper options"
msgstr ""
msgid "Encryption options"
msgstr "Krypterings muligheder"
msgid "General Options"
msgstr "Generelle indstillinger"
#, fuzzy
msgid "&Help"
msgstr "Hjælp"
@@ -709,16 +725,6 @@ msgstr "Joplins hjemmeside og dokumentation"
msgid "Make a donation"
msgstr "Giv en donation"
msgid "Check for updates..."
msgstr "Checker om der er opdateringer.."
msgid "About Joplin"
msgstr "Om Joplin"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, javascript-format
msgid "Open %s"
msgstr "Åben %s"
@@ -821,12 +827,12 @@ msgstr ""
msgid "Notes and settings are stored in: %s"
msgstr "Noter og indstillinger er gemt i: %s"
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Check synkroniserings Indstillinger"
msgid "Browse..."
msgstr ""
msgid "Apply"
msgstr ""
@@ -989,9 +995,33 @@ msgstr ""
msgid "URL"
msgstr ""
#, fuzzy
msgid "Note History"
msgstr "Notesbøger"
msgid "Previous versions of this note"
msgstr ""
msgid "Note properties"
msgstr ""
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr ""
#, fuzzy
msgid "This note has no history"
msgstr "Denne note er ændret:"
msgid "Restore"
msgstr ""
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
msgid "Open..."
msgstr "Åben..."
@@ -1137,18 +1167,15 @@ msgstr "Notesbøger"
#, fuzzy, javascript-format
msgid "Decrypting items: %d/%d"
msgstr "Hentede emner: %d/%d."
msgstr "Hentede emner: %d/%d"
#, fuzzy, javascript-format
msgid "Fetching resources: %d"
msgstr "Ressourcer: %d."
msgid "Fetching resources: %d/%d"
msgstr "Ressourcer: %d/%d"
msgid "Please select where the sync status should be exported to"
msgstr "Vælg hvor sync status skal eksporteres til"
msgid "Table of contents"
msgstr ""
msgid "Add or remove tags"
msgstr "Tilføj eller slet mærker"
@@ -1183,6 +1210,14 @@ msgstr "Slet noter?"
msgid "Delete these %d notes?"
msgstr "Slet disse noter?"
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
msgid "Goto Anything..."
msgstr ""
#, javascript-format
msgid "Usage: %s"
msgstr "Forbrug: %s"
@@ -1295,6 +1330,10 @@ msgstr "I gang"
msgid "Synchronisation is already in progress. State: %s"
msgstr "Synkronisering er allerede i gang: Tilstand: %s"
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr ""
msgid "Encrypted"
msgstr "Krypteret"
@@ -1335,6 +1374,13 @@ msgstr "Kan ikke kopiere note til \"%s\" notesbog"
msgid "Cannot move note to \"%s\" notebook"
msgstr "Kan ikke flytte note til \"%s\" notesbog"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
msgid "Language"
msgstr "Sprog"
@@ -1385,6 +1431,43 @@ msgstr "Fokuser på brødtekst"
msgid "When creating a new note:"
msgstr "Ved oprettelse af ny note:"
msgid "Enable soft breaks"
msgstr ""
#, fuzzy
msgid "Enable math expressions"
msgstr "Start kryptering"
msgid "Enable ==mark== syntax"
msgstr ""
msgid "Enable footnotes"
msgstr ""
msgid "Enable table of contents extension"
msgstr ""
msgid "Enable ~sub~ syntax"
msgstr ""
msgid "Enable ^sup^ syntax"
msgstr ""
msgid "Enable deflist syntax"
msgstr ""
msgid "Enable abbreviation syntax"
msgstr ""
msgid "Enable markdown emoji"
msgstr ""
msgid "Enable ++insert++ syntax"
msgstr ""
msgid "Enable multimarkdown table extension"
msgstr ""
msgid "Show tray icon"
msgstr "Vis ikon på bundbjælke"
@@ -1468,26 +1551,30 @@ msgstr ""
"Synkroniserings mål. Hver synk. mål kan have ekstra parametre som navngives "
"som `sync.NUM.NAME` (se dokumentation herunder)."
msgid "Attachment download behaviour"
msgstr ""
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
msgid "Always"
msgstr ""
msgid "Manual"
msgstr ""
msgid "Auto"
msgstr ""
msgid "Directory to synchronise with (absolute path)"
msgstr "Mappe der skal synkroniseres med (absolut sti)"
msgid ""
"The path to synchronise with when file system synchronisation is enabled. "
"See `sync.target`."
msgstr ""
"Sti til synkronisering, når filsystem synkronisering er slået til. Se `sync."
"target`."
msgid "Nextcloud WebDAV URL"
msgstr "Nextcloud WebDAV URL"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
msgid "Nextcloud username"
msgstr "Nextcloud brugernavn"
@@ -1516,6 +1603,20 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr ""
#, fuzzy
msgid "Enable note history"
msgstr "Start kryptering"
msgid "days"
msgstr ""
#, javascript-format
msgid "%d days"
msgstr ""
msgid "Keep note history for"
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Ulovlig værdi: \"%s\". Mulige valg er: %s."
@@ -1535,6 +1636,9 @@ msgstr ""
msgid "Note"
msgstr "Notesbøger"
msgid "Plugins"
msgstr ""
#, fuzzy
msgid "Application"
msgstr "Forlad/luk program."
@@ -1587,12 +1691,19 @@ msgstr "Der er ingen data at eksportere."
msgid "Please specify the notebook where the notes should be imported to."
msgstr "Angiv hvilken notesbog, noter skal importeres til."
msgid "Restored Notes"
msgstr ""
msgid "Items that cannot be synchronised"
msgstr "Emner kan ikke synkroniseres"
#, javascript-format
msgid "%s (%s): %s"
msgstr "%s (%s): %s"
#, fuzzy, javascript-format
msgid "%s (%s) could not be uploaded: %s"
msgstr "Notesbogen kan ikke gemmes: %s"
#, fuzzy, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr "Notesbogen kan ikke gemmes: %s"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
@@ -1864,6 +1975,16 @@ msgstr "Du har ingen notesbøger. Opret en ved at klikke på (+) knappen."
msgid "Welcome"
msgstr "Velkommen"
#~ msgid "%s (%s): %s"
#~ msgstr "%s (%s): %s"
#~ msgid ""
#~ "The path to synchronise with when file system synchronisation is enabled. "
#~ "See `sync.target`."
#~ msgstr ""
#~ "Sti til synkronisering, når filsystem synkronisering er slået til. Se "
#~ "`sync.target`."
#, fuzzy
#~ msgid "Joplin v%s"
#~ msgstr "Joplin hjemmeside"

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.2.1\n"
"X-Generator: Poedit 2.2.3\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
msgid "To delete a tag, untag the associated notes."
@@ -618,8 +618,8 @@ msgstr "Importiere „%s“ ins „%s“ Format. Bitte warten..."
msgid "PDF File"
msgstr "PDF-Datei"
msgid "&File"
msgstr "&Datei"
msgid "Synchronisation status"
msgstr "Status der Synchronisation"
msgid "New note"
msgstr "Neue Notiz"
@@ -630,6 +630,34 @@ msgstr "Neues To-Do"
msgid "New notebook"
msgstr "Neues Notizbuch"
msgid "Print"
msgstr "Drucken"
msgid "General Options"
msgstr "Allgemeine Einstellungen"
msgid "Encryption options"
msgstr "Verschlüsselungsoptionen"
msgid "Web clipper options"
msgstr "Web-Clipper Optionen"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
msgid "&File"
msgstr "&Datei"
msgid "About Joplin"
msgstr "Über Joplin"
msgid "Preferences..."
msgstr "Einstellungen..."
msgid "Check for updates..."
msgstr "Überprüfe auf Aktualisierungen..."
msgid "Import"
msgstr "Importieren"
@@ -639,9 +667,6 @@ msgstr "Exportieren"
msgid "Synchronise"
msgstr "Synchronisieren"
msgid "Print"
msgstr "Drucken"
#, javascript-format
msgid "Hide %s"
msgstr "%s ausblenden"
@@ -649,6 +674,9 @@ msgstr "%s ausblenden"
msgid "Quit"
msgstr "Verlassen"
msgid "Close Window"
msgstr "Fenster schließen"
msgid "&Edit"
msgstr "&Bearbeiten"
@@ -700,18 +728,6 @@ msgstr "Fokus"
msgid "&Tools"
msgstr "&Werkzeuge"
msgid "Synchronisation status"
msgstr "Status der Synchronisation"
msgid "Web clipper options"
msgstr "Web-Clipper Optionen"
msgid "Encryption options"
msgstr "Verschlüsselungsoptionen"
msgid "General Options"
msgstr "Allgemeine Einstellungen"
msgid "&Help"
msgstr "&Hilfe"
@@ -721,16 +737,6 @@ msgstr "Webseite und Dokumentation"
msgid "Make a donation"
msgstr "Spenden"
msgid "Check for updates..."
msgstr "Überprüfe auf Aktualisierungen..."
msgid "About Joplin"
msgstr "Über Joplin"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, javascript-format
msgid "Open %s"
msgstr "Öffne %s"
@@ -843,12 +849,12 @@ msgstr ""
msgid "Notes and settings are stored in: %s"
msgstr "Notizen und Einstellungen werden gespeichert in: %s"
msgid "Browse..."
msgstr "Durchsuche..."
msgid "Check synchronisation configuration"
msgstr "Überprüfen der Synchronisationseinstellungen"
msgid "Browse..."
msgstr "Durchsuche..."
msgid "Apply"
msgstr "Anwenden"
@@ -1015,9 +1021,35 @@ msgstr "Standort"
msgid "URL"
msgstr "URL"
msgid "Note History"
msgstr "Notizen-Verlauf"
msgid "Previous versions of this note"
msgstr "Vorherige Version von dieser Notiz"
msgid "Note properties"
msgstr "Notiz-Eigenschaften"
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr ""
"Die Notiz \"%s\" wurde erfolgreich wiederhergestellt und ist im Notizbuch "
"\"%s\" verfügbar."
msgid "This note has no history"
msgstr "Diese Notiz hat keinen Verlauf"
msgid "Restore"
msgstr "Wiederherstellen"
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
"Klicke \"%s\" um die Notiz wiederherzustellen. Sie wird in das Notizbuch \"%s"
"\" kopiert. Die aktuelle Version der Notiz wird nicht ersetzt oder verändert."
msgid "Open..."
msgstr "Öffne..."
@@ -1170,16 +1202,13 @@ msgid "Decrypting items: %d/%d"
msgstr "Entschlüsselte Objekte: %d/%d"
#, javascript-format
msgid "Fetching resources: %d"
msgstr "Ressourcen abrufen: %d"
msgid "Fetching resources: %d/%d"
msgstr "Ressourcen abrufen: %d/%d"
msgid "Please select where the sync status should be exported to"
msgstr ""
"Bitte wähle aus, wohin der Synchronisations-Status exportiert werden soll"
msgid "Table of contents"
msgstr "Inhaltsverzeichnis"
msgid "Add or remove tags"
msgstr "Schlagwörter hinzufügen oder entfernen"
@@ -1210,6 +1239,16 @@ msgstr "Notiz \"%s\" löschen?"
msgid "Delete these %d notes?"
msgstr "Sollen diese %d Notizen gelöscht werden?"
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
"Tippe einen Notiz Titel um hinzuspringen. Oder tippe # gefolgt von einem "
"Schlagwort, oder @ gefolgt von einem Notizbuch-Namen."
msgid "Goto Anything..."
msgstr "Gehe zu..."
#, javascript-format
msgid "Usage: %s"
msgstr "Nutzung: %s"
@@ -1322,6 +1361,10 @@ msgstr "In Bearbeitung"
msgid "Synchronisation is already in progress. State: %s"
msgstr "Synchronisation ist bereits im Gange. Status: %s"
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr "Unbekannter Eintrags-Typ heruntergeladen - bitte aktualisiere Joplin"
msgid "Encrypted"
msgstr "Verschlüsselt"
@@ -1359,6 +1402,16 @@ msgstr "Kann Notiz nicht zu Notizbuch \"%s\" kopieren"
msgid "Cannot move note to \"%s\" notebook"
msgstr "Kann Notiz nicht zu Notizbuch \"%s\" verschieben"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
"Achtung: Stelle sicher, dass Du vor der Synchronisation alle Inhalte an den "
"neuen Ablageort kopiert hast, sonst werden alle Dateien gelöscht! Lies auch "
"die FAQs hierzu: %s"
msgid "Language"
msgstr "Sprache"
@@ -1407,6 +1460,42 @@ msgstr "Fokussiere Inhalt"
msgid "When creating a new note:"
msgstr "Wenn eine neue Notiz erstellt wird:"
msgid "Enable soft breaks"
msgstr "Aktiviere weiche Zeilenumbrüche"
msgid "Enable math expressions"
msgstr "Aktiviere mathematische Ausdrücke"
msgid "Enable ==mark== syntax"
msgstr "Aktiviere ==mark== Syntax"
msgid "Enable footnotes"
msgstr "Aktiviere Fußnoten"
msgid "Enable table of contents extension"
msgstr "Aktiviere Inhaltsverzeichnis Erweiterung"
msgid "Enable ~sub~ syntax"
msgstr "Aktiviere ~sub~ Syntax"
msgid "Enable ^sup^ syntax"
msgstr "Aktiviere ^sup^ Syntax"
msgid "Enable deflist syntax"
msgstr "Aktiviere deflist Syntax"
msgid "Enable abbreviation syntax"
msgstr "Aktiviere abbreviation Syntax"
msgid "Enable markdown emoji"
msgstr "Aktiviere markdown emoji"
msgid "Enable ++insert++ syntax"
msgstr "Aktiviere ++insert++ Syntax"
msgid "Enable multimarkdown table extension"
msgstr "Aktiviere multimarkdown Tabellen Erweiterung"
msgid "Show tray icon"
msgstr "Zeige Tray-Icon"
@@ -1491,29 +1580,34 @@ msgstr ""
"kann zusätzliche Parameter haben, die als `sync.NUM.NAME` (alle unten "
"dokumentiert) bezeichnet werden."
msgid "Attachment download behaviour"
msgstr "Verhalten für das Herunterladen von Anhängen"
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
"Im \"Manuell\" Modus werden die Anhänge nur heruntergeladen wenn Du auf sie "
"klickst. Bei \"Automatisch\" werden sie heruntergeladen sobald die Notiz "
"geöffnet wird. Bei \"Immer\" werden die Anhänge heruntergeladen egal ob die "
"Notiz geöffnet wird oder nicht."
msgid "Always"
msgstr "Immer"
msgid "Manual"
msgstr "Manuell"
msgid "Auto"
msgstr "Automatisch"
msgid "Directory to synchronise with (absolute path)"
msgstr "Verzeichnis mit dem synchronisiert werden soll (absoluter Pfad)"
msgid ""
"The path to synchronise with when file system synchronisation is enabled. "
"See `sync.target`."
msgstr ""
"Der Pfad, mit dem synchronisiert werden soll, wenn die Dateisystem-"
"Synchronisation aktiviert ist. Siehe `sync.target`."
msgid "Nextcloud WebDAV URL"
msgstr "Nextcloud WebDAV-URL"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
"Achtung: Stelle sicher, dass Du vor der Synchronisation alle Inhalte an den "
"neuen Ablageort kopiert hast, sonst werden alle Dateien gelöscht! Lies auch "
"die FAQs hierzu: %s"
msgid "Nextcloud username"
msgstr "Nextcloud-Benutzername"
@@ -1547,6 +1641,19 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr "Ignoriere TLS-Zertifikatfehler"
msgid "Enable note history"
msgstr "Aktiviere Notizen-Verlauf"
msgid "days"
msgstr "Tage"
#, javascript-format
msgid "%d days"
msgstr "%d Tage"
msgid "Keep note history for"
msgstr "Speicher Notizen-Verlauf für"
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Ungültiger Optionswert: \"%s\". Mögliche Werte sind: %s."
@@ -1563,6 +1670,9 @@ msgstr "Erscheinungsbild"
msgid "Note"
msgstr "Notiz"
msgid "Plugins"
msgstr "Zusatzprogramme"
# 'Applikation' or 'Anwendung' - both translations are correct.
msgid "Application"
msgstr "Applikation"
@@ -1616,12 +1726,19 @@ msgid "Please specify the notebook where the notes should be imported to."
msgstr ""
"Bitte wähle aus, wohin der Synchronisations-Status exportiert werden soll."
msgid "Restored Notes"
msgstr "Wiederhergestellte Notizen"
msgid "Items that cannot be synchronised"
msgstr "Objekte können nicht synchronisiert werden"
#, javascript-format
msgid "%s (%s): %s"
msgstr "%s (%s): %s"
msgid "%s (%s) could not be uploaded: %s"
msgstr "%s (%s) konnte nicht hochgeladen werden: %s"
#, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr "Eintrag \"%s\" konnte nicht heruntergeladen werden: %s"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
@@ -1906,6 +2023,19 @@ msgstr ""
msgid "Welcome"
msgstr "Willkommen"
#~ msgid "%s (%s): %s"
#~ msgstr "%s (%s): %s"
#~ msgid "Table of contents"
#~ msgstr "Inhaltsverzeichnis"
#~ msgid ""
#~ "The path to synchronise with when file system synchronisation is enabled. "
#~ "See `sync.target`."
#~ msgstr ""
#~ "Der Pfad, mit dem synchronisiert werden soll, wenn die Dateisystem-"
#~ "Synchronisation aktiviert ist. Siehe `sync.target`."
#~ msgid "Joplin v%s"
#~ msgstr "Joplin v%s"

View File

@@ -527,7 +527,7 @@ msgstr ""
msgid "PDF File"
msgstr ""
msgid "&File"
msgid "Synchronisation status"
msgstr ""
msgid "New note"
@@ -539,6 +539,34 @@ msgstr ""
msgid "New notebook"
msgstr ""
msgid "Print"
msgstr ""
msgid "General Options"
msgstr ""
msgid "Encryption options"
msgstr ""
msgid "Web clipper options"
msgstr ""
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr ""
msgid "&File"
msgstr ""
msgid "About Joplin"
msgstr ""
msgid "Preferences..."
msgstr ""
msgid "Check for updates..."
msgstr ""
msgid "Import"
msgstr ""
@@ -548,9 +576,6 @@ msgstr ""
msgid "Synchronise"
msgstr ""
msgid "Print"
msgstr ""
#, javascript-format
msgid "Hide %s"
msgstr ""
@@ -558,6 +583,9 @@ msgstr ""
msgid "Quit"
msgstr ""
msgid "Close Window"
msgstr ""
msgid "&Edit"
msgstr ""
@@ -609,18 +637,6 @@ msgstr ""
msgid "&Tools"
msgstr ""
msgid "Synchronisation status"
msgstr ""
msgid "Web clipper options"
msgstr ""
msgid "Encryption options"
msgstr ""
msgid "General Options"
msgstr ""
msgid "&Help"
msgstr ""
@@ -630,16 +646,6 @@ msgstr ""
msgid "Make a donation"
msgstr ""
msgid "Check for updates..."
msgstr ""
msgid "About Joplin"
msgstr ""
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr ""
#, javascript-format
msgid "Open %s"
msgstr ""
@@ -741,10 +747,10 @@ msgstr ""
msgid "Notes and settings are stored in: %s"
msgstr ""
msgid "Browse..."
msgid "Check synchronisation configuration"
msgstr ""
msgid "Check synchronisation configuration"
msgid "Browse..."
msgstr ""
msgid "Apply"
@@ -891,9 +897,31 @@ msgstr ""
msgid "URL"
msgstr ""
msgid "Note History"
msgstr ""
msgid "Previous versions of this note"
msgstr ""
msgid "Note properties"
msgstr ""
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr ""
msgid "This note has no history"
msgstr ""
msgid "Restore"
msgstr ""
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
msgid "Open..."
msgstr ""
@@ -1040,15 +1068,12 @@ msgid "Decrypting items: %d/%d"
msgstr ""
#, javascript-format
msgid "Fetching resources: %d"
msgid "Fetching resources: %d/%d"
msgstr ""
msgid "Please select where the sync status should be exported to"
msgstr ""
msgid "Table of contents"
msgstr ""
msgid "Add or remove tags"
msgstr ""
@@ -1079,6 +1104,14 @@ msgstr ""
msgid "Delete these %d notes?"
msgstr ""
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
msgid "Goto Anything..."
msgstr ""
#, javascript-format
msgid "Usage: %s"
msgstr ""
@@ -1183,6 +1216,10 @@ msgstr ""
msgid "Synchronisation is already in progress. State: %s"
msgstr ""
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr ""
msgid "Encrypted"
msgstr ""
@@ -1219,6 +1256,13 @@ msgstr ""
msgid "Cannot move note to \"%s\" notebook"
msgstr ""
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
msgid "Language"
msgstr ""
@@ -1267,6 +1311,42 @@ msgstr ""
msgid "When creating a new note:"
msgstr ""
msgid "Enable soft breaks"
msgstr ""
msgid "Enable math expressions"
msgstr ""
msgid "Enable ==mark== syntax"
msgstr ""
msgid "Enable footnotes"
msgstr ""
msgid "Enable table of contents extension"
msgstr ""
msgid "Enable ~sub~ syntax"
msgstr ""
msgid "Enable ^sup^ syntax"
msgstr ""
msgid "Enable deflist syntax"
msgstr ""
msgid "Enable abbreviation syntax"
msgstr ""
msgid "Enable markdown emoji"
msgstr ""
msgid "Enable ++insert++ syntax"
msgstr ""
msgid "Enable multimarkdown table extension"
msgstr ""
msgid "Show tray icon"
msgstr ""
@@ -1340,24 +1420,30 @@ msgid ""
"which are named as `sync.NUM.NAME` (all documented below)."
msgstr ""
msgid "Attachment download behaviour"
msgstr ""
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
msgid "Always"
msgstr ""
msgid "Manual"
msgstr ""
msgid "Auto"
msgstr ""
msgid "Directory to synchronise with (absolute path)"
msgstr ""
msgid ""
"The path to synchronise with when file system synchronisation is enabled. "
"See `sync.target`."
msgstr ""
msgid "Nextcloud WebDAV URL"
msgstr ""
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
msgid "Nextcloud username"
msgstr ""
@@ -1386,6 +1472,19 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr ""
msgid "Enable note history"
msgstr ""
msgid "days"
msgstr ""
#, javascript-format
msgid "%d days"
msgstr ""
msgid "Keep note history for"
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr ""
@@ -1402,6 +1501,9 @@ msgstr ""
msgid "Note"
msgstr ""
msgid "Plugins"
msgstr ""
msgid "Application"
msgstr ""
@@ -1450,11 +1552,18 @@ msgstr ""
msgid "Please specify the notebook where the notes should be imported to."
msgstr ""
msgid "Restored Notes"
msgstr ""
msgid "Items that cannot be synchronised"
msgstr ""
#, javascript-format
msgid "%s (%s): %s"
msgid "%s (%s) could not be uploaded: %s"
msgstr ""
#, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr ""
msgid ""

1857
CliClient/locales/en_US.po Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -606,8 +606,8 @@ msgstr "Importando el formato de \"%s\" a \"%s\". Por favor espere..."
msgid "PDF File"
msgstr "Archivo PDF"
msgid "&File"
msgstr "&Archivo"
msgid "Synchronisation status"
msgstr "Estado de la sincronización"
msgid "New note"
msgstr "Nueva nota"
@@ -618,6 +618,34 @@ msgstr "Nueva lista de tareas"
msgid "New notebook"
msgstr "Nueva libreta"
msgid "Print"
msgstr "Imprimir"
msgid "General Options"
msgstr "Opciones generales"
msgid "Encryption options"
msgstr "Opciones de cifrado"
msgid "Web clipper options"
msgstr "Opciones de recorte web"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
msgid "&File"
msgstr "&Archivo"
msgid "About Joplin"
msgstr "Acerca de Joplin"
msgid "Preferences..."
msgstr ""
msgid "Check for updates..."
msgstr "Comprobar actualizaciones..."
msgid "Import"
msgstr "Importar"
@@ -627,9 +655,6 @@ msgstr "Exportar"
msgid "Synchronise"
msgstr "Sincronizar"
msgid "Print"
msgstr "Imprimir"
#, javascript-format
msgid "Hide %s"
msgstr "Oculta %s"
@@ -637,6 +662,9 @@ msgstr "Oculta %s"
msgid "Quit"
msgstr "Salir"
msgid "Close Window"
msgstr ""
msgid "&Edit"
msgstr "&Editar"
@@ -688,18 +716,6 @@ msgstr "Foco"
msgid "&Tools"
msgstr "&Herramientas"
msgid "Synchronisation status"
msgstr "Estado de la sincronización"
msgid "Web clipper options"
msgstr "Opciones de recorte web"
msgid "Encryption options"
msgstr "Opciones de cifrado"
msgid "General Options"
msgstr "Opciones generales"
msgid "&Help"
msgstr "&Ayuda"
@@ -709,16 +725,6 @@ msgstr "Sitio web y documentación"
msgid "Make a donation"
msgstr "Hacer una donación"
msgid "Check for updates..."
msgstr "Comprobar actualizaciones..."
msgid "About Joplin"
msgstr "Acerca de Joplin"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, javascript-format
msgid "Open %s"
msgstr "Abrir %s"
@@ -827,12 +833,12 @@ msgstr ""
msgid "Notes and settings are stored in: %s"
msgstr "Las notas y los ajustes se guardan en: %s"
msgid "Browse..."
msgstr "Explorar..."
msgid "Check synchronisation configuration"
msgstr "Comprobar sincronización"
msgid "Browse..."
msgstr "Explorar..."
msgid "Apply"
msgstr "Aplicar"
@@ -992,9 +998,33 @@ msgstr "Localización"
msgid "URL"
msgstr "URL"
#, fuzzy
msgid "Note History"
msgstr "Lista de notas"
msgid "Previous versions of this note"
msgstr ""
msgid "Note properties"
msgstr "Propiedades de nota"
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr ""
#, fuzzy
msgid "This note has no history"
msgstr "Esta nota ha sido modificada:"
msgid "Restore"
msgstr ""
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
msgid "Open..."
msgstr "Abrir..."
@@ -1146,15 +1176,12 @@ msgid "Decrypting items: %d/%d"
msgstr "Descifrando elementos: %d/%d"
#, javascript-format
msgid "Fetching resources: %d"
msgstr "Obteniendo refuersos: %d"
msgid "Fetching resources: %d/%d"
msgstr "Obteniendo refuersos: %d/%d"
msgid "Please select where the sync status should be exported to"
msgstr "Seleccione a dónde se debería exportar el estado de sincronización"
msgid "Table of contents"
msgstr ""
msgid "Add or remove tags"
msgstr "Añadir o borrar etiquetas"
@@ -1185,6 +1212,14 @@ msgstr "¿Borrar nota \"%s\"?"
msgid "Delete these %d notes?"
msgstr "Borrar %d notas?"
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
msgid "Goto Anything..."
msgstr ""
#, javascript-format
msgid "Usage: %s"
msgstr "Uso: %s"
@@ -1297,6 +1332,10 @@ msgstr "En progreso"
msgid "Synchronisation is already in progress. State: %s"
msgstr "La sincronización ya está en progreso. Estado: %s"
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr ""
msgid "Encrypted"
msgstr "Cifrado"
@@ -1334,6 +1373,16 @@ msgstr "No se ha podido copiar la nota a la libreta «%s»"
msgid "Cannot move note to \"%s\" notebook"
msgstr "No se ha podido mover la nota a la libreta «%s»"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
"Atención: Si cambias esta ubicación, asegúrate de copiar todo tu contenido "
"antes de sincronizarlo, de lo contrario todos los archivos serán eliminados. "
"Consulte las preguntas frecuentes para obtener más detalles: %s"
msgid "Language"
msgstr "Idioma"
@@ -1383,6 +1432,43 @@ msgstr "Foco en el cuerpo"
msgid "When creating a new note:"
msgstr "Cuando se crear una nota nueva:"
msgid "Enable soft breaks"
msgstr ""
#, fuzzy
msgid "Enable math expressions"
msgstr "Habilitar cifrado"
msgid "Enable ==mark== syntax"
msgstr ""
msgid "Enable footnotes"
msgstr ""
msgid "Enable table of contents extension"
msgstr ""
msgid "Enable ~sub~ syntax"
msgstr ""
msgid "Enable ^sup^ syntax"
msgstr ""
msgid "Enable deflist syntax"
msgstr ""
msgid "Enable abbreviation syntax"
msgstr ""
msgid "Enable markdown emoji"
msgstr ""
msgid "Enable ++insert++ syntax"
msgstr ""
msgid "Enable multimarkdown table extension"
msgstr ""
msgid "Show tray icon"
msgstr "Mostrar icono en la bandeja"
@@ -1468,29 +1554,30 @@ msgstr ""
"tener parámetros adicionales los cuales son llamados como `sync.NUM.NAME` "
"(todos abajo documentados)."
msgid "Attachment download behaviour"
msgstr ""
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
msgid "Always"
msgstr ""
msgid "Manual"
msgstr ""
msgid "Auto"
msgstr ""
msgid "Directory to synchronise with (absolute path)"
msgstr "Directorio con el que sincronizarse (ruta completa)"
msgid ""
"The path to synchronise with when file system synchronisation is enabled. "
"See `sync.target`."
msgstr ""
"La ruta a la que sincronizar cuando se activa la sincronización con sistema "
"de archivos. Vea «sync.target»."
msgid "Nextcloud WebDAV URL"
msgstr "Servidor WebDAV de Nextcloud"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
"Atención: Si cambias esta ubicación, asegúrate de copiar todo tu contenido "
"antes de sincronizarlo, de lo contrario todos los archivos serán eliminados. "
"Consulte las preguntas frecuentes para obtener más detalles: %s"
msgid "Nextcloud username"
msgstr "Usuario de Nextcloud"
@@ -1524,6 +1611,20 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr "Ignorar errores en certificados TLS"
#, fuzzy
msgid "Enable note history"
msgstr "Habilitar cifrado"
msgid "days"
msgstr ""
#, javascript-format
msgid "%d days"
msgstr ""
msgid "Keep note history for"
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Opción inválida: «%s». Los valores posibles son: %s."
@@ -1540,6 +1641,9 @@ msgstr "Apariencia"
msgid "Note"
msgstr "Nota"
msgid "Plugins"
msgstr ""
msgid "Application"
msgstr "Aplicación"
@@ -1590,12 +1694,19 @@ msgstr "No hay datos para exportar."
msgid "Please specify the notebook where the notes should be imported to."
msgstr "Por favor especifique la libreta donde las notas deben ser importadas."
msgid "Restored Notes"
msgstr ""
msgid "Items that cannot be synchronised"
msgstr "Elementos que no se pueden sincronizar"
#, javascript-format
msgid "%s (%s): %s"
msgstr "%s (%s): %s"
#, fuzzy, javascript-format
msgid "%s (%s) could not be uploaded: %s"
msgstr "No se ha podido abrir este archivo: %s"
#, fuzzy, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr "No se ha podido abrir este archivo: %s"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
@@ -1876,6 +1987,16 @@ msgstr ""
msgid "Welcome"
msgstr "Bienvenido"
#~ msgid "%s (%s): %s"
#~ msgstr "%s (%s): %s"
#~ msgid ""
#~ "The path to synchronise with when file system synchronisation is enabled. "
#~ "See `sync.target`."
#~ msgstr ""
#~ "La ruta a la que sincronizar cuando se activa la sincronización con "
#~ "sistema de archivos. Vea «sync.target»."
#~ msgid "Joplin v%s"
#~ msgstr "Joplin v%s"

View File

@@ -605,9 +605,8 @@ msgstr ""
msgid "PDF File"
msgstr "Fitxategia"
#, fuzzy
msgid "&File"
msgstr "Fitxategia"
msgid "Synchronisation status"
msgstr "Sinkronizazioaren egoera"
msgid "New note"
msgstr "Ohar berria"
@@ -618,6 +617,35 @@ msgstr "Zeregin berria"
msgid "New notebook"
msgstr "Koaderno berria"
msgid "Print"
msgstr ""
msgid "General Options"
msgstr "Ezarpenak"
msgid "Encryption options"
msgstr "Zifratzeko aukerak"
msgid "Web clipper options"
msgstr ""
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, fuzzy
msgid "&File"
msgstr "Fitxategia"
msgid "About Joplin"
msgstr "Joplin-i buruz"
msgid "Preferences..."
msgstr ""
msgid "Check for updates..."
msgstr ""
msgid "Import"
msgstr "Inportatu"
@@ -628,9 +656,6 @@ msgstr "Inportatu"
msgid "Synchronise"
msgstr "Sinkronizatu"
msgid "Print"
msgstr ""
#, javascript-format
msgid "Hide %s"
msgstr ""
@@ -638,6 +663,9 @@ msgstr ""
msgid "Quit"
msgstr "Irten"
msgid "Close Window"
msgstr ""
#, fuzzy
msgid "&Edit"
msgstr "Editatu"
@@ -693,18 +721,6 @@ msgstr ""
msgid "&Tools"
msgstr "Tresnak"
msgid "Synchronisation status"
msgstr "Sinkronizazioaren egoera"
msgid "Web clipper options"
msgstr ""
msgid "Encryption options"
msgstr "Zifratzeko aukerak"
msgid "General Options"
msgstr "Ezarpenak"
#, fuzzy
msgid "&Help"
msgstr "Laguntza"
@@ -716,16 +732,6 @@ msgstr "Web orria eta dokumentazioa (en)"
msgid "Make a donation"
msgstr "Web orria eta dokumentazioa (en)"
msgid "Check for updates..."
msgstr ""
msgid "About Joplin"
msgstr "Joplin-i buruz"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, fuzzy, javascript-format
msgid "Open %s"
msgstr "On %s: %s"
@@ -829,13 +835,13 @@ msgstr ""
msgid "Notes and settings are stored in: %s"
msgstr "Oharrak eta ezarpenak hemen daude gordeta: %s"
msgid "Browse..."
msgstr ""
#, fuzzy
msgid "Check synchronisation configuration"
msgstr "Sinkronizazioa utzi"
msgid "Browse..."
msgstr ""
msgid "Apply"
msgstr ""
@@ -997,9 +1003,33 @@ msgstr ""
msgid "URL"
msgstr ""
#, fuzzy
msgid "Note History"
msgstr "Koadernoak"
msgid "Previous versions of this note"
msgstr ""
msgid "Note properties"
msgstr ""
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr ""
#, fuzzy
msgid "This note has no history"
msgstr "Ohar hau mugitua izan da:"
msgid "Restore"
msgstr ""
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
msgid "Open..."
msgstr ""
@@ -1149,19 +1179,16 @@ msgstr "Koadernoak"
#, fuzzy, javascript-format
msgid "Decrypting items: %d/%d"
msgstr "Itemak eskuratuta: %d%d."
msgstr "Itemak eskuratuta: %d/%d"
#, fuzzy, javascript-format
msgid "Fetching resources: %d"
msgstr "Baliabideak: %d."
msgid "Fetching resources: %d/%d"
msgstr "Baliabideak: %d/%d"
#, fuzzy
msgid "Please select where the sync status should be exported to"
msgstr "Aukeratu nora esportatu sinkronizazioaren egoera, mesedez"
msgid "Table of contents"
msgstr ""
msgid "Add or remove tags"
msgstr "Gehitu edo ezabatu etiketak"
@@ -1195,6 +1222,14 @@ msgstr "Oharrak ezabatu?"
msgid "Delete these %d notes?"
msgstr "Oharrok ezabatu?"
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
msgid "Goto Anything..."
msgstr ""
#, javascript-format
msgid "Usage: %s"
msgstr "Erabili: %s"
@@ -1308,6 +1343,10 @@ msgstr ""
msgid "Synchronisation is already in progress. State: %s"
msgstr "Sinkronizazioa hasita dago. Egoera: %s"
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr ""
msgid "Encrypted"
msgstr "Zifratuta"
@@ -1349,6 +1388,13 @@ msgstr "Ezin kopia daiteke oharra \"%s\" koadernora"
msgid "Cannot move note to \"%s\" notebook"
msgstr "Ezin eraman daiteke oharra \"%s\" koadernora"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
msgid "Language"
msgstr "Hizkuntza"
@@ -1403,6 +1449,43 @@ msgstr ""
msgid "When creating a new note:"
msgstr "Ohar berria sortzen du."
msgid "Enable soft breaks"
msgstr ""
#, fuzzy
msgid "Enable math expressions"
msgstr "Zifratua gaitu"
msgid "Enable ==mark== syntax"
msgstr ""
msgid "Enable footnotes"
msgstr ""
msgid "Enable table of contents extension"
msgstr ""
msgid "Enable ~sub~ syntax"
msgstr ""
msgid "Enable ^sup^ syntax"
msgstr ""
msgid "Enable deflist syntax"
msgstr ""
msgid "Enable abbreviation syntax"
msgstr ""
msgid "Enable markdown emoji"
msgstr ""
msgid "Enable ++insert++ syntax"
msgstr ""
msgid "Enable multimarkdown table extension"
msgstr ""
msgid "Show tray icon"
msgstr ""
@@ -1485,25 +1568,30 @@ msgstr ""
"parametro gehigarriak, horrela izendatuta `sync.NUM.NAME` (dena beherago "
"dokumentatuta)."
msgid "Attachment download behaviour"
msgstr ""
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
msgid "Always"
msgstr ""
msgid "Manual"
msgstr ""
msgid "Auto"
msgstr ""
msgid "Directory to synchronise with (absolute path)"
msgstr "Sinkronizatzeko direktorioa (bide-izena osorik)"
msgid ""
"The path to synchronise with when file system synchronisation is enabled. "
"See `sync.target`."
msgstr ""
"Sinkronizazio sistema gaituta dagoenerako bide-izena. Ikus `sync.target`."
msgid "Nextcloud WebDAV URL"
msgstr "Nextcloud WebDAV URL"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
msgid "Nextcloud username"
msgstr "Nextcloud erabiltzaile-izena"
@@ -1535,6 +1623,20 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr ""
#, fuzzy
msgid "Enable note history"
msgstr "Zifratua gaitu"
msgid "days"
msgstr ""
#, javascript-format
msgid "%d days"
msgstr ""
msgid "Keep note history for"
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Balio aukera baliogabea: \"%s\". Litezkeen balioak: %s."
@@ -1554,6 +1656,9 @@ msgstr ""
msgid "Note"
msgstr "Koadernoak"
msgid "Plugins"
msgstr ""
#, fuzzy
msgid "Application"
msgstr "Irten aplikaziotik"
@@ -1607,12 +1712,19 @@ msgstr ""
msgid "Please specify the notebook where the notes should be imported to."
msgstr "Aukeratu nora esportatu sinkronizazioaren egoera, mesedez"
msgid "Restored Notes"
msgstr ""
msgid "Items that cannot be synchronised"
msgstr "Itemok ezin sinkronizatu"
#, javascript-format
msgid "%s (%s): %s"
msgstr "%s (%s): %s"
#, fuzzy, javascript-format
msgid "%s (%s) could not be uploaded: %s"
msgstr "Koadernoa ezin gorde daiteke: %s"
#, fuzzy, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr "Koadernoa ezin gorde daiteke: %s"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
@@ -1884,6 +1996,15 @@ msgstr "Oraindik ez duzu koadernorik. Sortu bat (+) botoian sakatuta."
msgid "Welcome"
msgstr "Ongi etorri!"
#~ msgid "%s (%s): %s"
#~ msgstr "%s (%s): %s"
#~ msgid ""
#~ "The path to synchronise with when file system synchronisation is enabled. "
#~ "See `sync.target`."
#~ msgstr ""
#~ "Sinkronizazio sistema gaituta dagoenerako bide-izena. Ikus `sync.target`."
#, fuzzy
#~ msgid "State: %s."
#~ msgstr "Egoera: \"%s\"."

1837
CliClient/locales/fa.po Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -603,8 +603,8 @@ msgstr "Importer depuis \"%s\" au format \"%s\". Veuillez patienter..."
msgid "PDF File"
msgstr "Fichier PDF"
msgid "&File"
msgstr "&Fichier"
msgid "Synchronisation status"
msgstr "État de la synchronisation"
msgid "New note"
msgstr "Nouvelle note"
@@ -615,6 +615,34 @@ msgstr "Nouvelle tâche"
msgid "New notebook"
msgstr "Nouveau carnet"
msgid "Print"
msgstr "Imprimer"
msgid "General Options"
msgstr "Options générales"
msgid "Encryption options"
msgstr "Options de chiffrement"
msgid "Web clipper options"
msgstr "Options du Web Clipper"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
msgid "&File"
msgstr "&Fichier"
msgid "About Joplin"
msgstr "A propos de Joplin"
msgid "Preferences..."
msgstr "Préférences…"
msgid "Check for updates..."
msgstr "Vérifier les mises à jour..."
msgid "Import"
msgstr "Importer"
@@ -624,9 +652,6 @@ msgstr "Exporter"
msgid "Synchronise"
msgstr "Synchroniser"
msgid "Print"
msgstr "Imprimer"
#, javascript-format
msgid "Hide %s"
msgstr "Cacher %s"
@@ -634,6 +659,9 @@ msgstr "Cacher %s"
msgid "Quit"
msgstr "Quitter"
msgid "Close Window"
msgstr "Fermer la fenêtre"
msgid "&Edit"
msgstr "&Édition"
@@ -685,18 +713,6 @@ msgstr "Naviguer"
msgid "&Tools"
msgstr "&Outils"
msgid "Synchronisation status"
msgstr "État de la synchronisation"
msgid "Web clipper options"
msgstr "Options du Web Clipper"
msgid "Encryption options"
msgstr "Options de chiffrement"
msgid "General Options"
msgstr "Options générales"
msgid "&Help"
msgstr "&Aide"
@@ -706,16 +722,6 @@ msgstr "Documentation en ligne"
msgid "Make a donation"
msgstr "Faire un don"
msgid "Check for updates..."
msgstr "Vérifier les mises à jour..."
msgid "About Joplin"
msgstr "A propos de Joplin"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, javascript-format
msgid "Open %s"
msgstr "Ouvrir %s"
@@ -827,12 +833,12 @@ msgstr ""
msgid "Notes and settings are stored in: %s"
msgstr "Les notes et paramètres se trouve dans : %s"
msgid "Browse..."
msgstr "Parcourir…"
msgid "Check synchronisation configuration"
msgstr "Vérifier config synchronisation"
msgid "Browse..."
msgstr "Parcourir…"
msgid "Apply"
msgstr "Appliquer"
@@ -999,9 +1005,34 @@ msgstr "Lieu"
msgid "URL"
msgstr "URL"
msgid "Note History"
msgstr "Historique des notes"
msgid "Previous versions of this note"
msgstr "Versions précédentes de cette note"
msgid "Note properties"
msgstr "Propriétés de la note"
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr "La note \"%s\" a été restaurée dans le carnet \"%s\"."
msgid "This note has no history"
msgstr "Cette note n'a pas d'historique"
msgid "Restore"
msgstr "Restaurer"
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
"Cliquez sur \"%s\" pour restaurer cette note. Elle sera copiée dans le "
"carnet \"%s\". La version actuelle de la note ne sera pas replacée ou "
"modifiée."
msgid "Open..."
msgstr "Ouvrir..."
@@ -1155,16 +1186,13 @@ msgid "Decrypting items: %d/%d"
msgstr "Déchiffrement des objets : %d/%d"
#, javascript-format
msgid "Fetching resources: %d"
msgstr "Tél. ressources : %d"
msgid "Fetching resources: %d/%d"
msgstr "Tél. ressources : %d/%d"
msgid "Please select where the sync status should be exported to"
msgstr ""
"Veuillez sélectionner un répertoire ou exporter l'état de la synchronisation"
msgid "Table of contents"
msgstr "Table des matières"
msgid "Add or remove tags"
msgstr "Gérer les étiquettes"
@@ -1195,6 +1223,16 @@ msgstr "Supprimer note \"%s\" ?"
msgid "Delete these %d notes?"
msgstr "Supprimer ces %d notes ?"
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
"Entrez le titre d’une note, ou entrez # suivit du nom d’une étiquette, ou @ "
"suivit du nom d’un carnet."
msgid "Goto Anything..."
msgstr "Navigation rapide…"
#, javascript-format
msgid "Usage: %s"
msgstr "Utilisation : %s"
@@ -1307,6 +1345,10 @@ msgstr "En cours"
msgid "Synchronisation is already in progress. State: %s"
msgstr "La synchronisation est déjà en cours. État : %s"
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr "Objet inconnu téléchargé - veuillez mettre Joplin à jour"
msgid "Encrypted"
msgstr "Chiffré"
@@ -1343,6 +1385,16 @@ msgstr "Impossible de copier la note vers le carnet \"%s\""
msgid "Cannot move note to \"%s\" notebook"
msgstr "Impossible de déplacer la note vers le carnet \"%s\""
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
"Attention : si vous changez cet emplacement, copiez-y tout le contenu avant "
"de synchroniser, sinon tous les fichiers seront supprimés ! Consulter la FAQ "
"pour plus de détails : %s"
msgid "Language"
msgstr "Langue"
@@ -1391,6 +1443,42 @@ msgstr "Curseur sur corps du message"
msgid "When creating a new note:"
msgstr "Lors de la création d'une note :"
msgid "Enable soft breaks"
msgstr "Activer retours à la ligne \"doux\""
msgid "Enable math expressions"
msgstr "Activer les expressions mathématiques"
msgid "Enable ==mark== syntax"
msgstr "Activer la syntaxe pour ==surligner=="
msgid "Enable footnotes"
msgstr "Activer les notes de bas de page"
msgid "Enable table of contents extension"
msgstr "Activer la table des matières"
msgid "Enable ~sub~ syntax"
msgstr "Activer la syntaxe ~indice~"
msgid "Enable ^sup^ syntax"
msgstr "Activer la syntaxe ^exposant^"
msgid "Enable deflist syntax"
msgstr "Activer les listes de définitions"
msgid "Enable abbreviation syntax"
msgstr "Activer la syntaxe pour abréviations"
msgid "Enable markdown emoji"
msgstr "Activer la syntaxe émoji"
msgid "Enable ++insert++ syntax"
msgstr "Activer la syntaxe ++insertion++"
msgid "Enable multimarkdown table extension"
msgstr "Activer les tables multi-markdown"
msgid "Show tray icon"
msgstr "Afficher l'icône dans la zone de notifications"
@@ -1475,29 +1563,34 @@ msgstr ""
"avoir des paramètres supplémentaires sous le nom `sync.NUM.NOM` (documentés "
"ci-dessous)."
msgid "Attachment download behaviour"
msgstr "Téléchargement des ressources"
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
"En mode \"manuel\", les ressources sont téléchargées uniquement lorsque vous "
"cliquez dessus. En mode \"auto\", elle sont téléchargée lorsque vous ouvrez "
"la note. En mode \"toujours\", toutes les ressources sont téléchargées, que "
"vous ayez ouvert la note ou pas."
msgid "Always"
msgstr "Toujours"
msgid "Manual"
msgstr "Manuel"
msgid "Auto"
msgstr "Auto"
msgid "Directory to synchronise with (absolute path)"
msgstr "Répertoire avec lequel synchroniser (chemin absolu)"
msgid ""
"The path to synchronise with when file system synchronisation is enabled. "
"See `sync.target`."
msgstr ""
"Le chemin du répertoire avec lequel synchroniser lorsque la synchronisation "
"par système de fichier est activée. Voir `sync.target`."
msgid "Nextcloud WebDAV URL"
msgstr "Nextcloud : URL WebDAV"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
"Attention : si vous changez cet emplacement, copiez-y tout le contenu avant "
"de synchroniser, sinon tous les fichiers seront supprimés ! Consulter la FAQ "
"pour plus de détails : %s"
msgid "Nextcloud username"
msgstr "Nextcloud : Nom utilisateur"
@@ -1531,6 +1624,19 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr "Ignorer les erreurs de certificats TLS"
msgid "Enable note history"
msgstr "Activer l'historique des notes"
msgid "days"
msgstr "jours"
#, javascript-format
msgid "%d days"
msgstr "%d jours"
msgid "Keep note history for"
msgstr "Garder l'historique des notes pour"
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Option invalide: \"%s\". Les valeurs possibles sont : %s."
@@ -1547,6 +1653,9 @@ msgstr "Apparence"
msgid "Note"
msgstr "Note"
msgid "Plugins"
msgstr "Modules"
msgid "Application"
msgstr "Application"
@@ -1597,12 +1706,19 @@ msgstr "Il n'y a pas de données à exporter."
msgid "Please specify the notebook where the notes should be imported to."
msgstr "Veuillez sélectionner le carnet où les notes doivent être importées."
msgid "Restored Notes"
msgstr "Notes restaurées"
msgid "Items that cannot be synchronised"
msgstr "Objets qui ne peuvent pas être synchronisés"
#, javascript-format
msgid "%s (%s): %s"
msgstr "%s (%s) : %s"
msgid "%s (%s) could not be uploaded: %s"
msgstr "%s (%s) n'a pas pu être envoyé : %s"
#, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr "L'objet \"%s\" n'a pas pu être téléchargé : %s"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
@@ -1885,6 +2001,19 @@ msgstr ""
msgid "Welcome"
msgstr "Bienvenue"
#~ msgid "%s (%s): %s"
#~ msgstr "%s (%s) : %s"
#~ msgid "Table of contents"
#~ msgstr "Table des matières"
#~ msgid ""
#~ "The path to synchronise with when file system synchronisation is enabled. "
#~ "See `sync.target`."
#~ msgstr ""
#~ "Le chemin du répertoire avec lequel synchroniser lorsque la "
#~ "synchronisation par système de fichier est activée. Voir `sync.target`."
#~ msgid "Joplin v%s"
#~ msgstr "Joplin v%s"

View File

@@ -598,9 +598,8 @@ msgstr "Importando de «%s» como formato «%s». Agarde..."
msgid "PDF File"
msgstr "Ficheiro PDF"
#, fuzzy
msgid "&File"
msgstr "Ficheiro"
msgid "Synchronisation status"
msgstr "Estado da sincronización"
msgid "New note"
msgstr "Nova nota"
@@ -611,6 +610,35 @@ msgstr "Nova tarefa"
msgid "New notebook"
msgstr "Novo caderno"
msgid "Print"
msgstr "Imprimir"
msgid "General Options"
msgstr "Opcións xerais"
msgid "Encryption options"
msgstr "Opcións de cifrado"
msgid "Web clipper options"
msgstr ""
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, fuzzy
msgid "&File"
msgstr "Ficheiro"
msgid "About Joplin"
msgstr "Sobre o Joplin"
msgid "Preferences..."
msgstr ""
msgid "Check for updates..."
msgstr "Buscar actualizacións…"
msgid "Import"
msgstr "Importar"
@@ -620,9 +648,6 @@ msgstr "Exportar"
msgid "Synchronise"
msgstr "Sincronizar"
msgid "Print"
msgstr "Imprimir"
#, javascript-format
msgid "Hide %s"
msgstr "Ocultar %s"
@@ -630,6 +655,9 @@ msgstr "Ocultar %s"
msgid "Quit"
msgstr "Saír"
msgid "Close Window"
msgstr ""
#, fuzzy
msgid "&Edit"
msgstr "Edtar"
@@ -687,18 +715,6 @@ msgstr "Focar no corpo"
msgid "&Tools"
msgstr "Ferramentas"
msgid "Synchronisation status"
msgstr "Estado da sincronización"
msgid "Web clipper options"
msgstr ""
msgid "Encryption options"
msgstr "Opcións de cifrado"
msgid "General Options"
msgstr "Opcións xerais"
#, fuzzy
msgid "&Help"
msgstr "Axuda"
@@ -709,16 +725,6 @@ msgstr "Sitio web e documentación"
msgid "Make a donation"
msgstr "Doar"
msgid "Check for updates..."
msgstr "Buscar actualizacións…"
msgid "About Joplin"
msgstr "Sobre o Joplin"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, javascript-format
msgid "Open %s"
msgstr "Abrir %s"
@@ -821,12 +827,12 @@ msgstr ""
msgid "Notes and settings are stored in: %s"
msgstr "As notas e axustes gardáronse en: %s"
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Comprobar a configuración da sincronización"
msgid "Browse..."
msgstr ""
msgid "Apply"
msgstr ""
@@ -986,9 +992,33 @@ msgstr ""
msgid "URL"
msgstr ""
#, fuzzy
msgid "Note History"
msgstr "Cadernos"
msgid "Previous versions of this note"
msgstr ""
msgid "Note properties"
msgstr ""
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr ""
#, fuzzy
msgid "This note has no history"
msgstr "Esta nota foi modificada:"
msgid "Restore"
msgstr ""
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
msgid "Open..."
msgstr "Abrir…"
@@ -1137,18 +1167,15 @@ msgstr "Cadernos"
#, fuzzy, javascript-format
msgid "Decrypting items: %d/%d"
msgstr "Elementos obtidos: %d/%d."
msgstr "Elementos obtidos: %d/%d"
#, fuzzy, javascript-format
msgid "Fetching resources: %d"
msgstr "Recursos: %d."
msgid "Fetching resources: %d/%d"
msgstr "Recursos: %d/%d"
msgid "Please select where the sync status should be exported to"
msgstr "Seleccione onde exportar o estado da sincronización"
msgid "Table of contents"
msgstr ""
msgid "Add or remove tags"
msgstr "Engadir ou eliminar etiquetas"
@@ -1183,6 +1210,14 @@ msgstr "Desexa eliminar as notas?"
msgid "Delete these %d notes?"
msgstr "Desexa eliminar estas notas?"
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
msgid "Goto Anything..."
msgstr ""
#, javascript-format
msgid "Usage: %s"
msgstr "Uso: %s"
@@ -1295,6 +1330,10 @@ msgstr "En proceso"
msgid "Synchronisation is already in progress. State: %s"
msgstr "A sincronización xa está en proceso. Estado: %s"
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr ""
msgid "Encrypted"
msgstr "Cifrado"
@@ -1335,6 +1374,13 @@ msgstr "Non é posíbel copiar a nota ao caderno «%s»"
msgid "Cannot move note to \"%s\" notebook"
msgstr "Non é posíbel mover a nota ao caderno «%s»"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
msgid "Language"
msgstr "Idioma"
@@ -1385,6 +1431,43 @@ msgstr "Focar no corpo"
msgid "When creating a new note:"
msgstr "Cando se crea unha nova nota:"
msgid "Enable soft breaks"
msgstr ""
#, fuzzy
msgid "Enable math expressions"
msgstr "Activar cifrado"
msgid "Enable ==mark== syntax"
msgstr ""
msgid "Enable footnotes"
msgstr ""
msgid "Enable table of contents extension"
msgstr ""
msgid "Enable ~sub~ syntax"
msgstr ""
msgid "Enable ^sup^ syntax"
msgstr ""
msgid "Enable deflist syntax"
msgstr ""
msgid "Enable abbreviation syntax"
msgstr ""
msgid "Enable markdown emoji"
msgstr ""
msgid "Enable ++insert++ syntax"
msgstr ""
msgid "Enable multimarkdown table extension"
msgstr ""
msgid "Show tray icon"
msgstr "Mostrar a icona na bandexa"
@@ -1468,26 +1551,30 @@ msgstr ""
"Destino co que sincronizar. Cada destino da sincronización pode ter "
"parámetros adicionais que se chaman «sync.NUM.NAME» (documentados arriba)."
msgid "Attachment download behaviour"
msgstr ""
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
msgid "Always"
msgstr ""
msgid "Manual"
msgstr ""
msgid "Auto"
msgstr ""
msgid "Directory to synchronise with (absolute path)"
msgstr "Cartafol a sincronizar con (ruta absoluta)"
msgid ""
"The path to synchronise with when file system synchronisation is enabled. "
"See `sync.target`."
msgstr ""
"Ruta para sincronizar cando estea activada a sincronización do sistema de "
"ficheiros. Vexa «sync.target»."
msgid "Nextcloud WebDAV URL"
msgstr "URL de Nextcloud WebDAV"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
msgid "Nextcloud username"
msgstr "Usuario de Nextcloud"
@@ -1516,6 +1603,20 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr ""
#, fuzzy
msgid "Enable note history"
msgstr "Activar cifrado"
msgid "days"
msgstr ""
#, javascript-format
msgid "%d days"
msgstr ""
msgid "Keep note history for"
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Valor incorrecto de opción: «%s». Os valores posíbeis son: %s."
@@ -1535,6 +1636,9 @@ msgstr ""
msgid "Note"
msgstr "Cadernos"
msgid "Plugins"
msgstr ""
#, fuzzy
msgid "Application"
msgstr "Sae do aplicativo."
@@ -1587,12 +1691,19 @@ msgstr "Non hai datos para exportar."
msgid "Please specify the notebook where the notes should be imported to."
msgstr "Indique o caderno ao que importar as notas."
msgid "Restored Notes"
msgstr ""
msgid "Items that cannot be synchronised"
msgstr "Elementos que non se poden sincronizar"
#, javascript-format
msgid "%s (%s): %s"
msgstr "%s (%s): %s"
#, fuzzy, javascript-format
msgid "%s (%s) could not be uploaded: %s"
msgstr "Non foi posíbel gardar o caderno: %s"
#, fuzzy, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr "Non foi posíbel gardar o caderno: %s"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
@@ -1864,6 +1975,16 @@ msgstr "Non ten cadernos actualmente. Cree un premendo no botón (+)."
msgid "Welcome"
msgstr "Benvido/a"
#~ msgid "%s (%s): %s"
#~ msgstr "%s (%s): %s"
#~ msgid ""
#~ "The path to synchronise with when file system synchronisation is enabled. "
#~ "See `sync.target`."
#~ msgstr ""
#~ "Ruta para sincronizar cando estea activada a sincronización do sistema de "
#~ "ficheiros. Vexa «sync.target»."
#, fuzzy
#~ msgid "Joplin v%s"
#~ msgstr "Sitio web de Joplin"

View File

@@ -601,9 +601,8 @@ msgstr ""
msgid "PDF File"
msgstr "Datoteka"
#, fuzzy
msgid "&File"
msgstr "Datoteka"
msgid "Synchronisation status"
msgstr "Status sinkronizacije"
msgid "New note"
msgstr "Nova bilješka"
@@ -614,6 +613,36 @@ msgstr "Novi zadatak"
msgid "New notebook"
msgstr "Nova bilježnica"
msgid "Print"
msgstr ""
#, fuzzy
msgid "General Options"
msgstr "Opcije"
msgid "Encryption options"
msgstr ""
msgid "Web clipper options"
msgstr ""
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, fuzzy
msgid "&File"
msgstr "Datoteka"
msgid "About Joplin"
msgstr "O Joplinu"
msgid "Preferences..."
msgstr ""
msgid "Check for updates..."
msgstr ""
msgid "Import"
msgstr "Uvoz"
@@ -624,9 +653,6 @@ msgstr "Uvoz"
msgid "Synchronise"
msgstr "Sinkroniziraj"
msgid "Print"
msgstr ""
#, javascript-format
msgid "Hide %s"
msgstr ""
@@ -634,6 +660,9 @@ msgstr ""
msgid "Quit"
msgstr "Izađi"
msgid "Close Window"
msgstr ""
#, fuzzy
msgid "&Edit"
msgstr "Uredi"
@@ -690,19 +719,6 @@ msgstr "Naslov bilješke:"
msgid "&Tools"
msgstr "Alati"
msgid "Synchronisation status"
msgstr "Status sinkronizacije"
msgid "Web clipper options"
msgstr ""
msgid "Encryption options"
msgstr ""
#, fuzzy
msgid "General Options"
msgstr "Opcije"
#, fuzzy
msgid "&Help"
msgstr "Pomoć"
@@ -714,16 +730,6 @@ msgstr "Website i dokumentacija"
msgid "Make a donation"
msgstr "Website i dokumentacija"
msgid "Check for updates..."
msgstr ""
msgid "About Joplin"
msgstr "O Joplinu"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, fuzzy, javascript-format
msgid "Open %s"
msgstr "On %s: %s"
@@ -827,13 +833,13 @@ msgstr ""
msgid "Notes and settings are stored in: %s"
msgstr "Bilješke i postavke su pohranjene u: %s"
msgid "Browse..."
msgstr ""
#, fuzzy
msgid "Check synchronisation configuration"
msgstr "Prekini sinkronizaciju"
msgid "Browse..."
msgstr ""
msgid "Apply"
msgstr ""
@@ -984,9 +990,33 @@ msgstr ""
msgid "URL"
msgstr ""
#, fuzzy
msgid "Note History"
msgstr "Bilježnice"
msgid "Previous versions of this note"
msgstr ""
msgid "Note properties"
msgstr ""
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr ""
#, fuzzy
msgid "This note has no history"
msgstr "Bilješka je promijenjena:"
msgid "Restore"
msgstr ""
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
msgid "Open..."
msgstr ""
@@ -1136,18 +1166,15 @@ msgstr "Bilježnice"
#, fuzzy, javascript-format
msgid "Decrypting items: %d/%d"
msgstr "Stvorene lokalne stavke: %d."
msgstr "Stvorene lokalne stavke: %d/%d"
#, fuzzy, javascript-format
msgid "Fetching resources: %d"
msgstr "Resursi: %d."
msgid "Fetching resources: %d/%d"
msgstr "Resursi: %d/%d"
msgid "Please select where the sync status should be exported to"
msgstr "Odaberi lokaciju za izvoz statusa sinkronizacije"
msgid "Table of contents"
msgstr ""
msgid "Add or remove tags"
msgstr "Dodaj ili makni oznake"
@@ -1181,6 +1208,14 @@ msgstr "Obriši bilješke?"
msgid "Delete these %d notes?"
msgstr "Obriši ove bilješke?"
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
msgid "Goto Anything..."
msgstr ""
#, javascript-format
msgid "Usage: %s"
msgstr "Korištenje: %s"
@@ -1291,6 +1326,10 @@ msgstr ""
msgid "Synchronisation is already in progress. State: %s"
msgstr "Sinkronizacija je već u toku. Stanje: %s"
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr ""
msgid "Encrypted"
msgstr ""
@@ -1332,6 +1371,13 @@ msgstr "Ne mogu kopirati bilješku u bilježnicu %s"
msgid "Cannot move note to \"%s\" notebook"
msgstr "Ne mogu premjestiti bilješku u bilježnicu %s"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
msgid "Language"
msgstr "Jezik"
@@ -1387,6 +1433,42 @@ msgstr ""
msgid "When creating a new note:"
msgstr "Stvara novu bilješku."
msgid "Enable soft breaks"
msgstr ""
msgid "Enable math expressions"
msgstr ""
msgid "Enable ==mark== syntax"
msgstr ""
msgid "Enable footnotes"
msgstr ""
msgid "Enable table of contents extension"
msgstr ""
msgid "Enable ~sub~ syntax"
msgstr ""
msgid "Enable ^sup^ syntax"
msgstr ""
msgid "Enable deflist syntax"
msgstr ""
msgid "Enable abbreviation syntax"
msgstr ""
msgid "Enable markdown emoji"
msgstr ""
msgid "Enable ++insert++ syntax"
msgstr ""
msgid "Enable multimarkdown table extension"
msgstr ""
msgid "Show tray icon"
msgstr ""
@@ -1465,26 +1547,30 @@ msgid ""
"which are named as `sync.NUM.NAME` (all documented below)."
msgstr ""
msgid "Attachment download behaviour"
msgstr ""
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
msgid "Always"
msgstr ""
msgid "Manual"
msgstr ""
msgid "Auto"
msgstr ""
msgid "Directory to synchronise with (absolute path)"
msgstr "Direktorij za sinkroniziranje (apsolutna putanja)"
msgid ""
"The path to synchronise with when file system synchronisation is enabled. "
"See `sync.target`."
msgstr ""
"Putanja do direktorija za sinkronizaciju u slučaju kad je sinkronizacija sa "
"datotečnim sustavom omogućena. Vidi `sync.target`."
msgid "Nextcloud WebDAV URL"
msgstr ""
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
msgid "Nextcloud username"
msgstr ""
@@ -1513,6 +1599,20 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr ""
#, fuzzy
msgid "Enable note history"
msgstr "Bilješka je promijenjena:"
msgid "days"
msgstr ""
#, javascript-format
msgid "%d days"
msgstr ""
msgid "Keep note history for"
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Nevažeća vrijednost: \"%s\". Moguće vrijednosti su: %s."
@@ -1532,6 +1632,9 @@ msgstr ""
msgid "Note"
msgstr "Bilježnice"
msgid "Plugins"
msgstr ""
#, fuzzy
msgid "Application"
msgstr "Izađi iz aplikacije."
@@ -1585,12 +1688,19 @@ msgstr ""
msgid "Please specify the notebook where the notes should be imported to."
msgstr "Odaberi lokaciju za izvoz statusa sinkronizacije"
msgid "Restored Notes"
msgstr ""
msgid "Items that cannot be synchronised"
msgstr "Stavke koje se ne mogu sinkronizirati"
#, fuzzy, javascript-format
msgid "%s (%s): %s"
msgstr "%s %s (%s)"
msgid "%s (%s) could not be uploaded: %s"
msgstr "Bilježnicu nije moguće snimiti: %s"
#, fuzzy, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr "Bilježnicu nije moguće snimiti: %s"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
@@ -1861,6 +1971,17 @@ msgstr "Trenutno nemaš nijednu bilježnicu. Stvori novu klikom na (+) gumb."
msgid "Welcome"
msgstr "Dobro došli"
#, fuzzy
#~ msgid "%s (%s): %s"
#~ msgstr "%s %s (%s)"
#~ msgid ""
#~ "The path to synchronise with when file system synchronisation is enabled. "
#~ "See `sync.target`."
#~ msgstr ""
#~ "Putanja do direktorija za sinkronizaciju u slučaju kad je sinkronizacija "
#~ "sa datotečnim sustavom omogućena. Vidi `sync.target`."
#, fuzzy
#~ msgid "State: %s."
#~ msgstr "Stanje: \"%s\"."

View File

@@ -611,9 +611,8 @@ msgstr "Importazione da \"%s\" come formato \"%s\". Si prega di attendere..."
msgid "PDF File"
msgstr "PDF File"
#, fuzzy
msgid "&File"
msgstr "File"
msgid "Synchronisation status"
msgstr "Stato di sincronizzazione"
msgid "New note"
msgstr "Nuova nota"
@@ -624,6 +623,35 @@ msgstr "Nuovo \"Cose-da-fare\""
msgid "New notebook"
msgstr "Nuovo taccuino"
msgid "Print"
msgstr "Stampa"
msgid "General Options"
msgstr "Opzioni Generali"
msgid "Encryption options"
msgstr "Opzioni Crittografia"
msgid "Web clipper options"
msgstr "Opzioni Web Clipper"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, fuzzy
msgid "&File"
msgstr "File"
msgid "About Joplin"
msgstr "Informazione su Joplin"
msgid "Preferences..."
msgstr ""
msgid "Check for updates..."
msgstr "Controlla aggiornamenti ..."
msgid "Import"
msgstr "Importa"
@@ -633,9 +661,6 @@ msgstr "Esporta"
msgid "Synchronise"
msgstr "Sincronizza"
msgid "Print"
msgstr "Stampa"
#, javascript-format
msgid "Hide %s"
msgstr "Nascondi %s"
@@ -643,6 +668,9 @@ msgstr "Nascondi %s"
msgid "Quit"
msgstr "Esci"
msgid "Close Window"
msgstr ""
#, fuzzy
msgid "&Edit"
msgstr "Modifica"
@@ -698,18 +726,6 @@ msgstr "Focus sul testo"
msgid "&Tools"
msgstr "Strumenti"
msgid "Synchronisation status"
msgstr "Stato di sincronizzazione"
msgid "Web clipper options"
msgstr "Opzioni Web Clipper"
msgid "Encryption options"
msgstr "Opzioni Crittografia"
msgid "General Options"
msgstr "Opzioni Generali"
#, fuzzy
msgid "&Help"
msgstr "Aiuto"
@@ -720,16 +736,6 @@ msgstr "Sito web e documentazione"
msgid "Make a donation"
msgstr "Fai una donazione"
msgid "Check for updates..."
msgstr "Controlla aggiornamenti ..."
msgid "About Joplin"
msgstr "Informazione su Joplin"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, javascript-format
msgid "Open %s"
msgstr "Aprire %s"
@@ -838,12 +844,12 @@ msgstr ""
msgid "Notes and settings are stored in: %s"
msgstr "Le note e le impostazioni sono memorizzate in: %s"
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Controlla la configurazione della sincronizzazione"
msgid "Browse..."
msgstr ""
msgid "Apply"
msgstr "Applica"
@@ -1008,9 +1014,33 @@ msgstr ""
msgid "URL"
msgstr ""
#, fuzzy
msgid "Note History"
msgstr "Taccuini"
msgid "Previous versions of this note"
msgstr ""
msgid "Note properties"
msgstr ""
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr ""
#, fuzzy
msgid "This note has no history"
msgstr "Questa note è stata modificata:"
msgid "Restore"
msgstr ""
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
msgid "Open..."
msgstr "Apri ..."
@@ -1162,15 +1192,12 @@ msgid "Decrypting items: %d/%d"
msgstr "Decrittografia Elementi: %d/%d"
#, fuzzy, javascript-format
msgid "Fetching resources: %d"
msgstr "Risorse: %d."
msgid "Fetching resources: %d/%d"
msgstr "Risorse: %d/%d"
msgid "Please select where the sync status should be exported to"
msgstr ""
msgid "Table of contents"
msgstr ""
msgid "Add or remove tags"
msgstr "Aggiungi o rimuovi etichetta"
@@ -1201,6 +1228,14 @@ msgstr "Eliminare il taccuino \"%s\"?"
msgid "Delete these %d notes?"
msgstr "Cancellare queste note?"
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
msgid "Goto Anything..."
msgstr ""
#, javascript-format
msgid "Usage: %s"
msgstr "Uso: %s"
@@ -1313,6 +1348,10 @@ msgstr "In corso"
msgid "Synchronisation is already in progress. State: %s"
msgstr "La sincronizzazione è già in corso. Stato: %s"
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr ""
msgid "Encrypted"
msgstr "Crittografato"
@@ -1349,6 +1388,13 @@ msgstr "Non posso copiare la nota nel Taccuino \"%s\""
msgid "Cannot move note to \"%s\" notebook"
msgstr "Non posso spostare la nota nel Taccuino \"%s\""
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
msgid "Language"
msgstr "Linguaggio"
@@ -1398,6 +1444,43 @@ msgstr "Focus sul testo"
msgid "When creating a new note:"
msgstr "Quando si crea una nuova nota:"
msgid "Enable soft breaks"
msgstr ""
#, fuzzy
msgid "Enable math expressions"
msgstr "Attiva Crittografia"
msgid "Enable ==mark== syntax"
msgstr ""
msgid "Enable footnotes"
msgstr ""
msgid "Enable table of contents extension"
msgstr ""
msgid "Enable ~sub~ syntax"
msgstr ""
msgid "Enable ^sup^ syntax"
msgstr ""
msgid "Enable deflist syntax"
msgstr ""
msgid "Enable abbreviation syntax"
msgstr ""
msgid "Enable markdown emoji"
msgstr ""
msgid "Enable ++insert++ syntax"
msgstr ""
msgid "Enable multimarkdown table extension"
msgstr ""
msgid "Show tray icon"
msgstr "Visualizza tray icon"
@@ -1482,26 +1565,30 @@ msgstr ""
"Ogni target di sincronizzazione può avere parametri aggiuntivi denominati "
"come `sync.NUM.NAME` (tutti documentati di seguito)."
msgid "Attachment download behaviour"
msgstr ""
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
msgid "Always"
msgstr ""
msgid "Manual"
msgstr ""
msgid "Auto"
msgstr ""
msgid "Directory to synchronise with (absolute path)"
msgstr "Cartella da sincronizzare con (percorso assoluto)"
msgid ""
"The path to synchronise with when file system synchronisation is enabled. "
"See `sync.target`."
msgstr ""
"Il percorso di sincronizzazione quando la sincronizzazione è abilitata. Vedi "
"`sync.target`."
msgid "Nextcloud WebDAV URL"
msgstr "URL Nextcloud WebDAV"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
msgid "Nextcloud username"
msgstr "Nome Utente Nextcloud"
@@ -1535,6 +1622,20 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr "Ignora gli errori del certificato TLS"
#, fuzzy
msgid "Enable note history"
msgstr "Attiva Crittografia"
msgid "days"
msgstr ""
#, javascript-format
msgid "%d days"
msgstr ""
msgid "Keep note history for"
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Opzione non valida: \"%s\". I valori possibili sono: %s."
@@ -1554,6 +1655,9 @@ msgstr ""
msgid "Note"
msgstr "Taccuini"
msgid "Plugins"
msgstr ""
#, fuzzy
msgid "Application"
msgstr "Esci dall'applicazione."
@@ -1605,12 +1709,19 @@ msgstr "Non ci sono dati da esportare."
msgid "Please specify the notebook where the notes should be imported to."
msgstr "Si prega di specificare il Taccuino in cui importare le note."
msgid "Restored Notes"
msgstr ""
msgid "Items that cannot be synchronised"
msgstr "Elementi che non possono essere sincronizzati"
#, javascript-format
msgid "%s (%s): %s"
msgstr "%s (%s): %s"
#, fuzzy, javascript-format
msgid "%s (%s) could not be uploaded: %s"
msgstr "Questo file non può essere aperto: %s"
#, fuzzy, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr "Questo file non può essere aperto: %s"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
@@ -1889,6 +2000,16 @@ msgstr ""
msgid "Welcome"
msgstr "Benvenuto"
#~ msgid "%s (%s): %s"
#~ msgstr "%s (%s): %s"
#~ msgid ""
#~ "The path to synchronise with when file system synchronisation is enabled. "
#~ "See `sync.target`."
#~ msgstr ""
#~ "Il percorso di sincronizzazione quando la sincronizzazione è abilitata. "
#~ "Vedi `sync.target`."
#~ msgid "Joplin v%s"
#~ msgstr "Joplin v%s"

View File

@@ -593,9 +593,8 @@ msgstr ""
msgid "PDF File"
msgstr "PDF ファイル"
#, fuzzy
msgid "&File"
msgstr "ファイル"
msgid "Synchronisation status"
msgstr "同期状況"
msgid "New note"
msgstr "新しいノート"
@@ -606,6 +605,35 @@ msgstr "新しいToDo"
msgid "New notebook"
msgstr "新しいノートブック"
msgid "Print"
msgstr "印刷"
msgid "General Options"
msgstr "全般のオプション"
msgid "Encryption options"
msgstr "暗号化のオプション"
msgid "Web clipper options"
msgstr "Webクリッパーのオプション"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, fuzzy
msgid "&File"
msgstr "ファイル"
msgid "About Joplin"
msgstr "Joplinについて"
msgid "Preferences..."
msgstr ""
msgid "Check for updates..."
msgstr "アップデートのチェック..."
msgid "Import"
msgstr "インポート"
@@ -615,9 +643,6 @@ msgstr "エクスポート"
msgid "Synchronise"
msgstr "同期"
msgid "Print"
msgstr "印刷"
#, javascript-format
msgid "Hide %s"
msgstr "%s を隠す"
@@ -625,6 +650,9 @@ msgstr "%s を隠す"
msgid "Quit"
msgstr "終了"
msgid "Close Window"
msgstr ""
#, fuzzy
msgid "&Edit"
msgstr "編集"
@@ -680,18 +708,6 @@ msgstr "本文にフォーカス"
msgid "&Tools"
msgstr "ツール"
msgid "Synchronisation status"
msgstr "同期状況"
msgid "Web clipper options"
msgstr "Webクリッパーのオプション"
msgid "Encryption options"
msgstr "暗号化のオプション"
msgid "General Options"
msgstr "全般のオプション"
#, fuzzy
msgid "&Help"
msgstr "ヘルプ"
@@ -702,16 +718,6 @@ msgstr "Webサイトとドキュメント"
msgid "Make a donation"
msgstr "寄付する"
msgid "Check for updates..."
msgstr "アップデートのチェック..."
msgid "About Joplin"
msgstr "Joplinについて"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, javascript-format
msgid "Open %s"
msgstr "%s を開く"
@@ -820,12 +826,12 @@ msgstr ""
msgid "Notes and settings are stored in: %s"
msgstr "ノートと設定は次の場所に保存されます: %s"
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "同期の設定を確認する"
msgid "Browse..."
msgstr ""
msgid "Apply"
msgstr "適用"
@@ -986,9 +992,33 @@ msgstr "場所"
msgid "URL"
msgstr "URL"
#, fuzzy
msgid "Note History"
msgstr "ノートブック"
msgid "Previous versions of this note"
msgstr ""
msgid "Note properties"
msgstr "ノートのプロパティ"
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr ""
#, fuzzy
msgid "This note has no history"
msgstr "ノートは変更されています:"
msgid "Restore"
msgstr ""
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
msgid "Open..."
msgstr "開く..."
@@ -1139,15 +1169,12 @@ msgid "Decrypting items: %d/%d"
msgstr "復号中のアイテム: %d/%d"
#, javascript-format
msgid "Fetching resources: %d"
msgstr "取得中のリソース: %d"
msgid "Fetching resources: %d/%d"
msgstr "取得中のリソース: %d/%d"
msgid "Please select where the sync status should be exported to"
msgstr "同期状況の出力先を選択してください"
msgid "Table of contents"
msgstr ""
msgid "Add or remove tags"
msgstr "タグの追加と削除"
@@ -1178,6 +1205,14 @@ msgstr "ノートを削除しますか?"
msgid "Delete these %d notes?"
msgstr "ノートを削除しますか?"
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
msgid "Goto Anything..."
msgstr ""
#, javascript-format
msgid "Usage: %s"
msgstr "使用方法: %s"
@@ -1290,6 +1325,10 @@ msgstr "実行中"
msgid "Synchronisation is already in progress. State: %s"
msgstr "同期作業はすでに実行中です。状態: %s"
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr ""
msgid "Encrypted"
msgstr "暗号化済"
@@ -1328,6 +1367,16 @@ msgstr "ノートをノートブック \"%s\" にコピーできません"
msgid "Cannot move note to \"%s\" notebook"
msgstr "ノートをノートブック \"%s\" に移動できません"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
"注意: この場所を変更する際は、同期する前に新しい場所にすべての内容をコピーし"
"ておきましょう。そうしないとすべてのファイルが削除されていまいます! 詳しくは"
"次のFAQをご覧ください: %s"
msgid "Language"
msgstr "言語"
@@ -1377,6 +1426,43 @@ msgstr "本文にフォーカス"
msgid "When creating a new note:"
msgstr "新しいノートを作成した際:"
msgid "Enable soft breaks"
msgstr ""
#, fuzzy
msgid "Enable math expressions"
msgstr "暗号化を有効にする"
msgid "Enable ==mark== syntax"
msgstr ""
msgid "Enable footnotes"
msgstr ""
msgid "Enable table of contents extension"
msgstr ""
msgid "Enable ~sub~ syntax"
msgstr ""
msgid "Enable ^sup^ syntax"
msgstr ""
msgid "Enable deflist syntax"
msgstr ""
msgid "Enable abbreviation syntax"
msgstr ""
msgid "Enable markdown emoji"
msgstr ""
msgid "Enable ++insert++ syntax"
msgstr ""
msgid "Enable multimarkdown table extension"
msgstr ""
msgid "Show tray icon"
msgstr "トレイアイコンの表示"
@@ -1458,29 +1544,30 @@ msgstr ""
"同期する先です。いずれの同期先も `sync.NUM.NAME` のように追加のパラメーターを"
"持つことができるでしょう(すべてのドキュメントは下にあります)。"
msgid "Attachment download behaviour"
msgstr ""
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
msgid "Always"
msgstr ""
msgid "Manual"
msgstr ""
msgid "Auto"
msgstr ""
msgid "Directory to synchronise with (absolute path)"
msgstr "同期先のディレクトリ(絶対パス)"
msgid ""
"The path to synchronise with when file system synchronisation is enabled. "
"See `sync.target`."
msgstr ""
"ファイルシステム同期の有効時に同期を行うパスです。`sync.target`も参考にしてく"
"ださい。"
msgid "Nextcloud WebDAV URL"
msgstr "Nextcloud WebDAV URL"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
"注意: この場所を変更する際は、同期する前に新しい場所にすべての内容をコピーし"
"ておきましょう。そうしないとすべてのファイルが削除されていまいます! 詳しくは"
"次のFAQをご覧ください: %s"
msgid "Nextcloud username"
msgstr "Nextcloud ユーザー名"
@@ -1513,6 +1600,20 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr "TLS証明書のエラーを無視"
#, fuzzy
msgid "Enable note history"
msgstr "暗号化を有効にする"
msgid "days"
msgstr ""
#, javascript-format
msgid "%d days"
msgstr ""
msgid "Keep note history for"
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "無効な設定値: \"%s\"。有効な値は: %sです。"
@@ -1532,6 +1633,9 @@ msgstr ""
msgid "Note"
msgstr "ノートブック"
msgid "Plugins"
msgstr ""
#, fuzzy
msgid "Application"
msgstr "場所"
@@ -1583,12 +1687,19 @@ msgstr "エクスポートするデータがありません。"
msgid "Please specify the notebook where the notes should be imported to."
msgstr "ノートをどのノートブックにインポートするのか指定してください。"
msgid "Restored Notes"
msgstr ""
msgid "Items that cannot be synchronised"
msgstr "同期ができなかったアイテム"
#, javascript-format
msgid "%s (%s): %s"
msgstr "%s (%s): %s"
#, fuzzy, javascript-format
msgid "%s (%s) could not be uploaded: %s"
msgstr "次のファイルは開くことができません:%s"
#, fuzzy, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr "次のファイルは開くことができません:%s"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
@@ -1867,6 +1978,16 @@ msgstr ""
msgid "Welcome"
msgstr "ようこそ"
#~ msgid "%s (%s): %s"
#~ msgstr "%s (%s): %s"
#~ msgid ""
#~ "The path to synchronise with when file system synchronisation is enabled. "
#~ "See `sync.target`."
#~ msgstr ""
#~ "ファイルシステム同期の有効時に同期を行うパスです。`sync.target`も参考にし"
#~ "てください。"
#, fuzzy
#~ msgid "Joplin v%s"
#~ msgstr "JoplinのWebサイト"

View File

@@ -527,7 +527,7 @@ msgstr ""
msgid "PDF File"
msgstr ""
msgid "&File"
msgid "Synchronisation status"
msgstr ""
msgid "New note"
@@ -539,6 +539,34 @@ msgstr ""
msgid "New notebook"
msgstr ""
msgid "Print"
msgstr ""
msgid "General Options"
msgstr ""
msgid "Encryption options"
msgstr ""
msgid "Web clipper options"
msgstr ""
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr ""
msgid "&File"
msgstr ""
msgid "About Joplin"
msgstr ""
msgid "Preferences..."
msgstr ""
msgid "Check for updates..."
msgstr ""
msgid "Import"
msgstr ""
@@ -548,9 +576,6 @@ msgstr ""
msgid "Synchronise"
msgstr ""
msgid "Print"
msgstr ""
#, javascript-format
msgid "Hide %s"
msgstr ""
@@ -558,6 +583,9 @@ msgstr ""
msgid "Quit"
msgstr ""
msgid "Close Window"
msgstr ""
msgid "&Edit"
msgstr ""
@@ -609,18 +637,6 @@ msgstr ""
msgid "&Tools"
msgstr ""
msgid "Synchronisation status"
msgstr ""
msgid "Web clipper options"
msgstr ""
msgid "Encryption options"
msgstr ""
msgid "General Options"
msgstr ""
msgid "&Help"
msgstr ""
@@ -630,16 +646,6 @@ msgstr ""
msgid "Make a donation"
msgstr ""
msgid "Check for updates..."
msgstr ""
msgid "About Joplin"
msgstr ""
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr ""
#, javascript-format
msgid "Open %s"
msgstr ""
@@ -741,10 +747,10 @@ msgstr ""
msgid "Notes and settings are stored in: %s"
msgstr ""
msgid "Browse..."
msgid "Check synchronisation configuration"
msgstr ""
msgid "Check synchronisation configuration"
msgid "Browse..."
msgstr ""
msgid "Apply"
@@ -891,9 +897,31 @@ msgstr ""
msgid "URL"
msgstr ""
msgid "Note History"
msgstr ""
msgid "Previous versions of this note"
msgstr ""
msgid "Note properties"
msgstr ""
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr ""
msgid "This note has no history"
msgstr ""
msgid "Restore"
msgstr ""
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
msgid "Open..."
msgstr ""
@@ -1040,15 +1068,12 @@ msgid "Decrypting items: %d/%d"
msgstr ""
#, javascript-format
msgid "Fetching resources: %d"
msgid "Fetching resources: %d/%d"
msgstr ""
msgid "Please select where the sync status should be exported to"
msgstr ""
msgid "Table of contents"
msgstr ""
msgid "Add or remove tags"
msgstr ""
@@ -1079,6 +1104,14 @@ msgstr ""
msgid "Delete these %d notes?"
msgstr ""
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
msgid "Goto Anything..."
msgstr ""
#, javascript-format
msgid "Usage: %s"
msgstr ""
@@ -1183,6 +1216,10 @@ msgstr ""
msgid "Synchronisation is already in progress. State: %s"
msgstr ""
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr ""
msgid "Encrypted"
msgstr ""
@@ -1219,6 +1256,13 @@ msgstr ""
msgid "Cannot move note to \"%s\" notebook"
msgstr ""
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
msgid "Language"
msgstr ""
@@ -1267,6 +1311,42 @@ msgstr ""
msgid "When creating a new note:"
msgstr ""
msgid "Enable soft breaks"
msgstr ""
msgid "Enable math expressions"
msgstr ""
msgid "Enable ==mark== syntax"
msgstr ""
msgid "Enable footnotes"
msgstr ""
msgid "Enable table of contents extension"
msgstr ""
msgid "Enable ~sub~ syntax"
msgstr ""
msgid "Enable ^sup^ syntax"
msgstr ""
msgid "Enable deflist syntax"
msgstr ""
msgid "Enable abbreviation syntax"
msgstr ""
msgid "Enable markdown emoji"
msgstr ""
msgid "Enable ++insert++ syntax"
msgstr ""
msgid "Enable multimarkdown table extension"
msgstr ""
msgid "Show tray icon"
msgstr ""
@@ -1340,24 +1420,30 @@ msgid ""
"which are named as `sync.NUM.NAME` (all documented below)."
msgstr ""
msgid "Attachment download behaviour"
msgstr ""
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
msgid "Always"
msgstr ""
msgid "Manual"
msgstr ""
msgid "Auto"
msgstr ""
msgid "Directory to synchronise with (absolute path)"
msgstr ""
msgid ""
"The path to synchronise with when file system synchronisation is enabled. "
"See `sync.target`."
msgstr ""
msgid "Nextcloud WebDAV URL"
msgstr ""
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
msgid "Nextcloud username"
msgstr ""
@@ -1386,6 +1472,19 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr ""
msgid "Enable note history"
msgstr ""
msgid "days"
msgstr ""
#, javascript-format
msgid "%d days"
msgstr ""
msgid "Keep note history for"
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr ""
@@ -1402,6 +1501,9 @@ msgstr ""
msgid "Note"
msgstr ""
msgid "Plugins"
msgstr ""
msgid "Application"
msgstr ""
@@ -1450,11 +1552,18 @@ msgstr ""
msgid "Please specify the notebook where the notes should be imported to."
msgstr ""
msgid "Restored Notes"
msgstr ""
msgid "Items that cannot be synchronised"
msgstr ""
#, javascript-format
msgid "%s (%s): %s"
msgid "%s (%s) could not be uploaded: %s"
msgstr ""
#, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr ""
msgid ""

View File

@@ -590,9 +590,8 @@ msgstr "\"%s\"에서 \"%s\" 포맷으로 가져오는 중입니다. 잠시만
msgid "PDF File"
msgstr "PDF 파일"
#, fuzzy
msgid "&File"
msgstr "파일"
msgid "Synchronisation status"
msgstr "동기화 상태"
msgid "New note"
msgstr "새 노트"
@@ -603,6 +602,35 @@ msgstr "새 '할 일'"
msgid "New notebook"
msgstr "새 노트북"
msgid "Print"
msgstr "인쇄"
msgid "General Options"
msgstr "일반 옵션"
msgid "Encryption options"
msgstr "암호화 옵션"
msgid "Web clipper options"
msgstr "웹 수집기 옵션"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, fuzzy
msgid "&File"
msgstr "파일"
msgid "About Joplin"
msgstr "조플린이란?"
msgid "Preferences..."
msgstr ""
msgid "Check for updates..."
msgstr "업데이트 확인..."
msgid "Import"
msgstr "가져오기"
@@ -612,9 +640,6 @@ msgstr "내보내기"
msgid "Synchronise"
msgstr "동기화"
msgid "Print"
msgstr "인쇄"
#, javascript-format
msgid "Hide %s"
msgstr "%s 숨기기"
@@ -622,6 +647,9 @@ msgstr "%s 숨기기"
msgid "Quit"
msgstr "종료"
msgid "Close Window"
msgstr ""
#, fuzzy
msgid "&Edit"
msgstr "편집"
@@ -677,18 +705,6 @@ msgstr "내용에 포커스"
msgid "&Tools"
msgstr "도구"
msgid "Synchronisation status"
msgstr "동기화 상태"
msgid "Web clipper options"
msgstr "웹 수집기 옵션"
msgid "Encryption options"
msgstr "암호화 옵션"
msgid "General Options"
msgstr "일반 옵션"
#, fuzzy
msgid "&Help"
msgstr "도움말"
@@ -699,16 +715,6 @@ msgstr "웹사이트 및 각종 문서"
msgid "Make a donation"
msgstr "기부하기"
msgid "Check for updates..."
msgstr "업데이트 확인..."
msgid "About Joplin"
msgstr "조플린이란?"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, javascript-format
msgid "Open %s"
msgstr "%s 열기"
@@ -816,12 +822,12 @@ msgstr ""
msgid "Notes and settings are stored in: %s"
msgstr "노트와 설정값이 다음에 저장되었습니다: %s"
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "동기화 설정 확인"
msgid "Browse..."
msgstr ""
msgid "Apply"
msgstr "적용"
@@ -980,9 +986,33 @@ msgstr "위치"
msgid "URL"
msgstr "URL"
#, fuzzy
msgid "Note History"
msgstr "노트북"
msgid "Previous versions of this note"
msgstr ""
msgid "Note properties"
msgstr "노트 속성"
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr ""
#, fuzzy
msgid "This note has no history"
msgstr "노트가 변경되었습니다:"
msgid "Restore"
msgstr ""
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
msgid "Open..."
msgstr "열기..."
@@ -1133,15 +1163,12 @@ msgid "Decrypting items: %d/%d"
msgstr "복호화 항목: %d/%d"
#, javascript-format
msgid "Fetching resources: %d"
msgstr "리소스 가져오는 중: %d."
msgid "Fetching resources: %d/%d"
msgstr "리소스 가져오는 중: %d/%d"
msgid "Please select where the sync status should be exported to"
msgstr "동기화 상태를 내보낼 대상을 선택하세요"
msgid "Table of contents"
msgstr ""
msgid "Add or remove tags"
msgstr "태그 추가 및 제거"
@@ -1172,6 +1199,14 @@ msgstr "노트를 삭제할까요?"
msgid "Delete these %d notes?"
msgstr "노트를 삭제할까요?"
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
msgid "Goto Anything..."
msgstr ""
#, javascript-format
msgid "Usage: %s"
msgstr "사용량: %s"
@@ -1284,6 +1319,10 @@ msgstr "진행 중"
msgid "Synchronisation is already in progress. State: %s"
msgstr "동기화가 이미 진행되고 있습니다. 상태: %s"
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr ""
msgid "Encrypted"
msgstr "암호화됨"
@@ -1320,6 +1359,15 @@ msgstr "노트를 \"%s\" 노트북으로 복사할 수 없습니다"
msgid "Cannot move note to \"%s\" notebook"
msgstr "노트를 \"%s\" 노트북으로 옮길 수 없습니다"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
"주의: 이 위치를 변경하시려면, 동기화 전에 모든 컨텐트를 복사했는지 확인하세"
"요, 그렇지 않으면 모든 파일이 삭제됩니다! 자세한 정보는 FAQ를 참조하세요: %s"
msgid "Language"
msgstr "언어"
@@ -1369,6 +1417,43 @@ msgstr "내용에 포커스"
msgid "When creating a new note:"
msgstr "새 노트를 만들 때:"
msgid "Enable soft breaks"
msgstr ""
#, fuzzy
msgid "Enable math expressions"
msgstr "암호화 사용"
msgid "Enable ==mark== syntax"
msgstr ""
msgid "Enable footnotes"
msgstr ""
msgid "Enable table of contents extension"
msgstr ""
msgid "Enable ~sub~ syntax"
msgstr ""
msgid "Enable ^sup^ syntax"
msgstr ""
msgid "Enable deflist syntax"
msgstr ""
msgid "Enable abbreviation syntax"
msgstr ""
msgid "Enable markdown emoji"
msgstr ""
msgid "Enable ++insert++ syntax"
msgstr ""
msgid "Enable multimarkdown table extension"
msgstr ""
msgid "Show tray icon"
msgstr "트레이 아이콘 표시"
@@ -1451,28 +1536,30 @@ msgstr ""
"동기화를 할 대상을 선택합니다. 각각의 동기화 대상은 `sync.NUM.NAME` 형식으로 "
"된 추가적인 매개 변수를 포함할 수 있습니다(아래에 문서화되어 있습니다)."
msgid "Attachment download behaviour"
msgstr ""
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
msgid "Always"
msgstr ""
msgid "Manual"
msgstr ""
msgid "Auto"
msgstr ""
msgid "Directory to synchronise with (absolute path)"
msgstr "동기화를 할 폴더 (절대적 경로)"
msgid ""
"The path to synchronise with when file system synchronisation is enabled. "
"See `sync.target`."
msgstr ""
"파일 시스템 동기화가 활성화된 경우에 동기화를 할 경로입니다. `sync.target`를 "
"참조하세요."
msgid "Nextcloud WebDAV URL"
msgstr "Nextcloud WebDAV URL"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
"주의: 이 위치를 변경하시려면, 동기화 전에 모든 컨텐트를 복사했는지 확인하세"
"요, 그렇지 않으면 모든 파일이 삭제됩니다! 자세한 정보는 FAQ를 참조하세요: %s"
msgid "Nextcloud username"
msgstr "Nextcloud 사용자 이름"
@@ -1505,6 +1592,20 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr "TLS 인증서 오류 무시"
#, fuzzy
msgid "Enable note history"
msgstr "암호화 사용"
msgid "days"
msgstr ""
#, javascript-format
msgid "%d days"
msgstr ""
msgid "Keep note history for"
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "올바르지 않은 옵션 값: \"%s\". 가능한 값은 다음과 같습니다: \"%s\"."
@@ -1524,6 +1625,9 @@ msgstr ""
msgid "Note"
msgstr "노트북"
msgid "Plugins"
msgstr ""
#, fuzzy
msgid "Application"
msgstr "위치"
@@ -1575,12 +1679,19 @@ msgstr "내보낼 데이터가 없습니다."
msgid "Please specify the notebook where the notes should be imported to."
msgstr "노트를 가져와서 저장할 노트북을 지정하세요."
msgid "Restored Notes"
msgstr ""
msgid "Items that cannot be synchronised"
msgstr "동기화를 할 수 없는 항목"
#, javascript-format
msgid "%s (%s): %s"
msgstr "%s (%s): %s"
#, fuzzy, javascript-format
msgid "%s (%s) could not be uploaded: %s"
msgstr "다음 파일을 열 수 없습니다: %s"
#, fuzzy, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr "다음 파일을 열 수 없습니다: %s"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
@@ -1856,6 +1967,16 @@ msgstr "노트북이 없습니다. (+) 버튼을 눌러 새로 만드세요."
msgid "Welcome"
msgstr "환영합니다"
#~ msgid "%s (%s): %s"
#~ msgstr "%s (%s): %s"
#~ msgid ""
#~ "The path to synchronise with when file system synchronisation is enabled. "
#~ "See `sync.target`."
#~ msgstr ""
#~ "파일 시스템 동기화가 활성화된 경우에 동기화를 할 경로입니다. `sync.target`"
#~ "를 참조하세요."
#~ msgid "Joplin v%s"
#~ msgstr "조플린 v%s"

View File

@@ -17,8 +17,7 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
msgid "To delete a tag, untag the associated notes."
msgstr ""
"For å slette en merkelapp, fjern merkelappen fra merkede notater."
msgstr "For å slette en merkelapp, fjern merkelappen fra merkede notater."
msgid "Please select the note or notebook to be deleted first."
msgstr "Vennligst velg notatet eller notatboken som skal slettes først."
@@ -128,9 +127,9 @@ msgid ""
"Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, "
"`status`, `decrypt-file` and `target-status`."
msgstr ""
"Konfigurerer E2EE-konfigurasjon. Tilgjengelige kommandoer er: `enable`(aktiver), "
"`disable`(lukk), `decrypt`(dekrypter), `status` og `target-status` (mottager-"
"status)."
"Konfigurerer E2EE-konfigurasjon. Tilgjengelige kommandoer er: "
"`enable`(aktiver), `disable`(lukk), `decrypt`(dekrypter), `status` og "
"`target-status` (mottager-status)."
msgid "Enter master password:"
msgstr "Skriv inn masterpassordet:"
@@ -595,8 +594,8 @@ msgstr "Importerer fra \"%s\" i \"%s\"-format. Vennligst vent..."
msgid "PDF File"
msgstr "PDF-fil"
msgid "&File"
msgstr "&Fil"
msgid "Synchronisation status"
msgstr "Synkroniseringsstatus"
msgid "New note"
msgstr "Nytt notat"
@@ -607,6 +606,34 @@ msgstr "Nytt gjøremål"
msgid "New notebook"
msgstr "Ny notatbok"
msgid "Print"
msgstr "Skriv ut"
msgid "General Options"
msgstr "Generelle innstillinger"
msgid "Encryption options"
msgstr "Krypteringsvalg"
msgid "Web clipper options"
msgstr "Web Clipper-innstillinger"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
msgid "&File"
msgstr "&Fil"
msgid "About Joplin"
msgstr "Om Joplin"
msgid "Preferences..."
msgstr ""
msgid "Check for updates..."
msgstr "Se etter oppdatering..."
msgid "Import"
msgstr "Importer"
@@ -616,9 +643,6 @@ msgstr "Eksporter"
msgid "Synchronise"
msgstr "Synkroniser"
msgid "Print"
msgstr "Skriv ut"
#, javascript-format
msgid "Hide %s"
msgstr "Skjul %s"
@@ -626,6 +650,9 @@ msgstr "Skjul %s"
msgid "Quit"
msgstr "Avslutt"
msgid "Close Window"
msgstr ""
msgid "&Edit"
msgstr "&Rediger"
@@ -677,18 +704,6 @@ msgstr "Fokuser"
msgid "&Tools"
msgstr "&Verktøy"
msgid "Synchronisation status"
msgstr "Synkroniseringsstatus"
msgid "Web clipper options"
msgstr "Web Clipper-innstillinger"
msgid "Encryption options"
msgstr "Krypteringsvalg"
msgid "General Options"
msgstr "Generelle innstillinger"
msgid "&Help"
msgstr "&Hjelp"
@@ -698,16 +713,6 @@ msgstr "Nettsted og dokumentasjon"
msgid "Make a donation"
msgstr "Gi et bidrag"
msgid "Check for updates..."
msgstr "Se etter oppdatering..."
msgid "About Joplin"
msgstr "Om Joplin"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, javascript-format
msgid "Open %s"
msgstr "Åpne %s"
@@ -816,12 +821,12 @@ msgstr ""
msgid "Notes and settings are stored in: %s"
msgstr "Notater og innstillinger er lagret i: %s"
msgid "Browse..."
msgstr "Utforsk..."
msgid "Check synchronisation configuration"
msgstr "Sjekk synkroniseringskonfigurasjon"
msgid "Browse..."
msgstr "Utforsk..."
msgid "Apply"
msgstr "Bruk"
@@ -985,9 +990,33 @@ msgstr "Lokasjon"
msgid "URL"
msgstr "URL"
#, fuzzy
msgid "Note History"
msgstr "Notatliste"
msgid "Previous versions of this note"
msgstr ""
msgid "Note properties"
msgstr "Notategenskaper"
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr ""
#, fuzzy
msgid "This note has no history"
msgstr "Dette notatet har blitt endret:"
msgid "Restore"
msgstr ""
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
msgid "Open..."
msgstr "Åpne..."
@@ -1113,10 +1142,10 @@ msgid ""
"\n"
"All notes and sub-notebooks within this notebook will also be deleted."
msgstr ""
"Slette notatbok \"&s\"?\n"
"Slette notatbok \"&s\"?\n"
"\n"
"Alle notater og underliggende notatbøker i denne notatboken "
"vil også bli slettet."
"Alle notater og underliggende notatbøker i denne notatboken vil også bli "
"slettet."
#, javascript-format
msgid "Remove tag \"%s\" from all notes?"
@@ -1139,15 +1168,12 @@ msgid "Decrypting items: %d/%d"
msgstr "Dekrypterer elementer: %d/%d"
#, javascript-format
msgid "Fetching resources: %d"
msgid "Fetching resources: %d/%d"
msgstr "Henter ressurser: %d"
msgid "Please select where the sync status should be exported to"
msgstr "Velg hvor synkroniseringsstatusen skal eksporteres til"
msgid "Table of contents"
msgstr "Liste over innhold"
msgid "Add or remove tags"
msgstr "Legg til eller fjern merkelapper"
@@ -1178,6 +1204,14 @@ msgstr "Slette notat \"%s\"?"
msgid "Delete these %d notes?"
msgstr "Slett disse %d notatene?"
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
msgid "Goto Anything..."
msgstr ""
#, javascript-format
msgid "Usage: %s"
msgstr "Bruk: %s"
@@ -1290,6 +1324,10 @@ msgstr "Pågår"
msgid "Synchronisation is already in progress. State: %s"
msgstr "Synkronisering pågår allerede. Status: %s"
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr ""
msgid "Encrypted"
msgstr "Kryptert"
@@ -1326,6 +1364,16 @@ msgstr "Kan ikke kopiere notat til notatenboken \"%s\""
msgid "Cannot move note to \"%s\" notebook"
msgstr "Kan ikke flytte notatet til notatboken \"%s\""
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
"Viktig: Dersom du endrer denne lokasjonen, sørg for at du kopierer alt "
"innhold dit før du synkroniserer. Hvis ikke blir alle filer fjernet! Se FAQ "
"for flere detaljer: %s"
msgid "Language"
msgstr "Språk"
@@ -1374,6 +1422,46 @@ msgstr "Fokuser på brødtekst"
msgid "When creating a new note:"
msgstr "Når du lager et nytt notat:"
#, fuzzy
msgid "Enable soft breaks"
msgstr "Liste over innhold"
#, fuzzy
msgid "Enable math expressions"
msgstr "Aktiver kryptering"
msgid "Enable ==mark== syntax"
msgstr ""
#, fuzzy
msgid "Enable footnotes"
msgstr "Liste over innhold"
#, fuzzy
msgid "Enable table of contents extension"
msgstr "Liste over innhold"
msgid "Enable ~sub~ syntax"
msgstr ""
msgid "Enable ^sup^ syntax"
msgstr ""
msgid "Enable deflist syntax"
msgstr ""
msgid "Enable abbreviation syntax"
msgstr ""
msgid "Enable markdown emoji"
msgstr ""
msgid "Enable ++insert++ syntax"
msgstr ""
msgid "Enable multimarkdown table extension"
msgstr ""
msgid "Show tray icon"
msgstr "Vis systemmenyikon"
@@ -1457,29 +1545,30 @@ msgstr ""
"Målet å synkronisere til. Hvert synkroniseringsmål kan ha tilleggsparametere "
"som er navngitt som `sync.NUM.NAME` (dokumentert nedenfor)."
msgid "Attachment download behaviour"
msgstr ""
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
msgid "Always"
msgstr ""
msgid "Manual"
msgstr ""
msgid "Auto"
msgstr ""
msgid "Directory to synchronise with (absolute path)"
msgstr "Katalog å synkronisere med (absolutt sti)"
msgid ""
"The path to synchronise with when file system synchronisation is enabled. "
"See `sync.target`."
msgstr ""
"Stien som skal synkroniseres når filsystemsynkronisering er aktivert. Se "
"`sync.target`."
msgid "Nextcloud WebDAV URL"
msgstr "Nextcloud WebDAV-URL"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
"Viktig: Dersom du endrer denne lokasjonen, sørg for at du kopierer alt "
"innhold dit før du synkroniserer. Hvis ikke blir alle filer fjernet! Se FAQ "
"for flere detaljer: %s"
msgid "Nextcloud username"
msgstr "Nextcloud-brukernavn"
@@ -1512,6 +1601,20 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr "Ignorer TLS-sertifikatfeil"
#, fuzzy
msgid "Enable note history"
msgstr "Liste over innhold"
msgid "days"
msgstr ""
#, javascript-format
msgid "%d days"
msgstr ""
msgid "Keep note history for"
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Ugyldig verdi: \"%s\". Mulige verdier er: %s."
@@ -1528,6 +1631,9 @@ msgstr "Utseende"
msgid "Note"
msgstr "Notat"
msgid "Plugins"
msgstr ""
msgid "Application"
msgstr "Applikasjon"
@@ -1578,12 +1684,19 @@ msgstr "Det er ingen data for eksportering."
msgid "Please specify the notebook where the notes should be imported to."
msgstr "Velg notatbok som notatene skal importeres til."
msgid "Restored Notes"
msgstr ""
msgid "Items that cannot be synchronised"
msgstr "Elementer som ikke vil synkronisere"
#, javascript-format
msgid "%s (%s): %s"
msgstr "%s (%s): %s"
#, fuzzy, javascript-format
msgid "%s (%s) could not be uploaded: %s"
msgstr "Filen kunne ikke åpnes: %s"
#, fuzzy, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr "Filen kunne ikke åpnes: %s"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
@@ -1859,6 +1972,19 @@ msgstr "Du har enda ingen notatbok. Opprett en ved å klikke på (+)-knappen."
msgid "Welcome"
msgstr "Velkommen"
#~ msgid "%s (%s): %s"
#~ msgstr "%s (%s): %s"
#~ msgid "Table of contents"
#~ msgstr "Liste over innhold"
#~ msgid ""
#~ "The path to synchronise with when file system synchronisation is enabled. "
#~ "See `sync.target`."
#~ msgstr ""
#~ "Stien som skal synkroniseres når filsystemsynkronisering er aktivert. Se "
#~ "`sync.target`."
#, fuzzy
#~ msgid "Joplin v%s"
#~ msgstr "Joplin v%s"

View File

@@ -607,9 +607,8 @@ msgstr ""
msgid "PDF File"
msgstr "Bestand"
#, fuzzy
msgid "&File"
msgstr "Bestand"
msgid "Synchronisation status"
msgstr "Synchronisatie status"
msgid "New note"
msgstr "Nieuwe notitie"
@@ -620,6 +619,35 @@ msgstr "Nieuwe to-do"
msgid "New notebook"
msgstr "Nieuw notitieboek"
msgid "Print"
msgstr ""
msgid "General Options"
msgstr "Algemene opties"
msgid "Encryption options"
msgstr "Versleutelopties"
msgid "Web clipper options"
msgstr ""
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, fuzzy
msgid "&File"
msgstr "Bestand"
msgid "About Joplin"
msgstr "Over Joplin"
msgid "Preferences..."
msgstr ""
msgid "Check for updates..."
msgstr ""
msgid "Import"
msgstr "Importeer"
@@ -630,9 +658,6 @@ msgstr "Importeer"
msgid "Synchronise"
msgstr "Synchroniseer"
msgid "Print"
msgstr ""
#, javascript-format
msgid "Hide %s"
msgstr ""
@@ -640,6 +665,9 @@ msgstr ""
msgid "Quit"
msgstr "Stop"
msgid "Close Window"
msgstr ""
#, fuzzy
msgid "&Edit"
msgstr "Bewerk"
@@ -695,18 +723,6 @@ msgstr ""
msgid "&Tools"
msgstr "Tools"
msgid "Synchronisation status"
msgstr "Synchronisatie status"
msgid "Web clipper options"
msgstr ""
msgid "Encryption options"
msgstr "Versleutelopties"
msgid "General Options"
msgstr "Algemene opties"
#, fuzzy
msgid "&Help"
msgstr "Help"
@@ -718,16 +734,6 @@ msgstr "Website en documentatie"
msgid "Make a donation"
msgstr "Website en documentatie"
msgid "Check for updates..."
msgstr ""
msgid "About Joplin"
msgstr "Over Joplin"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, fuzzy, javascript-format
msgid "Open %s"
msgstr "Op %s: %s"
@@ -831,13 +837,13 @@ msgstr ""
msgid "Notes and settings are stored in: %s"
msgstr "Notities en instellingen zijn opgeslaan in %s"
msgid "Browse..."
msgstr ""
#, fuzzy
msgid "Check synchronisation configuration"
msgstr "Annuleer synchronisatie"
msgid "Browse..."
msgstr ""
msgid "Apply"
msgstr ""
@@ -1001,9 +1007,33 @@ msgstr ""
msgid "URL"
msgstr ""
#, fuzzy
msgid "Note History"
msgstr "Notitieboeken"
msgid "Previous versions of this note"
msgstr ""
msgid "Note properties"
msgstr ""
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr ""
#, fuzzy
msgid "This note has no history"
msgstr "Deze notitie werd aangepast:"
msgid "Restore"
msgstr ""
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
msgid "Open..."
msgstr ""
@@ -1154,18 +1184,15 @@ msgstr "Notitieboeken"
#, fuzzy, javascript-format
msgid "Decrypting items: %d/%d"
msgstr "Opgehaalde items: %d/%d."
msgstr "Opgehaalde items: %d/%d"
#, fuzzy, javascript-format
msgid "Fetching resources: %d"
msgstr "Middelen: %d."
msgid "Fetching resources: %d/%d"
msgstr "Middelen: %d/%d"
msgid "Please select where the sync status should be exported to"
msgstr "Selecteer waar de synchronisatie status naar geëxporteerd moet worden"
msgid "Table of contents"
msgstr ""
msgid "Add or remove tags"
msgstr "Voeg tag toe of verwijder tag"
@@ -1199,6 +1226,14 @@ msgstr "Notities verwijderen?"
msgid "Delete these %d notes?"
msgstr "Deze notities verwijderen?"
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
msgid "Goto Anything..."
msgstr ""
#, javascript-format
msgid "Usage: %s"
msgstr "Gebruik: %s"
@@ -1312,6 +1347,10 @@ msgstr ""
msgid "Synchronisation is already in progress. State: %s"
msgstr "Synchronisatie is reeds bezig. Status: %s"
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr ""
msgid "Encrypted"
msgstr "Versleuteld"
@@ -1354,6 +1393,13 @@ msgstr "Kan notitie niet naar notitieboek \"%s\" kopiëren."
msgid "Cannot move note to \"%s\" notebook"
msgstr "Kan notitie niet naar notitieboek \"%s\" verplaatsen."
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
msgid "Language"
msgstr "Taal"
@@ -1408,6 +1454,43 @@ msgstr ""
msgid "When creating a new note:"
msgstr "Maakt een nieuwe notitie aan."
msgid "Enable soft breaks"
msgstr ""
#, fuzzy
msgid "Enable math expressions"
msgstr "Schakel encryptie in"
msgid "Enable ==mark== syntax"
msgstr ""
msgid "Enable footnotes"
msgstr ""
msgid "Enable table of contents extension"
msgstr ""
msgid "Enable ~sub~ syntax"
msgstr ""
msgid "Enable ^sup^ syntax"
msgstr ""
msgid "Enable deflist syntax"
msgstr ""
msgid "Enable abbreviation syntax"
msgstr ""
msgid "Enable markdown emoji"
msgstr ""
msgid "Enable ++insert++ syntax"
msgstr ""
msgid "Enable multimarkdown table extension"
msgstr ""
msgid "Show tray icon"
msgstr ""
@@ -1487,26 +1570,30 @@ msgid ""
"which are named as `sync.NUM.NAME` (all documented below)."
msgstr ""
msgid "Attachment download behaviour"
msgstr ""
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
msgid "Always"
msgstr ""
msgid "Manual"
msgstr ""
msgid "Auto"
msgstr ""
msgid "Directory to synchronise with (absolute path)"
msgstr "Folder om mee te synchroniseren (absolute pad)"
msgid ""
"The path to synchronise with when file system synchronisation is enabled. "
"See `sync.target`."
msgstr ""
"Het pad om mee te synchroniseren als bestandssysteem synchronisatie is "
"ingeschakeld. Zie `sync.target`."
msgid "Nextcloud WebDAV URL"
msgstr ""
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
msgid "Nextcloud username"
msgstr ""
@@ -1537,6 +1624,20 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr ""
#, fuzzy
msgid "Enable note history"
msgstr "Schakel encryptie in"
msgid "days"
msgstr ""
#, javascript-format
msgid "%d days"
msgstr ""
msgid "Keep note history for"
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Ongeldige optie: \"%s\". Geldige waarden zijn: %s."
@@ -1556,6 +1657,9 @@ msgstr ""
msgid "Note"
msgstr "Notitieboeken"
msgid "Plugins"
msgstr ""
#, fuzzy
msgid "Application"
msgstr "Sluit de applicatie."
@@ -1609,12 +1713,19 @@ msgstr ""
msgid "Please specify the notebook where the notes should be imported to."
msgstr "Selecteer waar de synchronisatie status naar geëxporteerd moet worden"
msgid "Restored Notes"
msgstr ""
msgid "Items that cannot be synchronised"
msgstr "Items die niet gesynchroniseerd kunnen worden"
#, javascript-format
msgid "%s (%s): %s"
msgstr "%s (%s): %s"
#, fuzzy, javascript-format
msgid "%s (%s) could not be uploaded: %s"
msgstr "Het notitieboek kon niet opgeslaan worden: %s"
#, fuzzy, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr "Het notitieboek kon niet opgeslaan worden: %s"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
@@ -1890,6 +2001,16 @@ msgstr ""
msgid "Welcome"
msgstr "Welkom"
#~ msgid "%s (%s): %s"
#~ msgstr "%s (%s): %s"
#~ msgid ""
#~ "The path to synchronise with when file system synchronisation is enabled. "
#~ "See `sync.target`."
#~ msgstr ""
#~ "Het pad om mee te synchroniseren als bestandssysteem synchronisatie is "
#~ "ingeschakeld. Zie `sync.target`."
#, fuzzy
#~ msgid "State: %s."
#~ msgstr "Status: \"%s\""

View File

@@ -607,9 +607,8 @@ msgstr "Bezig met importeren van \"%s\" in het formaat \"%s\". Even geduld..."
msgid "PDF File"
msgstr "PDF-bestand"
#, fuzzy
msgid "&File"
msgstr "Bestand"
msgid "Synchronisation status"
msgstr "Synchronisatiestatus"
msgid "New note"
msgstr "Nieuwe notitie"
@@ -620,6 +619,35 @@ msgstr "Nieuwe taak"
msgid "New notebook"
msgstr "Nieuw notitieboek"
msgid "Print"
msgstr "Afdrukken"
msgid "General Options"
msgstr "Algemene opties"
msgid "Encryption options"
msgstr "Versleutelingsopties"
msgid "Web clipper options"
msgstr "Webclipper-opties"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, fuzzy
msgid "&File"
msgstr "Bestand"
msgid "About Joplin"
msgstr "Over Joplin"
msgid "Preferences..."
msgstr ""
msgid "Check for updates..."
msgstr "Controleren op updates..."
msgid "Import"
msgstr "Importeren"
@@ -629,9 +657,6 @@ msgstr "Exporteren"
msgid "Synchronise"
msgstr "Synchroniseren"
msgid "Print"
msgstr "Afdrukken"
#, javascript-format
msgid "Hide %s"
msgstr "%s verbergen"
@@ -639,6 +664,9 @@ msgstr "%s verbergen"
msgid "Quit"
msgstr "Afsluiten"
msgid "Close Window"
msgstr ""
#, fuzzy
msgid "&Edit"
msgstr "Bewerken"
@@ -696,18 +724,6 @@ msgstr "Inhoud focussen"
msgid "&Tools"
msgstr "Hulpmiddelen"
msgid "Synchronisation status"
msgstr "Synchronisatiestatus"
msgid "Web clipper options"
msgstr "Webclipper-opties"
msgid "Encryption options"
msgstr "Versleutelingsopties"
msgid "General Options"
msgstr "Algemene opties"
#, fuzzy
msgid "&Help"
msgstr "Hulp"
@@ -718,16 +734,6 @@ msgstr "Website en documentatie"
msgid "Make a donation"
msgstr "Doneren"
msgid "Check for updates..."
msgstr "Controleren op updates..."
msgid "About Joplin"
msgstr "Over Joplin"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, javascript-format
msgid "Open %s"
msgstr "%s openen"
@@ -836,12 +842,12 @@ msgstr ""
msgid "Notes and settings are stored in: %s"
msgstr "Notities en instellingen worden opgeslagen in: %s"
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Synchronisatieconfiguratie controleren"
msgid "Browse..."
msgstr ""
msgid "Apply"
msgstr "Toepassen"
@@ -1009,9 +1015,33 @@ msgstr ""
msgid "URL"
msgstr ""
#, fuzzy
msgid "Note History"
msgstr "Notitieboeken"
msgid "Previous versions of this note"
msgstr ""
msgid "Note properties"
msgstr ""
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr ""
#, fuzzy
msgid "This note has no history"
msgstr "Deze notitie is bewerkt:"
msgid "Restore"
msgstr ""
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
msgid "Open..."
msgstr "Openen..."
@@ -1162,15 +1192,12 @@ msgid "Decrypting items: %d/%d"
msgstr "Bezig met ontsleutelen van items: %d/%d"
#, fuzzy, javascript-format
msgid "Fetching resources: %d"
msgstr "Bronnen: %d."
msgid "Fetching resources: %d/%d"
msgstr "Bronnen: %d/%d"
msgid "Please select where the sync status should be exported to"
msgstr "Kies waar de synchronisatiestatus naar moet worden geëxporteerd"
msgid "Table of contents"
msgstr ""
msgid "Add or remove tags"
msgstr "Labels toevoegen of verwijderen"
@@ -1203,6 +1230,14 @@ msgstr "Notities verwijderen?"
msgid "Delete these %d notes?"
msgstr "Deze notities verwijderen?"
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
msgid "Goto Anything..."
msgstr ""
#, javascript-format
msgid "Usage: %s"
msgstr "Gebruik: %s"
@@ -1315,6 +1350,10 @@ msgstr "Bezig"
msgid "Synchronisation is already in progress. State: %s"
msgstr "De synchronisatie loopt al. Status: %s"
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr ""
msgid "Encrypted"
msgstr "Versleuteld"
@@ -1351,6 +1390,13 @@ msgstr "Kan notitie niet kopiëren naar notitieboek \"%s\""
msgid "Cannot move note to \"%s\" notebook"
msgstr "Kan notitie niet verplaatsen naar notitieboek \"%s\""
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
msgid "Language"
msgstr "Taal"
@@ -1400,6 +1446,43 @@ msgstr "Inhoud focussen"
msgid "When creating a new note:"
msgstr "Bij het creëren van een nieuwe notitie:"
msgid "Enable soft breaks"
msgstr ""
#, fuzzy
msgid "Enable math expressions"
msgstr "Versleuteling inschakelen"
msgid "Enable ==mark== syntax"
msgstr ""
msgid "Enable footnotes"
msgstr ""
msgid "Enable table of contents extension"
msgstr ""
msgid "Enable ~sub~ syntax"
msgstr ""
msgid "Enable ^sup^ syntax"
msgstr ""
msgid "Enable deflist syntax"
msgstr ""
msgid "Enable abbreviation syntax"
msgstr ""
msgid "Enable markdown emoji"
msgstr ""
msgid "Enable ++insert++ syntax"
msgstr ""
msgid "Enable multimarkdown table extension"
msgstr ""
msgid "Show tray icon"
msgstr "Systeemvakpictogram tonen"
@@ -1483,26 +1566,30 @@ msgstr ""
"argumenten bevatten, welke `sync.NUM.NAME` worden genoemd (wordt hieronder "
"uitgelegd)."
msgid "Attachment download behaviour"
msgstr ""
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
msgid "Always"
msgstr ""
msgid "Manual"
msgstr ""
msgid "Auto"
msgstr ""
msgid "Directory to synchronise with (absolute path)"
msgstr "Map waarnaar gesynchroniseerd moet worden (absoluut pad)"
msgid ""
"The path to synchronise with when file system synchronisation is enabled. "
"See `sync.target`."
msgstr ""
"Het pad waarnaar gesynchroniseerd moet worden als bestandssysteem-"
"synchronisatie is ingeschakeld. Zie `sync.target`."
msgid "Nextcloud WebDAV URL"
msgstr "Nextcloud WebDAV-URL"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
msgid "Nextcloud username"
msgstr "Nextcloud-gebruikersnaam"
@@ -1536,6 +1623,20 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr "TLS-certificaatfouten negeren"
#, fuzzy
msgid "Enable note history"
msgstr "Versleuteling inschakelen"
msgid "days"
msgstr ""
#, javascript-format
msgid "%d days"
msgstr ""
msgid "Keep note history for"
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Ongeldige optie: \"%s\". Geldige waarden zijn: %s."
@@ -1555,6 +1656,9 @@ msgstr ""
msgid "Note"
msgstr "Notitieboeken"
msgid "Plugins"
msgstr ""
#, fuzzy
msgid "Application"
msgstr "Sluit de applicatie af."
@@ -1608,12 +1712,19 @@ msgid "Please specify the notebook where the notes should be imported to."
msgstr ""
"Geef het notitieboek op waar de notities naar moeten worden geïmporteerd."
msgid "Restored Notes"
msgstr ""
msgid "Items that cannot be synchronised"
msgstr "Items die niet kunnen worden gesynchroniseerd"
#, javascript-format
msgid "%s (%s): %s"
msgstr "%s (%s): %s"
#, fuzzy, javascript-format
msgid "%s (%s) could not be uploaded: %s"
msgstr "Dit bestand kan niet worden geopend: %s"
#, fuzzy, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr "Dit bestand kan niet worden geopend: %s"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
@@ -1893,6 +2004,16 @@ msgstr ""
msgid "Welcome"
msgstr "Welkom"
#~ msgid "%s (%s): %s"
#~ msgstr "%s (%s): %s"
#~ msgid ""
#~ "The path to synchronise with when file system synchronisation is enabled. "
#~ "See `sync.target`."
#~ msgstr ""
#~ "Het pad waarnaar gesynchroniseerd moet worden als bestandssysteem-"
#~ "synchronisatie is ingeschakeld. Zie `sync.target`."
#, fuzzy
#~ msgid "Joplin v%s"
#~ msgstr "Joplin-website"

View File

@@ -164,8 +164,8 @@ msgstr "Editar nota."
msgid ""
"No text editor is defined. Please set it using `config editor <editor-path>`"
msgstr ""
"Nenhum editor de texto está definido. Defina-o usando o comando `config editor "
"<caminho-do-editor>`"
"Nenhum editor de texto está definido. Defina-o usando o comando `config "
"editor <caminho-do-editor>`"
msgid "No active notebook."
msgstr "Nenhum caderno ativo."
@@ -604,9 +604,8 @@ msgstr "Importando de \"%s\" com o formato \"%s\". Por favor, aguarde..."
msgid "PDF File"
msgstr "Arquivo PDF"
#, fuzzy
msgid "&File"
msgstr "Arquivo"
msgid "Synchronisation status"
msgstr "Status de sincronização"
msgid "New note"
msgstr "Nova nota"
@@ -617,6 +616,35 @@ msgstr "Nova tarefa"
msgid "New notebook"
msgstr "Novo caderno"
msgid "Print"
msgstr "Imprimir"
msgid "General Options"
msgstr "Opções Gerais"
msgid "Encryption options"
msgstr "Opções de Encriptação"
msgid "Web clipper options"
msgstr "Opções do Web clipper"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, fuzzy
msgid "&File"
msgstr "Arquivo"
msgid "About Joplin"
msgstr "Sobre o Joplin"
msgid "Preferences..."
msgstr ""
msgid "Check for updates..."
msgstr "Verificar atualizações..."
msgid "Import"
msgstr "Importar"
@@ -626,9 +654,6 @@ msgstr "Exportar"
msgid "Synchronise"
msgstr "Sincronizar"
msgid "Print"
msgstr "Imprimir"
#, javascript-format
msgid "Hide %s"
msgstr "Ocultar %s"
@@ -636,6 +661,9 @@ msgstr "Ocultar %s"
msgid "Quit"
msgstr "Sair"
msgid "Close Window"
msgstr ""
#, fuzzy
msgid "&Edit"
msgstr "Editar"
@@ -691,18 +719,6 @@ msgstr "Focar no corpo"
msgid "&Tools"
msgstr "Ferramentas"
msgid "Synchronisation status"
msgstr "Status de sincronização"
msgid "Web clipper options"
msgstr "Opções do Web clipper"
msgid "Encryption options"
msgstr "Opções de Encriptação"
msgid "General Options"
msgstr "Opções Gerais"
#, fuzzy
msgid "&Help"
msgstr "Ajuda"
@@ -713,16 +729,6 @@ msgstr "Website e documentação"
msgid "Make a donation"
msgstr "Fazer uma doação"
msgid "Check for updates..."
msgstr "Verificar atualizações..."
msgid "About Joplin"
msgstr "Sobre o Joplin"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, javascript-format
msgid "Open %s"
msgstr "Abrir %s"
@@ -832,12 +838,12 @@ msgstr ""
msgid "Notes and settings are stored in: %s"
msgstr "Notas e configurações estão armazenadas em: %s"
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Verificar a configuração da sincronização"
msgid "Browse..."
msgstr ""
msgid "Apply"
msgstr "Aplicar"
@@ -999,9 +1005,33 @@ msgstr "Localização"
msgid "URL"
msgstr "URL"
#, fuzzy
msgid "Note History"
msgstr "Cadernos"
msgid "Previous versions of this note"
msgstr ""
msgid "Note properties"
msgstr "Propriedades da nota"
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr ""
#, fuzzy
msgid "This note has no history"
msgstr "Esta nota foi modificada:"
msgid "Restore"
msgstr ""
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
msgid "Open..."
msgstr "Abrir..."
@@ -1152,17 +1182,14 @@ msgid "Decrypting items: %d/%d"
msgstr "Decriptando itens: %d/%d"
#, javascript-format
msgid "Fetching resources: %d"
msgstr "Buscando recursos: %d"
msgid "Fetching resources: %d/%d"
msgstr "Buscando recursos: %d/%d"
msgid "Please select where the sync status should be exported to"
msgstr ""
"Favor selecionar o local para onde o status de sincronia deveria ser "
"exportado"
msgid "Table of contents"
msgstr ""
msgid "Add or remove tags"
msgstr "Adicionar ou remover tags"
@@ -1193,6 +1220,14 @@ msgstr "Apagar o caderno \"%s\"?"
msgid "Delete these %d notes?"
msgstr "Excluir estas notas?"
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
msgid "Goto Anything..."
msgstr ""
#, javascript-format
msgid "Usage: %s"
msgstr "Uso: %s"
@@ -1305,6 +1340,10 @@ msgstr "Em andamento"
msgid "Synchronisation is already in progress. State: %s"
msgstr "Sincronização já em andamento. Estado: %s"
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr ""
msgid "Encrypted"
msgstr "Encriptado"
@@ -1342,6 +1381,16 @@ msgstr "Não é possível copiar a nota para o caderno \"%s\""
msgid "Cannot move note to \"%s\" notebook"
msgstr "Não é possível mover a nota para o caderno \"%s\""
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
"Atenção: Se você modificar esse local, tenha certeza de copiar todo o seu "
"conteúdo para lá antes de sincronizar, do contrário todos os seus arquivos "
"serão removidos! Veja o FAQ para mais detalhes: %s"
msgid "Language"
msgstr "Idioma"
@@ -1391,6 +1440,43 @@ msgstr "Focar no corpo"
msgid "When creating a new note:"
msgstr "Quando criar uma nota nova:"
msgid "Enable soft breaks"
msgstr ""
#, fuzzy
msgid "Enable math expressions"
msgstr "Habilitar encriptação"
msgid "Enable ==mark== syntax"
msgstr ""
msgid "Enable footnotes"
msgstr ""
msgid "Enable table of contents extension"
msgstr ""
msgid "Enable ~sub~ syntax"
msgstr ""
msgid "Enable ^sup^ syntax"
msgstr ""
msgid "Enable deflist syntax"
msgstr ""
msgid "Enable abbreviation syntax"
msgstr ""
msgid "Enable markdown emoji"
msgstr ""
msgid "Enable ++insert++ syntax"
msgstr ""
msgid "Enable multimarkdown table extension"
msgstr ""
msgid "Show tray icon"
msgstr "Exibir tray icon"
@@ -1474,29 +1560,30 @@ msgstr ""
"O alvo para onde sincronizar. Cada alvo pode ter parâmetros adicionais que "
"são nomeados como `sync.NUM.NAME` (todos documentados abaixo)."
msgid "Attachment download behaviour"
msgstr ""
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
msgid "Always"
msgstr ""
msgid "Manual"
msgstr ""
msgid "Auto"
msgstr ""
msgid "Directory to synchronise with (absolute path)"
msgstr "Diretório para sincronizar (caminho absoluto)"
msgid ""
"The path to synchronise with when file system synchronisation is enabled. "
"See `sync.target`."
msgstr ""
"O caminho para sincronizar, quando a sincronização do sistema de arquivos "
"está habilitada. Veja `sync.target`."
msgid "Nextcloud WebDAV URL"
msgstr "Nextcloud WebDAV URL"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
"Atenção: Se você modificar esse local, tenha certeza de copiar todo o seu "
"conteúdo para lá antes de sincronizar, do contrário todos os seus arquivos "
"serão removidos! Veja o FAQ para mais detalhes: %s"
msgid "Nextcloud username"
msgstr "Usuário da Nextcloud"
@@ -1530,6 +1617,20 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr "Ignorar erros de certificados TLS"
#, fuzzy
msgid "Enable note history"
msgstr "Habilitar encriptação"
msgid "days"
msgstr ""
#, javascript-format
msgid "%d days"
msgstr ""
msgid "Keep note history for"
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Valor da opção inválida: \"%s\". Os valores possíveis são: %s."
@@ -1549,6 +1650,9 @@ msgstr ""
msgid "Note"
msgstr "Cadernos"
msgid "Plugins"
msgstr ""
#, fuzzy
msgid "Application"
msgstr "Localização"
@@ -1601,12 +1705,19 @@ msgid "Please specify the notebook where the notes should be imported to."
msgstr ""
"Por favor, especifique o caderno para onde as notas deveriam ser importadas."
msgid "Restored Notes"
msgstr ""
msgid "Items that cannot be synchronised"
msgstr "Os itens não podem ser sincronizados"
#, javascript-format
msgid "%s (%s): %s"
msgstr "%s (%s): %s"
#, fuzzy, javascript-format
msgid "%s (%s) could not be uploaded: %s"
msgstr "Este arquivo não pôde ser aberto: %s"
#, fuzzy, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr "Este arquivo não pôde ser aberto: %s"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
@@ -1887,6 +1998,16 @@ msgstr "Você não possui cadernos. Crie um clicando no botão (+)."
msgid "Welcome"
msgstr "Bem-vindo"
#~ msgid "%s (%s): %s"
#~ msgstr "%s (%s): %s"
#~ msgid ""
#~ "The path to synchronise with when file system synchronisation is enabled. "
#~ "See `sync.target`."
#~ msgstr ""
#~ "O caminho para sincronizar, quando a sincronização do sistema de arquivos "
#~ "está habilitada. Veja `sync.target`."
#, fuzzy
#~ msgid "Joplin v%s"
#~ msgstr "Site do Joplin"

View File

@@ -542,9 +542,8 @@ msgstr ""
msgid "PDF File"
msgstr "Fișier PDF"
#, fuzzy
msgid "&File"
msgstr "Fișier"
msgid "Synchronisation status"
msgstr "Statusul sincronizării"
msgid "New note"
msgstr "Adăugați o nouă notiță"
@@ -555,6 +554,35 @@ msgstr "Adăugați o nouă sarcină"
msgid "New notebook"
msgstr "Adăugați un nou caiet de notițe"
msgid "Print"
msgstr "Printați"
msgid "General Options"
msgstr "Opțiuni Generale"
msgid "Encryption options"
msgstr "Opțiuni de criptare"
msgid "Web clipper options"
msgstr ""
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, fuzzy
msgid "&File"
msgstr "Fișier"
msgid "About Joplin"
msgstr "Despre Joplin"
msgid "Preferences..."
msgstr ""
msgid "Check for updates..."
msgstr "Verificați actualizările..."
msgid "Import"
msgstr "Importați"
@@ -564,9 +592,6 @@ msgstr "Exportați"
msgid "Synchronise"
msgstr "Sincronizați"
msgid "Print"
msgstr "Printați"
#, javascript-format
msgid "Hide %s"
msgstr "Ascundeți %s"
@@ -574,6 +599,9 @@ msgstr "Ascundeți %s"
msgid "Quit"
msgstr "Ieșiți"
msgid "Close Window"
msgstr ""
#, fuzzy
msgid "&Edit"
msgstr "Editați"
@@ -630,18 +658,6 @@ msgstr ""
msgid "&Tools"
msgstr "Unelte"
msgid "Synchronisation status"
msgstr "Statusul sincronizării"
msgid "Web clipper options"
msgstr ""
msgid "Encryption options"
msgstr "Opțiuni de criptare"
msgid "General Options"
msgstr "Opțiuni Generale"
#, fuzzy
msgid "&Help"
msgstr "Ajutor"
@@ -652,16 +668,6 @@ msgstr "Website și documentație"
msgid "Make a donation"
msgstr "Faceți o donație"
msgid "Check for updates..."
msgstr "Verificați actualizările..."
msgid "About Joplin"
msgstr "Despre Joplin"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, javascript-format
msgid "Open %s"
msgstr "Deschideți %s"
@@ -764,10 +770,10 @@ msgstr ""
msgid "Notes and settings are stored in: %s"
msgstr ""
msgid "Browse..."
msgid "Check synchronisation configuration"
msgstr ""
msgid "Check synchronisation configuration"
msgid "Browse..."
msgstr ""
msgid "Apply"
@@ -915,9 +921,33 @@ msgstr ""
msgid "URL"
msgstr ""
#, fuzzy
msgid "Note History"
msgstr "Caiete de notițe"
msgid "Previous versions of this note"
msgstr ""
msgid "Note properties"
msgstr ""
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr ""
#, fuzzy
msgid "This note has no history"
msgstr "Această notiță a fost modificată:"
msgid "Restore"
msgstr ""
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
msgid "Open..."
msgstr "Deschideți..."
@@ -1064,15 +1094,12 @@ msgid "Decrypting items: %d/%d"
msgstr "Se decriptează itemi: %d/%d"
#, fuzzy, javascript-format
msgid "Fetching resources: %d"
msgstr "Resurse: %d."
msgid "Fetching resources: %d/%d"
msgstr "Resurse: %d/%d"
msgid "Please select where the sync status should be exported to"
msgstr ""
msgid "Table of contents"
msgstr ""
msgid "Add or remove tags"
msgstr "Adăugați ori eliminați etichete"
@@ -1106,6 +1133,14 @@ msgstr "Ștergeți notițele?"
msgid "Delete these %d notes?"
msgstr "Ștergeți aceste notițe?"
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
msgid "Goto Anything..."
msgstr ""
#, javascript-format
msgid "Usage: %s"
msgstr "Utilizare: %s"
@@ -1210,6 +1245,10 @@ msgstr "În progres"
msgid "Synchronisation is already in progress. State: %s"
msgstr ""
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr ""
msgid "Encrypted"
msgstr "Criptat"
@@ -1246,6 +1285,13 @@ msgstr "Nu se poate copia notița în caietul de notițe \"%s\""
msgid "Cannot move note to \"%s\" notebook"
msgstr "Nu se poate muta notița în caietul de notițe \"%s\""
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
msgid "Language"
msgstr "Limbă"
@@ -1295,6 +1341,43 @@ msgstr ""
msgid "When creating a new note:"
msgstr "Când este creată o nouă notiță:"
msgid "Enable soft breaks"
msgstr ""
#, fuzzy
msgid "Enable math expressions"
msgstr "Activați criptarea"
msgid "Enable ==mark== syntax"
msgstr ""
msgid "Enable footnotes"
msgstr ""
msgid "Enable table of contents extension"
msgstr ""
msgid "Enable ~sub~ syntax"
msgstr ""
msgid "Enable ^sup^ syntax"
msgstr ""
msgid "Enable deflist syntax"
msgstr ""
msgid "Enable abbreviation syntax"
msgstr ""
msgid "Enable markdown emoji"
msgstr ""
msgid "Enable ++insert++ syntax"
msgstr ""
msgid "Enable multimarkdown table extension"
msgstr ""
msgid "Show tray icon"
msgstr "Afișați iconița coșul de gunoi"
@@ -1369,24 +1452,30 @@ msgid ""
"which are named as `sync.NUM.NAME` (all documented below)."
msgstr ""
msgid "Directory to synchronise with (absolute path)"
msgid "Attachment download behaviour"
msgstr ""
msgid ""
"The path to synchronise with when file system synchronisation is enabled. "
"See `sync.target`."
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
msgid "Always"
msgstr ""
msgid "Manual"
msgstr ""
msgid "Auto"
msgstr ""
msgid "Directory to synchronise with (absolute path)"
msgstr ""
msgid "Nextcloud WebDAV URL"
msgstr "URL NextCloud WebDAV"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
msgid "Nextcloud username"
msgstr "Nume utilizator Nextcloud"
@@ -1415,6 +1504,20 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr "Ignoră erorile de certificat TLS"
#, fuzzy
msgid "Enable note history"
msgstr "Activați criptarea"
msgid "days"
msgstr ""
#, javascript-format
msgid "%d days"
msgstr ""
msgid "Keep note history for"
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr ""
@@ -1434,6 +1537,9 @@ msgstr ""
msgid "Note"
msgstr "Caiete de notițe"
msgid "Plugins"
msgstr ""
#, fuzzy
msgid "Application"
msgstr "Duplicați"
@@ -1483,12 +1589,19 @@ msgstr "Nu există date de exportat."
msgid "Please specify the notebook where the notes should be imported to."
msgstr ""
msgid "Restored Notes"
msgstr ""
msgid "Items that cannot be synchronised"
msgstr "Itemii nu pot fi sincronizați"
#, javascript-format
msgid "%s (%s): %s"
msgstr "%s (%s): %s"
#, fuzzy, javascript-format
msgid "%s (%s) could not be uploaded: %s"
msgstr "Acest fișier nu a putut fi deschis: %s"
#, fuzzy, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr "Acest fișier nu a putut fi deschis: %s"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
@@ -1754,6 +1867,9 @@ msgstr ""
msgid "Welcome"
msgstr "Bine ați venit"
#~ msgid "%s (%s): %s"
#~ msgstr "%s (%s): %s"
#, fuzzy
#~ msgid "Joplin v%s"
#~ msgstr "Website Joplin"

View File

@@ -133,7 +133,7 @@ msgid ""
"`status`, `decrypt-file` and `target-status`."
msgstr ""
"Управляет конфигурацией E2EE. Команды: `enable`, `disable`, `decrypt`, "
"`status` и `target-status`."
"`status`,'decrypt-file' и `target-status`."
msgid "Enter master password:"
msgstr "Введите мастер-пароль:"
@@ -190,7 +190,7 @@ msgid "Note has been saved."
msgstr "Заметка сохранена."
msgid "Exits the application."
msgstr "Выход из приложения."
msgstr "Выйти из приложения."
msgid ""
"Exports Joplin data to the given path. By default, it will export the "
@@ -579,10 +579,10 @@ msgid ""
"supplied the password, the encrypted items are being decrypted in the "
"background and will be available soon."
msgstr ""
"Один или несколько элементов сейчас зашифрованы и может потребоваться, чтобы "
"вы предоставили мастер-пароль. Для этого введите, пожалуйста, `e2ee "
"decrypt`. Если пароль уже был вами предоставлен, зашифрованные элементы "
"расшифруются в фоновом режиме и вскоре станут доступны."
"Один или несколько элементов зашифрованы, и для их расшифровки может "
"потребоваться пароль. Для этого введите `e2ee decrypt`. Если пароль уже был "
"вами предоставлен, зашифрованные элементы расшифруются в фоновом режиме и "
"вскоре станут доступны."
#, javascript-format
msgid "Exporting to \"%s\" as \"%s\" format. Please wait..."
@@ -607,8 +607,8 @@ msgstr "Импорт из \"%s\" в формате \"%s\". Пожалуйста,
msgid "PDF File"
msgstr "Файл PDF"
msgid "&File"
msgstr "&Файл"
msgid "Synchronisation status"
msgstr "Статус синхронизации"
msgid "New note"
msgstr "Новая заметка"
@@ -619,6 +619,34 @@ msgstr "Новая задача"
msgid "New notebook"
msgstr "Новый блокнот"
msgid "Print"
msgstr "Печать"
msgid "General Options"
msgstr "Основные настройки"
msgid "Encryption options"
msgstr "Настройки шифрования"
msgid "Web clipper options"
msgstr "Настройки веб-клиппера"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
msgid "&File"
msgstr "&Файл"
msgid "About Joplin"
msgstr "О Joplin"
msgid "Preferences..."
msgstr ""
msgid "Check for updates..."
msgstr "Проверить обновления..."
msgid "Import"
msgstr "Импорт"
@@ -628,9 +656,6 @@ msgstr "Экспорт"
msgid "Synchronise"
msgstr "Синхронизировать"
msgid "Print"
msgstr "Печать"
#, javascript-format
msgid "Hide %s"
msgstr "Скрыть %s"
@@ -638,6 +663,9 @@ msgstr "Скрыть %s"
msgid "Quit"
msgstr "Выход"
msgid "Close Window"
msgstr ""
msgid "&Edit"
msgstr "&Правка"
@@ -689,18 +717,6 @@ msgstr "Фокус"
msgid "&Tools"
msgstr "&Сервис"
msgid "Synchronisation status"
msgstr "Статус синхронизации"
msgid "Web clipper options"
msgstr "Настройки веб-клиппера"
msgid "Encryption options"
msgstr "Настройки шифрования"
msgid "General Options"
msgstr "Основные настройки"
msgid "&Help"
msgstr "&Помощь"
@@ -710,16 +726,6 @@ msgstr "Сайт и документация"
msgid "Make a donation"
msgstr "Сделать пожертвование"
msgid "Check for updates..."
msgstr "Проверить обновления..."
msgid "About Joplin"
msgstr "О Joplin"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, javascript-format
msgid "Open %s"
msgstr "Открыть %s"
@@ -828,12 +834,12 @@ msgstr ""
msgid "Notes and settings are stored in: %s"
msgstr "Заметки и настройки сохранены в: %s"
msgid "Browse..."
msgstr "Обзор..."
msgid "Check synchronisation configuration"
msgstr "Проверить настройки синхронизации"
msgid "Browse..."
msgstr "Обзор..."
msgid "Apply"
msgstr "Применить"
@@ -996,9 +1002,33 @@ msgstr "Местоположение"
msgid "URL"
msgstr "URL"
#, fuzzy
msgid "Note History"
msgstr "Список заметок"
msgid "Previous versions of this note"
msgstr ""
msgid "Note properties"
msgstr "Свойства заметки"
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr ""
#, fuzzy
msgid "This note has no history"
msgstr "Эта заметка была изменена:"
msgid "Restore"
msgstr ""
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
msgid "Open..."
msgstr "Открыть..."
@@ -1150,16 +1180,13 @@ msgid "Decrypting items: %d/%d"
msgstr "Расшифровано элементов: %d/%d"
#, javascript-format
msgid "Fetching resources: %d"
msgstr "Получение ресурсов: %d"
msgid "Fetching resources: %d/%d"
msgstr "Получение ресурсов: %d/%d"
msgid "Please select where the sync status should be exported to"
msgstr ""
"Пожалуйста, выберите, куда должен быть экспортирован статус синхронизации"
msgid "Table of contents"
msgstr ""
msgid "Add or remove tags"
msgstr "Добавить или удалить метки"
@@ -1190,6 +1217,14 @@ msgstr "Удалить заметку \"%s\"?"
msgid "Delete these %d notes?"
msgstr "Удалить эти %d заметки?"
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
msgid "Goto Anything..."
msgstr ""
#, javascript-format
msgid "Usage: %s"
msgstr "Использовано: %s"
@@ -1302,6 +1337,10 @@ msgstr "Выполнение"
msgid "Synchronisation is already in progress. State: %s"
msgstr "Синхронизация уже выполняется. Состояние: %s"
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr ""
msgid "Encrypted"
msgstr "Зашифровано"
@@ -1339,6 +1378,16 @@ msgstr "Не удалось скопировать заметку в блокн
msgid "Cannot move note to \"%s\" notebook"
msgstr "Не удалось переместить заметку в блокнот \"%s\""
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
"Внимание: если вы измените это местоположение, обязательно скопируйте все "
"содержимое перед синхронизацией, в противном случае все файлы будут удалены! "
"Смотрите FAQ для получения подробной информации: %s"
msgid "Language"
msgstr "Язык"
@@ -1387,6 +1436,43 @@ msgstr "Фокус на содержимом"
msgid "When creating a new note:"
msgstr "При создании новой заметки:"
msgid "Enable soft breaks"
msgstr ""
#, fuzzy
msgid "Enable math expressions"
msgstr "Включить шифрование"
msgid "Enable ==mark== syntax"
msgstr ""
msgid "Enable footnotes"
msgstr ""
msgid "Enable table of contents extension"
msgstr ""
msgid "Enable ~sub~ syntax"
msgstr ""
msgid "Enable ^sup^ syntax"
msgstr ""
msgid "Enable deflist syntax"
msgstr ""
msgid "Enable abbreviation syntax"
msgstr ""
msgid "Enable markdown emoji"
msgstr ""
msgid "Enable ++insert++ syntax"
msgstr ""
msgid "Enable multimarkdown table extension"
msgstr ""
msgid "Show tray icon"
msgstr "Показывать иконку в трее"
@@ -1472,29 +1558,30 @@ msgstr ""
"Цель синхронизации. Каждая цель синхронизации может иметь дополнительные "
"параметры, именованные как `sync.NUM.NAME` (все документировано ниже)."
msgid "Attachment download behaviour"
msgstr ""
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
msgid "Always"
msgstr ""
msgid "Manual"
msgstr ""
msgid "Auto"
msgstr ""
msgid "Directory to synchronise with (absolute path)"
msgstr "Каталог синхронизации (абсолютный путь)"
msgid ""
"The path to synchronise with when file system synchronisation is enabled. "
"See `sync.target`."
msgstr ""
"Путь для синхронизации, когда включена синхронизация файловой системы. См. "
"`sync.target`."
msgid "Nextcloud WebDAV URL"
msgstr "Nextcloud WebDAV URL"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
"Внимание: если вы измените это местоположение, обязательно скопируйте все "
"содержимое перед синхронизацией, в противном случае все файлы будут удалены! "
"Смотрите FAQ для получения подробной информации: %s"
msgid "Nextcloud username"
msgstr "Имя пользователя Nextcloud"
@@ -1528,6 +1615,20 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr "Игнорировать ошибки сертификата TLS"
#, fuzzy
msgid "Enable note history"
msgstr "Включить шифрование"
msgid "days"
msgstr ""
#, javascript-format
msgid "%d days"
msgstr ""
msgid "Keep note history for"
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Неверное значение параметра: \"%s\". Доступные значения: %s."
@@ -1544,6 +1645,9 @@ msgstr "Внешний вид"
msgid "Note"
msgstr "Заметки"
msgid "Plugins"
msgstr ""
msgid "Application"
msgstr "Приложение"
@@ -1595,12 +1699,19 @@ msgid "Please specify the notebook where the notes should be imported to."
msgstr ""
"Пожалуйста, укажите блокнот, в который должны быть импортированы заметки."
msgid "Restored Notes"
msgstr ""
msgid "Items that cannot be synchronised"
msgstr "Элементы, которые не могут быть синхронизированы"
#, javascript-format
msgid "%s (%s): %s"
msgstr "%s (%s): %s"
#, fuzzy, javascript-format
msgid "%s (%s) could not be uploaded: %s"
msgstr "Этот файл не может быть открыт: %s"
#, fuzzy, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr "Этот файл не может быть открыт: %s"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
@@ -1880,5 +1991,15 @@ msgstr "У вас сейчас нет блокнота. Создайте его
msgid "Welcome"
msgstr "Добро пожаловать"
#~ msgid "%s (%s): %s"
#~ msgstr "%s (%s): %s"
#~ msgid ""
#~ "The path to synchronise with when file system synchronisation is enabled. "
#~ "See `sync.target`."
#~ msgstr ""
#~ "Путь для синхронизации, когда включена синхронизация файловой системы. "
#~ "См. `sync.target`."
#~ msgid "Joplin v%s"
#~ msgstr "Joplin v%s"

View File

@@ -604,9 +604,8 @@ msgstr "Uvažam v \"%s\" kot \"%s\" format. Prosim počakajte..."
msgid "PDF File"
msgstr "PDF datoteka"
#, fuzzy
msgid "&File"
msgstr "Datoteka"
msgid "Synchronisation status"
msgstr "Status sinhronizacije"
msgid "New note"
msgstr "Nova zabeležka"
@@ -617,6 +616,35 @@ msgstr "Novi seznam opravil"
msgid "New notebook"
msgstr "Nova beležnica"
msgid "Print"
msgstr "Natisni"
msgid "General Options"
msgstr "Splošne možnosti"
msgid "Encryption options"
msgstr "Možnosti enkripcije"
msgid "Web clipper options"
msgstr ""
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, fuzzy
msgid "&File"
msgstr "Datoteka"
msgid "About Joplin"
msgstr "O Joplinu"
msgid "Preferences..."
msgstr ""
msgid "Check for updates..."
msgstr "Preverjanje za posodobitvami..."
msgid "Import"
msgstr "Uvozi"
@@ -626,9 +654,6 @@ msgstr "Izvozi"
msgid "Synchronise"
msgstr "Sinhroniziraj"
msgid "Print"
msgstr "Natisni"
#, javascript-format
msgid "Hide %s"
msgstr "Skrij %s"
@@ -636,6 +661,9 @@ msgstr "Skrij %s"
msgid "Quit"
msgstr "Izhod"
msgid "Close Window"
msgstr ""
#, fuzzy
msgid "&Edit"
msgstr "Uredi"
@@ -693,18 +721,6 @@ msgstr "Fokusiraj vsebino"
msgid "&Tools"
msgstr "Orodja"
msgid "Synchronisation status"
msgstr "Status sinhronizacije"
msgid "Web clipper options"
msgstr ""
msgid "Encryption options"
msgstr "Možnosti enkripcije"
msgid "General Options"
msgstr "Splošne možnosti"
#, fuzzy
msgid "&Help"
msgstr "Pomoč"
@@ -715,16 +731,6 @@ msgstr "Spletna stran in dokumentacija"
msgid "Make a donation"
msgstr "Doniraj"
msgid "Check for updates..."
msgstr "Preverjanje za posodobitvami..."
msgid "About Joplin"
msgstr "O Joplinu"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, javascript-format
msgid "Open %s"
msgstr "Odpri %s"
@@ -827,12 +833,12 @@ msgstr ""
msgid "Notes and settings are stored in: %s"
msgstr "Zabeležke in nastavitve so shranjene v: %s"
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "Preveri nastavitve sinhronizacije"
msgid "Browse..."
msgstr ""
msgid "Apply"
msgstr ""
@@ -1000,9 +1006,33 @@ msgstr ""
msgid "URL"
msgstr ""
#, fuzzy
msgid "Note History"
msgstr "Beležnice"
msgid "Previous versions of this note"
msgstr ""
msgid "Note properties"
msgstr ""
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr ""
#, fuzzy
msgid "This note has no history"
msgstr "Ta zabeležka je bila spremenjena:"
msgid "Restore"
msgstr ""
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
msgid "Open..."
msgstr "Odpri..."
@@ -1152,18 +1182,15 @@ msgstr "Beležnice"
#, fuzzy, javascript-format
msgid "Decrypting items: %d/%d"
msgstr "Preneseni predmeti: %d/%d."
msgstr "Preneseni predmeti: %d/%d"
#, fuzzy, javascript-format
msgid "Fetching resources: %d"
msgstr "Viri: %d."
msgid "Fetching resources: %d/%d"
msgstr "Viri: %d/%d"
msgid "Please select where the sync status should be exported to"
msgstr "Prosim izberite, kam želite izvoziti sinhronizacijski status"
msgid "Table of contents"
msgstr ""
msgid "Add or remove tags"
msgstr "Dodaj ali odstrani oznake"
@@ -1198,6 +1225,14 @@ msgstr "Izbriši zabeležke?"
msgid "Delete these %d notes?"
msgstr "Izbriši te zabeležke?"
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
msgid "Goto Anything..."
msgstr ""
#, javascript-format
msgid "Usage: %s"
msgstr "Uporaba: %s"
@@ -1310,6 +1345,10 @@ msgstr "V postopku"
msgid "Synchronisation is already in progress. State: %s"
msgstr "Sinhronizacija je že v postopku. Stanje: %s"
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr ""
msgid "Encrypted"
msgstr "Enkriptirano"
@@ -1350,6 +1389,13 @@ msgstr "Ni moč kopirati zabeležke v \"%s\" beležnico"
msgid "Cannot move note to \"%s\" notebook"
msgstr "Ni moč premakniti zabeležke v \"%s\" beležnico"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
msgid "Language"
msgstr "Jezik"
@@ -1400,6 +1446,43 @@ msgstr "Fokusiraj vsebino"
msgid "When creating a new note:"
msgstr "Ob ustvarjanju nove zabeležke:"
msgid "Enable soft breaks"
msgstr ""
#, fuzzy
msgid "Enable math expressions"
msgstr "Omogoči enkripcijo"
msgid "Enable ==mark== syntax"
msgstr ""
msgid "Enable footnotes"
msgstr ""
msgid "Enable table of contents extension"
msgstr ""
msgid "Enable ~sub~ syntax"
msgstr ""
msgid "Enable ^sup^ syntax"
msgstr ""
msgid "Enable deflist syntax"
msgstr ""
msgid "Enable abbreviation syntax"
msgstr ""
msgid "Enable markdown emoji"
msgstr ""
msgid "Enable ++insert++ syntax"
msgstr ""
msgid "Enable multimarkdown table extension"
msgstr ""
msgid "Show tray icon"
msgstr "Pokaži ikono v območju za obvestila(opravilna vrstica)"
@@ -1483,26 +1566,30 @@ msgstr ""
"Ciljno sinhronizacijsko mesto. Vsak sinhronizacijski cilj ima lahko dodatne "
"parametre imenovano kot `sync.NUM.NAME` (vse je dokumentirano spodaj)."
msgid "Attachment download behaviour"
msgstr ""
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
msgid "Always"
msgstr ""
msgid "Manual"
msgstr ""
msgid "Auto"
msgstr ""
msgid "Directory to synchronise with (absolute path)"
msgstr "Mesto ciljne sinhronizacije (absolutna pot)"
msgid ""
"The path to synchronise with when file system synchronisation is enabled. "
"See `sync.target`."
msgstr ""
"Pot za sinhronizacijo, ki bo uporabljena ob omogočeni sinhronizaciji. Poglej "
"`sync.target`."
msgid "Nextcloud WebDAV URL"
msgstr "Nextcloud WebDAV URL"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
msgid "Nextcloud username"
msgstr "Nextcloud uporabniško ime"
@@ -1531,6 +1618,20 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr ""
#, fuzzy
msgid "Enable note history"
msgstr "Omogoči enkripcijo"
msgid "days"
msgstr ""
#, javascript-format
msgid "%d days"
msgstr ""
msgid "Keep note history for"
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Neveljavna vrednost: \"%s\". Možne vrednosti so : %s."
@@ -1550,6 +1651,9 @@ msgstr ""
msgid "Note"
msgstr "Beležnice"
msgid "Plugins"
msgstr ""
#, fuzzy
msgid "Application"
msgstr "Izhod iz aplikacije."
@@ -1602,12 +1706,19 @@ msgstr "Ni datotek za izvoz."
msgid "Please specify the notebook where the notes should be imported to."
msgstr "Prosim navedite beležnico, kamor želite uvoziti zabeležke."
msgid "Restored Notes"
msgstr ""
msgid "Items that cannot be synchronised"
msgstr "Predmeti ne morejo biti sinhronizirani"
#, javascript-format
msgid "%s (%s): %s"
msgstr "%s (%s): %s"
#, fuzzy, javascript-format
msgid "%s (%s) could not be uploaded: %s"
msgstr "Beležnica ne more biti shranjena: %s"
#, fuzzy, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr "Beležnica ne more biti shranjena: %s"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
@@ -1879,6 +1990,16 @@ msgstr "Trenutno nimate nobene beležnice. Ustvarite jo s klikom na (+) gumb."
msgid "Welcome"
msgstr "Dobrodošli"
#~ msgid "%s (%s): %s"
#~ msgstr "%s (%s): %s"
#~ msgid ""
#~ "The path to synchronise with when file system synchronisation is enabled. "
#~ "See `sync.target`."
#~ msgstr ""
#~ "Pot za sinhronizacijo, ki bo uporabljena ob omogočeni sinhronizaciji. "
#~ "Poglej `sync.target`."
#, fuzzy
#~ msgid "Joplin v%s"
#~ msgstr "Joplin spletna stran"

View File

@@ -608,9 +608,8 @@ msgstr "Importerar från \"%s\" som \"%s\" format. Vänta..."
msgid "PDF File"
msgstr "PDF-fil"
#, fuzzy
msgid "&File"
msgstr "Fil"
msgid "Synchronisation status"
msgstr "Synkroniseringstillstånd"
msgid "New note"
msgstr "Ny anteckning"
@@ -621,6 +620,35 @@ msgstr "Ny att-göra"
msgid "New notebook"
msgstr "Ny anteckningsbok"
msgid "Print"
msgstr "Skriv ut"
msgid "General Options"
msgstr "Allmänna inställningar"
msgid "Encryption options"
msgstr "Krypteringsinställningar"
msgid "Web clipper options"
msgstr "Web clipper-inställningar"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, fuzzy
msgid "&File"
msgstr "Fil"
msgid "About Joplin"
msgstr "Om Joplin"
msgid "Preferences..."
msgstr ""
msgid "Check for updates..."
msgstr "Sök efter uppdateringar..."
msgid "Import"
msgstr "Importera"
@@ -630,9 +658,6 @@ msgstr "Exportera"
msgid "Synchronise"
msgstr "Synkronisera"
msgid "Print"
msgstr "Skriv ut"
#, javascript-format
msgid "Hide %s"
msgstr "Dölj %s"
@@ -640,6 +665,9 @@ msgstr "Dölj %s"
msgid "Quit"
msgstr "Avsluta"
msgid "Close Window"
msgstr ""
#, fuzzy
msgid "&Edit"
msgstr "Redigera"
@@ -694,18 +722,6 @@ msgstr "Fokus"
msgid "&Tools"
msgstr "Verktyg"
msgid "Synchronisation status"
msgstr "Synkroniseringstillstånd"
msgid "Web clipper options"
msgstr "Web clipper-inställningar"
msgid "Encryption options"
msgstr "Krypteringsinställningar"
msgid "General Options"
msgstr "Allmänna inställningar"
#, fuzzy
msgid "&Help"
msgstr "Hjälp"
@@ -716,16 +732,6 @@ msgstr "Webbplats och dokumentation"
msgid "Make a donation"
msgstr "Gör en donation"
msgid "Check for updates..."
msgstr "Sök efter uppdateringar..."
msgid "About Joplin"
msgstr "Om Joplin"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, javascript-format
msgid "Open %s"
msgstr "Öppna %s"
@@ -834,12 +840,12 @@ msgstr ""
msgid "Notes and settings are stored in: %s"
msgstr "Anteckningar och inställningar lagras i: %s"
msgid "Browse..."
msgstr "Bläddra..."
msgid "Check synchronisation configuration"
msgstr "Kontrollera synkroniseringskonfigurationen"
msgid "Browse..."
msgstr "Bläddra..."
msgid "Apply"
msgstr "Tillämpa"
@@ -1004,9 +1010,33 @@ msgstr "Plats"
msgid "URL"
msgstr "URL"
#, fuzzy
msgid "Note History"
msgstr "Anteckningsboken"
msgid "Previous versions of this note"
msgstr ""
msgid "Note properties"
msgstr "Anteckningens egenskaper"
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr ""
#, fuzzy
msgid "This note has no history"
msgstr "Denna anteckning har ändrats:"
msgid "Restore"
msgstr ""
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
msgid "Open..."
msgstr "Öppna..."
@@ -1158,15 +1188,12 @@ msgid "Decrypting items: %d/%d"
msgstr "Dekrypterar objekt: %d/%d"
#, javascript-format
msgid "Fetching resources: %d"
msgstr "Hämtar resurser: %d"
msgid "Fetching resources: %d/%d"
msgstr "Hämtar resurser: %d/%d"
msgid "Please select where the sync status should be exported to"
msgstr "Välj vart synkroniseringstillståndet ska exporteras till"
msgid "Table of contents"
msgstr ""
msgid "Add or remove tags"
msgstr "Lägg till eller ta bort taggar"
@@ -1199,6 +1226,14 @@ msgstr "Ta bort anteckningar?"
msgid "Delete these %d notes?"
msgstr "Ta bort dessa anteckningar?"
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
msgid "Goto Anything..."
msgstr ""
#, javascript-format
msgid "Usage: %s"
msgstr "Användning: %s"
@@ -1311,6 +1346,10 @@ msgstr "Pågår"
msgid "Synchronisation is already in progress. State: %s"
msgstr "Synkronisering pågår redan. Tillstånd: %s"
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr ""
msgid "Encrypted"
msgstr "Krypterad"
@@ -1348,6 +1387,16 @@ msgstr "Kan inte kopiera anteckning till \"%s\" anteckningsbok"
msgid "Cannot move note to \"%s\" notebook"
msgstr "Kan inte flytta anteckning till \"%s\" anteckningsbok"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
"OBS! Om du ändrar denna plats så se till att du har en kopia på allt "
"innehåll innan du synkroniserar. Annars kommer samtliga filer att raderas. "
"Läs FAQ för mer information: %s"
msgid "Language"
msgstr "Språk"
@@ -1397,6 +1446,43 @@ msgstr "Fokus på huvuddel"
msgid "When creating a new note:"
msgstr "När du skapar en ny anteckning:"
msgid "Enable soft breaks"
msgstr ""
#, fuzzy
msgid "Enable math expressions"
msgstr "Aktivera kryptering"
msgid "Enable ==mark== syntax"
msgstr ""
msgid "Enable footnotes"
msgstr ""
msgid "Enable table of contents extension"
msgstr ""
msgid "Enable ~sub~ syntax"
msgstr ""
msgid "Enable ^sup^ syntax"
msgstr ""
msgid "Enable deflist syntax"
msgstr ""
msgid "Enable abbreviation syntax"
msgstr ""
msgid "Enable markdown emoji"
msgstr ""
msgid "Enable ++insert++ syntax"
msgstr ""
msgid "Enable multimarkdown table extension"
msgstr ""
msgid "Show tray icon"
msgstr "Visa fältikon"
@@ -1481,29 +1567,30 @@ msgstr ""
"Målet att synkronisera till. Varje synkroniseringsmål kan ha ytterligare "
"parametrar som heter `sync.NUM.NAME` (alla dokumenterade nedan)."
msgid "Attachment download behaviour"
msgstr ""
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
msgid "Always"
msgstr ""
msgid "Manual"
msgstr ""
msgid "Auto"
msgstr ""
msgid "Directory to synchronise with (absolute path)"
msgstr "Katalog för att synkronisera med (absolut sökväg)"
msgid ""
"The path to synchronise with when file system synchronisation is enabled. "
"See `sync.target`."
msgstr ""
"Sökvägen att synkronisera med när synkronisering av filsystem är aktiverat. "
"Se `sync.target`."
msgid "Nextcloud WebDAV URL"
msgstr "Nextcloud-WebDAV-webbadress"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
"OBS! Om du ändrar denna plats så se till att du har en kopia på allt "
"innehåll innan du synkroniserar. Annars kommer samtliga filer att raderas. "
"Läs FAQ för mer information: %s"
msgid "Nextcloud username"
msgstr "Nextcloud-användarnamn"
@@ -1537,6 +1624,20 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr "Ignorera TLS-certifikatfel"
#, fuzzy
msgid "Enable note history"
msgstr "Aktivera kryptering"
msgid "days"
msgstr ""
#, javascript-format
msgid "%d days"
msgstr ""
msgid "Keep note history for"
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Ogiltigt inställningsvärde: \"%s\". Möjliga värden är: %s."
@@ -1554,6 +1655,9 @@ msgstr "Utseende"
msgid "Note"
msgstr "Anteckning"
msgid "Plugins"
msgstr ""
msgid "Application"
msgstr "Avslutar programmet"
@@ -1604,12 +1708,19 @@ msgstr "Det finns ingen data att exportera."
msgid "Please specify the notebook where the notes should be imported to."
msgstr "Ange anteckningsboken som anteckningarna ska importeras till."
msgid "Restored Notes"
msgstr ""
msgid "Items that cannot be synchronised"
msgstr "Objekt som inte kan synkroniseras"
#, javascript-format
msgid "%s (%s): %s"
msgstr "%s (%s): %s"
#, fuzzy, javascript-format
msgid "%s (%s) could not be uploaded: %s"
msgstr "Den här filen kunde inte öppnas: %s"
#, fuzzy, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr "Den här filen kunde inte öppnas: %s"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
@@ -1895,6 +2006,16 @@ msgstr ""
msgid "Welcome"
msgstr "Välkommen"
#~ msgid "%s (%s): %s"
#~ msgstr "%s (%s): %s"
#~ msgid ""
#~ "The path to synchronise with when file system synchronisation is enabled. "
#~ "See `sync.target`."
#~ msgstr ""
#~ "Sökvägen att synkronisera med när synkronisering av filsystem är "
#~ "aktiverat. Se `sync.target`."
#~ msgid "Joplin v%s"
#~ msgstr "Joplin v%s"

View File

@@ -575,9 +575,8 @@ msgstr "\"%s\" den \"%s\" biçiminde içe aktarılıyor. Lütfen bekleyin..."
msgid "PDF File"
msgstr "PDF Dosyası"
#, fuzzy
msgid "&File"
msgstr "Dosya"
msgid "Synchronisation status"
msgstr "Senkronizasyon durumu"
msgid "New note"
msgstr "Yeni not"
@@ -588,6 +587,35 @@ msgstr "Yeni yapılacak"
msgid "New notebook"
msgstr "Yeni not defteri"
msgid "Print"
msgstr "Yazdır"
msgid "General Options"
msgstr "Genel seçenekler"
msgid "Encryption options"
msgstr "Şifreleme seçenekleri"
msgid "Web clipper options"
msgstr "Web alıntılama ayarları"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, fuzzy
msgid "&File"
msgstr "Dosya"
msgid "About Joplin"
msgstr "Joplin hakkında"
msgid "Preferences..."
msgstr ""
msgid "Check for updates..."
msgstr "Güncellemeleri kontrol et..."
msgid "Import"
msgstr "İçe aktar"
@@ -597,9 +625,6 @@ msgstr "Dışa aktar"
msgid "Synchronise"
msgstr "Senkronize"
msgid "Print"
msgstr "Yazdır"
#, javascript-format
msgid "Hide %s"
msgstr "Gizle %s"
@@ -607,6 +632,9 @@ msgstr "Gizle %s"
msgid "Quit"
msgstr "Çıkış"
msgid "Close Window"
msgstr ""
#, fuzzy
msgid "&Edit"
msgstr "Düzenle"
@@ -661,18 +689,6 @@ msgstr "Odaklan"
msgid "&Tools"
msgstr "Araçlar"
msgid "Synchronisation status"
msgstr "Senkronizasyon durumu"
msgid "Web clipper options"
msgstr "Web alıntılama ayarları"
msgid "Encryption options"
msgstr "Şifreleme seçenekleri"
msgid "General Options"
msgstr "Genel seçenekler"
#, fuzzy
msgid "&Help"
msgstr "Yardım"
@@ -683,16 +699,6 @@ msgstr "Web sitesi ve dökümanlar"
msgid "Make a donation"
msgstr "Bağış yapın"
msgid "Check for updates..."
msgstr "Güncellemeleri kontrol et..."
msgid "About Joplin"
msgstr "Joplin hakkında"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, javascript-format
msgid "Open %s"
msgstr "Aç %s"
@@ -802,12 +808,12 @@ msgstr ""
msgid "Notes and settings are stored in: %s"
msgstr "Notlar ve ayarlar şu konumda saklanır: %s"
msgid "Browse..."
msgstr "Bul..."
msgid "Check synchronisation configuration"
msgstr "Senkronizasyon yapılandırmasını kontrol et"
msgid "Browse..."
msgstr "Bul..."
msgid "Apply"
msgstr "Uygula"
@@ -973,9 +979,33 @@ msgstr "Konum"
msgid "URL"
msgstr "URL"
#, fuzzy
msgid "Note History"
msgstr "Not listesi"
msgid "Previous versions of this note"
msgstr ""
msgid "Note properties"
msgstr "Not özellikleri"
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr ""
#, fuzzy
msgid "This note has no history"
msgstr "Bu not değiştirildi:"
msgid "Restore"
msgstr ""
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
msgid "Open..."
msgstr "Aç..."
@@ -1127,15 +1157,12 @@ msgid "Decrypting items: %d/%d"
msgstr "Şifresi çözülenler: %d/%d"
#, javascript-format
msgid "Fetching resources: %d"
msgstr "Kaynaklar alınıyor: %d"
msgid "Fetching resources: %d/%d"
msgstr "Kaynaklar alınıyor: %d/%d"
msgid "Please select where the sync status should be exported to"
msgstr "Lütfen senkronizasyon durumunun nereye aktarılacağını seçin"
msgid "Table of contents"
msgstr ""
#, fuzzy
msgid "Add or remove tags"
msgstr "Etiket ekle veya kaldır"
@@ -1168,6 +1195,14 @@ msgstr "\"%s\" Notunu sil?"
msgid "Delete these %d notes?"
msgstr "Bu notlar ( %d ) silinsin mi?"
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
msgid "Goto Anything..."
msgstr ""
#, javascript-format
msgid "Usage: %s"
msgstr "Kullanım: %s"
@@ -1280,6 +1315,10 @@ msgstr "Devam etmekte"
msgid "Synchronisation is already in progress. State: %s"
msgstr "Senkronizasyon zaten devam ediyor. Durum: %s"
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr ""
msgid "Encrypted"
msgstr "Şifrelenmiş"
@@ -1316,6 +1355,16 @@ msgstr "Not \"%s\" not defterine kopyalanamıyor."
msgid "Cannot move note to \"%s\" notebook"
msgstr "Not \"%s\" not defterine taşınamıyor."
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
"Dikkat: Bu konumu değiştirirseniz, senkronize etmeden önce tüm içeriğinizi "
"kopyaladığınızdan emin olun, aksi takdirde tüm dosyalar kaldırılır! Daha "
"fazla bilgi için SSS bölümüne bakın: %s"
msgid "Language"
msgstr "Dil"
@@ -1365,6 +1414,43 @@ msgstr "Gövde kısmına odaklan"
msgid "When creating a new note:"
msgstr "Yeni bir not oluştururken:"
msgid "Enable soft breaks"
msgstr ""
#, fuzzy
msgid "Enable math expressions"
msgstr "Şifrelemeyi etkinleştir"
msgid "Enable ==mark== syntax"
msgstr ""
msgid "Enable footnotes"
msgstr ""
msgid "Enable table of contents extension"
msgstr ""
msgid "Enable ~sub~ syntax"
msgstr ""
msgid "Enable ^sup^ syntax"
msgstr ""
msgid "Enable deflist syntax"
msgstr ""
msgid "Enable abbreviation syntax"
msgstr ""
msgid "Enable markdown emoji"
msgstr ""
msgid "Enable ++insert++ syntax"
msgstr ""
msgid "Enable multimarkdown table extension"
msgstr ""
msgid "Show tray icon"
msgstr "Tepsi simgesini göster"
@@ -1448,29 +1534,30 @@ msgstr ""
"Senkronize edilecek hedef. Her senkronizasyon hedefi, `sync.NUM.NAME` olarak "
"adlandırılan ek parametrelere sahip olabilir (tümü aşağıda belgelenmiştir)."
msgid "Attachment download behaviour"
msgstr ""
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
msgid "Always"
msgstr ""
msgid "Manual"
msgstr ""
msgid "Auto"
msgstr ""
msgid "Directory to synchronise with (absolute path)"
msgstr "Eşitlenecek dizin (kesin yol)"
msgid ""
"The path to synchronise with when file system synchronisation is enabled. "
"See `sync.target`."
msgstr ""
"Dosya sistemi senkronizasyonu etkinleştirildiğinde senkronize edilecek yol. "
"Bakınız `sync.target`."
msgid "Nextcloud WebDAV URL"
msgstr "Nextcloud WebDAV URL"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
"Dikkat: Bu konumu değiştirirseniz, senkronize etmeden önce tüm içeriğinizi "
"kopyaladığınızdan emin olun, aksi takdirde tüm dosyalar kaldırılır! Daha "
"fazla bilgi için SSS bölümüne bakın: %s"
msgid "Nextcloud username"
msgstr "Nextcloud kullanıcı adı"
@@ -1504,6 +1591,20 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr "TLS sertifikası hatalarını yoksay"
#, fuzzy
msgid "Enable note history"
msgstr "Şifrelemeyi etkinleştir"
msgid "days"
msgstr ""
#, javascript-format
msgid "%d days"
msgstr ""
msgid "Keep note history for"
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "Geçersiz seçenek değeri: \"%s\". Mümkün değerler: %s."
@@ -1520,6 +1621,9 @@ msgstr "Görünüm"
msgid "Note"
msgstr "Not"
msgid "Plugins"
msgstr ""
msgid "Application"
msgstr "Uygulama"
@@ -1570,12 +1674,19 @@ msgstr "Çıkartılacak veri bulunmuyor."
msgid "Please specify the notebook where the notes should be imported to."
msgstr "Lütfen notların alınacağı not defterini belirtin."
msgid "Restored Notes"
msgstr ""
msgid "Items that cannot be synchronised"
msgstr "Senkronize edilemeyen öğeler"
#, javascript-format
msgid "%s (%s): %s"
msgstr "%s (%s): %s"
#, fuzzy, javascript-format
msgid "%s (%s) could not be uploaded: %s"
msgstr "Bu dosya açılamadı: %s"
#, fuzzy, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr "Bu dosya açılamadı: %s"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
@@ -1854,5 +1965,15 @@ msgstr ""
msgid "Welcome"
msgstr "Hoşgeldiniz"
#~ msgid "%s (%s): %s"
#~ msgstr "%s (%s): %s"
#~ msgid ""
#~ "The path to synchronise with when file system synchronisation is enabled. "
#~ "See `sync.target`."
#~ msgstr ""
#~ "Dosya sistemi senkronizasyonu etkinleştirildiğinde senkronize edilecek "
#~ "yol. Bakınız `sync.target`."
#~ msgid "Joplin v%s"
#~ msgstr "Joplin v%s"

View File

@@ -47,7 +47,7 @@ msgid "y"
msgstr "是"
msgid "Cancelling background synchronisation... Please wait."
msgstr "正在取消后台同步... 请稍候。"
msgstr "正在取消后台同步……请稍候。"
#, javascript-format
msgid "No such command: %s"
@@ -566,8 +566,8 @@ msgstr "从 \"%s\" 导入,导入格式为 \"%s\" 。请稍等…"
msgid "PDF File"
msgstr "PDF 文件"
msgid "&File"
msgstr "文件 (&F)"
msgid "Synchronisation status"
msgstr "同步状态"
msgid "New note"
msgstr "新建笔记"
@@ -578,6 +578,34 @@ msgstr "新建待办事项"
msgid "New notebook"
msgstr "新建笔记本"
msgid "Print"
msgstr "打印"
msgid "General Options"
msgstr "通用选项"
msgid "Encryption options"
msgstr "加密选项"
msgid "Web clipper options"
msgstr "网页剪辑选项"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
msgid "&File"
msgstr "文件 (&F)"
msgid "About Joplin"
msgstr "关于 Joplin"
msgid "Preferences..."
msgstr "偏好……"
msgid "Check for updates..."
msgstr "检查更新..."
msgid "Import"
msgstr "导入"
@@ -587,9 +615,6 @@ msgstr "导出"
msgid "Synchronise"
msgstr "同步"
msgid "Print"
msgstr "打印"
#, javascript-format
msgid "Hide %s"
msgstr "隐藏 %s"
@@ -597,6 +622,9 @@ msgstr "隐藏 %s"
msgid "Quit"
msgstr "退出"
msgid "Close Window"
msgstr "关闭窗口"
msgid "&Edit"
msgstr "编辑 (&E)"
@@ -648,18 +676,6 @@ msgstr "聚焦于"
msgid "&Tools"
msgstr "工具 (&T)"
msgid "Synchronisation status"
msgstr "同步状态"
msgid "Web clipper options"
msgstr "网页剪辑选项"
msgid "Encryption options"
msgstr "加密选项"
msgid "General Options"
msgstr "通用选项"
msgid "&Help"
msgstr "帮助 (&H)"
@@ -669,16 +685,6 @@ msgstr "网站与文档"
msgid "Make a donation"
msgstr "捐赠"
msgid "Check for updates..."
msgstr "检查更新..."
msgid "About Joplin"
msgstr "关于 Joplin"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, javascript-format
msgid "Open %s"
msgstr "打开 %s"
@@ -782,12 +788,12 @@ msgstr "该授权令牌仅用于允许第三方应用程序访问 Joplin。"
msgid "Notes and settings are stored in: %s"
msgstr "笔记与设置文件储存在:%s"
msgid "Browse..."
msgstr "浏览..."
msgid "Check synchronisation configuration"
msgstr "检查同步配置"
msgid "Browse..."
msgstr "浏览..."
msgid "Apply"
msgstr "应用"
@@ -941,9 +947,33 @@ msgstr "位置"
msgid "URL"
msgstr "URL"
msgid "Note History"
msgstr "笔记历史"
msgid "Previous versions of this note"
msgstr "此笔记的早期版本"
msgid "Note properties"
msgstr "笔记属性"
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr "笔记\"%s\"已成功恢复到笔记本\"%s\"中。"
msgid "This note has no history"
msgstr "此笔记没有历史记录"
msgid "Restore"
msgstr "恢复"
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
"单击 \"%s\" 以恢复笔记。它将会被复制到名为 \"%s\" 的笔记本中。笔记的当前版本"
"不会被替换或修改。"
msgid "Open..."
msgstr "打开…"
@@ -1093,15 +1123,12 @@ msgid "Decrypting items: %d/%d"
msgstr "正在解密项目:%d/%d"
#, javascript-format
msgid "Fetching resources: %d"
msgstr "正在获取资源:%d"
msgid "Fetching resources: %d/%d"
msgstr "正在获取资源:%d/%d"
msgid "Please select where the sync status should be exported to"
msgstr "请选择同步状态的导出位置"
msgid "Table of contents"
msgstr "目录"
msgid "Add or remove tags"
msgstr "添加或删除标签"
@@ -1132,6 +1159,16 @@ msgstr "是否删除笔记“%s”?"
msgid "Delete these %d notes?"
msgstr "是否删除这 %d 条笔记?"
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
"输入笔记标题以便转跳到它。或者输入 # 跟着一个标签名字,或者输入 @ 跟着一个笔"
"记本名字。"
msgid "Goto Anything..."
msgstr "转到某处……"
#, javascript-format
msgid "Usage: %s"
msgstr "使用:%s"
@@ -1241,6 +1278,10 @@ msgstr "正在进行"
msgid "Synchronisation is already in progress. State: %s"
msgstr "已经在同步。状态:%s"
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr "已下载项目为未知类型,请将 Joplin 升级到最新版本"
msgid "Encrypted"
msgstr "已加密"
@@ -1277,6 +1318,15 @@ msgstr "无法复制笔记到笔记本“%s”"
msgid "Cannot move note to \"%s\" notebook"
msgstr "无法移动笔记到笔记本“%s”"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
"注意:如果您更改该位置,请确保在同步之前将所有内容复制到该位置,否则将删除所"
"有文件! 更多详细信息请参阅常见问题解答(FAQ):%s"
msgid "Language"
msgstr "语言"
@@ -1325,6 +1375,42 @@ msgstr "聚焦正文"
msgid "When creating a new note:"
msgstr "当新建笔记时:"
msgid "Enable soft breaks"
msgstr ""
msgid "Enable math expressions"
msgstr "启用数学表达式"
msgid "Enable ==mark== syntax"
msgstr "启用 ==mark== 句法"
msgid "Enable footnotes"
msgstr "启用脚注"
msgid "Enable table of contents extension"
msgstr "启用目录扩展"
msgid "Enable ~sub~ syntax"
msgstr "启用 ~sub~ 句法"
msgid "Enable ^sup^ syntax"
msgstr "启用 ^sup^ 句法"
msgid "Enable deflist syntax"
msgstr "启用术语表句法"
msgid "Enable abbreviation syntax"
msgstr "启用缩写句法"
msgid "Enable markdown emoji"
msgstr "启用 markdown emoji"
msgid "Enable ++insert++ syntax"
msgstr "启用 ++insert++ 句法"
msgid "Enable multimarkdown table extension"
msgstr "启用 multimarkdown 表格扩展"
msgid "Show tray icon"
msgstr "显示托盘图标"
@@ -1405,26 +1491,30 @@ msgid ""
msgstr ""
"所同步的目标。每个同步目标都可能有名为 `sync.NUM.NAME` 的附加参数(见下文)。"
msgid "Attachment download behaviour"
msgstr ""
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
msgid "Always"
msgstr ""
msgid "Manual"
msgstr ""
msgid "Auto"
msgstr ""
msgid "Directory to synchronise with (absolute path)"
msgstr "待同步的目录(绝对路径)。"
msgid ""
"The path to synchronise with when file system synchronisation is enabled. "
"See `sync.target`."
msgstr "启用文件系统同步时要同步的路径。见 `sync.target`。"
msgid "Nextcloud WebDAV URL"
msgstr "Nextcloud WebDAV URL"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
"注意:如果您更改该位置,请确保在同步之前将所有内容复制到该位置,否则将删除所"
"有文件! 更多详细信息请参阅常见问题解答(FAQ):%s"
msgid "Nextcloud username"
msgstr "Nextcloud 用户名"
@@ -1456,6 +1546,19 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr "忽略 TLS 证书错误"
msgid "Enable note history"
msgstr "启用笔记历史"
msgid "days"
msgstr ""
#, javascript-format
msgid "%d days"
msgstr ""
msgid "Keep note history for"
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "无效的选项值:\"%s\"。可用值有:%s。"
@@ -1472,6 +1575,9 @@ msgstr "外观"
msgid "Note"
msgstr "笔记"
msgid "Plugins"
msgstr "插件"
msgid "Application"
msgstr "应用程序"
@@ -1520,12 +1626,19 @@ msgstr "没有可导出的数据。"
msgid "Please specify the notebook where the notes should be imported to."
msgstr "请指定导入笔记的目标笔记本。"
msgid "Restored Notes"
msgstr "已恢复的笔记"
msgid "Items that cannot be synchronised"
msgstr "无法同步项目"
#, javascript-format
msgid "%s (%s): %s"
msgstr "%s (%s): %s"
msgid "%s (%s) could not be uploaded: %s"
msgstr "%s (%s) 无法上传到:%s"
#, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr "项目 \"%s\" 无法从 %s 中下载"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
@@ -1796,6 +1909,17 @@ msgstr "您目前未有笔记本。点击 (+) 按钮创建。"
msgid "Welcome"
msgstr "欢迎"
#~ msgid "%s (%s): %s"
#~ msgstr "%s (%s): %s"
#~ msgid "Table of contents"
#~ msgstr "目录"
#~ msgid ""
#~ "The path to synchronise with when file system synchronisation is enabled. "
#~ "See `sync.target`."
#~ msgstr "启用文件系统同步时要同步的路径。见 `sync.target`。"
#~ msgid "Joplin v%s"
#~ msgstr "Joplin v%s"

View File

@@ -570,9 +570,8 @@ msgstr "從 \"%s\" 匯入為 \"%s\" 格式。請稍候..."
msgid "PDF File"
msgstr "PDF 檔案"
#, fuzzy
msgid "&File"
msgstr "檔案"
msgid "Synchronisation status"
msgstr "顯示同步狀態"
msgid "New note"
msgstr "新增記事"
@@ -583,6 +582,35 @@ msgstr "新增待辦事項"
msgid "New notebook"
msgstr "新增記事本"
msgid "Print"
msgstr "列印"
msgid "General Options"
msgstr "一般選項"
msgid "Encryption options"
msgstr "加密選項"
msgid "Web clipper options"
msgstr "Web clipper 選項"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, fuzzy
msgid "&File"
msgstr "檔案"
msgid "About Joplin"
msgstr "關於 Joplin"
msgid "Preferences..."
msgstr ""
msgid "Check for updates..."
msgstr "檢查更新..."
msgid "Import"
msgstr "匯入"
@@ -592,9 +620,6 @@ msgstr "匯出"
msgid "Synchronise"
msgstr "進行同步"
msgid "Print"
msgstr "列印"
#, javascript-format
msgid "Hide %s"
msgstr "隱藏 %s"
@@ -602,6 +627,9 @@ msgstr "隱藏 %s"
msgid "Quit"
msgstr "結束"
msgid "Close Window"
msgstr ""
#, fuzzy
msgid "&Edit"
msgstr "編輯"
@@ -659,18 +687,6 @@ msgstr "游標置於內文"
msgid "&Tools"
msgstr "工具"
msgid "Synchronisation status"
msgstr "顯示同步狀態"
msgid "Web clipper options"
msgstr "Web clipper 選項"
msgid "Encryption options"
msgstr "加密選項"
msgid "General Options"
msgstr "一般選項"
#, fuzzy
msgid "&Help"
msgstr "說明"
@@ -681,16 +697,6 @@ msgstr "官方網站及線上說明"
msgid "Make a donation"
msgstr "捐助"
msgid "Check for updates..."
msgstr "檢查更新..."
msgid "About Joplin"
msgstr "關於 Joplin"
#, javascript-format
msgid "%s %s (%s, %s)"
msgstr "%s %s (%s, %s)"
#, javascript-format
msgid "Open %s"
msgstr "開啟 %s"
@@ -795,12 +801,12 @@ msgstr ""
msgid "Notes and settings are stored in: %s"
msgstr "所有記事和設置均儲存於: %s"
msgid "Browse..."
msgstr ""
msgid "Check synchronisation configuration"
msgstr "檢測同步設置"
msgid "Browse..."
msgstr ""
msgid "Apply"
msgstr "套用"
@@ -955,9 +961,33 @@ msgstr ""
msgid "URL"
msgstr ""
#, fuzzy
msgid "Note History"
msgstr "記事本"
msgid "Previous versions of this note"
msgstr ""
msgid "Note properties"
msgstr ""
#, javascript-format
msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"."
msgstr ""
#, fuzzy
msgid "This note has no history"
msgstr "此記事已被修改:"
msgid "Restore"
msgstr ""
#, javascript-format
msgid ""
"Click \"%s\" to restore the note. It will be copied in the notebook named "
"\"%s\". The current version of the note will not be replaced or modified."
msgstr ""
msgid "Open..."
msgstr "開啟..."
@@ -1104,15 +1134,12 @@ msgid "Decrypting items: %d/%d"
msgstr "正在解密項目: %d/%d 項"
#, fuzzy, javascript-format
msgid "Fetching resources: %d"
msgstr "資源: %d"
msgid "Fetching resources: %d/%d"
msgstr "資源: %d/%d"
msgid "Please select where the sync status should be exported to"
msgstr "請選擇將同步狀態導出到的位置"
msgid "Table of contents"
msgstr ""
msgid "Add or remove tags"
msgstr "新增或移除標籤"
@@ -1145,6 +1172,14 @@ msgstr "刪除此記事?"
msgid "Delete these %d notes?"
msgstr "刪除這些記事?"
msgid ""
"Type a note title to jump to it. Or type # followed by a tag name, or @ "
"followed by a notebook name."
msgstr ""
msgid "Goto Anything..."
msgstr ""
#, javascript-format
msgid "Usage: %s"
msgstr "使用資訊: %s"
@@ -1254,6 +1289,10 @@ msgstr "進行中"
msgid "Synchronisation is already in progress. State: %s"
msgstr "同步已在進行中。狀態: %s"
msgid ""
"Unknown item type downloaded - please upgrade Joplin to the latest version"
msgstr ""
msgid "Encrypted"
msgstr "已加密"
@@ -1290,6 +1329,13 @@ msgstr "無法複製此記事到 \"%s\" 記事本"
msgid "Cannot move note to \"%s\" notebook"
msgstr "無法移動此記事到 \"%s\" 記事本"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
msgid "Language"
msgstr "語言"
@@ -1339,6 +1385,43 @@ msgstr "游標置於內文"
msgid "When creating a new note:"
msgstr "當新增記事時:"
msgid "Enable soft breaks"
msgstr ""
#, fuzzy
msgid "Enable math expressions"
msgstr "啟用加密"
msgid "Enable ==mark== syntax"
msgstr ""
msgid "Enable footnotes"
msgstr ""
msgid "Enable table of contents extension"
msgstr ""
msgid "Enable ~sub~ syntax"
msgstr ""
msgid "Enable ^sup^ syntax"
msgstr ""
msgid "Enable deflist syntax"
msgstr ""
msgid "Enable abbreviation syntax"
msgstr ""
msgid "Enable markdown emoji"
msgstr ""
msgid "Enable ++insert++ syntax"
msgstr ""
msgid "Enable multimarkdown table extension"
msgstr ""
msgid "Show tray icon"
msgstr "顯示系統匣圖示"
@@ -1419,24 +1502,30 @@ msgstr ""
"要同步的目標。每個同步目標可能有附加的參數,它們被命名為 `sync.NUM.NAME` (全"
"部記錄如下)。"
msgid "Attachment download behaviour"
msgstr ""
msgid ""
"In \"Manual\" mode, attachments are downloaded only when you click on them. "
"In \"Auto\", they are downloaded when you open the note. In \"Always\", all "
"the attachments are downloaded whether you open the note or not."
msgstr ""
msgid "Always"
msgstr ""
msgid "Manual"
msgstr ""
msgid "Auto"
msgstr ""
msgid "Directory to synchronise with (absolute path)"
msgstr "要同步的目錄 (絕對路徑)"
msgid ""
"The path to synchronise with when file system synchronisation is enabled. "
"See `sync.target`."
msgstr "啟用檔案系統同步時要同步的路徑。請參閱 `sync.target`。"
msgid "Nextcloud WebDAV URL"
msgstr "Nextcloud WebDAV 網址"
#, javascript-format
msgid ""
"Attention: If you change this location, make sure you copy all your content "
"to it before syncing, otherwise all files will be removed! See the FAQ for "
"more details: %s"
msgstr ""
msgid "Nextcloud username"
msgstr "Nextcloud 用戶名稱"
@@ -1468,6 +1557,20 @@ msgstr ""
msgid "Ignore TLS certificate errors"
msgstr "忽略 TLS 證書錯誤"
#, fuzzy
msgid "Enable note history"
msgstr "啟用加密"
msgid "days"
msgstr ""
#, javascript-format
msgid "%d days"
msgstr ""
msgid "Keep note history for"
msgstr ""
#, javascript-format
msgid "Invalid option value: \"%s\". Possible values are: %s."
msgstr "不正確選項值: \"%s\"。可能的值為: %s。"
@@ -1487,6 +1590,9 @@ msgstr ""
msgid "Note"
msgstr "記事本"
msgid "Plugins"
msgstr ""
#, fuzzy
msgid "Application"
msgstr "離開本程式。"
@@ -1537,12 +1643,19 @@ msgstr "沒有資料可匯出。"
msgid "Please specify the notebook where the notes should be imported to."
msgstr "請指定將記事匯入到的筆記本。"
msgid "Restored Notes"
msgstr ""
msgid "Items that cannot be synchronised"
msgstr "無法同步的項目"
#, javascript-format
msgid "%s (%s): %s"
msgstr "%s (%s): %s"
#, fuzzy, javascript-format
msgid "%s (%s) could not be uploaded: %s"
msgstr "無法開啟檔案: %s"
#, fuzzy, javascript-format
msgid "Item \"%s\" could not be downloaded: %s"
msgstr "無法開啟檔案: %s"
msgid ""
"These items will remain on the device but will not be uploaded to the sync "
@@ -1811,6 +1924,14 @@ msgstr "您當前沒有任何筆記本。通過按一下 (+) 鍵去建立一本
msgid "Welcome"
msgstr "歡迎"
#~ msgid "%s (%s): %s"
#~ msgstr "%s (%s): %s"
#~ msgid ""
#~ "The path to synchronise with when file system synchronisation is enabled. "
#~ "See `sync.target`."
#~ msgstr "啟用檔案系統同步時要同步的路徑。請參閱 `sync.target`。"
#, fuzzy
#~ msgid "Joplin v%s"
#~ msgstr "Joplin 官方網站"

View File

@@ -1,6 +1,6 @@
{
"name": "joplin",
"version": "1.0.124",
"version": "1.0.137",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -346,9 +346,9 @@
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
},
"color": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz",
"integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/color/-/color-3.1.1.tgz",
"integrity": "sha512-PvUltIXRjehRKPSy89VnDWFKY58xyhTLyxIg21vwQBI6qLwZNPmC8k3C1uytIgFKEpOIzN4y32iPm8231zFHIg==",
"requires": {
"color-convert": "^1.9.1",
"color-string": "^1.5.2"
@@ -560,6 +560,11 @@
"resolved": "https://registry.npmjs.org/diacritics/-/diacritics-1.3.0.tgz",
"integrity": "sha1-PvqHMj67hj5mls67AILUj/PW96E="
},
"diff-match-patch": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.4.tgz",
"integrity": "sha512-Uv3SW8bmH9nAtHKaKSanOQmj2DnlH65fUpcrMdfdaOxUG02QQ4YGZ8AE7kKOMisF7UqvOlGKVYWRvezdncW9lg=="
},
"domexception": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz",
@@ -697,9 +702,9 @@
"dev": true
},
"expand-template": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-1.1.1.tgz",
"integrity": "sha512-cebqLtV8KOZfw0UI8TEFWxtczxxC1jvyUvx6H4fyp1K1FN7A4Q+uggVUlOsI1K8AGU0rwOGqP8nCapdrw8CYQg=="
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
"integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="
},
"extend": {
"version": "3.0.1",
@@ -739,6 +744,11 @@
"resolved": "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz",
"integrity": "sha1-G2AOX8ofvcboDApwxxyNul95BsU="
},
"file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
},
"find-up": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
@@ -1435,9 +1445,9 @@
}
},
"joplin-turndown-plugin-gfm": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/joplin-turndown-plugin-gfm/-/joplin-turndown-plugin-gfm-1.0.7.tgz",
"integrity": "sha512-z0SveNcchtWwglkO7SgvDzPnVHYk1WumD0QRcWvUchIihqXwDVlve3G8AHkIhM69LY1YdC0HCZJlSMp2spBe/g=="
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/joplin-turndown-plugin-gfm/-/joplin-turndown-plugin-gfm-1.0.8.tgz",
"integrity": "sha512-uXgq2zGvjiMl/sXG7946EGhh1pyGbZ0L/6z21LBi8D6BJgHQufmXdve/UP3zpgnhiFhfXvzGY10uNaTuDQ99iQ=="
},
"jpeg-js": {
"version": "0.1.2",
@@ -1853,9 +1863,14 @@
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"nan": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.11.0.tgz",
"integrity": "sha512-F4miItu2rGnV2ySkXOQoA8FKz/SR2Q2sWP0sbTxNxz/tuokeC8WxOhPMcwi0qIyGtVn/rrSeLbvVkznqCdwYnw=="
"version": "2.13.2",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz",
"integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw=="
},
"napi-build-utils": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.1.tgz",
"integrity": "sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA=="
},
"ndarray": {
"version": "1.0.18",
@@ -1876,13 +1891,28 @@
}
},
"needle": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/needle/-/needle-2.2.1.tgz",
"integrity": "sha512-t/ZswCM9JTWjAdXS9VpvqhI2Ct2sL2MdY4fUXqGJaGBk13ge99ObqRksRTbBE56K+wxUXwwfZYOuZHifFW9q+Q==",
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/needle/-/needle-2.3.1.tgz",
"integrity": "sha512-CaLXV3W8Vnbps8ZANqDGz7j4x7Yj1LW4TWF/TQuDfj7Cfx4nAPTvw98qgTevtto1oHDrh3pQkaODbqupXlsWTg==",
"requires": {
"debug": "^2.1.2",
"debug": "^4.1.0",
"iconv-lite": "^0.4.4",
"sax": "^1.2.4"
},
"dependencies": {
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"requires": {
"ms": "^2.1.1"
}
},
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
}
}
},
"nextgen-events": {
@@ -1899,9 +1929,9 @@
}
},
"node-abi": {
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.4.4.tgz",
"integrity": "sha512-DQ9Mo2mf/XectC+s6+grPPRQ1Z9gI3ZbrGv6nyXRkjwT3HrE0xvtvrfnH7YHYBLgC/KLadg+h3XHnhZw1sv88A==",
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.8.0.tgz",
"integrity": "sha512-1/aa2clS0pue0HjckL62CsbhWWU35HARvBDXcJtYKbYR7LnIutmpxmXbuDMV9kEviD2lP/wACOgWmmwljghHyQ==",
"requires": {
"semver": "^5.4.1"
}
@@ -1939,13 +1969,13 @@
}
},
"node-pre-gyp": {
"version": "0.10.2",
"resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.10.2.tgz",
"integrity": "sha512-16lql9QTqs6KsB9fl3neWyZm02KxIKdI9FlJjrB0y7eMTP5Nyz+xalwPbOlw3iw7EejllJPmlJSnY711PLD1ug==",
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz",
"integrity": "sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==",
"requires": {
"detect-libc": "^1.0.2",
"mkdirp": "^0.5.1",
"needle": "^2.2.0",
"needle": "^2.2.1",
"nopt": "^4.0.1",
"npm-packlist": "^1.1.6",
"npmlog": "^4.0.2",
@@ -1953,13 +1983,6 @@
"rimraf": "^2.6.1",
"semver": "^5.3.0",
"tar": "^4"
},
"dependencies": {
"detect-libc": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
}
}
},
"noop-logger": {
@@ -1977,14 +2000,14 @@
}
},
"npm-bundled": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.3.tgz",
"integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow=="
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz",
"integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g=="
},
"npm-packlist": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.1.10.tgz",
"integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==",
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.1.tgz",
"integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==",
"requires": {
"ignore-walk": "^3.0.1",
"npm-bundled": "^1.0.1"
@@ -2187,21 +2210,22 @@
"integrity": "sha1-EdHhK5y2TWPjDBQ6Mw9MH1Z9qF8="
},
"prebuild-install": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-4.0.0.tgz",
"integrity": "sha512-7tayxeYboJX0RbVzdnKyGl2vhQRWr6qfClEXDhOkXjuaOKCw2q8aiuFhONRYVsG/czia7KhpykIlI2S2VaPunA==",
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.0.tgz",
"integrity": "sha512-aaLVANlj4HgZweKttFNUVNRxDukytuIuxeK2boIMHjagNJCiVKWFsKF4tCE3ql3GbrD2tExPQ7/pwtEJcHNZeg==",
"requires": {
"detect-libc": "^1.0.3",
"expand-template": "^1.0.2",
"expand-template": "^2.0.3",
"github-from-package": "0.0.0",
"minimist": "^1.2.0",
"mkdirp": "^0.5.1",
"node-abi": "^2.2.0",
"napi-build-utils": "^1.0.1",
"node-abi": "^2.7.0",
"noop-logger": "^0.1.1",
"npmlog": "^4.0.1",
"os-homedir": "^1.0.1",
"pump": "^2.0.1",
"rc": "^1.1.6",
"rc": "^1.2.7",
"simple-get": "^2.7.0",
"tar-fs": "^1.13.0",
"tunnel-agent": "^0.6.0",
@@ -2212,6 +2236,16 @@
"version": "1.2.0",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
},
"simple-get": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.1.tgz",
"integrity": "sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==",
"requires": {
"decompress-response": "^3.3.0",
"once": "^1.3.1",
"simple-concat": "^1.0.0"
}
}
}
},
@@ -2443,50 +2477,63 @@
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
},
"sharp": {
"version": "0.20.8",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.20.8.tgz",
"integrity": "sha512-A8NaPGWRDKpmHTi8sl2xzozYXhTQWBb/GaJ8ZPU7L/vKW8wVvd4Yq+isJ0c7p9sX5gnjPQcM3eOfHuvvnZ2fOQ==",
"version": "0.22.1",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.22.1.tgz",
"integrity": "sha512-lXzSk/FL5b/MpWrT1pQZneKe25stVjEbl6uhhJcTULm7PhmJgKKRbTDM/vtjyUuC/RLqL2PRyC4rpKwbv3soEw==",
"requires": {
"color": "^3.0.0",
"color": "^3.1.1",
"detect-libc": "^1.0.3",
"fs-copy-file-sync": "^1.1.1",
"nan": "^2.11.0",
"nan": "^2.13.2",
"npmlog": "^4.1.2",
"prebuild-install": "^4.0.0",
"semver": "^5.5.1",
"simple-get": "^2.8.1",
"tar": "^4.4.6",
"prebuild-install": "^5.3.0",
"semver": "^6.0.0",
"simple-get": "^3.0.3",
"tar": "^4.4.8",
"tunnel-agent": "^0.6.0"
},
"dependencies": {
"chownr": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
"integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g=="
},
"minipass": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.4.tgz",
"integrity": "sha512-mlouk1OHlaUE8Odt1drMtG1bAJA4ZA6B/ehysgV0LUIrDHdKgo1KorZq3pK0b/7Z7LJIQ12MNM6aC+Tn6lUZ5w==",
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
"integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
}
},
"minizlib": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz",
"integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
"requires": {
"minipass": "^2.2.1"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"semver": {
"version": "5.5.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz",
"integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw=="
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.0.0.tgz",
"integrity": "sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ=="
},
"tar": {
"version": "4.4.6",
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.6.tgz",
"integrity": "sha512-tMkTnh9EdzxyfW+6GK6fCahagXsnYk6kE6S9Gr9pjVdys769+laCTbodXDhPAjzVtEBazRgP0gYqOjnk9dQzLg==",
"version": "4.4.8",
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz",
"integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==",
"requires": {
"chownr": "^1.0.1",
"chownr": "^1.1.1",
"fs-minipass": "^1.2.5",
"minipass": "^2.3.3",
"minizlib": "^1.1.0",
"minipass": "^2.3.4",
"minizlib": "^1.1.1",
"mkdirp": "^0.5.0",
"safe-buffer": "^5.1.2",
"yallist": "^3.0.2"
@@ -2505,9 +2552,9 @@
"integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY="
},
"simple-get": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.1.tgz",
"integrity": "sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.0.3.tgz",
"integrity": "sha512-Wvre/Jq5vgoz31Z9stYWPLn0PqRqmBDpFSdypAnHu5AvRVCYPRYGnvryNLiXu8GOBNDH82J2FRHUGMjjHUpXFw==",
"requires": {
"decompress-response": "^3.3.0",
"once": "^1.3.1",
@@ -2554,18 +2601,136 @@
"integrity": "sha1-Nr54Mgr+WAH2zqPueLblqrlA6gw="
},
"sqlite3": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.0.1.tgz",
"integrity": "sha512-i8LtU2fdEGFEt4Kcs7eNjYdGmnAQ8zWlaOv6Esbq/jfVfR0Qbn/1dgVyKebrMc2zN7h3oHsqla9zq7AJ0+34ZA==",
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.0.7.tgz",
"integrity": "sha512-TGEeSBB8O48bEu8KUUMqzeB22WrfTxzhIf0lFm8wLTo3a6yJBonF2sPKMYrYtOne1F1t9AHAEn+DTISq8WebQg==",
"requires": {
"nan": "~2.10.0",
"node-pre-gyp": "~0.10.1"
"nan": "^2.12.1",
"node-pre-gyp": "^0.11.0",
"request": "^2.87.0"
},
"dependencies": {
"nan": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz",
"integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA=="
"ajv": {
"version": "6.10.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz",
"integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==",
"requires": {
"fast-deep-equal": "^2.0.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
},
"aws4": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
},
"combined-stream": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz",
"integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==",
"requires": {
"delayed-stream": "~1.0.0"
}
},
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
},
"fast-deep-equal": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
},
"form-data": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.6",
"mime-types": "^2.1.12"
}
},
"har-validator": {
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
"integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
"requires": {
"ajv": "^6.5.5",
"har-schema": "^2.0.0"
}
},
"json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
},
"mime-db": {
"version": "1.40.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
"integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA=="
},
"mime-types": {
"version": "2.1.24",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
"integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
"requires": {
"mime-db": "1.40.0"
}
},
"oauth-sign": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
},
"request": {
"version": "2.88.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
"integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
"requires": {
"aws-sign2": "~0.7.0",
"aws4": "^1.8.0",
"caseless": "~0.12.0",
"combined-stream": "~1.0.6",
"extend": "~3.0.2",
"forever-agent": "~0.6.1",
"form-data": "~2.3.2",
"har-validator": "~5.1.0",
"http-signature": "~1.2.0",
"is-typedarray": "~1.0.0",
"isstream": "~0.1.2",
"json-stringify-safe": "~5.0.1",
"mime-types": "~2.1.19",
"oauth-sign": "~0.9.0",
"performance-now": "^2.1.0",
"qs": "~6.5.2",
"safe-buffer": "^5.1.2",
"tough-cookie": "~2.4.3",
"tunnel-agent": "^0.6.0",
"uuid": "^3.3.2"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"tough-cookie": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
"integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
"requires": {
"psl": "^1.1.24",
"punycode": "^1.4.1"
}
},
"uuid": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
}
}
},

View File

@@ -20,7 +20,7 @@
],
"owner": "Laurent Cozic"
},
"version": "1.0.124",
"version": "1.0.137",
"bin": {
"joplin": "./main.js"
},
@@ -33,7 +33,9 @@
"base-64": "^0.1.0",
"compare-version": "^0.1.2",
"diacritics": "^1.3.0",
"diff-match-patch": "^1.0.4",
"es6-promise-pool": "^2.5.0",
"file-uri-to-path": "^1.0.0",
"follow-redirects": "^1.2.4",
"form-data": "^2.1.4",
"fs-extra": "^5.0.0",
@@ -42,7 +44,7 @@
"image-data-uri": "^2.0.0",
"image-type": "^3.0.0",
"joplin-turndown": "^4.0.11",
"joplin-turndown-plugin-gfm": "^1.0.7",
"joplin-turndown-plugin-gfm": "^1.0.8",
"jssha": "^2.3.0",
"levenshtein": "^1.0.5",
"lodash": "^4.17.4",
@@ -60,9 +62,9 @@
"redux": "^3.7.2",
"sax": "^1.2.2",
"server-destroy": "^1.0.1",
"sharp": "^0.20.8",
"sharp": "^0.22.1",
"sprintf-js": "^1.1.1",
"sqlite3": "^4.0.1",
"sqlite3": "^4.0.7",
"string-padding": "^1.0.2",
"string-to-stream": "^1.1.0",
"strip-ansi": "^4.0.0",

View File

@@ -31,6 +31,7 @@ npm test tests-build/models_Folder.js
npm test tests-build/models_ItemChange.js
npm test tests-build/models_Note.js
npm test tests-build/models_Resource.js
npm test tests-build/models_Revision.js
npm test tests-build/models_Setting.js
npm test tests-build/models_Tag.js
npm test tests-build/pathUtils.js
@@ -38,6 +39,7 @@ npm test tests-build/services_InteropService.js
npm test tests-build/services_ResourceService.js
npm test tests-build/services_rest_Api.js
npm test tests-build/services_SearchEngine.js
npm test tests-build/services_Revision.js
npm test tests-build/StringUtils.js
npm test tests-build/synchronizer.js
npm test tests-build/urlUtils.js

View File

@@ -35,7 +35,7 @@ describe('EnexToMd', function() {
const htmlPath = basePath + '/' + htmlFilename;
const mdPath = basePath + '/' + filename(htmlFilename) + '.md';
// if (htmlFilename !== 'text2.html') continue;
// if (htmlFilename !== 'list5.html') continue;
const html = await shim.fsDriver().readFile(htmlPath);
let expectedMd = await shim.fsDriver().readFile(mdPath);

View File

@@ -25,8 +25,7 @@ describe('Encryption', function() {
beforeEach(async (done) => {
await setupDatabaseAndSynchronizer(1);
//await setupDatabaseAndSynchronizer(2);
//await switchClient(1);
await switchClient(1);
service = new EncryptionService();
BaseItem.encryptionService_ = service;
Setting.setValue('encryption.enabled', true);

View File

@@ -0,0 +1,16 @@
<ul>
<li lang="en-US">
<div>Protocols</div>
</li>
<ul type="circle">
<li lang="en-US">
<div>two common network protocols used to send data packets over a network</div>
</li>
<li lang="en-US">
<div>TCP Transmission control protocol</div>
</li>
</ul>
<li lang="en-US">
<div>Network port - a network port is a process-specific or an application-specific software construct serving as a communication endpoint, which is used by the Transport Layer protocols of Internet Protocol suite, such as UDP and TCP</div>
</li>
</ul>

View File

@@ -0,0 +1,7 @@
- Protocols
- two common network protocols used to send data packets over a network
- TCP Transmission control protocol
- Network port - a network port is a process-specific or an application-specific software construct serving as a communication endpoint, which is used by the Transport Layer protocols of Internet Protocol suite, such as UDP and TCP

View File

@@ -1 +1 @@
<a href="https://joplin.cozic.net"><h1 id="joplin"><img class="title-icon" src="https://joplin.cozic.net/images/Icon512.png">oplin</h1></a>
<a href="https://joplinapp.org"><h1 id="joplin"><img class="title-icon" src="https://joplinapp.org/images/Icon512.png">oplin</h1></a>

View File

@@ -1 +1 @@
[# ![](https://joplin.cozic.net/images/Icon512.png)oplin](https://joplin.cozic.net)
[# ![](https://joplinapp.org/images/Icon512.png)oplin](https://joplinapp.org)

View File

@@ -0,0 +1,42 @@
<table>
<thead>
<tr>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Official Things</strong></td>
<td></td>
</tr>
<tr>
<td><a href="https://nim-lang.org">Web Site</a></td>
<td>The project’s entry point</td>
</tr>
<tr>
<td><a href="https://github.com/nim-lang/nim">Source</a></td>
<td>The github project</td>
</tr>
<tr>
<td><a href="https://github.com/nim-lang/nimble">nimble</a></td>
<td>The nim package manager</td>
</tr>
<tr>
<td><a href="https://github.com/dom96/choosenim">choosenim</a></td>
<td>Toolchain installer</td>
</tr>
<tr>
<td>&nbsp;</td>
<td></td>
</tr>
<tr>
<td><strong>Community</strong></td>
<td></td>
</tr>
<tr>
<td><a href="https://forum.nim-lang.org">Forums</a></td>
<td>An async discussion board</td>
</tr>
</tbody>
</table>

View File

@@ -0,0 +1,9 @@
| | |
| --- | --- |
| **Official Things** | |
| [Web Site](https://nim-lang.org) | The project’s entry point |
| [Source](https://github.com/nim-lang/nim) | The github project |
| [nimble](https://github.com/nim-lang/nimble) | The nim package manager |
| [choosenim](https://github.com/dom96/choosenim) | Toolchain installer |
| **Community** | |
| [Forums](https://forum.nim-lang.org) | An async discussion board |

View File

@@ -47,5 +47,20 @@ describe('models_BaseItem', function() {
expect('ignore_me' in unserialized).toBe(false);
}));
it('should not modify title when unserializing', asyncTest(async () => {
let folder1 = await Folder.save({ title: "" });
let folder2 = await Folder.save({ title: "folder1" });
let serialized1 = await Folder.serialize(folder1);
let unserialized1 = await Folder.unserialize(serialized1);
expect(unserialized1.title).toBe(folder1.title);
let serialized2 = await Folder.serialize(folder2);
let unserialized2 = await Folder.unserialize(serialized2);
expect(unserialized2.title).toBe(folder2.title);
}));
});

View File

@@ -119,8 +119,8 @@ describe('models_Folder', function() {
folders = await Folder.orderByLastModified(await Folder.all(), 'desc');
expect(folders.length).toBe(4);
expect(folders[0].id).toBe(f4.id);
expect(folders[1].id).toBe(f1.id);
expect(folders[0].id).toBe(f1.id);
expect(folders[1].id).toBe(f4.id);
expect(folders[2].id).toBe(f3.id);
expect(folders[3].id).toBe(f2.id);
}));

View File

@@ -1,7 +1,7 @@
require('app-module-path').addPath(__dirname);
const { time } = require('lib/time-utils.js');
const { asyncTest, fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
const { asyncTest, fileContentEqual, revisionService, setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
const SearchEngine = require('lib/services/SearchEngine');
const ResourceService = require('lib/services/ResourceService');
const ItemChangeUtils = require('lib/services/ItemChangeUtils');
@@ -34,19 +34,17 @@ describe('models_ItemChange', function() {
const resourceService = new ResourceService();
await searchEngine.syncTables();
// If we run this now, it should not delete any change because
// the resource service has not yet processed the change
await ItemChangeUtils.deleteProcessedChanges();
expect(await ItemChange.lastChangeId()).toBe(1);
await resourceService.indexNoteResources();
// Now that the resource service has processed the change,
// the change can be deleted.
await ItemChangeUtils.deleteProcessedChanges();
expect(await ItemChange.lastChangeId()).toBe(1);
await revisionService().collectRevisions();
await ItemChangeUtils.deleteProcessedChanges();
expect(await ItemChange.lastChangeId()).toBe(0);
}));

View File

@@ -86,5 +86,32 @@ describe('models_Note', function() {
expect(changedNote === note1).toBe(false);
expect(!!changedNote.is_todo).toBe(false);
}));
it('should serialize and unserialize without modifying data', asyncTest(async () => {
let folder1 = await Folder.save({ title: "folder1"});
const testCases = [
[ {title: '', body:'Body and no title\nSecond line\nThird Line', parent_id: folder1.id},
'', 'Body and no title\nSecond line\nThird Line'],
[ {title: 'Note title', body:'Body and title', parent_id: folder1.id},
'Note title', 'Body and title'],
[ {title: 'Title and no body', body:'', parent_id: folder1.id},
'Title and no body', ''],
]
for (let i = 0; i < testCases.length; i++) {
const t = testCases[i];
const input = t[0];
const expectedTitle = t[1];
const expectedBody = t[1];
let note1 = await Note.save(input);
let serialized = await Note.serialize(note1);
let unserialized = await Note.unserialize( serialized);
expect(unserialized.title).toBe(input.title);
expect(unserialized.body).toBe(input.body);
}
}));
});

View File

@@ -8,10 +8,14 @@ const Resource = require('lib/models/Resource.js');
const BaseModel = require('lib/BaseModel.js');
const { shim } = require('lib/shim');
jasmine.DEFAULT_TIMEOUT_INTERVAL = 15000; // The first test is slow because the database needs to be built
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
});
const testImagePath = __dirname + '/../tests/support/photo.jpg';
describe('models_Resource', function() {
beforeEach(async (done) => {
@@ -23,7 +27,7 @@ describe('models_Resource', function() {
it('should have a "done" fetch_status when created locally', asyncTest(async () => {
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');
await shim.attachFileToNote(note1, testImagePath);
let resource1 = (await Resource.all())[0];
let ls = await Resource.localState(resource1);
expect(ls.fetch_status).toBe(Resource.FETCH_STATUS_DONE);
@@ -32,7 +36,7 @@ describe('models_Resource', function() {
it('should have a default local state', asyncTest(async () => {
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');
await shim.attachFileToNote(note1, testImagePath);
let resource1 = (await Resource.all())[0];
let ls = await Resource.localState(resource1);
expect(!ls.id).toBe(true);
@@ -43,7 +47,7 @@ describe('models_Resource', function() {
it('should save and delete local state', asyncTest(async () => {
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');
await shim.attachFileToNote(note1, testImagePath);
let resource1 = (await Resource.all())[0];
await Resource.setLocalState(resource1, { fetch_status: Resource.FETCH_STATUS_IDLE });
@@ -56,4 +60,31 @@ describe('models_Resource', function() {
expect(!ls.id).toBe(true);
}));
it('should resize the resource if the image is below the required dimensions', asyncTest(async () => {
let folder1 = await Folder.save({ title: "folder1" });
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
const previousMax = Resource.IMAGE_MAX_DIMENSION;
Resource.IMAGE_MAX_DIMENSION = 5;
await shim.attachFileToNote(note1, testImagePath);
Resource.IMAGE_MAX_DIMENSION = previousMax;
let resource1 = (await Resource.all())[0];
const originalStat = await shim.fsDriver().stat(testImagePath);
const newStat = await shim.fsDriver().stat(Resource.fullPath(resource1));
expect(newStat.size < originalStat.size).toBe(true);
}));
it('should not resize the resource if the image is below the required dimensions', asyncTest(async () => {
let folder1 = await Folder.save({ title: "folder1" });
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
await shim.attachFileToNote(note1, testImagePath);
let resource1 = (await Resource.all())[0];
const originalStat = await shim.fsDriver().stat(testImagePath);
const newStat = await shim.fsDriver().stat(Resource.fullPath(resource1));
expect(originalStat.size).toBe(newStat.size);
}));
});

View File

@@ -0,0 +1,71 @@
require('app-module-path').addPath(__dirname);
const { time } = require('lib/time-utils.js');
const { asyncTest, fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const NoteTag = require('lib/models/NoteTag.js');
const Tag = require('lib/models/Tag.js');
const Revision = require('lib/models/Revision.js');
const BaseModel = require('lib/BaseModel.js');
const { shim } = require('lib/shim');
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
});
describe('models_Revision', function() {
beforeEach(async (done) => {
await setupDatabaseAndSynchronizer(1);
await switchClient(1);
done();
});
it('should create patches of text and apply it', asyncTest(async () => {
const note1 = await Note.save({ body: 'my note\nsecond line' });
const patch = Revision.createTextPatch(note1.body, 'my new note\nsecond line');
const merged = Revision.applyTextPatch(note1.body, patch);
expect(merged).toBe('my new note\nsecond line');
}));
it('should create patches of objects and apply it', asyncTest(async () => {
const oldObject = {
one: '123',
two: '456',
three: '789',
};
const newObject = {
one: '123',
three: '999',
}
const patch = Revision.createObjectPatch(oldObject, newObject);
const merged = Revision.applyObjectPatch(oldObject, patch);
expect(JSON.stringify(merged)).toBe(JSON.stringify(newObject));
}));
it('should move target revision to the top', asyncTest(async () => {
const revs = [
{ id: '123' },
{ id: '456' },
{ id: '789' },
];
let newRevs;
newRevs = Revision.moveRevisionToTop({ id: '456' }, revs);
expect(newRevs[0].id).toBe('123');
expect(newRevs[1].id).toBe('789');
expect(newRevs[2].id).toBe('456');
newRevs = Revision.moveRevisionToTop({ id: '789' }, revs);
expect(newRevs[0].id).toBe('123');
expect(newRevs[1].id).toBe('456');
expect(newRevs[2].id).toBe('789');
}));
});

View File

@@ -1,7 +1,7 @@
require('app-module-path').addPath(__dirname);
const { time } = require('lib/time-utils.js');
const { asyncTest, fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
const { asyncTest, resourceService, decryptionWorker, encryptionService, loadEncryptionMasterKey, allSyncTargetItemsEncrypted, fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
const InteropService = require('lib/services/InteropService.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
@@ -15,6 +15,7 @@ const fs = require('fs-extra');
const ArrayUtils = require('lib/ArrayUtils');
const ObjectUtils = require('lib/ObjectUtils');
const { shim } = require('lib/shim.js');
const SearchEngine = require('lib/services/SearchEngine');
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
@@ -37,6 +38,7 @@ describe('services_ResourceService', function() {
beforeEach(async (done) => {
await setupDatabaseAndSynchronizer(1);
await setupDatabaseAndSynchronizer(2);
await switchClient(1);
done();
});
@@ -146,4 +148,69 @@ describe('services_ResourceService', function() {
expect(before.last_seen_time).toBe(after.last_seen_time);
}));
it('should not delete resources that are associated with an encrypted note', asyncTest(async () => {
// https://github.com/laurent22/joplin/issues/1433
//
// Client 1 and client 2 have E2EE setup.
//
// - Client 1 creates note N1 and add resource R1 to it
// - Client 1 syncs
// - Client 2 syncs and get N1
// - Client 2 add resource R2 to N1
// - Client 2 syncs
// - Client 1 syncs
// - Client 1 runs resource indexer - but because N1 hasn't been decrypted yet, it found that R1 is no longer associated with any note
// - Client 1 decrypts notes, but too late
//
// Eventually R1 is deleted because service thinks that it was at some point associated with a note, but no longer.
const masterKey = await loadEncryptionMasterKey();
await encryptionService().enableEncryption(masterKey, '123456');
await encryptionService().loadMasterKeysFromSettings();
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'); // R1
await resourceService().indexNoteResources();
await synchronizer().start();
expect(await allSyncTargetItemsEncrypted()).toBe(true);
await switchClient(2);
await synchronizer().start();
await encryptionService().enableEncryption(masterKey, '123456');
await encryptionService().loadMasterKeysFromSettings();
await decryptionWorker().start();
{
const n1 = await Note.load(note1.id);
await shim.attachFileToNote(n1, __dirname + '/../tests/support/photo.jpg'); // R2
}
await synchronizer().start();
await switchClient(1);
await synchronizer().start();
await resourceService().indexNoteResources();
await resourceService().deleteOrphanResources(0); // Previously, R1 would be deleted here because it's not indexed
expect((await Resource.all()).length).toBe(2);
}));
it('should double-check if the resource is still linked before deleting it', asyncTest(async () => {
SearchEngine.instance().setDb(db()); // /!\ Note that we use the global search engine here, which we shouldn't but will work for now
let folder1 = await Folder.save({ title: "folder1" });
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
note1 = await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
await resourceService().indexNoteResources();
const bodyWithResource = note1.body;
await Note.save({ id: note1.id, body: '' });
await resourceService().indexNoteResources();
await Note.save({ id: note1.id, body: bodyWithResource });
await SearchEngine.instance().syncTables();
await resourceService().deleteOrphanResources(0);
expect((await Resource.all()).length).toBe(1); // It should not have deleted the resource
const nr = (await NoteResource.all())[0];
expect(!!nr.is_associated).toBe(true); // And it should have fixed the situation by re-indexing the note content
}));
});

View File

@@ -0,0 +1,420 @@
require('app-module-path').addPath(__dirname);
const { time } = require('lib/time-utils.js');
const { asyncTest, fileContentEqual, setupDatabase, revisionService, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
const Folder = require('lib/models/Folder.js');
const Setting = require('lib/models/Setting.js');
const Note = require('lib/models/Note.js');
const NoteTag = require('lib/models/NoteTag.js');
const ItemChange = require('lib/models/ItemChange.js');
const Tag = require('lib/models/Tag.js');
const Revision = require('lib/models/Revision.js');
const BaseModel = require('lib/BaseModel.js');
const RevisionService = require('lib/services/RevisionService.js');
const { shim } = require('lib/shim');
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
});
describe('services_Revision', function() {
beforeEach(async (done) => {
await setupDatabaseAndSynchronizer(1);
await switchClient(1);
Setting.setValue('revisionService.intervalBetweenRevisions', 0)
done();
});
it('should create diff and rebuild notes', asyncTest(async () => {
const service = new RevisionService();
const n1_v1 = await Note.save({ title: '', author: 'testing' });
await service.collectRevisions();
await Note.save({ id: n1_v1.id, title: 'hello', author: 'testing' });
await service.collectRevisions();
const n1_v2 = await Note.save({ id: n1_v1.id, title: 'hello welcome', author: '' });
await service.collectRevisions();
const revisions = await Revision.allByType(BaseModel.TYPE_NOTE, n1_v1.id);
expect(revisions.length).toBe(2);
expect(revisions[1].parent_id).toBe(revisions[0].id);
const rev1 = await service.revisionNote(revisions, 0);
expect(rev1.title).toBe('hello');
expect(rev1.author).toBe('testing');
const rev2 = await service.revisionNote(revisions, 1);
expect(rev2.title).toBe('hello welcome');
expect(rev2.author).toBe('');
await time.sleep(0.5);
await service.deleteOldRevisions(400);
const revisions2 = await Revision.allByType(BaseModel.TYPE_NOTE, n1_v1.id);
expect(revisions2.length).toBe(0);
}));
it('should delete old revisions (1 note, 2 rev)', asyncTest(async () => {
const service = new RevisionService();
const n1_v0 = await Note.save({ title: '' });
const n1_v1 = await Note.save({ id: n1_v0.id, title: 'hello' });
await service.collectRevisions();
await time.sleep(1);
const n1_v2 = await Note.save({ id: n1_v1.id, title: 'hello welcome' });
await service.collectRevisions();
expect((await Revision.allByType(BaseModel.TYPE_NOTE, n1_v1.id)).length).toBe(2);
await service.deleteOldRevisions(1000);
const revisions = await Revision.allByType(BaseModel.TYPE_NOTE, n1_v1.id);
expect(revisions.length).toBe(1);
const rev1 = await service.revisionNote(revisions, 0);
expect(rev1.title).toBe('hello welcome');
}));
it('should delete old revisions (1 note, 3 rev)', asyncTest(async () => {
const service = new RevisionService();
const n1_v0 = await Note.save({ title: '' });
const n1_v1 = await Note.save({ id: n1_v0.id, title: 'one' });
await service.collectRevisions();
await time.sleep(1);
const n1_v2 = await Note.save({ id: n1_v1.id, title: 'one two' });
await service.collectRevisions();
await time.sleep(1);
const n1_v3 = await Note.save({ id: n1_v1.id, title: 'one two three' });
await service.collectRevisions();
{
await service.deleteOldRevisions(2000);
const revisions = await Revision.allByType(BaseModel.TYPE_NOTE, n1_v1.id);
expect(revisions.length).toBe(2);
const rev1 = await service.revisionNote(revisions, 0);
expect(rev1.title).toBe('one two');
const rev2 = await service.revisionNote(revisions, 1);
expect(rev2.title).toBe('one two three');
}
{
await service.deleteOldRevisions(1000);
const revisions = await Revision.allByType(BaseModel.TYPE_NOTE, n1_v1.id);
expect(revisions.length).toBe(1);
const rev1 = await service.revisionNote(revisions, 0);
expect(rev1.title).toBe('one two three');
}
}));
it('should delete old revisions (2 notes, 2 rev)', asyncTest(async () => {
const service = new RevisionService();
const n1_v0 = await Note.save({ title: '' });
const n1_v1 = await Note.save({ id: n1_v0.id, title: 'note 1' });
const n2_v0 = await Note.save({ title: '' });
const n2_v1 = await Note.save({ id: n2_v0.id, title: 'note 2' });
await service.collectRevisions();
await time.sleep(1);
const n1_v2 = await Note.save({ id: n1_v1.id, title: 'note 1 (v2)' });
const n2_v2 = await Note.save({ id: n2_v1.id, title: 'note 2 (v2)' });
await service.collectRevisions();
expect((await Revision.all()).length).toBe(4);
await service.deleteOldRevisions(1000);
{
const revisions = await Revision.allByType(BaseModel.TYPE_NOTE, n1_v1.id);
expect(revisions.length).toBe(1);
const rev1 = await service.revisionNote(revisions, 0);
expect(rev1.title).toBe('note 1 (v2)');
}
{
const revisions = await Revision.allByType(BaseModel.TYPE_NOTE, n2_v1.id);
expect(revisions.length).toBe(1);
const rev1 = await service.revisionNote(revisions, 0);
expect(rev1.title).toBe('note 2 (v2)');
}
}));
it('should handle conflicts', asyncTest(async () => {
const service = new RevisionService();
// A conflict happens in this case:
// - Device 1 creates note1 (rev1)
// - Device 2 syncs and get note1
// - Device 1 modifies note1 (rev2)
// - Device 2 modifies note1 (rev3)
// When reconstructing the notes based on the revisions, we need to make sure it follow the right
// "path". For example, to reconstruct the note at rev2 it would be:
// rev1 => rev2
// To reconstruct the note at rev3 it would be:
// rev1 => rev3
// And not, for example, rev1 => rev2 => rev3
const n1_v1 = await Note.save({ title: 'hello' });
const noteId = n1_v1.id;
const rev1 = await service.createNoteRevision_(n1_v1);
const n1_v2 = await Note.save({ id: noteId, title: 'hello Paul' });
const rev2 = await service.createNoteRevision_(n1_v2, rev1.id);
const n1_v3 = await Note.save({ id: noteId, title: 'hello John' });
const rev3 = await service.createNoteRevision_(n1_v3, rev1.id);
const revisions = await Revision.allByType(BaseModel.TYPE_NOTE, noteId);
expect(revisions.length).toBe(3);
expect(revisions[1].parent_id).toBe(rev1.id);
expect(revisions[2].parent_id).toBe(rev1.id);
const revNote1 = await service.revisionNote(revisions, 0);
const revNote2 = await service.revisionNote(revisions, 1);
const revNote3 = await service.revisionNote(revisions, 2);
expect(revNote1.title).toBe('hello');
expect(revNote2.title).toBe('hello Paul');
expect(revNote3.title).toBe('hello John');
}));
it('should create a revision for notes that are older than a given interval', asyncTest(async () => {
const n1 = await Note.save({ title: 'hello' });
const noteId = n1.id;
await sleep(0.1);
// Set the interval in such a way that the note is considered an old one.
Setting.setValue('revisionService.oldNoteInterval', 50);
// A revision is created the first time a note is overwritten with new content, and
// if this note doesn't already have an existing revision.
// This is mostly to handle old notes that existed before the revision service. If these
// old notes are changed, there's a chance it's accidental or due to some bug, so we
// want to preserve a revision just in case.
{
await Note.save({ id: noteId, title: 'hello 2' });
await revisionService().collectRevisions(); // Rev for old note created + Rev for new note
const all = await Revision.allByType(BaseModel.TYPE_NOTE, noteId);
expect(all.length).toBe(2);
const revNote1 = await revisionService().revisionNote(all, 0);
const revNote2 = await revisionService().revisionNote(all, 1);
expect(revNote1.title).toBe('hello');
expect(revNote2.title).toBe('hello 2');
}
// If the note is saved a third time, we don't automatically create a revision. One
// will be created x minutes later when the service collects revisions.
{
await Note.save({ id: noteId, title: 'hello 3' });
const all = await Revision.allByType(BaseModel.TYPE_NOTE, noteId);
expect(all.length).toBe(2);
}
}));
it('should create a revision for notes that get deleted (recyle bin)', asyncTest(async () => {
const n1 = await Note.save({ title: 'hello' });
const noteId = n1.id;
await Note.delete(noteId);
await revisionService().collectRevisions();
const all = await Revision.allByType(BaseModel.TYPE_NOTE, noteId);
expect(all.length).toBe(1);
const rev1 = await revisionService().revisionNote(all, 0);
expect(rev1.title).toBe('hello');
}));
it('should not create a revision for notes that get deleted if there is already a revision', asyncTest(async () => {
const n1 = await Note.save({ title: 'hello' });
await revisionService().collectRevisions();
const noteId = n1.id;
await Note.save({ id: noteId, title: 'hello Paul' });
await revisionService().collectRevisions(); // REV 1
expect((await Revision.allByType(BaseModel.TYPE_NOTE, n1.id)).length).toBe(1);
await Note.delete(noteId);
// At this point there is no need to create a new revision for the deleted note
// because we already have the latest version as REV 1
await revisionService().collectRevisions();
expect((await Revision.allByType(BaseModel.TYPE_NOTE, n1.id)).length).toBe(1);
}));
it('should not create a revision for new note the first time they are saved', asyncTest(async () => {
const n1 = await Note.save({ title: 'hello' });
{
const revisions = await Revision.allByType(BaseModel.TYPE_NOTE, n1.id);
expect(revisions.length).toBe(0);
}
await revisionService().collectRevisions();
{
const revisions = await Revision.allByType(BaseModel.TYPE_NOTE, n1.id);
expect(revisions.length).toBe(0);
}
}));
it('should abort collecting revisions when one of them is encrypted', asyncTest(async () => {
const n1 = await Note.save({ title: 'hello' }); // CHANGE 1
await revisionService().collectRevisions();
await Note.save({ id: n1.id, title: 'hello Ringo' }); // CHANGE 2
await revisionService().collectRevisions();
await Note.save({ id: n1.id, title: 'hello George' }); // CHANGE 3
await revisionService().collectRevisions();
const revisions = await Revision.allByType(BaseModel.TYPE_NOTE, n1.id);
expect(revisions.length).toBe(2);
const encryptedRevId = revisions[0].id;
// Simulate receiving an encrypted revision
await Revision.save({ id: encryptedRevId, encryption_applied: 1 });
await Note.save({ id: n1.id, title: 'hello Paul' }); // CHANGE 4
await revisionService().collectRevisions();
// Although change 4 is a note update, check that it has not been processed
// by the collector, due to one of the revisions being encrypted.
expect(await ItemChange.lastChangeId()).toBe(4);
expect(Setting.value('revisionService.lastProcessedChangeId')).toBe(3);
// Simulate the revision being decrypted by DecryptionService
await Revision.save({ id: encryptedRevId, encryption_applied: 0 });
await revisionService().collectRevisions();
// Now that the revision has been decrypted, all the changes can be processed
expect(await ItemChange.lastChangeId()).toBe(4);
expect(Setting.value('revisionService.lastProcessedChangeId')).toBe(4);
}));
it('should not delete old revisions if one of them is still encrypted (1)', asyncTest(async () => {
// Test case 1: Two revisions and the first one is encrypted.
// Calling deleteOldRevisions() with low TTL, which means all revisions
// should be deleted, but they won't be due to the encrypted one.
const n1_v0 = await Note.save({ title: '' });
const n1_v1 = await Note.save({ id: n1_v0.id, title: 'hello' });
await revisionService().collectRevisions(); // REV 1
await time.sleep(0.1);
const n1_v2 = await Note.save({ id: n1_v1.id, title: 'hello welcome' });
await revisionService().collectRevisions(); // REV 2
await time.sleep(0.1);
expect((await Revision.all()).length).toBe(2);
const revisions = await Revision.all();
await Revision.save({ id: revisions[0].id, encryption_applied: 1 });
await revisionService().deleteOldRevisions(0);
expect((await Revision.all()).length).toBe(2);
await Revision.save({ id: revisions[0].id, encryption_applied: 0 });
await revisionService().deleteOldRevisions(0);
expect((await Revision.all()).length).toBe(0);
}));
it('should not delete old revisions if one of them is still encrypted (2)', asyncTest(async () => {
// Test case 2: Two revisions and the first one is encrypted.
// Calling deleteOldRevisions() with higher TTL, which means the oldest
// revision should be deleted, but it won't be due to the encrypted one.
const n1_v0 = await Note.save({ title: '' });
const n1_v1 = await Note.save({ id: n1_v0.id, title: 'hello' });
await revisionService().collectRevisions(); // REV 1
await time.sleep(0.5);
const n1_v2 = await Note.save({ id: n1_v1.id, title: 'hello welcome' });
await revisionService().collectRevisions(); // REV 2
expect((await Revision.all()).length).toBe(2);
const revisions = await Revision.all();
await Revision.save({ id: revisions[0].id, encryption_applied: 1 });
await revisionService().deleteOldRevisions(500);
expect((await Revision.all()).length).toBe(2);
}));
it('should not delete old revisions if one of them is still encrypted (3)', asyncTest(async () => {
// Test case 2: Two revisions and the second one is encrypted.
// Calling deleteOldRevisions() with higher TTL, which means the oldest
// revision should be deleted, but it won't be due to the encrypted one.
const n1_v0 = await Note.save({ title: '' });
const n1_v1 = await Note.save({ id: n1_v0.id, title: 'hello' });
await revisionService().collectRevisions(); // REV 1
await time.sleep(0.5);
const n1_v2 = await Note.save({ id: n1_v1.id, title: 'hello welcome' });
await revisionService().collectRevisions(); // REV 2
expect((await Revision.all()).length).toBe(2);
const revisions = await Revision.all();
await Revision.save({ id: revisions[1].id, encryption_applied: 1 });
await revisionService().deleteOldRevisions(500);
expect((await Revision.all()).length).toBe(2);
await Revision.save({ id: revisions[1].id, encryption_applied: 0 });
await revisionService().deleteOldRevisions(500);
expect((await Revision.all()).length).toBe(1);
}));
it('should not create a revision if the note has not changed', asyncTest(async () => {
const n1_v0 = await Note.save({ title: '' });
const n1_v1 = await Note.save({ id: n1_v0.id, title: 'hello' });
await revisionService().collectRevisions(); // REV 1
expect((await Revision.all()).length).toBe(1);
const n1_v2 = await Note.save({ id: n1_v0.id, title: 'hello' });
await revisionService().collectRevisions(); // Note has not changed (except its timestamp) so don't create a revision
expect((await Revision.all()).length).toBe(1);
}));
it('should preserve user update time', asyncTest(async () => {
// user_updated_time is kind of tricky and can be changed automatically in various
// places so make sure it is saved correctly with the revision
const n1_v0 = await Note.save({ title: '' });
const n1_v1 = await Note.save({ id: n1_v0.id, title: 'hello' });
await revisionService().collectRevisions(); // REV 1
expect((await Revision.all()).length).toBe(1);
const userUpdatedTime = Date.now() - 1000 * 60 * 60;
const n1_v2 = await Note.save({ id: n1_v0.id, title: 'hello', updated_time: Date.now(), user_updated_time: userUpdatedTime }, { autoTimestamp: false });
await revisionService().collectRevisions(); // Only the user timestamp has changed, but that needs to be saved
const revisions = await Revision.all();
expect(revisions.length).toBe(2);
const revNote = await revisionService().revisionNote(revisions, 1);
expect(revNote.user_updated_time).toBe(userUpdatedTime);
}));
it('should not create a revision if there is already a recent one', asyncTest(async () => {
const n1_v0 = await Note.save({ title: '' });
const n1_v1 = await Note.save({ id: n1_v0.id, title: 'hello' });
await revisionService().collectRevisions(); // REV 1
const n1_v2 = await Note.save({ id: n1_v0.id, title: 'hello 2' });
await revisionService().collectRevisions(); // REV 2
expect((await Revision.all()).length).toBe(2);
Setting.setValue('revisionService.intervalBetweenRevisions', 1000);
const n1_v3 = await Note.save({ id: n1_v0.id, title: 'hello 3' });
await revisionService().collectRevisions(); // No rev because there's already a rev that is less than 1000 ms old
expect((await Revision.all()).length).toBe(2);
}));
});

View File

@@ -256,6 +256,23 @@ describe('services_SearchEngine', function() {
expect((await engine.search('말')).length).toBe(1);
}));
it('should support field restricted queries with Chinese characters', asyncTest(async () => {
let rows;
const n1 = await Note.save({ title: "你好", body: "我是法国人" });
await engine.syncTables();
expect((await engine.search('title:你好*')).length).toBe(1);
expect((await engine.search('body:你好')).length).toBe(0);
expect((await engine.search('title:你好 body:法国人')).length).toBe(1);
expect((await engine.search('title:你好 body:bla')).length).toBe(0);
expect((await engine.search('title:你好 我是')).length).toBe(1);
expect((await engine.search('title:bla 我是')).length).toBe(0);
// For non-alpha char, only the first field is looked at, the following ones are ignored
expect((await engine.search('title:你好 title:hello')).length).toBe(1);
}));
it('should parse normal query strings', asyncTest(async () => {
let rows;
@@ -265,6 +282,7 @@ describe('services_SearchEngine', function() {
['title:abcd efgh', { _: ['efgh'], title: ['abcd'] }],
['title:abcd', { title: ['abcd'] }],
['"abcd efgh"', { _: ['abcd efgh'] }],
['title:abcd title:efgh', { title: ['abcd', 'efgh'] }],
];
for (let i = 0; i < testCases.length; i++) {
@@ -283,33 +301,6 @@ describe('services_SearchEngine', function() {
}
}));
// it('should parse query strings with wildcards', asyncTest(async () => {
// let rows;
// const testCases = [
// ['do*', ['do', 'dog', 'domino'], [] ],
// // "*" is a wildcard only when used at the end (to search for documents with the specified prefix)
// // If it's at the beginning, it's ignored, if it's in the middle, it's treated as a litteral "*".
// ['*an*', ['an', 'anneau'], ['piano', 'plan'] ],
// ['no*no', ['no*no'], ['nonono'] ],
// ];
// for (let i = 0; i < testCases.length; i++) {
// const t = testCases[i];
// const input = t[0];
// const shouldMatch = t[1];
// const shouldNotMatch = t[2];
// const regex = new RegExp(engine.parseQuery(input).terms._[0].value, 'gmi');
// for (let j = 0; j < shouldMatch.length; j++) {
// const r = shouldMatch[j].match(regex);
// expect(!!r).toBe(true, '"' + input + '" should match "' + shouldMatch[j] + '"');
// }
// }
// expect(engine.parseQuery('*').termCount).toBe(0);
// }));
it('should handle queries with special characters', asyncTest(async () => {
let rows;

View File

@@ -1,7 +1,7 @@
require('app-module-path').addPath(__dirname);
const { time } = require('lib/time-utils.js');
const { setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, encryptionService, loadEncryptionMasterKey, fileContentEqual, decryptionWorker, checkThrowAsync, asyncTest } = require('test-utils.js');
const { setupDatabase, allSyncTargetItemsEncrypted, revisionService, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, encryptionService, loadEncryptionMasterKey, fileContentEqual, decryptionWorker, checkThrowAsync, asyncTest } = require('test-utils.js');
const { shim } = require('lib/shim.js');
const fs = require('fs-extra');
const Folder = require('lib/models/Folder.js');
@@ -13,6 +13,7 @@ const { Database } = require('lib/database.js');
const Setting = require('lib/models/Setting.js');
const MasterKey = require('lib/models/MasterKey');
const BaseItem = require('lib/models/BaseItem.js');
const Revision = require('lib/models/Revision.js');
const BaseModel = require('lib/BaseModel.js');
const SyncTargetRegistry = require('lib/SyncTargetRegistry.js');
const WelcomeUtils = require('lib/WelcomeUtils');
@@ -23,51 +24,44 @@ process.on('unhandledRejection', (reason, p) => {
jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000 + 30000; // The first test is slow because the database needs to be built
async function allItems() {
async function allNotesFolders() {
let folders = await Folder.all();
let notes = await Note.all();
return folders.concat(notes);
}
async function allSyncTargetItemsEncrypted() {
async function remoteItemsByTypes(types) {
const list = await fileApi().list();
if (list.has_more) throw new Error('Not implemented!!!');
const files = list.items;
//console.info(Setting.value('resourceDir'));
let totalCount = 0;
let encryptedCount = 0;
for (let i = 0; i < files.length; i++) {
const file = files[i];
const remoteContentString = await fileApi().get(file.path);
const remoteContent = await BaseItem.unserialize(remoteContentString);
const ItemClass = BaseItem.itemClass(remoteContent);
if (!ItemClass.encryptionSupported()) continue;
totalCount++;
if (remoteContent.type_ === BaseModel.TYPE_RESOURCE) {
const content = await fileApi().get('.resource/' + remoteContent.id);
totalCount++;
if (content.substr(0, 5) === 'JED01') output = encryptedCount++;
}
if (!!remoteContent.encryption_applied) encryptedCount++;
const output = [];
for (const file of files) {
const remoteContent = await fileApi().get(file.path);
const content = await BaseItem.unserialize(remoteContent);
if (types.indexOf(content.type_) < 0) continue;
output.push(content);
}
if (!totalCount) throw new Error('No encryptable item on sync target');
return totalCount === encryptedCount;
return output;
}
async function localItemsSameAsRemote(locals, expect) {
async function remoteNotesAndFolders() {
return remoteItemsByTypes([BaseModel.TYPE_NOTE, BaseModel.TYPE_FOLDER]);
}
async function remoteNotesFoldersResources() {
return remoteItemsByTypes([BaseModel.TYPE_NOTE, BaseModel.TYPE_FOLDER, BaseModel.TYPE_RESOURCE]);
}
async function remoteResources() {
return remoteItemsByTypes([BaseModel.TYPE_RESOURCE]);
}
async function localNotesFoldersSameAsRemote(locals, expect) {
let error = null;
try {
let files = await fileApi().list();
files = files.items;
expect(locals.length).toBe(files.length);
const nf = await remoteNotesAndFolders();
expect(locals.length).toBe(nf.length);
for (let i = 0; i < locals.length; i++) {
let dbItem = locals[i];
@@ -77,12 +71,6 @@ async function localItemsSameAsRemote(locals, expect) {
expect(!!remote).toBe(true);
if (!remote) continue;
// if (syncTargetId() == SyncTargetRegistry.nameToId('filesystem')) {
// expect(remote.updated_time).toBe(Math.floor(dbItem.updated_time / 1000) * 1000);
// } else {
// expect(remote.updated_time).toBe(dbItem.updated_time);
// }
let remoteContent = await fileApi().get(path);
remoteContent = dbItem.type_ == BaseModel.TYPE_NOTE ? await Note.unserialize(remoteContent) : await Folder.unserialize(remoteContent);
@@ -114,11 +102,11 @@ describe('Synchronizer', function() {
let folder = await Folder.save({ title: "folder1" });
await Note.save({ title: "un", parent_id: folder.id });
let all = await allItems();
let all = await allNotesFolders();
await synchronizer().start();
await localItemsSameAsRemote(all, expect);
await localNotesFoldersSameAsRemote(all, expect);
}));
it('should update remote items', asyncTest(async () => {
@@ -128,10 +116,10 @@ describe('Synchronizer', function() {
await Note.save({ title: "un UPDATE", id: note.id });
let all = await allItems();
let all = await allNotesFolders();
await synchronizer().start();
await localItemsSameAsRemote(all, expect);
await localNotesFoldersSameAsRemote(all, expect);
}));
it('should create local items', asyncTest(async () => {
@@ -143,9 +131,9 @@ describe('Synchronizer', function() {
await synchronizer().start();
let all = await allItems();
let all = await allNotesFolders();
await localItemsSameAsRemote(all, expect);
await localNotesFoldersSameAsRemote(all, expect);
}));
it('should update local items', asyncTest(async () => {
@@ -170,9 +158,9 @@ describe('Synchronizer', function() {
await synchronizer().start();
let all = await allItems();
let all = await allNotesFolders();
await localItemsSameAsRemote(all, expect);
await localNotesFoldersSameAsRemote(all, expect);
}));
it('should resolve note conflicts', asyncTest(async () => {
@@ -264,11 +252,9 @@ describe('Synchronizer', function() {
await synchronizer().start();
let files = await fileApi().list();
files = files.items;
expect(files.length).toBe(1);
expect(files[0].path).toBe(Folder.systemPath(folder1));
const remotes = await remoteNotesAndFolders();
expect(remotes.length).toBe(1);
expect(remotes[0].id).toBe(folder1.id);
let deletedItems = await BaseItem.deletedItems(syncTargetId());
expect(deletedItems.length).toBe(0);
@@ -311,7 +297,7 @@ describe('Synchronizer', function() {
await switchClient(1);
context1 = await synchronizer().start({ context: context1 });
let items = await allItems();
let items = await allNotesFolders();
expect(items.length).toBe(2);
let deletedItems = await BaseItem.deletedItems(syncTargetId());
expect(deletedItems.length).toBe(0);
@@ -334,8 +320,8 @@ describe('Synchronizer', function() {
await synchronizer().start();
let all = await allItems();
await localItemsSameAsRemote(all, expect);
let all = await allNotesFolders();
await localNotesFoldersSameAsRemote(all, expect);
}));
it('should delete local folder', asyncTest(async () => {
@@ -352,8 +338,8 @@ describe('Synchronizer', function() {
await switchClient(1);
await synchronizer().start({ context: context1 });
let items = await allItems();
await localItemsSameAsRemote(items, expect);
let items = await allNotesFolders();
await localNotesFoldersSameAsRemote(items, expect);
}));
it('should resolve conflict if remote folder has been deleted, but note has been added to folder locally', asyncTest(async () => {
@@ -370,7 +356,7 @@ describe('Synchronizer', function() {
let note = await Note.save({ title: "note1", parent_id: folder1.id });
await synchronizer().start();
let items = await allItems();
let items = await allNotesFolders();
expect(items.length).toBe(1);
expect(items[0].title).toBe('note1');
expect(items[0].is_conflict).toBe(1);
@@ -392,11 +378,11 @@ describe('Synchronizer', function() {
await Note.delete(note.id);
await synchronizer().start();
let items = await allItems();
let items = await allNotesFolders();
expect(items.length).toBe(1);
expect(items[0].title).toBe('folder');
await localItemsSameAsRemote(items, expect);
await localNotesFoldersSameAsRemote(items, expect);
}));
it('should cross delete all folders', asyncTest(async () => {
@@ -425,13 +411,13 @@ describe('Synchronizer', function() {
await synchronizer().start();
let items2 = await allItems();
let items2 = await allNotesFolders();
await switchClient(1);
await synchronizer().start();
let items1 = await allItems();
let items1 = await allNotesFolders();
expect(items1.length).toBe(0);
expect(items1.length).toBe(items2.length);
@@ -494,7 +480,7 @@ describe('Synchronizer', function() {
await synchronizer().start();
let items = await allItems();
let items = await allNotesFolders();
expect(items.length).toBe(1);
}));
@@ -712,7 +698,7 @@ describe('Synchronizer', function() {
let disabledItems = await BaseItem.syncDisabledItems(syncTargetId());
expect(disabledItems.length).toBe(0);
await Note.save({ id: noteId, title: "un mod", });
synchronizer().testingHooks_ = ['rejectedByTarget'];
synchronizer().testingHooks_ = ['notesRejectedByTarget'];
await synchronizer().start();
synchronizer().testingHooks_ = [];
await synchronizer().start(); // Another sync to check that this item is now excluded from sync
@@ -865,8 +851,8 @@ describe('Synchronizer', function() {
await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
let resource1 = (await Resource.all())[0];
let resourcePath1 = Resource.fullPath(resource1);
await synchronizer().start();
expect((await fileApi().list()).items.length).toBe(3);
await synchronizer().start();
expect((await remoteNotesFoldersResources()).length).toBe(3);
await switchClient(2);
@@ -879,7 +865,7 @@ describe('Synchronizer', function() {
expect(ls.fetch_status).toBe(Resource.FETCH_STATUS_IDLE);
const fetcher = new ResourceFetcher(() => { return synchronizer().api() });
fetcher.queueDownload(resource1_2.id);
fetcher.queueDownload_(resource1_2.id);
await fetcher.waitForAllFinished();
resource1_2 = await Resource.load(resource1.id);
@@ -908,7 +894,7 @@ describe('Synchronizer', function() {
// Simulate a failed download
get: () => { return new Promise((resolve, reject) => { reject(new Error('did not work')) }); }
} });
fetcher.queueDownload(resource1.id);
fetcher.queueDownload_(resource1.id);
await fetcher.waitForAllFinished();
resource1 = await Resource.load(resource1.id);
@@ -917,6 +903,29 @@ describe('Synchronizer', function() {
expect(ls.fetch_error).toBe('did not work');
}));
it('should set the resource file size if it is missing', asyncTest(async () => {
while (insideBeforeEach) await time.msleep(500);
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');
await synchronizer().start();
await switchClient(2);
await synchronizer().start();
let r1 = (await Resource.all())[0];
await Resource.setFileSizeOnly(r1.id, -1);
r1 = await Resource.load(r1.id);
expect(r1.size).toBe(-1);
const fetcher = new ResourceFetcher(() => { return synchronizer().api() });
fetcher.queueDownload_(r1.id);
await fetcher.waitForAllFinished();
r1 = await Resource.load(r1.id);
expect(r1.size).toBe(2720);
}));
it('should delete resources', asyncTest(async () => {
while (insideBeforeEach) await time.msleep(500);
@@ -933,11 +942,10 @@ describe('Synchronizer', function() {
let allResources = await Resource.all();
expect(allResources.length).toBe(1);
let all = await fileApi().list();
expect(all.items.length).toBe(3);
expect((await remoteNotesFoldersResources()).length).toBe(3);
await Resource.delete(resource1.id);
await synchronizer().start();
all = await fileApi().list();
expect(all.items.length).toBe(2);
expect((await remoteNotesFoldersResources()).length).toBe(2);
await switchClient(1);
@@ -966,7 +974,7 @@ describe('Synchronizer', function() {
await encryptionService().loadMasterKeysFromSettings();
const fetcher = new ResourceFetcher(() => { return synchronizer().api() });
fetcher.queueDownload(resource1.id);
fetcher.queueDownload_(resource1.id);
await fetcher.waitForAllFinished();
let resource1_2 = (await Resource.all())[0];
@@ -1030,6 +1038,33 @@ describe('Synchronizer', function() {
expect(allEncrypted).toBe(false);
}));
it('should set the resource file size after decryption', asyncTest(async () => {
Setting.setValue('encryption.enabled', true);
const masterKey = await loadEncryptionMasterKey();
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');
let resource1 = (await Resource.all())[0];
await Resource.setFileSizeOnly(resource1.id, -1);
let resourcePath1 = Resource.fullPath(resource1);
await synchronizer().start();
await switchClient(2);
await synchronizer().start();
Setting.setObjectKey('encryption.passwordCache', masterKey.id, '123456');
await encryptionService().loadMasterKeysFromSettings();
const fetcher = new ResourceFetcher(() => { return synchronizer().api() });
fetcher.queueDownload_(resource1.id);
await fetcher.waitForAllFinished();
await decryptionWorker().start();
const resource1_2 = await Resource.load(resource1.id);
expect(resource1_2.size).toBe(2720);
}));
it('should encrypt remote resources after encryption has been enabled', asyncTest(async () => {
while (insideBeforeEach) await time.msleep(100);
@@ -1068,11 +1103,11 @@ describe('Synchronizer', function() {
it('should create remote items with UTF-8 content', asyncTest(async () => {
let folder = await Folder.save({ title: "Fahrräder" });
await Note.save({ title: "Fahrräder", body: "Fahrräder", parent_id: folder.id });
let all = await allItems();
let all = await allNotesFolders();
await synchronizer().start();
await localItemsSameAsRemote(all, expect);
await localNotesFoldersSameAsRemote(all, expect);
}));
it("should update remote items but not pull remote changes", asyncTest(async () => {
@@ -1090,7 +1125,7 @@ describe('Synchronizer', function() {
await Note.save({ title: "un UPDATE", id: note.id });
await synchronizer().start({ syncSteps: ["update_remote"] });
let all = await allItems();
let all = await allNotesFolders();
expect(all.length).toBe(2);
await switchClient(2);
@@ -1142,4 +1177,212 @@ describe('Synchronizer', function() {
expect(tags.length).toBe(2);
}));
it("should not save revisions when updating a note via sync", asyncTest(async () => {
// When a note is updated, a revision of the original is created.
// Here, on client 1, the note is updated for the first time, however since it is
// via sync, we don't create a revision - that revision has already been created on client
// 2 and is going to be synced.
const n1 = await Note.save({ title: 'testing' });
await synchronizer().start();
await switchClient(2);
await synchronizer().start();
await Note.save({ id: n1.id, title: 'mod from client 2' });
await revisionService().collectRevisions();
const allRevs1 = await Revision.allByType(BaseModel.TYPE_NOTE, n1.id);
expect(allRevs1.length).toBe(1);
await synchronizer().start();
await switchClient(1);
await synchronizer().start();
const allRevs2 = await Revision.allByType(BaseModel.TYPE_NOTE, n1.id);
expect(allRevs2.length).toBe(1);
expect(allRevs2[0].id).toBe(allRevs1[0].id);
}));
it("should not save revisions when deleting a note via sync", asyncTest(async () => {
const n1 = await Note.save({ title: 'testing' });
await synchronizer().start();
await switchClient(2);
await synchronizer().start();
await Note.delete(n1.id);
await revisionService().collectRevisions(); // REV 1
{
const allRevs = await Revision.allByType(BaseModel.TYPE_NOTE, n1.id);
expect(allRevs.length).toBe(1);
}
await synchronizer().start();
await switchClient(1);
await synchronizer().start(); // The local note gets deleted here, however a new rev is *not* created
{
const allRevs = await Revision.allByType(BaseModel.TYPE_NOTE, n1.id);
expect(allRevs.length).toBe(1);
}
const notes = await Note.all();
expect(notes.length).toBe(0);
}));
it("should not save revisions when an item_change has been generated as a result of a sync", asyncTest(async () => {
// When a note is modified an item_change object is going to be created. This
// is used for example to tell the search engine, when note should be indexed. It is
// also used by the revision service to tell what note should get a new revision.
// When a note is modified via sync, this item_change object is also created. The issue
// is that we don't want to create revisions for these particular item_changes, because
// such revision has already been created on another client (whatever client initially
// modified the note), and that rev is going to be synced.
//
// So in the end we need to make sure that we don't create these unecessary additional revisions.
const n1 = await Note.save({ title: 'testing' });
await synchronizer().start();
await switchClient(2);
await synchronizer().start();
await Note.save({ id: n1.id, title: 'mod from client 2' });
await revisionService().collectRevisions();
await synchronizer().start();
await switchClient(1);
await synchronizer().start();
{
const allRevs = await Revision.allByType(BaseModel.TYPE_NOTE, n1.id);
expect(allRevs.length).toBe(1);
}
await revisionService().collectRevisions();
{
const allRevs = await Revision.allByType(BaseModel.TYPE_NOTE, n1.id);
expect(allRevs.length).toBe(1);
}
}));
it("should handle case when new rev is created on client, then older rev arrives later via sync", asyncTest(async () => {
// - C1 creates note 1
// - C1 modifies note 1 - REV1 created
// - C1 sync
// - C2 sync
// - C2 receives note 1
// - C2 modifies note 1 - REV2 created (but not based on REV1)
// - C2 receives REV1
//
// In that case, we need to make sure that REV1 and REV2 are both valid and can be retrieved.
// Even though REV1 was created before REV2, REV2 is *not* based on REV1. This is not ideal
// due to unecessary data being saved, but a possible edge case and we simply need to check
// all the data is valid.
const n1 = await Note.save({ title: 'note' });
await Note.save({ id: n1.id, title: 'note REV1' });
await revisionService().collectRevisions(); // REV1
expect((await Revision.allByType(BaseModel.TYPE_NOTE, n1.id)).length).toBe(1);
await synchronizer().start();
await switchClient(2);
synchronizer().testingHooks_ = ['skipRevisions'];
await synchronizer().start();
synchronizer().testingHooks_ = [];
await Note.save({ id: n1.id, title: 'note REV2' });
await revisionService().collectRevisions(); // REV2
expect((await Revision.allByType(BaseModel.TYPE_NOTE, n1.id)).length).toBe(1);
await synchronizer().start(); // Sync the rev that had been skipped above with skipRevisions
const revisions = await Revision.allByType(BaseModel.TYPE_NOTE, n1.id);
expect(revisions.length).toBe(2);
expect((await revisionService().revisionNote(revisions, 0)).title).toBe('note REV1');
expect((await revisionService().revisionNote(revisions, 1)).title).toBe('note REV2');
}));
it("should not download resources over the limit", asyncTest(async () => {
const note1 = await Note.save({ title: 'note' });
await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
await synchronizer().start();
await switchClient(2);
const previousMax = synchronizer().maxResourceSize_;
synchronizer().maxResourceSize_ = 1;
await synchronizer().start();
synchronizer().maxResourceSize_ = previousMax;
const syncItems = await BaseItem.allSyncItems(syncTargetId());
expect(syncItems.length).toBe(2);
expect(syncItems[1].item_location).toBe(BaseItem.SYNC_ITEM_LOCATION_REMOTE);
expect(syncItems[1].sync_disabled).toBe(1);
}));
it("should not upload a resource if it has not been fetched yet", asyncTest(async () => {
// In some rare cases, the synchronizer might try to upload a resource even though it
// doesn't have the resource file. It can happen in this situation:
// - C1 create resource
// - C1 sync
// - C2 sync
// - C2 resource metadata is received but ResourceFetcher hasn't downloaded the file yet
// - C2 enables E2EE - all the items are marked for forced sync
// - C2 sync
// The synchronizer will try to upload the resource, even though it doesn't have the file,
// so we need to make sure it doesn't. But also that once it gets the file, the resource
// does get uploaded.
const note1 = await Note.save({ title: 'note' });
await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
const resource = (await Resource.all())[0];
await Resource.setLocalState(resource.id, { fetch_status: Resource.FETCH_STATUS_IDLE });
await synchronizer().start();
expect((await remoteResources()).length).toBe(0);
await Resource.setLocalState(resource.id, { fetch_status: Resource.FETCH_STATUS_DONE });
await synchronizer().start();
expect((await remoteResources()).length).toBe(1);
}));
it('should decrypt the resource metadata, but not try to decrypt the file, if it is not present', asyncTest(async () => {
const note1 = await Note.save({ title: 'note' });
await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
const masterKey = await loadEncryptionMasterKey();
await encryptionService().enableEncryption(masterKey, '123456');
await encryptionService().loadMasterKeysFromSettings();
await synchronizer().start();
expect(await allSyncTargetItemsEncrypted()).toBe(true);
await switchClient(2);
await synchronizer().start();
Setting.setObjectKey('encryption.passwordCache', masterKey.id, '123456');
await encryptionService().loadMasterKeysFromSettings();
await decryptionWorker().start();
let resource = (await Resource.all())[0];
expect(!!resource.encryption_applied).toBe(false);
expect(!!resource.encryption_blob_encrypted).toBe(true);
const resourceFetcher = new ResourceFetcher(() => { return synchronizer().api() });
await resourceFetcher.start();
await resourceFetcher.waitForAllFinished();
const ls = await Resource.localState(resource);
expect(ls.fetch_status).toBe(Resource.FETCH_STATUS_DONE);
await decryptionWorker().start();
resource = (await Resource.all())[0];
expect(!!resource.encryption_blob_encrypted).toBe(false);
}));
});

View File

@@ -8,6 +8,7 @@ const ItemChange = require('lib/models/ItemChange.js');
const Resource = require('lib/models/Resource.js');
const Tag = require('lib/models/Tag.js');
const NoteTag = require('lib/models/NoteTag.js');
const Revision = require('lib/models/Revision.js');
const { Logger } = require('lib/logger.js');
const Setting = require('lib/models/Setting.js');
const MasterKey = require('lib/models/MasterKey');
@@ -30,13 +31,17 @@ const SyncTargetNextcloud = require('lib/SyncTargetNextcloud.js');
const SyncTargetDropbox = require('lib/SyncTargetDropbox.js');
const EncryptionService = require('lib/services/EncryptionService.js');
const DecryptionWorker = require('lib/services/DecryptionWorker.js');
const ResourceService = require('lib/services/ResourceService.js');
const RevisionService = require('lib/services/RevisionService.js');
const WebDavApi = require('lib/WebDavApi');
const DropboxApi = require('lib/DropboxApi');
let databases_ = [];
let synchronizers_ = [];
let encryptionServices_ = [];
let revisionServices_ = [];
let decryptionWorkers_ = [];
let resourceServices_ = [];
let fileApi_ = null;
let currentClient_ = 1;
@@ -69,6 +74,11 @@ const sleepTime = syncTargetId_ == SyncTargetRegistry.nameToId('filesystem') ? 1
console.info('Testing with sync target: ' + SyncTargetRegistry.idToName(syncTargetId_));
const dbLogger = new Logger();
dbLogger.addTarget('console');
dbLogger.addTarget('file', { path: logDir + '/log.txt' });
dbLogger.setLevel(Logger.LEVEL_WARN);
const logger = new Logger();
logger.addTarget('console');
logger.addTarget('file', { path: logDir + '/log.txt' });
@@ -80,6 +90,7 @@ BaseItem.loadClass('Resource', Resource);
BaseItem.loadClass('Tag', Tag);
BaseItem.loadClass('NoteTag', NoteTag);
BaseItem.loadClass('MasterKey', MasterKey);
BaseItem.loadClass('Revision', Revision);
Setting.setConstant('appId', 'net.cozic.joplin-cli');
Setting.setConstant('appType', 'cli');
@@ -102,6 +113,8 @@ function sleep(n) {
}
async function switchClient(id) {
if (!databases_[id]) throw new Error('Call setupDatabaseAndSynchronizer(' + id + ') first!!');
await time.msleep(sleepTime); // Always leave a little time so that updated_time properties don't overlap
await Setting.saveAll();
@@ -111,9 +124,11 @@ async function switchClient(id) {
Note.db_ = databases_[id];
BaseItem.db_ = databases_[id];
Setting.db_ = databases_[id];
Resource.db_ = databases_[id];
BaseItem.encryptionService_ = encryptionServices_[id];
Resource.encryptionService_ = encryptionServices_[id];
BaseItem.revisionService_ = revisionServices_[id];
Setting.setConstant('resourceDir', resourceDir(id));
@@ -125,21 +140,28 @@ async function clearDatabase(id = null) {
await ItemChange.waitForAllSaved();
let queries = [
'DELETE FROM notes',
'DELETE FROM folders',
'DELETE FROM resources',
'DELETE FROM tags',
'DELETE FROM note_tags',
'DELETE FROM master_keys',
'DELETE FROM item_changes',
'DELETE FROM note_resources',
'DELETE FROM settings',
'DELETE FROM deleted_items',
'DELETE FROM sync_items',
'DELETE FROM notes_normalized',
const tableNames = [
'notes',
'folders',
'resources',
'tags',
'note_tags',
'master_keys',
'item_changes',
'note_resources',
'settings',
'deleted_items',
'sync_items',
'notes_normalized',
'revisions',
];
const queries = [];
for (const n of tableNames) {
queries.push('DELETE FROM ' + n);
queries.push('DELETE FROM sqlite_sequence WHERE name="' + n + '"'); // Reset autoincremented IDs
}
await databases_[id].transactionExecBatch(queries);
}
@@ -164,6 +186,7 @@ async function setupDatabase(id = null) {
};
databases_[id] = new JoplinDatabase(new DatabaseDriverNode());
databases_[id].setLogger(dbLogger);
await databases_[id].open({ name: filePath });
BaseModel.db_ = databases_[id];
@@ -196,8 +219,10 @@ async function setupDatabaseAndSynchronizer(id = null) {
}
encryptionServices_[id] = new EncryptionService();
revisionServices_[id] = new RevisionService();
decryptionWorkers_[id] = new DecryptionWorker();
decryptionWorkers_[id].setEncryptionService(encryptionServices_[id]);
resourceServices_[id] = new ResourceService();
await fileApi().clearRoot();
}
@@ -217,11 +242,21 @@ function encryptionService(id = null) {
return encryptionServices_[id];
}
function revisionService(id = null) {
if (id === null) id = currentClient_;
return revisionServices_[id];
}
function decryptionWorker(id = null) {
if (id === null) id = currentClient_;
return decryptionWorkers_[id];
}
function resourceService(id = null) {
if (id === null) id = currentClient_;
return resourceServices_[id];
}
async function loadEncryptionMasterKey(id = null, useExisting = false) {
const service = encryptionService(id);
@@ -314,4 +349,34 @@ function asyncTest(callback) {
}
}
module.exports = { setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync, encryptionService, loadEncryptionMasterKey, fileContentEqual, decryptionWorker, asyncTest };
async function allSyncTargetItemsEncrypted() {
const list = await fileApi().list();
const files = list.items;
let totalCount = 0;
let encryptedCount = 0;
for (let i = 0; i < files.length; i++) {
const file = files[i];
const remoteContentString = await fileApi().get(file.path);
const remoteContent = await BaseItem.unserialize(remoteContentString);
const ItemClass = BaseItem.itemClass(remoteContent);
if (!ItemClass.encryptionSupported()) continue;
totalCount++;
if (remoteContent.type_ === BaseModel.TYPE_RESOURCE) {
const content = await fileApi().get('.resource/' + remoteContent.id);
totalCount++;
if (content.substr(0, 5) === 'JED01') output = encryptedCount++;
}
if (!!remoteContent.encryption_applied) encryptedCount++;
}
if (!totalCount) throw new Error('No encryptable item on sync target');
return totalCount === encryptedCount;
}
module.exports = { resourceService, allSyncTargetItemsEncrypted, setupDatabase, revisionService, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync, encryptionService, loadEncryptionMasterKey, fileContentEqual, decryptionWorker, asyncTest };

View File

@@ -1,3 +1,5 @@
// https://github.com/mozilla/readability/tree/814f0a3884350b6f1adfdebb79ca3599e9806605
/*eslint-env es6:false*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
@@ -496,17 +498,9 @@
},
setValue: function(newValue) {
this._value = newValue;
delete this._decodedValue;
},
setDecodedValue: function(newValue) {
this._value = encodeHTML(newValue);
this._decodedValue = newValue;
},
getDecodedValue: function() {
if (typeof this._decodedValue === "undefined") {
this._decodedValue = (this._value && decodeHTML(this._value)) || "";
}
return this._decodedValue;
getEncodedValue: function() {
return encodeHTML(this._value);
},
};
@@ -611,6 +605,13 @@
};
var Element = function (tag) {
// We use this to find the closing tag.
this._matchingTag = tag;
// We're explicitly a non-namespace aware parser, we just pretend it's all HTML.
var lastColonIndex = tag.lastIndexOf(":");
if (lastColonIndex != -1) {
tag = tag.substring(lastColonIndex + 1);
}
this.attributes = [];
this.childNodes = [];
this.children = [];
@@ -659,6 +660,14 @@
this.setAttribute("src", str);
},
get srcset() {
return this.getAttribute("srcset") || "";
},
set srcset(str) {
this.setAttribute("srcset", str);
},
get nodeName() {
return this.tagName;
},
@@ -675,9 +684,9 @@
for (var j = 0; j < child.attributes.length; j++) {
var attr = child.attributes[j];
// the attribute value will be HTML escaped.
var val = attr.value;
var val = attr.getEncodedValue();
var quote = (val.indexOf('"') === -1 ? '"' : "'");
arr.push(" " + attr.name + '=' + quote + val + quote);
arr.push(" " + attr.name + "=" + quote + val + quote);
}
if (child.localName in voidElems && !child.childNodes.length) {
@@ -753,8 +762,9 @@
getAttribute: function (name) {
for (var i = this.attributes.length; --i >= 0;) {
var attr = this.attributes[i];
if (attr.name === name)
return attr.getDecodedValue();
if (attr.name === name) {
return attr.value;
}
}
return undefined;
},
@@ -763,11 +773,11 @@
for (var i = this.attributes.length; --i >= 0;) {
var attr = this.attributes[i];
if (attr.name === name) {
attr.setDecodedValue(value);
attr.setValue(value);
return;
}
}
this.attributes.push(new Attribute(name, encodeHTML(value)));
this.attributes.push(new Attribute(name, value));
},
removeAttribute: function (name) {
@@ -778,7 +788,13 @@
break;
}
}
}
},
hasAttribute: function (name) {
return this.attributes.some(function (attr) {
return attr.name == name;
});
},
};
var Style = function (node) {
@@ -925,7 +941,7 @@
// Read the attribute value (and consume the matching quote)
var value = this.readString(c);
node.attributes.push(new Attribute(name, value));
node.attributes.push(new Attribute(name, decodeHTML(value)));
return;
},
@@ -950,7 +966,7 @@
strBuf.push(c);
c = this.nextChar();
}
var tag = strBuf.join('');
var tag = strBuf.join("");
if (!tag)
return false;
@@ -961,7 +977,9 @@
while (c !== "/" && c !== ">") {
if (c === undefined)
return false;
while (whitespace.indexOf(this.html[this.currentChar++]) != -1);
while (whitespace.indexOf(this.html[this.currentChar++]) != -1) {
// Advance cursor to first non-whitespace char.
}
this.currentChar--;
c = this.nextChar();
if (c !== "/" && c !== ">") {
@@ -1055,9 +1073,10 @@
return null;
// Read any text as Text node
var textNode;
if (c !== "<") {
--this.currentChar;
var textNode = new Text();
textNode = new Text();
var n = this.html.indexOf("<", this.currentChar);
if (n === -1) {
textNode.innerHTML = this.html.substring(this.currentChar, this.html.length);
@@ -1069,6 +1088,18 @@
return textNode;
}
if (this.match("![CDATA[")) {
var endChar = this.html.indexOf("]]>", this.currentChar);
if (endChar === -1) {
this.error("unclosed CDATA section");
return null;
}
textNode = new Text();
textNode.textContent = this.html.substring(this.currentChar, endChar);
this.currentChar = endChar + ("]]>").length;
return textNode;
}
c = this.peekNext();
// Read Comment node. Normally, Comment nodes know their inner
@@ -1100,7 +1131,7 @@
// If this isn't a void Element, read its child nodes
if (!closed) {
this.readChildren(node);
var closingTag = "</" + localName + ">";
var closingTag = "</" + node._matchingTag + ">";
if (!this.match(closingTag)) {
this.error("expected '" + closingTag + "' and got " + this.html.substr(this.currentChar, closingTag.length));
return null;

View File

@@ -0,0 +1,99 @@
// https://github.com/mozilla/readability/tree/814f0a3884350b6f1adfdebb79ca3599e9806605
/* eslint-env es6:false */
/* globals exports */
/*
* Copyright (c) 2010 Arc90 Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* This code is heavily based on Arc90's readability.js (1.7.1) script
* available at: http://code.google.com/p/arc90labs-readability
*/
var REGEXPS = {
// NOTE: These two regular expressions are duplicated in
// Readability.js. Please keep both copies in sync.
unlikelyCandidates: /-ad-|ai2html|banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|foot|gdpr|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i,
okMaybeItsACandidate: /and|article|body|column|main|shadow/i,
};
function isNodeVisible(node) {
// Have to null-check node.style to deal with SVG and MathML nodes.
return (!node.style || node.style.display != "none") && !node.hasAttribute("hidden");
}
/**
* Decides whether or not the document is reader-able without parsing the whole thing.
*
* @return boolean Whether or not we suspect Readability.parse() will suceeed at returning an article object.
*/
function isProbablyReaderable(doc, isVisible) {
if (!isVisible) {
isVisible = isNodeVisible;
}
var nodes = doc.querySelectorAll("p, pre");
// Get <div> nodes which have <br> node(s) and append them into the `nodes` variable.
// Some articles' DOM structures might look like
// <div>
// Sentences<br>
// <br>
// Sentences<br>
// </div>
var brNodes = doc.querySelectorAll("div > br");
if (brNodes.length) {
var set = new Set(nodes);
[].forEach.call(brNodes, function(node) {
set.add(node.parentNode);
});
nodes = Array.from(set);
}
var score = 0;
// This is a little cheeky, we use the accumulator 'score' to decide what to return from
// this callback:
return [].some.call(nodes, function(node) {
if (!isVisible(node))
return false;
var matchString = node.className + " " + node.id;
if (REGEXPS.unlikelyCandidates.test(matchString) &&
!REGEXPS.okMaybeItsACandidate.test(matchString)) {
return false;
}
if (node.matches("li p")) {
return false;
}
var textContentLength = node.textContent.trim().length;
if (textContentLength < 140) {
return false;
}
score += Math.sqrt(textContentLength - 140);
if (score > 20) {
return true;
}
return false;
});
}
if (typeof exports === "object") {
exports.isProbablyReaderable = isProbablyReaderable;
}

View File

@@ -1,3 +1,5 @@
// https://github.com/mozilla/readability/tree/814f0a3884350b6f1adfdebb79ca3599e9806605
/*eslint-env es6:false*/
/*
* Copyright (c) 2010 Arc90 Inc
@@ -39,6 +41,7 @@ function Readability(doc, options) {
this._articleTitle = null;
this._articleByline = null;
this._articleDir = null;
this._articleSiteName = null;
this._attempts = [];
// Configurable options
@@ -111,15 +114,18 @@ Readability.prototype = {
// All of the regular expressions in use within readability.
// Defined up here so we don't instantiate them repeatedly in loops.
REGEXPS: {
unlikelyCandidates: /banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|foot|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i,
// NOTE: These two regular expressions are duplicated in
// Readability-readerable.js. Please keep both copies in sync.
unlikelyCandidates: /-ad-|ai2html|banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|foot|gdpr|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i,
okMaybeItsACandidate: /and|article|body|column|main|shadow/i,
positive: /article|body|content|entry|hentry|h-entry|main|page|pagination|post|text|blog|story/i,
negative: /hidden|^hid$| hid$| hid |^hid |banner|combx|comment|com-|contact|foot|footer|footnote|masthead|media|meta|outbrain|promo|related|scroll|share|shoutbox|sidebar|skyscraper|sponsor|shopping|tags|tool|widget/i,
negative: /hidden|^hid$| hid$| hid |^hid |banner|combx|comment|com-|contact|foot|footer|footnote|gdpr|masthead|media|meta|outbrain|promo|related|scroll|share|shoutbox|sidebar|skyscraper|sponsor|shopping|tags|tool|widget/i,
extraneous: /print|archive|comment|discuss|e[\-]?mail|share|reply|all|login|sign|single|utility/i,
byline: /byline|author|dateline|writtenby|p-author/i,
replaceFonts: /<(\/?)font[^>]*>/gi,
normalize: /\s{2,}/g,
videos: /\/\/(www\.)?(dailymotion|youtube|youtube-nocookie|player\.vimeo)\.com/i,
videos: /\/\/(www\.)?((dailymotion|youtube|youtube-nocookie|player\.vimeo|v\.qq)\.com|(archive|upload\.wikimedia)\.org|player\.twitch\.tv)/i,
nextLink: /(next|weiter|continue|>([^\|]|$)|»([^\|]|$))/i,
prevLink: /(prev|earl|old|new|<|«)/i,
whitespace: /^\s*$/,
@@ -260,7 +266,7 @@ Readability.prototype = {
_getAllNodesWithTag: function(node, tagNames) {
if (node.querySelectorAll) {
return node.querySelectorAll(tagNames.join(','));
return node.querySelectorAll(tagNames.join(","));
}
return [].concat.apply([], tagNames.map(function(tag) {
var collection = node.getElementsByTagName(tag);
@@ -320,7 +326,7 @@ Readability.prototype = {
return uri;
}
var links = articleContent.getElementsByTagName("a");
var links = this._getAllNodesWithTag(articleContent, ["a"]);
this._forEachNode(links, function(link) {
var href = link.getAttribute("href");
if (href) {
@@ -335,7 +341,7 @@ Readability.prototype = {
}
});
var imgs = articleContent.getElementsByTagName("img");
var imgs = this._getAllNodesWithTag(articleContent, ["img"]);
this._forEachNode(imgs, function(img) {
var src = img.getAttribute("src");
if (src) {
@@ -355,11 +361,11 @@ Readability.prototype = {
var origTitle = "";
try {
curTitle = origTitle = doc.title;
curTitle = origTitle = doc.title.trim();
// If they had an element with id "title" in their HTML
if (typeof curTitle !== "string")
curTitle = origTitle = this._getInnerText(doc.getElementsByTagName('title')[0]);
curTitle = origTitle = this._getInnerText(doc.getElementsByTagName("title")[0]);
} catch (e) {/* ignore exceptions setting the title. */}
var titleHadHierarchicalSeparators = false;
@@ -370,44 +376,45 @@ Readability.prototype = {
// If there's a separator in the title, first remove the final part
if ((/ [\|\-\\\/>»] /).test(curTitle)) {
titleHadHierarchicalSeparators = / [\\\/>»] /.test(curTitle);
curTitle = origTitle.replace(/(.*)[\|\-\\\/>»] .*/gi, '$1');
curTitle = origTitle.replace(/(.*)[\|\-\\\/>»] .*/gi, "$1");
// If the resulting title is too short (3 words or fewer), remove
// the first part instead:
if (wordCount(curTitle) < 3)
curTitle = origTitle.replace(/[^\|\-\\\/>»]*[\|\-\\\/>»](.*)/gi, '$1');
} else if (curTitle.indexOf(': ') !== -1) {
curTitle = origTitle.replace(/[^\|\-\\\/>»]*[\|\-\\\/>»](.*)/gi, "$1");
} else if (curTitle.indexOf(": ") !== -1) {
// Check if we have an heading containing this exact string, so we
// could assume it's the full title.
var headings = this._concatNodeLists(
doc.getElementsByTagName('h1'),
doc.getElementsByTagName('h2')
doc.getElementsByTagName("h1"),
doc.getElementsByTagName("h2")
);
var trimmedTitle = curTitle.trim();
var match = this._someNode(headings, function(heading) {
return heading.textContent === curTitle;
return heading.textContent.trim() === trimmedTitle;
});
// If we don't, let's extract the title out of the original title string.
if (!match) {
curTitle = origTitle.substring(origTitle.lastIndexOf(':') + 1);
curTitle = origTitle.substring(origTitle.lastIndexOf(":") + 1);
// If the title is now too short, try the first colon instead:
if (wordCount(curTitle) < 3) {
curTitle = origTitle.substring(origTitle.indexOf(':') + 1);
curTitle = origTitle.substring(origTitle.indexOf(":") + 1);
// But if we have too many words before the colon there's something weird
// with the titles and the H tags so let's just use the original title instead
} else if (wordCount(origTitle.substr(0, origTitle.indexOf(':'))) > 5) {
} else if (wordCount(origTitle.substr(0, origTitle.indexOf(":"))) > 5) {
curTitle = origTitle;
}
}
} else if (curTitle.length > 150 || curTitle.length < 15) {
var hOnes = doc.getElementsByTagName('h1');
var hOnes = doc.getElementsByTagName("h1");
if (hOnes.length === 1)
curTitle = this._getInnerText(hOnes[0]);
}
curTitle = curTitle.trim();
curTitle = curTitle.trim().replace(this.REGEXPS.normalize, " ");
// If we now have 4 words or fewer as our title, and either no
// 'hierarchical' separators (\, /, > or ») were found in the original
// title or we decreased the number of words by more than 1 word, use
@@ -497,7 +504,8 @@ Readability.prototype = {
break;
}
if (!this._isPhrasingContent(next)) break;
if (!this._isPhrasingContent(next))
break;
// Otherwise, make this node a child of the new <p>.
var sibling = next.nextSibling;
@@ -505,7 +513,12 @@ Readability.prototype = {
next = sibling;
}
while (p.lastChild && this._isWhitespace(p.lastChild)) p.removeChild(p.lastChild);
while (p.lastChild && this._isWhitespace(p.lastChild)) {
p.removeChild(p.lastChild);
}
if (p.parentNode.tagName === "P")
this._setNodeTag(p.parentNode, "DIV");
}
});
},
@@ -527,7 +540,16 @@ Readability.prototype = {
replacement.readability = node.readability;
for (var i = 0; i < node.attributes.length; i++) {
replacement.setAttribute(node.attributes[i].name, node.attributes[i].value);
try {
replacement.setAttribute(node.attributes[i].name, node.attributes[i].value);
} catch (ex) {
/* it's possible for setAttribute() to throw if the attribute name
* isn't a valid XML Name. Such attributes can however be parsed from
* source in HTML docs, see https://github.com/whatwg/html/issues/4275,
* so we can hit them here and then throw. We don't care about such
* attributes so we ignore them.
*/
}
}
return replacement;
},
@@ -547,6 +569,8 @@ Readability.prototype = {
// visually linked to other content-ful elements (text, images, etc.).
this._markDataTables(articleContent);
this._fixLazyImages(articleContent);
// Clean out junk from the article content
this._cleanConditionally(articleContent, "form");
this._cleanConditionally(articleContent, "fieldset");
@@ -557,16 +581,21 @@ Readability.prototype = {
this._clean(articleContent, "link");
this._clean(articleContent, "aside");
// Clean out elements have "share" in their id/class combinations from final top candidates,
// Clean out elements with little content that have "share" in their id/class combinations from final top candidates,
// which means we don't remove the top candidates even they have "share".
this._forEachNode(articleContent.children, function(topCandidate) {
this._cleanMatchedNodes(topCandidate, /share/);
var shareElementThreshold = this.DEFAULT_CHAR_THRESHOLD;
this._forEachNode(articleContent.children, function (topCandidate) {
this._cleanMatchedNodes(topCandidate, function (node, matchString) {
return /share/.test(matchString) && node.textContent.length < shareElementThreshold;
});
});
// If there is only one h2 and its text content substantially equals article title,
// they are probably using it as a header and not a subheader,
// so remove it since we already extract the title separately.
var h2 = articleContent.getElementsByTagName('h2');
var h2 = articleContent.getElementsByTagName("h2");
if (h2.length === 1) {
var lengthSimilarRate = (h2[0].textContent.length - this._articleTitle.length) / this._articleTitle.length;
if (Math.abs(lengthSimilarRate) < 0.5) {
@@ -596,12 +625,12 @@ Readability.prototype = {
this._cleanConditionally(articleContent, "div");
// Remove extra paragraphs
this._removeNodes(articleContent.getElementsByTagName('p'), function (paragraph) {
var imgCount = paragraph.getElementsByTagName('img').length;
var embedCount = paragraph.getElementsByTagName('embed').length;
var objectCount = paragraph.getElementsByTagName('object').length;
this._removeNodes(articleContent.getElementsByTagName("p"), function (paragraph) {
var imgCount = paragraph.getElementsByTagName("img").length;
var embedCount = paragraph.getElementsByTagName("embed").length;
var objectCount = paragraph.getElementsByTagName("object").length;
// At this point, nasty iframes have been removed, only remain embedded video ones.
var iframeCount = paragraph.getElementsByTagName('iframe').length;
var iframeCount = paragraph.getElementsByTagName("iframe").length;
var totalCount = imgCount + embedCount + objectCount + iframeCount;
return totalCount === 0 && !this._getInnerText(paragraph, false);
@@ -612,6 +641,19 @@ Readability.prototype = {
if (next && next.tagName == "P")
br.parentNode.removeChild(br);
});
// Remove single-cell tables
this._forEachNode(this._getAllNodesWithTag(articleContent, ["table"]), function(table) {
var tbody = this._hasSingleTagInsideElement(table, "TBODY") ? table.firstElementChild : table;
if (this._hasSingleTagInsideElement(tbody, "TR")) {
var row = tbody.firstElementChild;
if (this._hasSingleTagInsideElement(row, "TD")) {
var cell = row.firstElementChild;
cell = this._setNodeTag(cell, this._everyNode(cell.childNodes, this._isPhrasingContent) ? "P" : "DIV");
table.parentNode.replaceChild(cell, table);
}
}
});
},
/**
@@ -625,34 +667,34 @@ Readability.prototype = {
node.readability = {"contentScore": 0};
switch (node.tagName) {
case 'DIV':
case "DIV":
node.readability.contentScore += 5;
break;
case 'PRE':
case 'TD':
case 'BLOCKQUOTE':
case "PRE":
case "TD":
case "BLOCKQUOTE":
node.readability.contentScore += 3;
break;
case 'ADDRESS':
case 'OL':
case 'UL':
case 'DL':
case 'DD':
case 'DT':
case 'LI':
case 'FORM':
case "ADDRESS":
case "OL":
case "UL":
case "DL":
case "DD":
case "DT":
case "LI":
case "FORM":
node.readability.contentScore -= 3;
break;
case 'H1':
case 'H2':
case 'H3':
case 'H4':
case 'H5':
case 'H6':
case 'TH':
case "H1":
case "H2":
case "H3":
case "H4":
case "H5":
case "H6":
case "TH":
node.readability.contentScore -= 5;
break;
}
@@ -691,37 +733,6 @@ Readability.prototype = {
return node && node.nextElementSibling;
},
/**
* Like _getNextNode, but for DOM implementations with no
* firstElementChild/nextElementSibling functionality...
*/
_getNextNodeNoElementProperties: function(node, ignoreSelfAndKids) {
function nextSiblingEl(n) {
do {
n = n.nextSibling;
} while (n && n.nodeType !== n.ELEMENT_NODE);
return n;
}
// First check for kids if those aren't being ignored
if (!ignoreSelfAndKids && node.children[0]) {
return node.children[0];
}
// Then for siblings...
var next = nextSiblingEl(node);
if (next) {
return next;
}
// And finally, move up the parent chain *and* find a sibling
// (because this is depth-first traversal, we will have already
// seen the parent nodes themselves).
do {
node = node.parentNode;
if (node)
next = nextSiblingEl(node);
} while (node && !next);
return node && next;
},
_checkByline: function(node, matchString) {
if (this._articleByline) {
return false;
@@ -729,9 +740,10 @@ Readability.prototype = {
if (node.getAttribute !== undefined) {
var rel = node.getAttribute("rel");
var itemprop = node.getAttribute("itemprop");
}
if ((rel === "author" || this.REGEXPS.byline.test(matchString)) && this._isValidByline(node.textContent)) {
if ((rel === "author" || (itemprop && itemprop.indexOf("author") !== -1) || this.REGEXPS.byline.test(matchString)) && this._isValidByline(node.textContent)) {
this._articleByline = node.textContent.trim();
return true;
}
@@ -784,6 +796,12 @@ Readability.prototype = {
while (node) {
var matchString = node.className + " " + node.id;
if (!this._isProbablyVisible(node)) {
this.log("Removing hidden node - " + matchString);
node = this._removeAndGetNext(node);
continue;
}
// Check to see if this node is a byline, and remove it if it is.
if (this._checkByline(node, matchString)) {
node = this._removeAndGetNext(node);
@@ -794,6 +812,7 @@ Readability.prototype = {
if (stripUnlikelyCandidates) {
if (this.REGEXPS.unlikelyCandidates.test(matchString) &&
!this.REGEXPS.okMaybeItsACandidate.test(matchString) &&
!this._hasAncestorTag(node, "table") &&
node.tagName !== "BODY" &&
node.tagName !== "A") {
this.log("Removing unlikely candidate - " + matchString);
@@ -826,12 +845,14 @@ Readability.prototype = {
if (p !== null) {
p.appendChild(childNode);
} else if (!this._isWhitespace(childNode)) {
p = doc.createElement('p');
p = doc.createElement("p");
node.replaceChild(p, childNode);
p.appendChild(childNode);
}
} else if (p !== null) {
while (p.lastChild && this._isWhitespace(p.lastChild)) p.removeChild(p.lastChild);
while (p.lastChild && this._isWhitespace(p.lastChild)) {
p.removeChild(p.lastChild);
}
p = null;
}
childNode = nextSibling;
@@ -841,7 +862,7 @@ Readability.prototype = {
// element. DIVs with only a P element inside and no text content can be
// safely converted into plain P elements to avoid confusing the scoring
// algorithm with DIVs with are, in practice, paragraphs.
if (this._hasSinglePInsideElement(node) && this._getLinkDensity(node) < 0.25) {
if (this._hasSingleTagInsideElement(node, "P") && this._getLinkDensity(node) < 0.25) {
var newNode = node.children[0];
node.parentNode.replaceChild(newNode, node);
node = newNode;
@@ -862,7 +883,7 @@ Readability.prototype = {
**/
var candidates = [];
this._forEachNode(elementsToScore, function(elementToScore) {
if (!elementToScore.parentNode || typeof(elementToScore.parentNode.tagName) === 'undefined')
if (!elementToScore.parentNode || typeof(elementToScore.parentNode.tagName) === "undefined")
return;
// If this paragraph is less than 25 characters, don't even count it.
@@ -881,17 +902,17 @@ Readability.prototype = {
contentScore += 1;
// Add points for any commas within this paragraph.
contentScore += innerText.split(',').length;
contentScore += innerText.split(",").length;
// For every 100 characters in this paragraph, add another point. Up to 3 points.
contentScore += Math.min(Math.floor(innerText.length / 100), 3);
// Initialize and score ancestors.
this._forEachNode(ancestors, function(ancestor, level) {
if (!ancestor.tagName || !ancestor.parentNode || typeof(ancestor.parentNode.tagName) === 'undefined')
if (!ancestor.tagName || !ancestor.parentNode || typeof(ancestor.parentNode.tagName) === "undefined")
return;
if (typeof(ancestor.readability) === 'undefined') {
if (typeof(ancestor.readability) === "undefined") {
this._initializeNode(ancestor);
candidates.push(ancestor);
}
@@ -922,7 +943,7 @@ Readability.prototype = {
var candidateScore = candidate.readability.contentScore * (1 - this._getLinkDensity(candidate));
candidate.readability.contentScore = candidateScore;
this.log('Candidate:', candidate, "with score " + candidateScore);
this.log("Candidate:", candidate, "with score " + candidateScore);
for (var t = 0; t < this._nbTopCandidates; t++) {
var aTopCandidate = topCandidates[t];
@@ -1041,8 +1062,8 @@ Readability.prototype = {
var sibling = siblings[s];
var append = false;
this.log("Looking at sibling node:", sibling, sibling.readability ? ("with score " + sibling.readability.contentScore) : '');
this.log("Sibling has score", sibling.readability ? sibling.readability.contentScore : 'Unknown');
this.log("Looking at sibling node:", sibling, sibling.readability ? ("with score " + sibling.readability.contentScore) : "");
this.log("Sibling has score", sibling.readability ? sibling.readability.contentScore : "Unknown");
if (sibling === topCandidate) {
append = true;
@@ -1076,7 +1097,7 @@ Readability.prototype = {
if (this.ALTER_TO_DIV_EXCEPTIONS.indexOf(sibling.nodeName) === -1) {
// We have a node that isn't a common block level element, like a form or td tag.
// Turn it into a div so it doesn't get filtered out later by accident.
this.log("Altering sibling:", sibling, 'to div.');
this.log("Altering sibling:", sibling, "to div.");
sibling = this._setNodeTag(sibling, "DIV");
}
@@ -1144,7 +1165,7 @@ Readability.prototype = {
this._attempts.push({articleContent: articleContent, textLength: textLength});
// No luck after removing flags, just return the longest text we found during the different loops
this._attempts.sort(function (a, b) {
return a.textLength < b.textLength;
return b.textLength - a.textLength;
});
// But first check if we actually have something
@@ -1184,7 +1205,7 @@ Readability.prototype = {
* @return Boolean - whether the input string is a byline.
*/
_isValidByline: function(byline) {
if (typeof byline == 'string' || byline instanceof String) {
if (typeof byline == "string" || byline instanceof String) {
byline = byline.trim();
return (byline.length > 0) && (byline.length < 100);
}
@@ -1201,61 +1222,75 @@ Readability.prototype = {
var values = {};
var metaElements = this._doc.getElementsByTagName("meta");
// Match "description", or Twitter's "twitter:description" (Cards)
// in name attribute.
var namePattern = /^\s*((twitter)\s*:\s*)?(description|title)\s*$/gi;
// property is a space-separated list of values
var propertyPattern = /\s*(dc|dcterm|og|twitter)\s*:\s*(author|creator|description|title|site_name)\s*/gi;
// Match Facebook's Open Graph title & description properties.
var propertyPattern = /^\s*og\s*:\s*(description|title)\s*$/gi;
// name is a single value
var namePattern = /^\s*(?:(dc|dcterm|og|twitter|weibo:(article|webpage))\s*[\.:]\s*)?(author|creator|description|title|site_name)\s*$/i;
// Find description tags.
this._forEachNode(metaElements, function(element) {
var elementName = element.getAttribute("name");
var elementProperty = element.getAttribute("property");
if ([elementName, elementProperty].indexOf("author") !== -1) {
metadata.byline = element.getAttribute("content");
var content = element.getAttribute("content");
if (!content) {
return;
}
var matches = null;
var name = null;
if (namePattern.test(elementName)) {
name = elementName;
} else if (propertyPattern.test(elementProperty)) {
name = elementProperty;
}
if (name) {
var content = element.getAttribute("content");
if (elementProperty) {
matches = elementProperty.match(propertyPattern);
if (matches) {
for (var i = matches.length - 1; i >= 0; i--) {
// Convert to lowercase, and remove any whitespace
// so we can match below.
name = matches[i].toLowerCase().replace(/\s/g, "");
// multiple authors
values[name] = content.trim();
}
}
}
if (!matches && elementName && namePattern.test(elementName)) {
name = elementName;
if (content) {
// Convert to lowercase and remove any whitespace
// so we can match below.
name = name.toLowerCase().replace(/\s/g, '');
// Convert to lowercase, remove any whitespace, and convert dots
// to colons so we can match below.
name = name.toLowerCase().replace(/\s/g, "").replace(/\./g, ":");
values[name] = content.trim();
}
}
});
if ("description" in values) {
metadata.excerpt = values["description"];
} else if ("og:description" in values) {
// Use facebook open graph description.
metadata.excerpt = values["og:description"];
} else if ("twitter:description" in values) {
// Use twitter cards description.
metadata.excerpt = values["twitter:description"];
// get title
metadata.title = values["dc:title"] ||
values["dcterm:title"] ||
values["og:title"] ||
values["weibo:article:title"] ||
values["weibo:webpage:title"] ||
values["title"] ||
values["twitter:title"];
if (!metadata.title) {
metadata.title = this._getArticleTitle();
}
metadata.title = this._getArticleTitle();
if (!metadata.title) {
if ("og:title" in values) {
// Use facebook open graph title.
metadata.title = values["og:title"];
} else if ("twitter:title" in values) {
// Use twitter cards title.
metadata.title = values["twitter:title"];
}
}
// get author
metadata.byline = values["dc:creator"] ||
values["dcterm:creator"] ||
values["author"];
// get description
metadata.excerpt = values["dc:description"] ||
values["dcterm:description"] ||
values["og:description"] ||
values["weibo:article:description"] ||
values["weibo:webpage:description"] ||
values["description"] ||
values["twitter:description"];
// get site name
metadata.siteName = values["og:site_name"];
return metadata;
},
@@ -1266,24 +1301,25 @@ Readability.prototype = {
* @param Element
**/
_removeScripts: function(doc) {
this._removeNodes(doc.getElementsByTagName('script'), function(scriptNode) {
this._removeNodes(doc.getElementsByTagName("script"), function(scriptNode) {
scriptNode.nodeValue = "";
scriptNode.removeAttribute('src');
scriptNode.removeAttribute("src");
return true;
});
this._removeNodes(doc.getElementsByTagName('noscript'));
this._removeNodes(doc.getElementsByTagName("noscript"));
},
/**
* Check if this node has only whitespace and a single P element
* Check if this node has only whitespace and a single element with given tag
* Returns false if the DIV node contains non-empty text nodes
* or if it contains no P or more than 1 element.
* or if it contains no element with given tag or more than 1 element.
*
* @param Element
* @param string tag of child element
**/
_hasSinglePInsideElement: function(element) {
// There should be exactly 1 element child which is a P:
if (element.children.length != 1 || element.children[0].tagName !== "P") {
_hasSingleTagInsideElement: function(element, tag) {
// There should be exactly 1 element child with given tag
if (element.children.length != 1 || element.children[0].tagName !== tag) {
return false;
}
@@ -1337,7 +1373,7 @@ Readability.prototype = {
* @return string
**/
_getInnerText: function(e, normalizeSpaces) {
normalizeSpaces = (typeof normalizeSpaces === 'undefined') ? true : normalizeSpaces;
normalizeSpaces = (typeof normalizeSpaces === "undefined") ? true : normalizeSpaces;
var textContent = e.textContent.trim();
if (normalizeSpaces) {
@@ -1366,7 +1402,7 @@ Readability.prototype = {
* @return void
**/
_cleanStyles: function(e) {
if (!e || e.tagName.toLowerCase() === 'svg')
if (!e || e.tagName.toLowerCase() === "svg")
return;
// Remove `style` and deprecated presentational attributes
@@ -1375,8 +1411,8 @@ Readability.prototype = {
}
if (this.DEPRECATED_SIZE_ATTRIBUTE_ELEMS.indexOf(e.tagName) !== -1) {
e.removeAttribute('width');
e.removeAttribute('height');
e.removeAttribute("width");
e.removeAttribute("height");
}
var cur = e.firstElementChild;
@@ -1422,7 +1458,7 @@ Readability.prototype = {
var weight = 0;
// Look for a special classname
if (typeof(e.className) === 'string' && e.className !== '') {
if (typeof(e.className) === "string" && e.className !== "") {
if (this.REGEXPS.negative.test(e.className))
weight -= 25;
@@ -1431,7 +1467,7 @@ Readability.prototype = {
}
// Look for a special ID
if (typeof(e.id) === 'string' && e.id !== '') {
if (typeof(e.id) === "string" && e.id !== "") {
if (this.REGEXPS.negative.test(e.id))
weight -= 25;
@@ -1456,17 +1492,17 @@ Readability.prototype = {
this._removeNodes(e.getElementsByTagName(tag), function(element) {
// Allow youtube and vimeo videos through as people usually want to see those.
if (isEmbed) {
var attributeValues = [].map.call(element.attributes, function(attr) {
return attr.value;
}).join("|");
// First, check the elements attributes to see if any of them contain youtube or vimeo
if (this.REGEXPS.videos.test(attributeValues))
return false;
for (var i = 0; i < element.attributes.length; i++) {
if (this.REGEXPS.videos.test(element.attributes[i].value)) {
return false;
}
}
// Then check the elements inside this element for the same.
if (this.REGEXPS.videos.test(element.innerHTML))
// For embed with <object> tag, check inner HTML as well.
if (element.tagName === "object" && this.REGEXPS.videos.test(element.innerHTML)) {
return false;
}
}
return true;
@@ -1584,6 +1620,39 @@ Readability.prototype = {
}
},
/* convert images and figures that have properties like data-src into images that can be loaded without JS */
_fixLazyImages: function (root) {
this._forEachNode(this._getAllNodesWithTag(root, ["img", "picture", "figure"]), function (elem) {
// also check for "null" to work around https://github.com/jsdom/jsdom/issues/2580
if ((!elem.src && (!elem.srcset || elem.srcset == "null")) || elem.className.toLowerCase().indexOf("lazy") !== -1) {
for (var i = 0; i < elem.attributes.length; i++) {
var attr = elem.attributes[i];
if (attr.name === "src" || attr.name === "srcset") {
continue;
}
var copyTo = null;
if (/\.(jpg|jpeg|png|webp)\s+\d/.test(attr.value)) {
copyTo = "srcset";
} else if (/^\s*\S+\.(jpg|jpeg|png|webp)\S*\s*$/.test(attr.value)) {
copyTo = "src";
}
if (copyTo) {
//if this is an img or picture, set the attribute directly
if (elem.tagName === "IMG" || elem.tagName === "PICTURE") {
elem.setAttribute(copyTo, attr.value);
} else if (elem.tagName === "FIGURE" && !this._getAllNodesWithTag(elem, ["img", "picture"]).length) {
//if the item is a <figure> that does not contain an image or picture, create one and place it inside the figure
//see the nytimes-3 testcase for an example
var img = this._doc.createElement("img");
img.setAttribute(copyTo, attr.value);
elem.appendChild(img);
}
}
}
}
});
},
/**
* Clean an element of all tags of type "tag" if they look fishy.
* "Fishy" is an algorithm based on content length, classnames, link density, number of images & embeds, etc.
@@ -1602,11 +1671,16 @@ Readability.prototype = {
//
// TODO: Consider taking into account original contentScore here.
this._removeNodes(e.getElementsByTagName(tag), function(node) {
// First check if we're in a data table, in which case don't remove us.
// First check if this node IS data table, in which case don't remove it.
var isDataTable = function(t) {
return t._readabilityDataTable;
};
if (tag === "table" && isDataTable(node)) {
return false;
}
// Next check if we're inside a data table, in which case don't remove it as well.
if (this._hasAncestorTag(node, "table", -1, isDataTable)) {
return false;
}
@@ -1620,7 +1694,7 @@ Readability.prototype = {
return true;
}
if (this._getCharCount(node, ',') < 10) {
if (this._getCharCount(node, ",") < 10) {
// If there are not very many commas, and the number of
// non-paragraph elements is more than paragraphs or other
// ominous signs, remove the element.
@@ -1630,10 +1704,25 @@ Readability.prototype = {
var input = node.getElementsByTagName("input").length;
var embedCount = 0;
var embeds = node.getElementsByTagName("embed");
for (var ei = 0, il = embeds.length; ei < il; ei += 1) {
if (!this.REGEXPS.videos.test(embeds[ei].src))
embedCount += 1;
var embeds = this._concatNodeLists(
node.getElementsByTagName("object"),
node.getElementsByTagName("embed"),
node.getElementsByTagName("iframe"));
for (var i = 0; i < embeds.length; i++) {
// If this embed has attribute that matches video regex, don't delete it.
for (var j = 0; j < embeds[i].attributes.length; j++) {
if (this.REGEXPS.videos.test(embeds[i].attributes[j].value)) {
return false;
}
}
// For embed with <object> tag, check inner HTML as well.
if (embeds[i].tagName === "object" && this.REGEXPS.videos.test(embeds[i].innerHTML)) {
return false;
}
embedCount++;
}
var linkDensity = this._getLinkDensity(node);
@@ -1654,17 +1743,17 @@ Readability.prototype = {
},
/**
* Clean out elements whose id/class combinations match specific string.
* Clean out elements that match the specified conditions
*
* @param Element
* @param RegExp match id/class combination.
* @param Function determines whether a node should be removed
* @return void
**/
_cleanMatchedNodes: function(e, regex) {
_cleanMatchedNodes: function(e, filter) {
var endOfSearchMarkerNode = this._getNextNode(e, true);
var next = this._getNextNode(e);
while (next && next != endOfSearchMarkerNode) {
if (regex.test(next.className + " " + next.id)) {
if (filter(next, next.className + " " + next.id)) {
next = this._removeAndGetNext(next);
} else {
next = this._getNextNode(next);
@@ -1680,7 +1769,7 @@ Readability.prototype = {
**/
_cleanHeaders: function(e) {
for (var headerIndex = 1; headerIndex < 3; headerIndex += 1) {
this._removeNodes(e.getElementsByTagName('h' + headerIndex), function (header) {
this._removeNodes(e.getElementsByTagName("h" + headerIndex), function (header) {
return this._getClassWeight(header) < 0;
});
}
@@ -1694,63 +1783,8 @@ Readability.prototype = {
this._flags = this._flags & ~flag;
},
/**
* Decides whether or not the document is reader-able without parsing the whole thing.
*
* @return boolean Whether or not we suspect parse() will suceeed at returning an article object.
*/
isProbablyReaderable: function(helperIsVisible) {
var nodes = this._getAllNodesWithTag(this._doc, ["p", "pre"]);
// Get <div> nodes which have <br> node(s) and append them into the `nodes` variable.
// Some articles' DOM structures might look like
// <div>
// Sentences<br>
// <br>
// Sentences<br>
// </div>
var brNodes = this._getAllNodesWithTag(this._doc, ["div > br"]);
if (brNodes.length) {
var set = new Set();
[].forEach.call(brNodes, function(node) {
set.add(node.parentNode);
});
nodes = [].concat.apply(Array.from(set), nodes);
}
// FIXME we should have a fallback for helperIsVisible, but this is
// problematic because of jsdom's elem.style handling - see
// https://github.com/mozilla/readability/pull/186 for context.
var score = 0;
// This is a little cheeky, we use the accumulator 'score' to decide what to return from
// this callback:
return this._someNode(nodes, function(node) {
if (helperIsVisible && !helperIsVisible(node))
return false;
var matchString = node.className + " " + node.id;
if (this.REGEXPS.unlikelyCandidates.test(matchString) &&
!this.REGEXPS.okMaybeItsACandidate.test(matchString)) {
return false;
}
if (node.matches && node.matches("li p")) {
return false;
}
var textContentLength = node.textContent.trim().length;
if (textContentLength < 140) {
return false;
}
score += Math.sqrt(textContentLength - 140);
if (score > 20) {
return true;
}
return false;
});
_isProbablyVisible: function(node) {
return (!node.style || node.style.display != "none") && !node.hasAttribute("hidden");
},
/**
@@ -1774,9 +1808,6 @@ Readability.prototype = {
}
}
if (typeof this._doc.documentElement.firstElementChild === "undefined") {
this._getNextNode = this._getNextNodeNoElementProperties;
}
// Remove script tags from the document.
this._removeScripts(this._doc);
@@ -1812,6 +1843,7 @@ Readability.prototype = {
textContent: textContent,
length: textContent.length,
excerpt: metadata.excerpt,
siteName: metadata.siteName || this._articleSiteName
};
}
};

View File

@@ -14,6 +14,20 @@
browserSupportsPromises_ = false;
}
function absoluteUrl(url) {
if (!url) return url;
const protocol = url.toLowerCase().split(':')[0];
if (['http', 'https', 'file'].indexOf(protocol) >= 0) return url;
if (url.indexOf('//')) {
return location.protocol + url;
} else if (url[0] === '/') {
return location.protocol + '//' + location.host + url;
} else {
return baseUrl() + '/' + url;
}
}
function pageTitle() {
const titleElements = document.getElementsByTagName("title");
if (titleElements.length) return titleElements[0].text.trim();
@@ -30,12 +44,13 @@
return output;
}
function getImageSizes(element) {
function getImageSizes(element, forceAbsoluteUrls = false) {
const images = element.getElementsByTagName('img');
const output = {};
for (let i = 0; i < images.length; i++) {
const img = images[i];
output[img.src] = {
const src = forceAbsoluteUrls ? absoluteUrl(img.src) : img.src;
output[src] = {
width: img.width,
height: img.height,
naturalWidth: img.naturalWidth,
@@ -46,7 +61,7 @@
}
// Cleans up element by removing all its invisible children (which we don't want to render as Markdown)
function cleanUpElement(element) {
function cleanUpElement(element, imageSizes) {
const childNodes = element.childNodes;
for (let i = 0; i < childNodes.length; i++) {
@@ -58,11 +73,27 @@
if (!isVisible) {
element.removeChild(node);
} else {
cleanUpElement(node);
if (node.nodeName.toLowerCase() === 'img') {
node.src = absoluteUrl(node.src);
const imageSize = imageSizes[node.src];
if (imageSize) {
node.width = imageSize.width;
node.height = imageSize.height;
}
}
cleanUpElement(node, imageSizes);
}
}
}
function documentForReadability() {
// Readability directly change the passed document so clone it so as
// to preserve the original web page.
return document.cloneNode(true);
}
function readabilityProcess() {
var uri = {
spec: location.href,
@@ -72,10 +103,7 @@
pathBase: location.protocol + "//" + location.host + location.pathname.substr(0, location.pathname.lastIndexOf("/") + 1)
};
// Readability directly change the passed document so clone it so as
// to preserve the original web page.
const documentClone = document.cloneNode(true);
const readability = new Readability(documentClone); // new window.Readability(uri, documentClone);
const readability = new Readability(documentForReadability());
const article = readability.parse();
if (!article) throw new Error('Could not parse HTML document with Readability');
@@ -117,11 +145,18 @@
}
return clippedContentResponse(article.title, article.body, getImageSizes(document));
} else if (command.name === "isProbablyReaderable") {
const ok = isProbablyReaderable(documentForReadability());
console.info('isProbablyReaderable', ok);
return { name: 'isProbablyReaderable', value: ok };
} else if (command.name === "completePageHtml") {
const cleanDocument = document.body.cloneNode(true);
cleanUpElement(cleanDocument);
return clippedContentResponse(pageTitle(), cleanDocument.innerHTML, getImageSizes(document));
const imageSizes = getImageSizes(document, true);
cleanUpElement(cleanDocument, imageSizes);
return clippedContentResponse(pageTitle(), cleanDocument.innerHTML, imageSizes);
} else if (command.name === "selectedHtml") {
@@ -250,6 +285,7 @@
return {};
} else if (command.name === "pageUrl") {
let url = location.origin + location.pathname + location.search;
return clippedContentResponse(pageTitle(), url, getImageSizes(document));

View File

@@ -1,9 +1,9 @@
{
"manifest_version": 2,
"name": "Joplin Web Clipper [DEV]",
"version": "1.0.10",
"version": "1.0.14",
"description": "Capture and save web pages and screenshots from your browser to Joplin.",
"homepage_url": "https://joplin.cozic.net",
"homepage_url": "https://joplinapp.org",
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
"icons": {
"32": "icons/32.png",

View File

@@ -0,0 +1 @@
INLINE_RUNTIME_CHUNK=false

View File

@@ -7,6 +7,39 @@ import led_orange from './led_orange.png';
const { connect } = require('react-redux');
const { bridge } = require('./bridge');
class PreviewComponent extends React.PureComponent {
constructor() {
super();
this.bodyRef = React.createRef();
}
componentDidMount() {
// Because the text size is made twice smaller with CSS, we need
// to also reduce the size of the images
const imgs = this.bodyRef.current.getElementsByTagName('img');
for (const img of imgs) {
img.width /= 2;
img.height /= 2;
}
}
render() {
return (
<div className="Preview">
<a className={"Confirm Button"} onClick={this.props.onConfirmClick}>Confirm</a>
<h2>Preview:</h2>
<input className={"Title"} value={this.props.title} onChange={this.props.onTitleChange}/>
<div className={"BodyWrapper"}>
<div className={"Body"} ref={this.bodyRef} dangerouslySetInnerHTML={{__html: this.props.body_html}}></div>
</div>
</div>
);
}
}
class AppComponent extends Component {
constructor() {
@@ -74,7 +107,7 @@ class AppComponent extends Component {
}
this.clipperServerHelpLink_click = () => {
bridge().tabsCreate({ url: 'https://joplin.cozic.net/clipper' });
bridge().tabsCreate({ url: 'https://joplinapp.org/clipper/' });
}
this.folderSelect_change = (event) => {
@@ -123,6 +156,7 @@ class AppComponent extends Component {
async loadContentScripts() {
await bridge().tabsExecuteScript({file: "/content_scripts/JSDOMParser.js"});
await bridge().tabsExecuteScript({file: "/content_scripts/Readability.js"});
await bridge().tabsExecuteScript({file: "/content_scripts/Readability-readerable.js"});
await bridge().tabsExecuteScript({file: "/content_scripts/index.js"});
}
@@ -158,6 +192,8 @@ class AppComponent extends Component {
id: newFolderId,
});
}
bridge().sendCommandToActiveTab({ name: 'isProbablyReaderable' });
}
componentDidUpdate() {
@@ -208,16 +244,12 @@ class AppComponent extends Component {
</div>
);
} else if (hasContent) {
previewComponent = (
<div className="Preview">
<h2>Preview:</h2>
<input className={"Title"} value={content.title} onChange={this.contentTitle_change}/>
<div className={"BodyWrapper"}>
<div className={"Body"} dangerouslySetInnerHTML={{__html: content.body_html}}></div>
</div>
<a className={"Confirm Button"} onClick={this.confirm_click}>Confirm</a>
</div>
);
previewComponent = <PreviewComponent
onConfirmClick={this.confirm_click}
title={content.title}
body_html={content.body_html}
onTitleChange={this.contentTitle_change}
/>
}
const clipperStatusComp = () => {
@@ -278,11 +310,10 @@ class AppComponent extends Component {
const tagsComp = () => {
const comps = [];
for (let i = 0; i < this.state.selectedTags.length; i++) {
comps.push(<div>
comps.push(<div key={i}>
<input
ref={'tagSelector' + i}
data-index={i}
key={i}
type="text"
list="tags"
value={this.state.selectedTags[i]}
@@ -306,11 +337,18 @@ class AppComponent extends Component {
tagDataListOptions.push(<option key={tag.id}>{tag.title}</option>);
}
let simplifiedPageButtonLabel = 'Clip simplified page';
let simplifiedPageButtonTooltip = '';
if (!this.props.isProbablyReaderable) {
simplifiedPageButtonLabel += ' ⚠️';
simplifiedPageButtonTooltip = 'It might not be possible to create a good simplified version of this page.\nYou may want to clip the complete page instead.';
}
return (
<div className="App">
<div className="Controls">
<ul>
<li><a className="Button" onClick={this.clipSimplified_click}>Clip simplified page</a></li>
<li><a className="Button" onClick={this.clipSimplified_click} title={simplifiedPageButtonTooltip}>{simplifiedPageButtonLabel}</a></li>
<li><a className="Button" onClick={this.clipComplete_click}>Clip complete page</a></li>
<li><a className="Button" onClick={this.clipSelection_click}>Clip selection</a></li>
<li><a className="Button" onClick={this.clipScreenshot_click}>Clip screenshot</a></li>
@@ -343,6 +381,7 @@ const mapStateToProps = (state) => {
folders: state.folders,
tags: state.tags,
selectedFolderId: state.selectedFolderId,
isProbablyReaderable: state.isProbablyReaderable,
};
};

View File

@@ -2,6 +2,10 @@ const randomClipperPort = require('./randomClipperPort');
class Bridge {
constructor() {
this.nounce_ = Date.now();
}
async init(browser, browserSupportsPromises, dispatch) {
console.info('Popup: Init bridge');
@@ -34,6 +38,10 @@ class Bridge {
this.dispatch({ type: 'CLIPPED_CONTENT_SET', content: content });
}
if (command.name === 'isProbablyReaderable') {
this.dispatch({ type: 'IS_PROBABLY_READERABLE', value: command.value });
}
}
this.browser_.runtime.onMessage.addListener(this.browser_notify);
@@ -264,7 +272,7 @@ class Bridge {
await this.tabsSendMessage(tabs[0].id, command);
}
async clipperApiExec(method, path, body) {
async clipperApiExec(method, path, query, body) {
console.info('Popup: ' + method + ' ' + path);
const baseUrl = await this.clipperServerBaseUrl();
@@ -278,7 +286,18 @@ class Bridge {
if (body) fetchOptions.body = typeof body === 'string' ? body : JSON.stringify(body);
const response = await fetch(baseUrl + "/" + path, fetchOptions)
let queryString = '';
if (query) {
const s = [];
for (const k in query) {
if (!query.hasOwnProperty(k)) continue;
s.push(encodeURIComponent(k) + '=' + encodeURIComponent(query[k]));
}
queryString = s.join('&');
if (queryString) queryString = '?' + queryString;
}
const response = await fetch(baseUrl + "/" + path + queryString, fetchOptions)
if (!response.ok) {
const msg = await response.text();
throw new Error(msg);
@@ -296,11 +315,39 @@ class Bridge {
if (!content) throw new Error('Cannot send empty content');
await this.clipperApiExec('POST', 'notes', content);
// There is a bug in Chrome that somehow makes the app send the same request twice, which
// results in Joplin having the same note twice. There's a 2-3 sec delay between
// each request. The bug only happens the first time the extension popup is open and the
// Complete button is clicked.
//
// It's beyond my understanding how it's happening. I don't know how this sendContentToJoplin function
// can be called twice. But even if it is, logically, it's impossible that this
// call below would be done with twice the same nounce. Even if the function sendContentToJoplin
// is called twice in parallel, the increment is atomic and should result in two nounces
// being generated. But it's not. Somehow the function below is called twice with the exact same nounce.
//
// It's also not something internal to Chrome that repeat the request since the error is caught
// so it really seems like a double function call.
//
// So this is why below, when we get the duplicate nounce error, we just ignore it so as not to display
// a useless error message. The whole nounce feature is not for security (it's not to prevent replay
// attacks), but simply to detect these double-requests and ignore them on Joplin side.
//
// This nounce feature is optional, it's only active when the nounce query parameter is provided
// so it shouldn't affect any other call.
//
// This is the perfect Heisenbug - it happens always when opening the popup the first time EXCEPT
// when the debugger is open. Then everything is working fine and the bug NEVER EVER happens,
// so it's impossible to understand what's going on.
await this.clipperApiExec('POST', 'notes', { nounce: this.nounce_++ }, content);
this.dispatch({ type: 'CONTENT_UPLOAD', operation: { uploading: false, success: true } });
} catch (error) {
this.dispatch({ type: 'CONTENT_UPLOAD', operation: { uploading: false, success: false, errorMessage: error.message } });
if (error.message === '{"error":"Duplicate Nounce"}') {
this.dispatch({ type: 'CONTENT_UPLOAD', operation: { uploading: false, success: true } });
} else {
this.dispatch({ type: 'CONTENT_UPLOAD', operation: { uploading: false, success: false, errorMessage: error.message } });
}
}
}

View File

@@ -19,6 +19,7 @@ const defaultState = {
tags: [],
selectedFolderId: null,
env: 'prod',
isProbablyReaderable: true,
};
const reduxMiddleware = store => next => async (action) => {
@@ -40,6 +41,11 @@ function reducer(state = defaultState, action) {
newState = Object.assign({}, state);
newState.warning = action.text;
} else if (action.type === 'IS_PROBABLY_READERABLE') {
newState = Object.assign({}, state);
newState.isProbablyReaderable = action.value;
} else if (action.type === 'CLIPPED_CONTENT_SET') {
newState = Object.assign({}, state);

View File

@@ -3,4 +3,5 @@ app/packageInfo.js
dist/
app/lib/
app/gui/*.min.js
app/plugins/*.min.js
.DS_Store

View File

@@ -54,6 +54,7 @@ class ElectronAppWrapper {
y: windowState.y,
width: windowState.width,
height: windowState.height,
backgroundColor: '#fff', // required to enable sub pixel rendering, can't be in css
webPreferences: {
nodeIntegration: true,
},
@@ -80,7 +81,7 @@ class ElectronAppWrapper {
}))
// Uncomment this to view errors if the application does not start
// if (this.env_ === 'dev') this.win_.webContents.openDevTools();
if (this.env_ === 'dev') this.win_.webContents.openDevTools();
this.win_.on('close', (event) => {
// If it's on macOS, the app is completely closed only if the user chooses to close the app (willQuitApp_ will be true)

View File

@@ -28,6 +28,13 @@ const ExternalEditWatcher = require('lib/services/ExternalEditWatcher');
const { bridge } = require('electron').remote.require('./bridge');
const Menu = bridge().Menu;
const MenuItem = bridge().MenuItem;
const PluginManager = require('lib/services/PluginManager');
const RevisionService = require('lib/services/RevisionService');
const MigrationService = require('lib/services/MigrationService');
const pluginClasses = [
require('./plugins/GotoAnything.min'),
];
const appDefaultState = Object.assign({}, defaultState, {
route: {
@@ -308,6 +315,8 @@ class Application extends BaseApplication {
const importItems = [];
const exportItems = [];
const preferencesItems = [];
const toolsItemsFirst = [];
const ioService = new InteropService();
const ioModules = ioService.modules();
for (let i = 0; i < ioModules.length; i++) {
@@ -355,6 +364,9 @@ class Application extends BaseApplication {
importOptions.path = path;
importOptions.format = module.format;
importOptions.destinationFolderId = !module.isNoteArchive && moduleSource === 'file' ? selectedFolderId : null;
importOptions.onError = (error) => {
console.warn(error);
}
const service = new InteropService();
try {
@@ -385,42 +397,203 @@ class Application extends BaseApplication {
}
});
const template = [
{
label: _('&File'),
/* `&` before one of the char in the label name mean, that
* <Alt + F> will open this menu. It's needed becase electron
* opens the first menu on Alt press if no hotkey assigned.
* Issue: https://github.com/laurent22/joplin/issues/934 */
submenu: [{
label: _('New note'),
accelerator: 'CommandOrControl+N',
screens: ['Main'],
click: () => {
this.dispatch({
type: 'WINDOW_COMMAND',
name: 'newNote',
});
}
}, {
label: _('New to-do'),
accelerator: 'CommandOrControl+T',
screens: ['Main'],
click: () => {
this.dispatch({
type: 'WINDOW_COMMAND',
name: 'newTodo',
});
}
}, {
label: _('New notebook'),
screens: ['Main'],
click: () => {
this.dispatch({
type: 'WINDOW_COMMAND',
name: 'newNotebook',
});
}
/* We need a dummy entry, otherwise the ternary operator to show a
* menu item only on a specific OS does not work. */
const noItem = {
type: 'separator',
visible: false
}
const syncStatusItem = {
label: _('Synchronisation status'),
click: () => {
this.dispatch({
type: 'NAV_GO',
routeName: 'Status',
});
}
}
const newNoteItem = {
label: _('New note'),
accelerator: 'CommandOrControl+N',
screens: ['Main'],
click: () => {
this.dispatch({
type: 'WINDOW_COMMAND',
name: 'newNote',
});
}
}
const newTodoItem = {
label: _('New to-do'),
accelerator: 'CommandOrControl+T',
screens: ['Main'],
click: () => {
this.dispatch({
type: 'WINDOW_COMMAND',
name: 'newTodo',
});
}
}
const newNotebookItem = {
label: _('New notebook'),
screens: ['Main'],
click: () => {
this.dispatch({
type: 'WINDOW_COMMAND',
name: 'newNotebook',
});
}
}
const printItem = {
label: _('Print'),
accelerator: 'CommandOrControl+P',
screens: ['Main'],
click: () => {
this.dispatch({
type: 'WINDOW_COMMAND',
name: 'print',
});
}
}
preferencesItems.push({
label: _('General Options'),
accelerator: 'CommandOrControl+,',
click: () => {
this.dispatch({
type: 'NAV_GO',
routeName: 'Config',
});
}
}, {
label: _('Encryption options'),
click: () => {
this.dispatch({
type: 'NAV_GO',
routeName: 'EncryptionConfig',
});
}
}, {
label: _('Web clipper options'),
click: () => {
this.dispatch({
type: 'NAV_GO',
routeName: 'ClipperConfig',
});
}
});
toolsItemsFirst.push(syncStatusItem, {
type: 'separator',
screens: ['Main'],
});
const toolsItems = toolsItemsFirst.concat(preferencesItems);
function _checkForUpdates(ctx) {
bridge().checkForUpdates(false, bridge().window(), ctx.checkForUpdateLoggerPath(), { includePreReleases: Setting.value('autoUpdate.includePreReleases') });
}
function _showAbout() {
const p = packageInfo;
let message = [
p.description,
'',
'Copyright © 2016-2019 Laurent Cozic',
_('%s %s (%s, %s)', p.name, p.version, Setting.value('env'), process.platform),
];
bridge().showInfoMessageBox(message.join('\n'), {
icon: bridge().electronApp().buildDir() + '/icons/32x32.png',
});
}
const rootMenuFile = {
/* Using a dummy entry for macOS here, because first menu
* becomes 'Joplin' and we need a nenu called 'File' later. */
label: shim.isMac() ? '&JoplinMainMenu' : _('&File'),
/* `&` before one of the char in the label name mean, that
* <Alt + F> will open this menu. It's needed becase electron
* opens the first menu on Alt press if no hotkey assigned.
* Issue: https://github.com/laurent22/joplin/issues/934 */
submenu: [{
label: _('About Joplin'),
visible: shim.isMac() ? true : false,
click: () => _showAbout()
}, {
type: 'separator',
visible: shim.isMac() ? true : false
}, {
label: _('Preferences...'),
visible: shim.isMac() ? true : false,
submenu: preferencesItems
}, {
label: _('Check for updates...'),
visible: shim.isMac() ? true : false,
click: () => _checkForUpdates(this)
}, {
type: 'separator',
visible: shim.isMac() ? true : false
},
shim.isMac() ? noItem : newNoteItem,
shim.isMac() ? noItem : newTodoItem,
shim.isMac() ? noItem : newNotebookItem, {
type: 'separator',
visible: shim.isMac() ? false : true
}, {
label: _('Import'),
visible: shim.isMac() ? false : true,
submenu: importItems,
}, {
label: _('Export'),
visible: shim.isMac() ? false : true,
submenu: exportItems,
}, {
type: 'separator',
}, {
label: _('Synchronise'),
accelerator: 'CommandOrControl+S',
screens: ['Main'],
click: async () => {
this.dispatch({
type: 'WINDOW_COMMAND',
name: 'synchronize',
});
}
}, shim.isMac() ? syncStatusItem : noItem, {
type: 'separator',
}, shim.isMac() ? noItem : printItem, {
type: 'separator',
platforms: ['darwin'],
}, {
label: _('Hide %s', 'Joplin'),
platforms: ['darwin'],
accelerator: 'CommandOrControl+H',
click: () => { bridge().electronApp().hide() }
}, {
type: 'separator',
}, {
label: _('Quit'),
accelerator: 'CommandOrControl+Q',
click: () => { bridge().electronApp().quit() }
}]
};
const rootMenuFileMacOs = {
label: _('&File'),
visible: shim.isMac() ? true : false,
submenu: [
newNoteItem,
newTodoItem,
newNotebookItem, {
label: _('Close Window'),
platforms: ['darwin'],
accelerator: 'Command+W',
selector: 'performClose:',
}, {
type: 'separator',
}, {
@@ -431,44 +604,13 @@ class Application extends BaseApplication {
submenu: exportItems,
}, {
type: 'separator',
}, {
label: _('Synchronise'),
accelerator: 'CommandOrControl+S',
screens: ['Main'],
click: async () => {
this.dispatch({
type: 'WINDOW_COMMAND',
name: 'synchronize',
});
}
}, {
type: 'separator',
}, {
label: _('Print'),
accelerator: 'CommandOrControl+P',
screens: ['Main'],
click: () => {
this.dispatch({
type: 'WINDOW_COMMAND',
name: 'print',
});
}
}, {
type: 'separator',
platforms: ['darwin'],
}, {
label: _('Hide %s', 'Joplin'),
platforms: ['darwin'],
accelerator: 'CommandOrControl+H',
click: () => { bridge().electronApp().hide() }
}, {
type: 'separator',
}, {
label: _('Quit'),
accelerator: 'CommandOrControl+Q',
click: () => { bridge().electronApp().quit() }
}]
}, {
},
printItem
]
};
const rootMenus = {
edit: {
label: _('&Edit'),
submenu: [{
label: _('Copy'),
@@ -569,7 +711,8 @@ class Application extends BaseApplication {
});
},
}],
}, {
},
view: {
label: _('&View'),
submenu: [{
label: _('Toggle sidebar'),
@@ -626,80 +769,59 @@ class Application extends BaseApplication {
screens: ['Main'],
submenu: focusItems,
}],
}, {
},
tools: {
label: _('&Tools'),
submenu: [{
label: _('Synchronisation status'),
click: () => {
this.dispatch({
type: 'NAV_GO',
routeName: 'Status',
});
}
}, {
type: 'separator',
screens: ['Main'],
},{
label: _('Web clipper options'),
click: () => {
this.dispatch({
type: 'NAV_GO',
routeName: 'ClipperConfig',
});
}
},{
label: _('Encryption options'),
click: () => {
this.dispatch({
type: 'NAV_GO',
routeName: 'EncryptionConfig',
});
}
},{
label: _('General Options'),
accelerator: 'CommandOrControl+,',
click: () => {
this.dispatch({
type: 'NAV_GO',
routeName: 'Config',
});
}
}],
}, {
submenu: shim.isMac() ? [] : toolsItems,
},
help: {
label: _('&Help'),
submenu: [{
label: _('Website and documentation'),
accelerator: 'F1',
click () { bridge().openExternal('https://joplin.cozic.net') }
click () { bridge().openExternal('https://joplinapp.org') }
}, {
label: _('Make a donation'),
click () { bridge().openExternal('https://joplin.cozic.net/donate') }
click () { bridge().openExternal('https://joplinapp.org/donate/') }
}, {
label: _('Check for updates...'),
click: () => {
bridge().checkForUpdates(false, bridge().window(), this.checkForUpdateLoggerPath(), { includePreReleases: Setting.value('autoUpdate.includePreReleases') });
}
visible: shim.isMac() ? false : true,
click: () => _checkForUpdates(this)
}, {
type: 'separator',
visible: shim.isMac() ? false : true,
screens: ['Main'],
}, {
label: _('About Joplin'),
click: () => {
const p = packageInfo;
let message = [
p.description,
'',
'Copyright © 2016-2019 Laurent Cozic',
_('%s %s (%s, %s)', p.name, p.version, Setting.value('env'), process.platform),
];
bridge().showInfoMessageBox(message.join('\n'), {
icon: bridge().electronApp().buildDir() + '/icons/32x32.png',
});
}
visible: shim.isMac() ? false : true,
click: () => _showAbout()
}]
},
},
};
if (shim.isMac()) {
rootMenus.macOsApp = rootMenuFile;
rootMenus.file = rootMenuFileMacOs;
} else {
rootMenus.file = rootMenuFile;
}
const pluginMenuItems = PluginManager.instance().menuItems();
for (const item of pluginMenuItems) {
let itemParent = rootMenus[item.parent] ? rootMenus[item.parent] : 'tools';
itemParent.submenu.push(item);
}
const template = [
rootMenus.file,
rootMenus.edit,
rootMenus.view,
rootMenus.tools,
rootMenus.help,
];
if (shim.isMac()) template.splice(0, 0, rootMenus.macOsApp);
function isEmptyMenu(template) {
for (let i = 0; i < template.length; i++) {
const t = template[i];
@@ -813,6 +935,10 @@ class Application extends BaseApplication {
bridge().window().webContents.openDevTools();
}
PluginManager.instance().dispatch_ = this.dispatch.bind(this);
PluginManager.instance().setLogger(reg.logger());
PluginManager.instance().register(pluginClasses);
this.updateMenu('Main');
this.initRedux();
@@ -907,6 +1033,12 @@ class Application extends BaseApplication {
ExternalEditWatcher.instance().setLogger(reg.logger());
ExternalEditWatcher.instance().dispatch = this.store().dispatch;
RevisionService.instance().runInBackground();
// Make it available to the console window - useful to call revisionService.collectRevisions()
window.revisionService = RevisionService.instance();
window.migrationService = MigrationService.instance();
}
}

View File

@@ -77,13 +77,16 @@ class Bridge {
});
}
showConfirmMessageBox(message) {
const result = this.showMessageBox_(this.window(), {
showConfirmMessageBox(message, options = null) {
if (options === null) options = {};
const result = this.showMessageBox_(this.window(), Object.assign({}, {
type: 'question',
message: message,
cancelId: 1,
buttons: [_('OK'), _('Cancel')],
});
}, options));
return result === 0;
}

View File

@@ -3,7 +3,6 @@ const spawnSync = require('child_process').spawnSync;
const babelPath = __dirname + '/node_modules/.bin/babel' + (process.platform === 'win32' ? '.cmd' : '');
const basePath = __dirname + '/../..';
const guiPath = __dirname + '/gui';
function fileIsNewerThan(path1, path2) {
if (!fs.existsSync(path2)) return true;
@@ -14,31 +13,36 @@ function fileIsNewerThan(path1, path2) {
return stat1.mtime > stat2.mtime;
}
fs.readdirSync(guiPath).forEach((filename) => {
const jsxPath = guiPath + '/' + filename;
const p = jsxPath.split('.');
if (p.length <= 1) return;
const ext = p[p.length - 1];
if (ext !== 'jsx') return;
p.pop();
function convertJsx(path) {
fs.readdirSync(path).forEach((filename) => {
const jsxPath = path + '/' + filename;
const p = jsxPath.split('.');
if (p.length <= 1) return;
const ext = p[p.length - 1];
if (ext !== 'jsx') return;
p.pop();
const basePath = p.join('.');
const basePath = p.join('.');
const jsPath = basePath + '.min.js';
const jsPath = basePath + '.min.js';
if (fileIsNewerThan(jsxPath, jsPath)) {
console.info('Compiling ' + jsxPath + '...');
const result = spawnSync(babelPath, ['--presets', 'react', '--out-file', jsPath, jsxPath]);
if (result.status !== 0) {
const msg = [];
if (result.stdout) msg.push(result.stdout.toString());
if (result.stderr) msg.push(result.stderr.toString());
console.error(msg.join('\n'));
if (result.error) console.error(result.error);
process.exit(result.status);
if (fileIsNewerThan(jsxPath, jsPath)) {
console.info('Compiling ' + jsxPath + '...');
const result = spawnSync(babelPath, ['--presets', 'react', '--out-file', jsPath, jsxPath]);
if (result.status !== 0) {
const msg = [];
if (result.stdout) msg.push(result.stdout.toString());
if (result.stderr) msg.push(result.stderr.toString());
console.error(msg.join('\n'));
if (result.error) console.error(result.error);
process.exit(result.status);
}
}
}
});
});
}
convertJsx(__dirname + '/gui');
convertJsx(__dirname + '/plugins');
const libContent = [
fs.readFileSync(basePath + '/ReactNativeClient/lib/string-utils-common.js', 'utf8'),

View File

@@ -76,6 +76,26 @@ class ConfigScreenComponent extends React.Component {
</div>
);
if (section.name === 'sync') {
const syncTargetMd = SyncTargetRegistry.idToMetadata(settings['sync.target']);
if (syncTargetMd.supportsConfigCheck) {
const messages = shared.checkSyncConfigMessages(this);
const statusStyle = Object.assign({}, theme.textStyle, { marginTop: 10 });
const statusComp = !messages.length ? null : (
<div style={statusStyle}>
{messages[0]}
{messages.length >= 1 ? (<p>{messages[1]}</p>) : null}
</div>);
settingComps.push(
<div key="check_sync_config_button" style={this.rowStyle_}>
<button disabled={this.state.checkSyncConfigResult === 'checking'} style={theme.buttonStyle} onClick={this.checkSyncConfig_}>{_('Check synchronisation configuration')}</button>
{ statusComp }
</div>);
}
}
return (
<div key={key} style={sectionStyle}>
<h2 style={headerStyle}>{Setting.sectionNameToLabel(section.name)}</h2>
@@ -265,9 +285,12 @@ class ConfigScreenComponent extends React.Component {
updateSettingValue(key, event.target.value);
};
const label = [md.label()];
if (md.unitLabel) label.push('(' + md.unitLabel() + ')');
return (
<div key={key} style={rowStyle}>
<div style={labelStyle}><label>{md.label()}</label></div>
<div style={labelStyle}><label>{label.join(' ')}</label></div>
<input type="number" style={controlStyle} value={this.state.settings[key]} onChange={(event) => {onNumChange(event)}} min={md.minimum} max={md.maximum} step={md.step}/>
{ descriptionComp }
</div>
@@ -320,24 +343,6 @@ class ConfigScreenComponent extends React.Component {
const settingComps = shared.settingsToComponents2(this, 'desktop', settings);
const syncTargetMd = SyncTargetRegistry.idToMetadata(settings['sync.target']);
if (syncTargetMd.supportsConfigCheck) {
const messages = shared.checkSyncConfigMessages(this);
const statusStyle = Object.assign({}, theme.textStyle, { marginTop: 10 });
const statusComp = !messages.length ? null : (
<div style={statusStyle}>
{messages[0]}
{messages.length >= 1 ? (<p>{messages[1]}</p>) : null}
</div>);
settingComps.push(
<div key="check_sync_config_button" style={this.rowStyle_}>
<button disabled={this.state.checkSyncConfigResult === 'checking'} style={buttonStyle} onClick={this.checkSyncConfig_}>{_('Check synchronisation configuration')}</button>
{ statusComp }
</div>);
}
const buttonBarStyle = {
display: 'flex',
alignItems: 'center',

View File

@@ -189,7 +189,7 @@ class EncryptionConfigScreenComponent extends React.Component {
<div style={containerStyle}>
{<div style={{backgroundColor: theme.warningBackgroundColor, paddingLeft: 10, paddingRight: 10, paddingTop: 2, paddingBottom: 2 }}>
<p style={theme.textStyle}>
<span>{_('For more information about End-To-End Encryption (E2EE) and advices on how to enable it please check the documentation:')}</span> <a onClick={() => {bridge().openExternal('https://joplin.cozic.net/e2ee')}} href="#">https://joplin.cozic.net/e2ee</a>
<span>{_('For more information about End-To-End Encryption (E2EE) and advices on how to enable it please check the documentation:')}</span> <a onClick={() => {bridge().openExternal('https://joplinapp.org/e2ee/')}} href="#">https://joplinapp.org/e2ee/</a>
</p>
</div>}
<h1 style={theme.h1Style}>{_('Status')}</h1>

View File

@@ -35,8 +35,7 @@ class HeaderComponent extends React.Component {
};
this.search_onClear = (event) => {
this.setState({ searchQuery: '' });
triggerOnQuery('');
this.resetSearch();
if (this.searchElement_) this.searchElement_.focus();
}
@@ -56,9 +55,20 @@ class HeaderComponent extends React.Component {
this.setState({ showSearchUsageLink: false });
}, 5000);
}
this.search_keyDown = event => {
if (event.keyCode === 27) { // ESCAPE
this.resetSearch();
}
}
this.resetSearch = () => {
this.setState({ searchQuery: '' });
triggerOnQuery('');
}
this.searchUsageLink_click = event => {
bridge().openExternal('https://joplin.cozic.net/#searching');
bridge().openExternal('https://joplinapp.org/#searching');
}
}
@@ -68,6 +78,12 @@ class HeaderComponent extends React.Component {
}
}
componentDidUpdate(prevProps) {
if(prevProps.notesParentType !== this.props.notesParentType && this.props.notesParentType !== 'Search' && this.state.searchQuery) {
this.resetSearch();
}
}
componentWillUnmount() {
if (this.hideSearchUsageLinkIID_) {
clearTimeout(this.hideSearchUsageLinkIID_);
@@ -102,11 +118,14 @@ class HeaderComponent extends React.Component {
let icon = null;
if (options.iconName) {
const iconStyle = {
fontSize: Math.round(style.fontSize * 1.4),
fontSize: Math.round(style.fontSize * 1.1),
color: style.color,
};
if (options.title) iconStyle.marginRight = 5;
if (options.iconRotation) iconStyle.transform = 'rotate(' + options.iconRotation + 'deg)';
if("undefined" != typeof(options.iconRotation)) {
iconStyle.transition = "transform 0.15s ease-in-out";
iconStyle.transform = 'rotate(' + options.iconRotation + 'deg)';
}
icon = <i style={iconStyle} className={"fa " + options.iconName}></i>
}
@@ -135,8 +154,11 @@ class HeaderComponent extends React.Component {
const inputStyle = {
display: 'flex',
flex: 1,
paddingLeft: 4,
paddingRight: 4,
paddingLeft: 6,
paddingRight: 6,
paddingTop: 1, // vertical alignment with buttons
paddingBottom: 0, // vertical alignment with buttons
height: style.fontSize * 2,
color: style.color,
fontSize: style.fontSize,
fontFamily: style.fontFamily,
@@ -184,6 +206,7 @@ class HeaderComponent extends React.Component {
ref={elem => this.searchElement_ = elem}
onFocus={this.search_onFocus}
onBlur={this.search_onBlur}
onKeyDown={this.search_keyDown}
/>
<a
href="#"
@@ -251,6 +274,7 @@ const mapStateToProps = (state) => {
return {
theme: state.settings.theme,
windowCommand: state.windowCommand,
notesParentType: state.notesParentType,
};
};

View File

@@ -0,0 +1,39 @@
const React = require('react');
const { connect } = require('react-redux');
const { reg } = require('lib/registry.js');
const { themeStyle } = require('../theme.js');
const { _ } = require('lib/locale.js');
const { bridge } = require('electron').remote.require('./bridge');
class HelpButtonComponent extends React.Component {
constructor() {
super();
this.onClick = this.onClick.bind(this);
}
onClick() {
if (this.props.onClick) this.props.onClick();
}
render() {
const theme = themeStyle(this.props.theme);
let style = Object.assign({}, this.props.style, {color: theme.color, textDecoration: 'none'});
const helpIconStyle = {flex:0, width: 16, height: 16, marginLeft: 10};
const extraProps = {};
if (this.props.tip) extraProps['data-tip'] = this.props.tip;
return <a href="#" style={style} onClick={this.onClick} {...extraProps}><i style={helpIconStyle} className={"fa fa-question-circle"}></i></a>
}
}
const mapStateToProps = (state) => {
return {
theme: state.settings.theme,
};
};
const HelpButton = connect(mapStateToProps)(HelpButtonComponent);
module.exports = HelpButton;

View File

@@ -18,6 +18,7 @@ const layoutUtils = require('lib/layout-utils.js');
const { bridge } = require('electron').remote.require('./bridge');
const eventManager = require('../eventManager');
const VerticalResizer = require('./VerticalResizer.min');
const PluginManager = require('lib/services/PluginManager');
class MainScreenComponent extends React.Component {
@@ -226,6 +227,7 @@ class MainScreenComponent extends React.Component {
notePropertiesDialogOptions: {
noteId: command.noteId,
visible: true,
onRevisionLinkClick: command.onRevisionLinkClick,
},
});
} else if (command.name === 'toggleVisiblePanes') {
@@ -458,6 +460,9 @@ class MainScreenComponent extends React.Component {
);
}
const dialogInfo = PluginManager.instance().pluginDialogToShow(this.props.plugins);
const pluginDialog = !dialogInfo ? null : <dialogInfo.Dialog {...dialogInfo.props}/>;
const modalLayerStyle = Object.assign({}, styles.modalLayer, { display: this.state.modalLayer.visible ? 'block' : 'none' });
const notePropertiesDialogOptions = this.state.notePropertiesDialogOptions;
@@ -470,6 +475,7 @@ class MainScreenComponent extends React.Component {
theme={this.props.theme}
noteId={notePropertiesDialogOptions.noteId}
onClose={this.notePropertiesDialog_close}
onRevisionLinkClick={notePropertiesDialogOptions.onRevisionLinkClick}
/> }
<PromptDialog
@@ -491,6 +497,8 @@ class MainScreenComponent extends React.Component {
<NoteList style={styles.noteList} />
<VerticalResizer style={styles.verticalResizer} onDrag={this.noteList_onDrag}/>
<NoteText style={styles.noteText} visiblePanes={this.props.noteVisiblePanes} />
{pluginDialog}
</div>
);
}
@@ -512,6 +520,7 @@ const mapStateToProps = (state) => {
sidebarWidth: state.settings['style.sidebar.width'],
noteListWidth: state.settings['style.noteList.width'],
selectedNoteId: state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null,
plugins: state.plugins,
};
};

View File

@@ -17,6 +17,7 @@ class NotePropertiesDialog extends React.Component {
this.okButton_click = this.okButton_click.bind(this);
this.cancelButton_click = this.cancelButton_click.bind(this);
this.onKeyDown = this.onKeyDown.bind(this);
this.revisionsLink_click = this.revisionsLink_click.bind(this);
this.okButton = React.createRef();
this.state = {
@@ -31,6 +32,7 @@ class NotePropertiesDialog extends React.Component {
user_updated_time: _('Updated'),
location: _('Location'),
source_url: _('URL'),
revisionsLink: _('Note History'),
};
}
@@ -79,6 +81,7 @@ class NotePropertiesDialog extends React.Component {
formNote.location = note.latitude + ', ' + note.longitude;
}
formNote.revisionsLink = note.id;
formNote.id = note.id;
return formNote;
@@ -102,26 +105,6 @@ class NotePropertiesDialog extends React.Component {
this.styles_ = {};
this.styleKey_ = styleKey;
this.styles_.modalLayer = {
zIndex: 9999,
display: 'flex',
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
backgroundColor: 'rgba(0,0,0,0.6)',
alignItems: 'flex-start',
justifyContent: 'center',
};
this.styles_.dialogBox = {
backgroundColor: theme.backgroundColor,
padding: 16,
boxShadow: '6px 6px 20px rgba(0,0,0,0.5)',
marginTop: 20,
}
this.styles_.controlBox = {
marginBottom: '1em',
color: 'black', //This will apply for the calendar
@@ -153,8 +136,6 @@ class NotePropertiesDialog extends React.Component {
borderColor: theme.dividerColor,
};
this.styles_.dialogTitle = Object.assign({}, theme.h1Style, { marginBottom: '1.2em' });
return this.styles_;
}
@@ -181,6 +162,11 @@ class NotePropertiesDialog extends React.Component {
this.closeDialog(false);
}
revisionsLink_click() {
this.closeDialog(false);
if (this.props.onRevisionLinkClick) this.props.onRevisionLinkClick();
}
onKeyDown(event) {
if (event.keyCode === 13) {
this.closeDialog(true);
@@ -300,11 +286,13 @@ class NotePropertiesDialog extends React.Component {
url = Note.geoLocationUrlFromLatLong(ll.latitude, ll.longitude);
}
controlComp = <a href="#" onClick={() => bridge().openExternal(url)} style={theme.urlStyle}>{displayedValue}</a>
} else if (key === 'revisionsLink') {
controlComp = <a href="#" onClick={this.revisionsLink_click} style={theme.urlStyle}>{_('Previous versions of this note')}</a>
} else {
controlComp = <div style={Object.assign({}, theme.textStyle, {display: 'inline-block'})}>{displayedValue}</div>
}
if (key !== 'id') {
if (key !== 'id' && key !== 'revisionsLink') {
editCompHandler = () => {this.editPropertyButtonClick(key, value)};
editCompIcon = 'fa-edit';
}
@@ -368,8 +356,6 @@ class NotePropertiesDialog extends React.Component {
const noteComps = [];
const modalLayerStyle = Object.assign({}, styles.modalLayer);
if (formNote) {
for (let key in formNote) {
if (!formNote.hasOwnProperty(key)) continue;
@@ -379,9 +365,9 @@ class NotePropertiesDialog extends React.Component {
}
return (
<div style={modalLayerStyle}>
<div style={styles.dialogBox}>
<div style={styles.dialogTitle}>{_('Note properties')}</div>
<div style={theme.dialogModalLayer}>
<div style={theme.dialogBox}>
<div style={theme.dialogTitle}>{_('Note properties')}</div>
<div>{noteComps}</div>
<div style={{ textAlign: 'right', marginTop: 10 }}>
{buttonComps}

View File

@@ -0,0 +1,175 @@
const React = require('react');
const { connect } = require('react-redux');
const { themeStyle } = require('../theme.js');
const { _ } = require('lib/locale.js');
const NoteTextViewer = require('./NoteTextViewer.min');
const HelpButton = require('./HelpButton.min');
const BaseModel = require('lib/BaseModel');
const Revision = require('lib/models/Revision');
const Setting = require('lib/models/Setting');
const RevisionService = require('lib/services/RevisionService');
const shared = require('lib/components/shared/note-screen-shared.js');
const MdToHtml = require('lib/MdToHtml');
const { time } = require('lib/time-utils.js');
const ReactTooltip = require('react-tooltip');
const { substrWithEllipsis } = require('lib/string-utils');
class NoteRevisionViewerComponent extends React.PureComponent {
constructor() {
super();
this.state = {
revisions: [],
currentRevId: '',
note: null,
restoring: false,
};
this.viewerRef_ = React.createRef();
this.viewer_domReady = this.viewer_domReady.bind(this);
this.revisionList_onChange = this.revisionList_onChange.bind(this);
this.importButton_onClick = this.importButton_onClick.bind(this);
this.backButton_click = this.backButton_click.bind(this);
}
style() {
const theme = themeStyle(this.props.theme);
let style = {
root: {
backgroundColor: theme.backgroundColor,
display: 'flex',
flex: 1,
flexDirection: 'column',
},
titleInput: Object.assign({}, theme.inputStyle, { flex: 1 }),
revisionList: Object.assign({}, theme.dropdownList, { marginLeft: 10, flex: 0.5 }),
};
return style;
}
async viewer_domReady() {
// this.viewerRef_.current.wrappedInstance.openDevTools();
const revisions = await Revision.allByType(BaseModel.TYPE_NOTE, this.props.noteId);
this.setState({
revisions: revisions,
currentRevId: revisions.length ? revisions[revisions.length - 1].id : '',
}, () => {
this.reloadNote();
});
}
async importButton_onClick() {
if (!this.state.note) return;
this.setState({ restoring: true });
await RevisionService.instance().importRevisionNote(this.state.note);
this.setState({ restoring: false });
alert(_('The note "%s" has been successfully restored to the notebook "%s".', substrWithEllipsis(this.state.note.title, 0, 32), RevisionService.instance().restoreFolderTitle()));
}
backButton_click() {
if (this.props.onBack) this.props.onBack();
}
revisionList_onChange(event) {
const value = event.target.value;
if (!value) {
if (this.props.onBack) this.props.onBack();
} else {
this.setState({
currentRevId: value,
}, () => {
this.reloadNote();
});
}
}
async reloadNote() {
let noteBody = '';
if (!this.state.revisions.length || !this.state.currentRevId) {
noteBody = _('This note has no history');
this.setState({ note: null });
} else {
const revIndex = BaseModel.modelIndexById(this.state.revisions, this.state.currentRevId);
const note = await RevisionService.instance().revisionNote(this.state.revisions, revIndex);
if (!note) return;
noteBody = note.body;
this.setState({ note: note });
}
const theme = themeStyle(this.props.theme);
const mdToHtml = new MdToHtml({
resourceBaseUrl: 'file://' + Setting.value('resourceDir') + '/',
});
const result = mdToHtml.render(noteBody, theme, {
codeTheme: theme.codeThemeCss,
userCss: this.props.customCss ? this.props.customCss : '',
resources: await shared.attachedResources(noteBody),
});
this.viewerRef_.current.wrappedInstance.send('setHtml', result.html, { cssFiles: result.cssFiles });
}
render() {
const theme = themeStyle(this.props.theme);
const style = this.style();
const revisionListItems = [];
const revs = this.state.revisions.slice().reverse();
for (let i = 0; i < revs.length; i++) {
const rev = revs[i];
revisionListItems.push(<option
key={rev.id}
value={rev.id}
>{time.formatMsToLocal(rev.item_updated_time)}</option>);
}
const restoreButtonTitle = _('Restore');
const helpMessage = _('Click "%s" to restore the note. It will be copied in the notebook named "%s". The current version of the note will not be replaced or modified.', restoreButtonTitle, RevisionService.instance().restoreFolderTitle());
const titleInput = (
<div style={{display:'flex', flexDirection: 'row', alignItems:'center', marginBottom: 10, borderWidth: 1, borderBottomStyle: 'solid', borderColor: theme.dividerColor, paddingBottom:10}}>
<button onClick={this.backButton_click} style={Object.assign({}, theme.buttonStyle, { marginRight: 10, height: theme.inputStyle.height })}>{'⬅ ' + _('Back')}</button>
<input readOnly type="text" style={style.titleInput} value={this.state.note ? this.state.note.title : ''}/>
<select disabled={!this.state.revisions.length} value={this.state.currentRevId} style={style.revisionList} onChange={this.revisionList_onChange}>
{revisionListItems}
</select>
<button disabled={!this.state.revisions.length || this.state.restoring} onClick={this.importButton_onClick} style={Object.assign({}, theme.buttonStyle, { marginLeft: 10, height: theme.inputStyle.height })}>{restoreButtonTitle}</button>
<HelpButton tip={helpMessage} id="noteRevisionHelpButton" onClick={this.helpButton_onClick}/>
</div>
);
const viewer = <NoteTextViewer
viewerStyle={{display:'flex', flex:1}}
ref={this.viewerRef_}
onDomReady={this.viewer_domReady}
/>
return (
<div style={style.root}>
{titleInput}
{viewer}
<ReactTooltip place="bottom" delayShow={300} className="help-tooltip"/>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
theme: state.settings.theme,
};
};
const NoteRevisionViewer = connect(mapStateToProps)(NoteRevisionViewerComponent);
module.exports = NoteRevisionViewer;

View File

@@ -36,8 +36,10 @@ const ResourceFetcher = require('lib/services/ResourceFetcher');
const { toSystemSlashes, safeFilename } = require('lib/path-utils');
const { clipboard } = require('electron');
const SearchEngine = require('lib/services/SearchEngine');
const DecryptionWorker = require('lib/services/DecryptionWorker');
const ModelCache = require('lib/services/ModelCache');
const NoteTextViewer = require('./NoteTextViewer.min');
const NoteRevisionViewer = require('./NoteRevisionViewer.min');
require('brace/mode/markdown');
// https://ace.c9.io/build/kitchen-sink.html
@@ -70,6 +72,7 @@ class NoteTextComponent extends React.Component {
editorScrollTop: 0,
newNote: null,
noteTags: [],
showRevisions: false,
// If the current note was just created, and the title has never been
// changed by the user, this variable contains that note ID. Used
@@ -224,14 +227,13 @@ class NoteTextComponent extends React.Component {
}
}
this.resourceFetcher_downloadComplete = async (resource) => {
this.refreshResource = async (event) => {
if (!this.state.note || !this.state.note.body) return;
const resourceIds = await Note.linkedResourceIds(this.state.note.body);
if (resourceIds.indexOf(resource.id) >= 0) {
// this.mdToHtml().clearCache();
if (resourceIds.indexOf(event.id) >= 0) {
shared.clearResourceCache();
this.lastSetHtml_ = '';
this.scheduleHtmlUpdate();
//this.updateHtml(this.state.note.body);
}
}
@@ -268,6 +270,7 @@ class NoteTextComponent extends React.Component {
this.titleField_keyDown = this.titleField_keyDown.bind(this);
this.webview_ipcMessage = this.webview_ipcMessage.bind(this);
this.webview_domReady = this.webview_domReady.bind(this);
this.noteRevisionViewer_onBack = this.noteRevisionViewer_onBack.bind(this);
}
// Note:
@@ -360,7 +363,8 @@ class NoteTextComponent extends React.Component {
eventManager.on('noteTypeToggle', this.onNoteTypeToggle_);
eventManager.on('todoToggle', this.onTodoToggle_);
ResourceFetcher.instance().on('downloadComplete', this.resourceFetcher_downloadComplete);
shared.installResourceHandling(this.refreshResource);
ExternalEditWatcher.instance().on('noteChange', this.externalEditWatcher_noteChange);
}
@@ -373,7 +377,8 @@ class NoteTextComponent extends React.Component {
eventManager.removeListener('noteTypeToggle', this.onNoteTypeToggle_);
eventManager.removeListener('todoToggle', this.onTodoToggle_);
ResourceFetcher.instance().off('downloadComplete', this.resourceFetcher_downloadComplete);
shared.uninstallResourceHandling(this.refreshResource);
ExternalEditWatcher.instance().off('noteChange', this.externalEditWatcher_noteChange);
}
@@ -471,6 +476,8 @@ class NoteTextComponent extends React.Component {
// Scroll back to top when loading new note
if (loadingNewNote) {
shared.clearResourceCache();
this.editorMaxScrollTop_ = 0;
// HACK: To go around a bug in Ace editor, we first set the scroll position to 1
@@ -501,7 +508,7 @@ class NoteTextComponent extends React.Component {
// 2. It resets the undo manager - fixes https://github.com/laurent22/joplin/issues/355
// Note: calling undoManager.reset() doesn't work
try {
this.editor_.editor.getSession().setValue(note ? note.body : '');
this.editor_.editor.getSession().setValue(note && note.body? note.body : '');
} catch (error) {
if (error.message === "Cannot read property 'match' of undefined") {
// The internals of Ace Editor throws an exception when creating a new note,
@@ -518,6 +525,11 @@ class NoteTextComponent extends React.Component {
this.setViewerPercentScroll(scrollPercent ? scrollPercent : 0);
}, 10);
}
if (note && note.body && Setting.value('sync.resourceDownloadMode') === 'auto') {
const resourceIds = await Note.linkedResourceIds(note.body);
await ResourceFetcher.instance().markForDownload(resourceIds);
}
}
if (note) {
@@ -530,7 +542,8 @@ class NoteTextComponent extends React.Component {
webviewReady: webviewReady,
folder: parentFolder,
lastKeys: [],
noteTags: noteTags
noteTags: noteTags,
showRevisions: false,
};
if (!note) {
@@ -619,6 +632,13 @@ class NoteTextComponent extends React.Component {
return shared.refreshNoteMetadata(this, force);
}
async noteRevisionViewer_onBack() {
this.setState({ showRevisions: false });
this.lastSetHtml_ = '';
this.scheduleReloadNote(this.props);
}
title_changeText(event) {
shared.noteComponent_change(this, 'title', event.target.value);
this.setState({ newAndNoTitleChangeNoteId: null });
@@ -636,7 +656,7 @@ class NoteTextComponent extends React.Component {
async webview_ipcMessage(event) {
const msg = event.channel ? event.channel : '';
const args = event.args;
const args = event.args;
const arg0 = args && args.length >= 1 ? args[0] : null;
const arg1 = args && args.length >= 2 ? args[1] : null;
@@ -655,6 +675,10 @@ class NoteTextComponent extends React.Component {
const ls = Object.assign({}, this.state.localSearch);
ls.resultCount = arg0;
this.setState({ localSearch: ls });
} else if (msg.indexOf('markForDownload:') === 0) {
const s = msg.split(':');
if (s.length < 2) throw new Error('Invalid message: ' + msg);
ResourceFetcher.instance().markForDownload(s[1]);
} else if (msg === 'percentScroll') {
this.ignoreNextEditorScroll_ = true;
this.setEditorPercentScroll(arg0);
@@ -800,7 +824,7 @@ class NoteTextComponent extends React.Component {
});
if (Setting.value('env') === 'dev') {
this.webviewRef_.current.wrappedInstance.openDevTools();
// this.webviewRef_.current.wrappedInstance.openDevTools();
}
}
@@ -820,7 +844,7 @@ class NoteTextComponent extends React.Component {
this.editor_.editor.renderer.on('afterRender', this.onAfterEditorRender_);
const cancelledKeys = [];
const letters = ['F', 'T', 'P', 'Q', 'L', ','];
const letters = ['F', 'T', 'P', 'Q', 'L', ',', 'G'];
for (let i = 0; i < letters.length; i++) {
const l = letters[i];
cancelledKeys.push('Ctrl+' + l);
@@ -853,6 +877,9 @@ class NoteTextComponent extends React.Component {
}
return output;
}
//fixes #1426 but this is an Ace issue, so it can be removed if ace/brace is updated.
this.editor_.editor.getSession().getMode().$quotes = {'"': '"', "'": "'", "`": "`"};
// Disable Markdown auto-completion (eg. auto-adding a dash after a line with a dash.
// https://github.com/ajaxorg/ace/issues/2754
@@ -1529,6 +1556,7 @@ class NoteTextComponent extends React.Component {
type: 'WINDOW_COMMAND',
name: 'commandNoteProperties',
noteId: n.id,
onRevisionLinkClick: () => { this.setState({ showRevisions: true}) },
});
},
});
@@ -1610,6 +1638,18 @@ class NoteTextComponent extends React.Component {
const innerWidth = rootStyle.width - rootStyle.paddingLeft - rootStyle.paddingRight - borderWidth;
if (this.state.showRevisions && note && note.id) {
rootStyle.paddingRight = rootStyle.paddingLeft;
rootStyle.paddingTop = rootStyle.paddingLeft;
rootStyle.paddingBottom = rootStyle.paddingLeft;
rootStyle.display = 'inline-flex';
return (
<div style={rootStyle}>
<NoteRevisionViewer noteId={note.id} customCss={this.props.customCss} onBack={this.noteRevisionViewer_onBack}/>
</div>
);
}
if (this.props.selectedNoteIds.length > 1) {
return this.renderMultiNotes(rootStyle);
} else if (!note || !!note.encryption_applied) { //|| (note && !this.props.newNote && this.props.noteId && note.id !== this.props.noteId)) { // note.id !== props.noteId is when the note has not been loaded yet, and the previous one is still in the state
@@ -1710,13 +1750,14 @@ class NoteTextComponent extends React.Component {
viewerStyle.borderLeft = 'none';
}
if (this.state.webviewReady) {
if (this.state.webviewReady && this.webviewRef_.current) {
let html = this.state.bodyHtml;
const htmlHasChanged = this.lastSetHtml_ !== html;
if (htmlHasChanged) {
let options = {
cssFiles: this.state.lastRenderCssFiles,
downloadResources: Setting.value('sync.resourceDownloadMode'),
};
this.webviewRef_.current.wrappedInstance.send('setHtml', html, options);
this.lastSetHtml_ = html;

View File

@@ -18,11 +18,11 @@ class NoteTextViewerComponent extends React.Component {
}
webview_domReady(event) {
this.props.onDomReady(event);
if (this.props.onDomReady) this.props.onDomReady(event);
}
webview_ipcMessage(event) {
this.props.onIpcMessage(event);
if (this.props.onIpcMessage) this.props.onIpcMessage(event);
}
initWebview() {
@@ -67,13 +67,21 @@ class NoteTextViewerComponent extends React.Component {
}
}
componentDidUpdate() {
tryInit() {
if (!this.initialized_ && this.webviewRef_.current) {
this.initWebview();
this.initialized_ = true;
}
}
componentDidMount() {
this.tryInit();
}
componentDidUpdate() {
this.tryInit();
}
componentWillUnmount() {
this.destroyWebview();
}

View File

@@ -152,7 +152,7 @@ class SideBarComponent extends React.Component {
header: {
height: itemHeight * 1.8,
fontFamily: theme.fontFamily,
fontSize: theme.fontSize * 1.3,
fontSize: theme.fontSize * 1.16,
textDecoration: "none",
boxSizing: "border-box",
color: theme.color2,
@@ -221,7 +221,7 @@ class SideBarComponent extends React.Component {
}
}
} else if (command.name === 'synchronize') {
this.sync_click();
if (!this.props.syncStarted) this.sync_click();
} else {
commandProcessed = false;
}
@@ -509,7 +509,7 @@ class SideBarComponent extends React.Component {
makeHeader(key, label, iconName, extraProps = {}) {
const style = this.style().header;
const icon = <i style={{ fontSize: style.fontSize * 1.2, marginRight: 5 }} className={"fa " + iconName} />;
const icon = <i style={{ fontSize: style.fontSize, marginRight: 5 }} className={"fa " + iconName} />;
if (extraProps.toggleblock || extraProps.onClick) {
style.cursor = "pointer";
@@ -642,9 +642,15 @@ class SideBarComponent extends React.Component {
synchronizeButton(type) {
const style = Object.assign({}, this.style().button, { marginBottom: 5 });
const iconName = type === "sync" ? "fa-refresh" : "fa-times";
const iconName = "fa-refresh";
const label = type === "sync" ? _("Synchronise") : _("Cancel");
const icon = <i style={{ fontSize: style.fontSize, marginRight: 5 }} className={"fa " + iconName} />;
let iconStyle = { fontSize: style.fontSize, marginRight: 5 };
if(type !== 'sync'){
iconStyle.animation = 'icon-infinite-rotation 1s linear infinite';
}
const icon = <i style={iconStyle} className={"fa " + iconName} />;
return (
<a
className="synchronize-button"
@@ -708,7 +714,7 @@ class SideBarComponent extends React.Component {
let resourceFetcherText = '';
if (this.props.resourceFetcher && this.props.resourceFetcher.toFetchCount) {
resourceFetcherText = _('Fetching resources: %d', this.props.resourceFetcher.toFetchCount);
resourceFetcherText = _('Fetching resources: %d/%d', this.props.resourceFetcher.fetchingCount, this.props.resourceFetcher.toFetchCount);
}
let lines = Synchronizer.reportToLines(this.props.syncReport);
@@ -738,8 +744,8 @@ class SideBarComponent extends React.Component {
{items}
</div>
<div style={{flex:0}}>
{syncReportComp}
{syncButton}
{syncReportComp}
</div>
</div>
);

View File

@@ -106,7 +106,6 @@
let previousContentHeight = contentElement.scrollHeight;
let startTime = Date.now();
ignoreNextScrollEvent = true;
restorePercentScroll();
if (!checkScrollIID_) {
@@ -114,7 +113,6 @@
const h = contentElement.scrollHeight;
if (h !== previousContentHeight) {
previousContentHeight = h;
ignoreNextScrollEvent = true;
restorePercentScroll();
}
if (Date.now() - startTime >= 1000) {
@@ -125,6 +123,10 @@
}
loadCssFiles(event.options.cssFiles);
if (event.options.downloadResources === 'manual') {
webviewLib.setupResourceManualDownload();
}
}
let ignoreNextScrollEvent = false;
@@ -310,7 +312,7 @@
updateBodyHeight();
});
updateBodyHeight();
updateBodyHeight();
</script>
</body>

View File

@@ -127,7 +127,11 @@ class NoteListUtils {
msg = _('Delete these %d notes?', noteIds.length);
}
const ok = bridge().showConfirmMessageBox(msg);
const ok = bridge().showConfirmMessageBox(msg, {
buttons: [_('Delete'), _('Cancel')],
defaultId: 1,
});
if (!ok) return;
await Note.batchDelete(noteIds);
}

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

Some files were not shown because too many files have changed in this diff Show More