From 68ab5dcda554962723c415f14f8116e8a2829a9d Mon Sep 17 00:00:00 2001 From: Joplin Bot Date: Sat, 1 Mar 2025 02:08:23 +0000 Subject: [PATCH 001/158] Doc: Auto-update documentation Auto-updated using release-website.sh --- readme/about/stats.md | 459 +++++++++++++++++++++--------------------- 1 file changed, 231 insertions(+), 228 deletions(-) diff --git a/readme/about/stats.md b/readme/about/stats.md index 701e534631..6dee2a876d 100644 --- a/readme/about/stats.md +++ b/readme/about/stats.md @@ -1,15 +1,15 @@ --- -updated: 2025-02-01T00:53:21Z +updated: 2025-03-01T02:07:09Z --- # Joplin statistics | Name | Value | | ----- | ----- | -| Total Windows downloads | 6,004,354 | -| Total macOs downloads | 1,908,812 | -| Total Linux downloads | 1,422,483 | -| Windows % | 64% | +| Total Windows downloads | 6,120,235 | +| Total macOs downloads | 1,924,690 | +| Total Linux downloads | 1,443,432 | +| Windows % | 65% | | macOS % | 20% | | Linux % | 15% | @@ -17,213 +17,216 @@ updated: 2025-02-01T00:53:21Z | Version | Date | Windows | macOS | Linux | Total | | ----- | ----- | ----- | ----- | ----- | ----- | -| [v3.2.12](https://github.com/laurent22/joplin/releases/tag/v3.2.12) | 2025-01-23T23:52:04Z | 56,558 | 12,124 | 7,940 | 76,622 | -| [v3.2.11](https://github.com/laurent22/joplin/releases/tag/v3.2.11) | 2025-01-13T17:48:21Z | 64,735 | 14,677 | 6,791 | 86,203 | -| [v3.2.10](https://github.com/laurent22/joplin/releases/tag/v3.2.10) (p) | 2025-01-10T10:17:28Z | 974 | 154 | 178 | 1,306 | -| [v3.2.9](https://github.com/laurent22/joplin/releases/tag/v3.2.9) (p) | 2025-01-09T22:58:42Z | 340 | 77 | 44 | 461 | -| [v3.2.7](https://github.com/laurent22/joplin/releases/tag/v3.2.7) (p) | 2025-01-06T16:35:41Z | 844 | 141 | 590 | 1,575 | -| [v3.2.6](https://github.com/laurent22/joplin/releases/tag/v3.2.6) (p) | 2024-12-23T21:54:40Z | 1,629 | 327 | 468 | 2,424 | -| [v3.2.5](https://github.com/laurent22/joplin/releases/tag/v3.2.5) (p) | 2024-12-18T10:41:13Z | 982 | 191 | 216 | 1,389 | -| [v3.2.4](https://github.com/laurent22/joplin/releases/tag/v3.2.4) (p) | 2024-12-12T17:59:52Z | 998 | 144 | 218 | 1,360 | -| [v3.2.3](https://github.com/laurent22/joplin/releases/tag/v3.2.3) (p) | 2024-11-18T00:09:05Z | 2,683 | 547 | 865 | 4,095 | -| [v3.2.1](https://github.com/laurent22/joplin/releases/tag/v3.2.1) (p) | 2024-11-10T16:16:27Z | 1,218 | 224 | 343 | 1,785 | -| [v3.1.24](https://github.com/laurent22/joplin/releases/tag/v3.1.24) | 2024-11-09T15:08:29Z | 205,998 | 33,385 | 43,644 | 283,027 | -| [v3.1.23](https://github.com/laurent22/joplin/releases/tag/v3.1.23) | 2024-11-07T10:56:45Z | 26,547 | 6,728 | 1,515 | 34,790 | -| [v3.1.22](https://github.com/laurent22/joplin/releases/tag/v3.1.22) | 2024-11-05T08:59:32Z | 28,381 | 8,691 | 1,221 | 38,293 | -| [v3.1.20](https://github.com/laurent22/joplin/releases/tag/v3.1.20) | 2024-10-22T12:21:32Z | 93,704 | 19,089 | 13,887 | 126,680 | -| [v3.1.18](https://github.com/laurent22/joplin/releases/tag/v3.1.18) (p) | 2024-10-11T23:27:10Z | 1,502 | 278 | 585 | 2,365 | -| [v3.1.17](https://github.com/laurent22/joplin/releases/tag/v3.1.17) (p) | 2024-09-26T11:57:54Z | 1,695 | 348 | 528 | 2,571 | -| [v3.1.15](https://github.com/laurent22/joplin/releases/tag/v3.1.15) (p) | 2024-09-17T09:15:10Z | 1,175 | 221 | 490 | 1,886 | +| [v3.2.13](https://github.com/laurent22/joplin/releases/tag/v3.2.13) | 2025-02-28T14:38:21Z | 7,380 | 2,161 | 381 | 9,922 | +| [v3.3.2](https://github.com/laurent22/joplin/releases/tag/v3.3.2) (p) | 2025-02-19T17:34:26Z | 1,575 | 315 | 372 | 2,262 | +| [v3.3.1](https://github.com/laurent22/joplin/releases/tag/v3.3.1) (p) | 2025-02-16T17:06:26Z | 797 | 156 | 152 | 1,105 | +| [v3.2.12](https://github.com/laurent22/joplin/releases/tag/v3.2.12) | 2025-01-23T23:52:04Z | 150,526 | 25,007 | 27,451 | 202,984 | +| [v3.2.11](https://github.com/laurent22/joplin/releases/tag/v3.2.11) | 2025-01-13T17:48:21Z | 65,131 | 14,766 | 6,823 | 86,720 | +| [v3.2.10](https://github.com/laurent22/joplin/releases/tag/v3.2.10) (p) | 2025-01-10T10:17:28Z | 1,039 | 160 | 184 | 1,383 | +| [v3.2.9](https://github.com/laurent22/joplin/releases/tag/v3.2.9) (p) | 2025-01-09T22:58:42Z | 349 | 83 | 49 | 481 | +| [v3.2.7](https://github.com/laurent22/joplin/releases/tag/v3.2.7) (p) | 2025-01-06T16:35:41Z | 856 | 147 | 689 | 1,692 | +| [v3.2.6](https://github.com/laurent22/joplin/releases/tag/v3.2.6) (p) | 2024-12-23T21:54:40Z | 1,707 | 329 | 471 | 2,507 | +| [v3.2.5](https://github.com/laurent22/joplin/releases/tag/v3.2.5) (p) | 2024-12-18T10:41:13Z | 985 | 193 | 217 | 1,395 | +| [v3.2.4](https://github.com/laurent22/joplin/releases/tag/v3.2.4) (p) | 2024-12-12T17:59:52Z | 999 | 145 | 226 | 1,370 | +| [v3.2.3](https://github.com/laurent22/joplin/releases/tag/v3.2.3) (p) | 2024-11-18T00:09:05Z | 2,688 | 547 | 870 | 4,105 | +| [v3.2.1](https://github.com/laurent22/joplin/releases/tag/v3.2.1) (p) | 2024-11-10T16:16:27Z | 1,223 | 224 | 343 | 1,790 | +| [v3.1.24](https://github.com/laurent22/joplin/releases/tag/v3.1.24) | 2024-11-09T15:08:29Z | 207,018 | 33,436 | 43,732 | 284,186 | +| [v3.1.23](https://github.com/laurent22/joplin/releases/tag/v3.1.23) | 2024-11-07T10:56:45Z | 26,752 | 6,728 | 1,517 | 34,997 | +| [v3.1.22](https://github.com/laurent22/joplin/releases/tag/v3.1.22) | 2024-11-05T08:59:32Z | 28,549 | 8,694 | 1,221 | 38,464 | +| [v3.1.20](https://github.com/laurent22/joplin/releases/tag/v3.1.20) | 2024-10-22T12:21:32Z | 94,034 | 19,117 | 13,893 | 127,044 | +| [v3.1.18](https://github.com/laurent22/joplin/releases/tag/v3.1.18) (p) | 2024-10-11T23:27:10Z | 1,502 | 278 | 586 | 2,366 | +| [v3.1.17](https://github.com/laurent22/joplin/releases/tag/v3.1.17) (p) | 2024-09-26T11:57:54Z | 1,696 | 348 | 529 | 2,573 | +| [v3.1.15](https://github.com/laurent22/joplin/releases/tag/v3.1.15) (p) | 2024-09-17T09:15:10Z | 1,177 | 222 | 491 | 1,890 | | [v3.1.8](https://github.com/laurent22/joplin/releases/tag/v3.1.8) (p) | 2024-09-08T20:32:44Z | 1,216 | 252 | 332 | 1,800 | -| [v3.1.6](https://github.com/laurent22/joplin/releases/tag/v3.1.6) (p) | 2024-09-02T13:19:40Z | 958 | 225 | 423 | 1,606 | +| [v3.1.6](https://github.com/laurent22/joplin/releases/tag/v3.1.6) (p) | 2024-09-02T13:19:40Z | 959 | 225 | 423 | 1,607 | | [v3.1.4](https://github.com/laurent22/joplin/releases/tag/v3.1.4) (p) | 2024-08-27T17:46:38Z | 940 | 173 | 245 | 1,358 | -| [v3.0.15](https://github.com/laurent22/joplin/releases/tag/v3.0.15) | 2024-08-21T09:19:58Z | 202,289 | 37,783 | 44,948 | 285,020 | +| [v3.0.15](https://github.com/laurent22/joplin/releases/tag/v3.0.15) | 2024-08-21T09:19:58Z | 202,506 | 37,787 | 45,049 | 285,342 | | [v3.1.3](https://github.com/laurent22/joplin/releases/tag/v3.1.3) (p) | 2024-08-17T13:08:21Z | 1,222 | 269 | 475 | 1,966 | -| [v3.1.2](https://github.com/laurent22/joplin/releases/tag/v3.1.2) (p) | 2024-08-16T09:00:59Z | 432 | 98 | 78 | 608 | -| [v3.1.1](https://github.com/laurent22/joplin/releases/tag/v3.1.1) (p) | 2024-08-10T11:36:02Z | 1,073 | 197 | 259 | 1,529 | -| [v2.14.23](https://github.com/laurent22/joplin/releases/tag/v2.14.23) | 2024-08-07T11:15:25Z | 10,632 | 2,582 | 600 | 13,814 | -| [v3.0.14](https://github.com/laurent22/joplin/releases/tag/v3.0.14) | 2024-07-28T13:55:50Z | 88,473 | 18,560 | 18,794 | 125,827 | -| [v3.0.12](https://github.com/laurent22/joplin/releases/tag/v3.0.12) | 2024-07-02T17:11:14Z | 43,044 | 12,798 | 7,228 | 63,070 | -| [v3.0.11](https://github.com/laurent22/joplin/releases/tag/v3.0.11) (p) | 2024-06-29T10:20:02Z | 837 | 161 | 264 | 1,262 | +| [v3.1.2](https://github.com/laurent22/joplin/releases/tag/v3.1.2) (p) | 2024-08-16T09:00:59Z | 432 | 98 | 79 | 609 | +| [v3.1.1](https://github.com/laurent22/joplin/releases/tag/v3.1.1) (p) | 2024-08-10T11:36:02Z | 1,074 | 197 | 259 | 1,530 | +| [v2.14.23](https://github.com/laurent22/joplin/releases/tag/v2.14.23) | 2024-08-07T11:15:25Z | 10,652 | 2,585 | 602 | 13,839 | +| [v3.0.14](https://github.com/laurent22/joplin/releases/tag/v3.0.14) | 2024-07-28T13:55:50Z | 88,695 | 18,564 | 18,797 | 126,056 | +| [v3.0.12](https://github.com/laurent22/joplin/releases/tag/v3.0.12) | 2024-07-02T17:11:14Z | 43,364 | 12,806 | 7,263 | 63,433 | +| [v3.0.11](https://github.com/laurent22/joplin/releases/tag/v3.0.11) (p) | 2024-06-29T10:20:02Z | 839 | 161 | 264 | 1,264 | | [v3.0.10](https://github.com/laurent22/joplin/releases/tag/v3.0.10) (p) | 2024-06-19T15:24:07Z | 1,613 | 287 | 558 | 2,458 | | [v3.0.9](https://github.com/laurent22/joplin/releases/tag/v3.0.9) (p) | 2024-06-12T19:07:50Z | 1,258 | 253 | 377 | 1,888 | -| [v3.0.8](https://github.com/laurent22/joplin/releases/tag/v3.0.8) (p) | 2024-05-22T14:20:45Z | 2,654 | 0 | 909 | 3,563 | -| [v2.14.22](https://github.com/laurent22/joplin/releases/tag/v2.14.22) | 2024-05-22T19:19:02Z | 142,144 | 30,659 | 25,446 | 198,249 | -| [v3.0.6](https://github.com/laurent22/joplin/releases/tag/v3.0.6) (p) | 2024-04-27T13:16:04Z | 2,998 | 680 | 860 | 4,538 | +| [v3.0.8](https://github.com/laurent22/joplin/releases/tag/v3.0.8) (p) | 2024-05-22T14:20:45Z | 2,655 | 0 | 910 | 3,565 | +| [v2.14.22](https://github.com/laurent22/joplin/releases/tag/v2.14.22) | 2024-05-22T19:19:02Z | 142,333 | 30,681 | 25,447 | 198,461 | +| [v3.0.6](https://github.com/laurent22/joplin/releases/tag/v3.0.6) (p) | 2024-04-27T13:16:04Z | 3,000 | 680 | 860 | 4,540 | | [v3.0.3](https://github.com/laurent22/joplin/releases/tag/v3.0.3) (p) | 2024-04-18T15:41:38Z | 1,475 | 306 | 328 | 2,109 | -| [v3.0.2](https://github.com/laurent22/joplin/releases/tag/v3.0.2) (p) | 2024-03-21T18:18:49Z | 2,852 | 701 | 1,096 | 4,649 | -| [v2.14.20](https://github.com/laurent22/joplin/releases/tag/v2.14.20) | 2024-03-18T17:05:17Z | 191,753 | 39,474 | 38,177 | 269,404 | -| [v2.14.19](https://github.com/laurent22/joplin/releases/tag/v2.14.19) | 2024-03-08T10:45:16Z | 64,295 | 18,466 | 8,542 | 91,303 | -| [v2.14.17](https://github.com/laurent22/joplin/releases/tag/v2.14.17) | 2024-03-01T18:10:26Z | 63,030 | 18,627 | 7,611 | 89,268 | -| [v2.14.16](https://github.com/laurent22/joplin/releases/tag/v2.14.16) (p) | 2024-02-22T22:49:10Z | 1,343 | 282 | 377 | 2,002 | -| [v2.14.15](https://github.com/laurent22/joplin/releases/tag/v2.14.15) (p) | 2024-02-19T11:24:57Z | 850 | 178 | 189 | 1,217 | +| [v3.0.2](https://github.com/laurent22/joplin/releases/tag/v3.0.2) (p) | 2024-03-21T18:18:49Z | 2,855 | 701 | 1,096 | 4,652 | +| [v2.14.20](https://github.com/laurent22/joplin/releases/tag/v2.14.20) | 2024-03-18T17:05:17Z | 192,056 | 39,482 | 38,187 | 269,725 | +| [v2.14.19](https://github.com/laurent22/joplin/releases/tag/v2.14.19) | 2024-03-08T10:45:16Z | 64,444 | 18,466 | 8,543 | 91,453 | +| [v2.14.17](https://github.com/laurent22/joplin/releases/tag/v2.14.17) | 2024-03-01T18:10:26Z | 63,162 | 18,628 | 7,611 | 89,401 | +| [v2.14.16](https://github.com/laurent22/joplin/releases/tag/v2.14.16) (p) | 2024-02-22T22:49:10Z | 1,346 | 282 | 377 | 2,005 | +| [v2.14.15](https://github.com/laurent22/joplin/releases/tag/v2.14.15) (p) | 2024-02-19T11:24:57Z | 851 | 178 | 189 | 1,218 | | [v2.14.14](https://github.com/laurent22/joplin/releases/tag/v2.14.14) (p) | 2024-02-10T16:03:08Z | 1,269 | 242 | 378 | 1,889 | | [v2.14.13](https://github.com/laurent22/joplin/releases/tag/v2.14.13) (p) | 2024-02-09T16:31:54Z | 409 | 80 | 79 | 568 | | [v2.14.12](https://github.com/laurent22/joplin/releases/tag/v2.14.12) (p) | 2024-02-03T12:11:47Z | 976 | 216 | 244 | 1,436 | -| [v2.14.11](https://github.com/laurent22/joplin/releases/tag/v2.14.11) (p) | 2024-01-26T11:53:05Z | 1,262 | 258 | 456 | 1,976 | +| [v2.14.11](https://github.com/laurent22/joplin/releases/tag/v2.14.11) (p) | 2024-01-26T11:53:05Z | 1,263 | 258 | 456 | 1,977 | | [v2.14.10](https://github.com/laurent22/joplin/releases/tag/v2.14.10) (p) | 2024-01-18T22:45:04Z | 2,084 | 267 | 370 | 2,721 | -| [v2.13.15](https://github.com/laurent22/joplin/releases/tag/v2.13.15) | 2024-01-15T13:01:19Z | 149,121 | 34,128 | 29,245 | 212,494 | -| [v2.13.14](https://github.com/laurent22/joplin/releases/tag/v2.13.14) | 2024-01-13T19:11:04Z | 19,430 | 7,823 | 2,359 | 29,612 | -| [v2.14.9](https://github.com/laurent22/joplin/releases/tag/v2.14.9) (p) | 2024-01-11T22:17:59Z | 1,055 | 0 | 238 | 1,293 | +| [v2.13.15](https://github.com/laurent22/joplin/releases/tag/v2.13.15) | 2024-01-15T13:01:19Z | 149,325 | 34,128 | 29,246 | 212,699 | +| [v2.13.14](https://github.com/laurent22/joplin/releases/tag/v2.13.14) | 2024-01-13T19:11:04Z | 19,554 | 7,823 | 2,359 | 29,736 | +| [v2.14.9](https://github.com/laurent22/joplin/releases/tag/v2.14.9) (p) | 2024-01-11T22:17:59Z | 1,055 | 0 | 239 | 1,294 | | [v2.14.8](https://github.com/laurent22/joplin/releases/tag/v2.14.8) (p) | 2024-01-09T22:57:07Z | 752 | 235 | 173 | 1,160 | | [v2.14.7](https://github.com/laurent22/joplin/releases/tag/v2.14.7) (p) | 2024-01-08T11:51:49Z | 620 | 127 | 173 | 920 | -| [v2.14.6](https://github.com/laurent22/joplin/releases/tag/v2.14.6) (p) | 2024-01-06T16:38:32Z | 725 | 149 | 149 | 1,023 | -| [v2.13.13](https://github.com/laurent22/joplin/releases/tag/v2.13.13) | 2024-01-06T13:33:11Z | 53,345 | 15,929 | 6,345 | 75,619 | -| [v2.13.12](https://github.com/laurent22/joplin/releases/tag/v2.13.12) | 2023-12-31T16:08:02Z | 44,729 | 14,282 | 5,083 | 64,094 | -| [v2.13.11](https://github.com/laurent22/joplin/releases/tag/v2.13.11) | 2023-12-24T12:58:53Z | 45,663 | 13,260 | 5,970 | 64,893 | -| [v2.13.10](https://github.com/laurent22/joplin/releases/tag/v2.13.10) | 2023-12-22T10:11:08Z | 19,535 | 8,688 | 1,452 | 29,675 | -| [v2.13.9](https://github.com/laurent22/joplin/releases/tag/v2.13.9) | 2023-12-09T17:18:58Z | 67,456 | 21,923 | 8,601 | 97,980 | -| [v2.13.8](https://github.com/laurent22/joplin/releases/tag/v2.13.8) | 2023-12-03T12:07:08Z | 50,231 | 17,900 | 5,211 | 73,342 | +| [v2.14.6](https://github.com/laurent22/joplin/releases/tag/v2.14.6) (p) | 2024-01-06T16:38:32Z | 726 | 149 | 149 | 1,024 | +| [v2.13.13](https://github.com/laurent22/joplin/releases/tag/v2.13.13) | 2024-01-06T13:33:11Z | 53,547 | 15,929 | 6,345 | 75,821 | +| [v2.13.12](https://github.com/laurent22/joplin/releases/tag/v2.13.12) | 2023-12-31T16:08:02Z | 44,874 | 14,295 | 5,083 | 64,252 | +| [v2.13.11](https://github.com/laurent22/joplin/releases/tag/v2.13.11) | 2023-12-24T12:58:53Z | 45,797 | 13,260 | 5,970 | 65,027 | +| [v2.13.10](https://github.com/laurent22/joplin/releases/tag/v2.13.10) | 2023-12-22T10:11:08Z | 19,601 | 8,691 | 1,457 | 29,749 | +| [v2.13.9](https://github.com/laurent22/joplin/releases/tag/v2.13.9) | 2023-12-09T17:18:58Z | 67,598 | 21,923 | 8,603 | 98,124 | +| [v2.13.8](https://github.com/laurent22/joplin/releases/tag/v2.13.8) | 2023-12-03T12:07:08Z | 50,352 | 17,900 | 5,211 | 73,463 | | [v2.13.6](https://github.com/laurent22/joplin/releases/tag/v2.13.6) (p) | 2023-11-17T19:24:03Z | 2,155 | 443 | 573 | 3,171 | -| [v2.13.5](https://github.com/laurent22/joplin/releases/tag/v2.13.5) (p) | 2023-11-09T20:24:09Z | 1,466 | 338 | 437 | 2,241 | -| [v2.13.4](https://github.com/laurent22/joplin/releases/tag/v2.13.4) (p) | 2023-10-31T00:01:00Z | 1,538 | 372 | 482 | 2,392 | +| [v2.13.5](https://github.com/laurent22/joplin/releases/tag/v2.13.5) (p) | 2023-11-09T20:24:09Z | 1,467 | 338 | 437 | 2,242 | +| [v2.13.4](https://github.com/laurent22/joplin/releases/tag/v2.13.4) (p) | 2023-10-31T00:01:00Z | 1,539 | 372 | 482 | 2,393 | | [v2.13.3](https://github.com/laurent22/joplin/releases/tag/v2.13.3) (p) | 2023-10-24T09:25:33Z | 1,302 | 281 | 301 | 1,884 | -| [v2.12.19](https://github.com/laurent22/joplin/releases/tag/v2.12.19) | 2023-10-21T09:39:18Z | 166,039 | 43,649 | 27,829 | 237,517 | -| [v2.13.2](https://github.com/laurent22/joplin/releases/tag/v2.13.2) (p) | 2023-10-06T17:00:07Z | 2,032 | 503 | 701 | 3,236 | -| [v2.12.18](https://github.com/laurent22/joplin/releases/tag/v2.12.18) | 2023-09-22T14:37:24Z | 108,367 | 36,512 | 18,692 | 163,571 | -| [v2.12.17](https://github.com/laurent22/joplin/releases/tag/v2.12.17) | 2023-09-14T21:54:52Z | 47,051 | 21,030 | 6,625 | 74,706 | -| [v2.13.1](https://github.com/laurent22/joplin/releases/tag/v2.13.1) (p) | 2023-09-13T09:31:50Z | 1,390 | 427 | 660 | 2,477 | -| [v2.12.16](https://github.com/laurent22/joplin/releases/tag/v2.12.16) | 2023-09-11T22:33:37Z | 28,194 | 14,665 | 2,446 | 45,305 | -| [v2.12.15](https://github.com/laurent22/joplin/releases/tag/v2.12.15) | 2023-08-27T11:35:39Z | 63,935 | 28,043 | 8,346 | 100,324 | -| [v2.12.12](https://github.com/laurent22/joplin/releases/tag/v2.12.12) (p) | 2023-08-19T22:44:56Z | 2,619 | 387 | 428 | 3,434 | -| [v2.12.10](https://github.com/laurent22/joplin/releases/tag/v2.12.10) (p) | 2023-07-30T18:25:58Z | 7,260 | 3,814 | 912 | 11,986 | -| [v2.12.9](https://github.com/laurent22/joplin/releases/tag/v2.12.9) (p) | 2023-07-25T16:06:08Z | 2,079 | 369 | 321 | 2,769 | -| [v2.12.7](https://github.com/laurent22/joplin/releases/tag/v2.12.7) (p) | 2023-07-13T12:55:31Z | 2,133 | 662 | 590 | 3,385 | -| [v2.12.5](https://github.com/laurent22/joplin/releases/tag/v2.12.5) (p) | 2023-07-12T15:03:46Z | 1,736 | 162 | 146 | 2,044 | +| [v2.12.19](https://github.com/laurent22/joplin/releases/tag/v2.12.19) | 2023-10-21T09:39:18Z | 166,234 | 43,649 | 27,833 | 237,716 | +| [v2.13.2](https://github.com/laurent22/joplin/releases/tag/v2.13.2) (p) | 2023-10-06T17:00:07Z | 2,032 | 503 | 703 | 3,238 | +| [v2.12.18](https://github.com/laurent22/joplin/releases/tag/v2.12.18) | 2023-09-22T14:37:24Z | 108,531 | 36,513 | 18,693 | 163,737 | +| [v2.12.17](https://github.com/laurent22/joplin/releases/tag/v2.12.17) | 2023-09-14T21:54:52Z | 47,173 | 21,030 | 6,626 | 74,829 | +| [v2.13.1](https://github.com/laurent22/joplin/releases/tag/v2.13.1) (p) | 2023-09-13T09:31:50Z | 1,390 | 427 | 661 | 2,478 | +| [v2.12.16](https://github.com/laurent22/joplin/releases/tag/v2.12.16) | 2023-09-11T22:33:37Z | 28,266 | 14,665 | 2,446 | 45,377 | +| [v2.12.15](https://github.com/laurent22/joplin/releases/tag/v2.12.15) | 2023-08-27T11:35:39Z | 64,101 | 28,054 | 8,359 | 100,514 | +| [v2.12.12](https://github.com/laurent22/joplin/releases/tag/v2.12.12) (p) | 2023-08-19T22:44:56Z | 2,671 | 387 | 428 | 3,486 | +| [v2.12.10](https://github.com/laurent22/joplin/releases/tag/v2.12.10) (p) | 2023-07-30T18:25:58Z | 7,312 | 3,815 | 913 | 12,040 | +| [v2.12.9](https://github.com/laurent22/joplin/releases/tag/v2.12.9) (p) | 2023-07-25T16:06:08Z | 2,130 | 369 | 321 | 2,820 | +| [v2.12.7](https://github.com/laurent22/joplin/releases/tag/v2.12.7) (p) | 2023-07-13T12:55:31Z | 2,145 | 662 | 590 | 3,397 | +| [v2.12.5](https://github.com/laurent22/joplin/releases/tag/v2.12.5) (p) | 2023-07-12T15:03:46Z | 1,796 | 163 | 148 | 2,107 | | [v2.12.4](https://github.com/laurent22/joplin/releases/tag/v2.12.4) (p) | 2023-07-07T22:36:53Z | 1,047 | 430 | 215 | 1,692 | -| [v2.12.3](https://github.com/laurent22/joplin/releases/tag/v2.12.3) (p) | 2023-07-07T10:16:55Z | 382 | 184 | 93 | 659 | -| [v2.11.11](https://github.com/laurent22/joplin/releases/tag/v2.11.11) | 2023-06-23T15:16:37Z | 188,772 | 67,215 | 38,833 | 294,820 | +| [v2.12.3](https://github.com/laurent22/joplin/releases/tag/v2.12.3) (p) | 2023-07-07T10:16:55Z | 383 | 184 | 93 | 660 | +| [v2.11.11](https://github.com/laurent22/joplin/releases/tag/v2.11.11) | 2023-06-23T15:16:37Z | 188,935 | 67,215 | 38,837 | 294,987 | | [v2.11.9](https://github.com/laurent22/joplin/releases/tag/v2.11.9) (p) | 2023-06-06T16:23:27Z | 2,294 | 571 | 744 | 3,609 | | [v2.11.6](https://github.com/laurent22/joplin/releases/tag/v2.11.6) (p) | 2023-05-31T20:13:08Z | 1,156 | 433 | 342 | 1,931 | -| [v2.11.5](https://github.com/laurent22/joplin/releases/tag/v2.11.5) (p) | 2023-05-28T00:41:40Z | 1,019 | 306 | 279 | 1,604 | -| [v2.10.19](https://github.com/laurent22/joplin/releases/tag/v2.10.19) | 2023-05-17T12:25:41Z | 124,108 | 48,327 | 22,464 | 194,899 | +| [v2.11.5](https://github.com/laurent22/joplin/releases/tag/v2.11.5) (p) | 2023-05-28T00:41:40Z | 1,021 | 306 | 279 | 1,606 | +| [v2.10.19](https://github.com/laurent22/joplin/releases/tag/v2.10.19) | 2023-05-17T12:25:41Z | 124,237 | 48,328 | 22,466 | 195,031 | | [v2.11.4](https://github.com/laurent22/joplin/releases/tag/v2.11.4) (p) | 2023-05-16T10:02:21Z | 1,078 | 466 | 412 | 1,956 | -| [v2.11.3](https://github.com/laurent22/joplin/releases/tag/v2.11.3) (p) | 2023-05-16T09:09:57Z | 120 | 38 | 37 | 195 | -| [v2.10.18](https://github.com/laurent22/joplin/releases/tag/v2.10.18) | 2023-05-09T13:27:43Z | 56,058 | 24,252 | 6,774 | 87,084 | -| [v2.10.17](https://github.com/laurent22/joplin/releases/tag/v2.10.17) | 2023-05-08T17:27:28Z | 18,786 | 11,506 | 885 | 31,177 | -| [v2.10.16](https://github.com/laurent22/joplin/releases/tag/v2.10.16) | 2023-04-27T09:27:45Z | 9,049 | 4,255 | 779 | 14,083 | +| [v2.11.3](https://github.com/laurent22/joplin/releases/tag/v2.11.3) (p) | 2023-05-16T09:09:57Z | 124 | 38 | 37 | 199 | +| [v2.10.18](https://github.com/laurent22/joplin/releases/tag/v2.10.18) | 2023-05-09T13:27:43Z | 56,146 | 24,252 | 6,774 | 87,172 | +| [v2.10.17](https://github.com/laurent22/joplin/releases/tag/v2.10.17) | 2023-05-08T17:27:28Z | 18,887 | 11,506 | 885 | 31,278 | +| [v2.10.16](https://github.com/laurent22/joplin/releases/tag/v2.10.16) | 2023-04-27T09:27:45Z | 9,130 | 4,255 | 779 | 14,164 | | [v2.10.15](https://github.com/laurent22/joplin/releases/tag/v2.10.15) (p) | 2023-04-26T22:02:16Z | 370 | 139 | 56 | 565 | -| [v2.10.13](https://github.com/laurent22/joplin/releases/tag/v2.10.13) (p) | 2023-04-03T16:53:46Z | 4,392 | 829 | 1,078 | 6,299 | -| [v2.10.12](https://github.com/laurent22/joplin/releases/tag/v2.10.12) (p) | 2023-03-23T12:17:13Z | 3,364 | 518 | 604 | 4,486 | -| [v2.10.11](https://github.com/laurent22/joplin/releases/tag/v2.10.11) (p) | 2023-03-17T10:54:02Z | 2,729 | 383 | 392 | 3,504 | -| [v2.10.10](https://github.com/laurent22/joplin/releases/tag/v2.10.10) (p) | 2023-03-13T23:16:37Z | 2,239 | 283 | 255 | 2,777 | -| [v2.10.9](https://github.com/laurent22/joplin/releases/tag/v2.10.9) (p) | 2023-03-12T16:16:45Z | 1,770 | 214 | 297 | 2,281 | -| [v2.10.8](https://github.com/laurent22/joplin/releases/tag/v2.10.8) (p) | 2023-02-26T12:53:55Z | 4,250 | 573 | 872 | 5,695 | -| [v2.10.7](https://github.com/laurent22/joplin/releases/tag/v2.10.7) (p) | 2023-02-24T10:56:20Z | 1,915 | 191 | 279 | 2,385 | -| [v2.10.6](https://github.com/laurent22/joplin/releases/tag/v2.10.6) (p) | 2023-02-20T14:00:05Z | 2,715 | 342 | 290 | 3,347 | +| [v2.10.13](https://github.com/laurent22/joplin/releases/tag/v2.10.13) (p) | 2023-04-03T16:53:46Z | 4,438 | 829 | 1,078 | 6,345 | +| [v2.10.12](https://github.com/laurent22/joplin/releases/tag/v2.10.12) (p) | 2023-03-23T12:17:13Z | 3,412 | 518 | 604 | 4,534 | +| [v2.10.11](https://github.com/laurent22/joplin/releases/tag/v2.10.11) (p) | 2023-03-17T10:54:02Z | 2,776 | 383 | 392 | 3,551 | +| [v2.10.10](https://github.com/laurent22/joplin/releases/tag/v2.10.10) (p) | 2023-03-13T23:16:37Z | 2,286 | 283 | 255 | 2,824 | +| [v2.10.9](https://github.com/laurent22/joplin/releases/tag/v2.10.9) (p) | 2023-03-12T16:16:45Z | 1,818 | 214 | 297 | 2,329 | +| [v2.10.8](https://github.com/laurent22/joplin/releases/tag/v2.10.8) (p) | 2023-02-26T12:53:55Z | 4,296 | 573 | 872 | 5,741 | +| [v2.10.7](https://github.com/laurent22/joplin/releases/tag/v2.10.7) (p) | 2023-02-24T10:56:20Z | 1,963 | 191 | 279 | 2,433 | +| [v2.10.6](https://github.com/laurent22/joplin/releases/tag/v2.10.6) (p) | 2023-02-20T14:00:05Z | 2,762 | 342 | 290 | 3,394 | | [v2.10.5](https://github.com/laurent22/joplin/releases/tag/v2.10.5) | 2023-01-16T15:00:53Z | 365 | 101 | 307 | 773 | -| [v2.10.4](https://github.com/laurent22/joplin/releases/tag/v2.10.4) (p) | 2023-01-05T13:09:20Z | 7,932 | 1,303 | 1,812 | 11,047 | -| [v2.10.3](https://github.com/laurent22/joplin/releases/tag/v2.10.3) (p) | 2022-12-31T15:53:23Z | 2,503 | 312 | 411 | 3,226 | -| [v2.10.2](https://github.com/laurent22/joplin/releases/tag/v2.10.2) (p) | 2022-12-18T18:05:08Z | 3,937 | 587 | 634 | 5,158 | -| [v2.9.17](https://github.com/laurent22/joplin/releases/tag/v2.9.17) | 2022-11-15T10:28:37Z | 335,069 | 108,775 | 83,339 | 527,183 | -| [v2.9.12](https://github.com/laurent22/joplin/releases/tag/v2.9.12) (p) | 2022-11-01T17:06:05Z | 11,116 | 611 | 540 | 12,267 | -| [v2.9.11](https://github.com/laurent22/joplin/releases/tag/v2.9.11) (p) | 2022-10-23T16:09:58Z | 3,266 | 529 | 755 | 4,550 | -| [v2.9.4](https://github.com/laurent22/joplin/releases/tag/v2.9.4) (p) | 2022-08-18T16:52:26Z | 8,309 | 1,867 | 2,193 | 12,369 | -| [v2.9.3](https://github.com/laurent22/joplin/releases/tag/v2.9.3) (p) | 2022-08-18T13:11:09Z | 363 | 91 | 269 | 723 | -| [v2.9.2](https://github.com/laurent22/joplin/releases/tag/v2.9.2) (p) | 2022-08-12T18:12:12Z | 1,533 | 446 | 0 | 1,979 | -| [v2.9.1](https://github.com/laurent22/joplin/releases/tag/v2.9.1) (p) | 2022-07-11T09:59:32Z | 7,750 | 1,342 | 1,404 | 10,496 | -| [v2.8.8](https://github.com/laurent22/joplin/releases/tag/v2.8.8) | 2022-05-17T14:48:06Z | 351,157 | 114,351 | 113,560 | 579,068 | -| [v2.8.7](https://github.com/laurent22/joplin/releases/tag/v2.8.7) (p) | 2022-05-06T11:34:27Z | 4,255 | 365 | 422 | 5,042 | -| [v2.8.6](https://github.com/laurent22/joplin/releases/tag/v2.8.6) (p) | 2022-05-03T10:08:25Z | 3,881 | 402 | 328 | 4,611 | -| [v2.8.5](https://github.com/laurent22/joplin/releases/tag/v2.8.5) (p) | 2022-04-27T13:51:50Z | 3,972 | 369 | 351 | 4,692 | -| [v2.8.4](https://github.com/laurent22/joplin/releases/tag/v2.8.4) (p) | 2022-04-19T18:00:09Z | 4,461 | 589 | 327 | 5,377 | -| [v2.8.2](https://github.com/laurent22/joplin/releases/tag/v2.8.2) (p) | 2022-04-14T11:35:45Z | 3,860 | 279 | 266 | 4,405 | -| [v2.7.15](https://github.com/laurent22/joplin/releases/tag/v2.7.15) | 2022-03-17T13:03:23Z | 156,090 | 56,775 | 51,261 | 264,126 | -| [v2.7.14](https://github.com/laurent22/joplin/releases/tag/v2.7.14) | 2022-02-27T11:30:53Z | 34,428 | 16,782 | 4,802 | 56,012 | -| [v2.7.13](https://github.com/laurent22/joplin/releases/tag/v2.7.13) | 2022-02-24T17:42:12Z | 54,789 | 25,724 | 11,712 | 92,225 | -| [v2.7.12](https://github.com/laurent22/joplin/releases/tag/v2.7.12) (p) | 2022-02-14T15:06:14Z | 4,651 | 464 | 482 | 5,597 | -| [v2.7.11](https://github.com/laurent22/joplin/releases/tag/v2.7.11) (p) | 2022-02-12T13:00:02Z | 3,791 | 194 | 168 | 4,153 | -| [v2.7.10](https://github.com/laurent22/joplin/releases/tag/v2.7.10) (p) | 2022-02-11T18:19:09Z | 3,297 | 125 | 82 | 3,504 | -| [v2.7.8](https://github.com/laurent22/joplin/releases/tag/v2.7.8) (p) | 2022-01-19T09:35:27Z | 5,523 | 770 | 824 | 7,117 | -| [v2.7.7](https://github.com/laurent22/joplin/releases/tag/v2.7.7) (p) | 2022-01-18T14:05:07Z | 3,621 | 156 | 135 | 3,912 | -| [v2.7.6](https://github.com/laurent22/joplin/releases/tag/v2.7.6) (p) | 2022-01-17T17:08:28Z | 3,543 | 182 | 114 | 3,839 | -| [v2.6.10](https://github.com/laurent22/joplin/releases/tag/v2.6.10) | 2021-12-19T11:31:16Z | 135,988 | 51,198 | 49,310 | 236,496 | -| [v2.6.9](https://github.com/laurent22/joplin/releases/tag/v2.6.9) | 2021-12-17T11:57:32Z | 19,038 | 9,495 | 3,186 | 31,719 | -| [v2.6.7](https://github.com/laurent22/joplin/releases/tag/v2.6.7) (p) | 2021-12-16T10:47:23Z | 3,763 | 166 | 103 | 4,032 | -| [v2.6.6](https://github.com/laurent22/joplin/releases/tag/v2.6.6) (p) | 2021-12-13T12:31:43Z | 3,756 | 256 | 166 | 4,178 | -| [v2.6.5](https://github.com/laurent22/joplin/releases/tag/v2.6.5) (p) | 2021-12-13T10:07:04Z | 3,092 | 50 | 30 | 3,172 | -| [v2.6.4](https://github.com/laurent22/joplin/releases/tag/v2.6.4) (p) | 2021-12-09T19:53:43Z | 3,834 | 290 | 201 | 4,325 | -| [v2.6.2](https://github.com/laurent22/joplin/releases/tag/v2.6.2) (p) | 2021-11-18T12:19:12Z | 5,623 | 793 | 702 | 7,118 | -| [v2.5.12](https://github.com/laurent22/joplin/releases/tag/v2.5.12) | 2021-11-08T11:07:11Z | 82,745 | 32,504 | 25,233 | 140,482 | -| [v2.5.10](https://github.com/laurent22/joplin/releases/tag/v2.5.10) | 2021-11-01T08:22:42Z | 46,998 | 19,049 | 10,096 | 76,143 | -| [v2.5.8](https://github.com/laurent22/joplin/releases/tag/v2.5.8) | 2021-10-31T11:38:03Z | 15,727 | 6,578 | 2,323 | 24,628 | -| [v2.5.7](https://github.com/laurent22/joplin/releases/tag/v2.5.7) (p) | 2021-10-29T14:47:33Z | 3,362 | 203 | 164 | 3,729 | -| [v2.5.6](https://github.com/laurent22/joplin/releases/tag/v2.5.6) (p) | 2021-10-28T22:03:09Z | 3,415 | 177 | 107 | 3,699 | -| [v2.5.4](https://github.com/laurent22/joplin/releases/tag/v2.5.4) (p) | 2021-10-19T10:10:54Z | 4,912 | 568 | 579 | 6,059 | -| [v2.4.12](https://github.com/laurent22/joplin/releases/tag/v2.4.12) | 2021-10-13T17:24:34Z | 47,368 | 19,980 | 9,786 | 77,134 | -| [v2.5.1](https://github.com/laurent22/joplin/releases/tag/v2.5.1) (p) | 2021-10-02T09:51:58Z | 5,948 | 907 | 947 | 7,802 | -| [v2.4.9](https://github.com/laurent22/joplin/releases/tag/v2.4.9) | 2021-09-29T19:08:58Z | 59,115 | 23,259 | 15,912 | 98,286 | -| [v2.4.8](https://github.com/laurent22/joplin/releases/tag/v2.4.8) (p) | 2021-09-22T19:01:46Z | 9,763 | 1,774 | 535 | 12,072 | -| [v2.4.7](https://github.com/laurent22/joplin/releases/tag/v2.4.7) (p) | 2021-09-19T12:53:22Z | 3,881 | 259 | 210 | 4,350 | -| [v2.4.6](https://github.com/laurent22/joplin/releases/tag/v2.4.6) (p) | 2021-09-09T18:57:17Z | 4,647 | 460 | 520 | 5,627 | -| [v2.4.5](https://github.com/laurent22/joplin/releases/tag/v2.4.5) (p) | 2021-09-06T18:03:28Z | 3,887 | 275 | 225 | 4,387 | -| [v2.4.4](https://github.com/laurent22/joplin/releases/tag/v2.4.4) (p) | 2021-08-30T16:02:51Z | 4,097 | 380 | 368 | 4,845 | -| [v2.4.3](https://github.com/laurent22/joplin/releases/tag/v2.4.3) (p) | 2021-08-28T15:27:32Z | 3,597 | 207 | 180 | 3,984 | -| [v2.4.2](https://github.com/laurent22/joplin/releases/tag/v2.4.2) (p) | 2021-08-27T17:13:21Z | 3,359 | 151 | 91 | 3,601 | -| [v2.4.1](https://github.com/laurent22/joplin/releases/tag/v2.4.1) (p) | 2021-08-21T11:52:30Z | 4,209 | 372 | 337 | 4,918 | -| [v2.3.5](https://github.com/laurent22/joplin/releases/tag/v2.3.5) | 2021-08-17T06:43:30Z | 85,049 | 31,433 | 33,139 | 149,621 | -| [v2.3.3](https://github.com/laurent22/joplin/releases/tag/v2.3.3) | 2021-08-14T09:19:40Z | 18,272 | 6,885 | 4,062 | 29,219 | -| [v2.2.7](https://github.com/laurent22/joplin/releases/tag/v2.2.7) | 2021-08-11T11:03:26Z | 18,162 | 7,524 | 2,607 | 28,293 | -| [v2.2.6](https://github.com/laurent22/joplin/releases/tag/v2.2.6) (p) | 2021-08-09T19:29:20Z | 10,620 | 4,619 | 958 | 16,197 | -| [v2.2.5](https://github.com/laurent22/joplin/releases/tag/v2.2.5) (p) | 2021-08-07T10:35:24Z | 3,940 | 278 | 208 | 4,426 | -| [v2.2.4](https://github.com/laurent22/joplin/releases/tag/v2.2.4) (p) | 2021-08-05T16:42:48Z | 3,604 | 208 | 133 | 3,945 | -| [v2.2.2](https://github.com/laurent22/joplin/releases/tag/v2.2.2) (p) | 2021-07-19T10:28:35Z | 5,511 | 737 | 648 | 6,896 | -| [v2.1.9](https://github.com/laurent22/joplin/releases/tag/v2.1.9) | 2021-07-19T10:28:43Z | 49,761 | 18,958 | 16,816 | 85,535 | -| [v2.2.1](https://github.com/laurent22/joplin/releases/tag/v2.2.1) (p) | 2021-07-09T17:38:25Z | 5,141 | 417 | 394 | 5,952 | -| [v2.1.8](https://github.com/laurent22/joplin/releases/tag/v2.1.8) | 2021-07-03T08:25:16Z | 33,376 | 12,205 | 12,736 | 58,317 | -| [v2.1.7](https://github.com/laurent22/joplin/releases/tag/v2.1.7) | 2021-06-26T19:48:55Z | 16,706 | 6,410 | 3,636 | 26,752 | -| [v2.1.5](https://github.com/laurent22/joplin/releases/tag/v2.1.5) (p) | 2021-06-23T15:08:52Z | 4,037 | 254 | 202 | 4,493 | -| [v2.1.3](https://github.com/laurent22/joplin/releases/tag/v2.1.3) (p) | 2021-06-19T16:32:51Z | 4,107 | 312 | 217 | 4,636 | -| [v2.0.11](https://github.com/laurent22/joplin/releases/tag/v2.0.11) | 2021-06-16T17:55:49Z | 26,392 | 9,279 | 9,902 | 45,573 | -| [v2.0.10](https://github.com/laurent22/joplin/releases/tag/v2.0.10) | 2021-06-16T07:58:29Z | 5,606 | 945 | 399 | 6,950 | -| [v2.0.9](https://github.com/laurent22/joplin/releases/tag/v2.0.9) (p) | 2021-06-12T09:30:30Z | 4,021 | 306 | 897 | 5,224 | -| [v2.0.8](https://github.com/laurent22/joplin/releases/tag/v2.0.8) (p) | 2021-06-10T16:15:08Z | 3,530 | 246 | 597 | 4,373 | +| [v2.10.4](https://github.com/laurent22/joplin/releases/tag/v2.10.4) (p) | 2023-01-05T13:09:20Z | 7,980 | 1,303 | 1,812 | 11,095 | +| [v2.10.3](https://github.com/laurent22/joplin/releases/tag/v2.10.3) (p) | 2022-12-31T15:53:23Z | 2,549 | 313 | 412 | 3,274 | +| [v2.10.2](https://github.com/laurent22/joplin/releases/tag/v2.10.2) (p) | 2022-12-18T18:05:08Z | 3,984 | 589 | 635 | 5,208 | +| [v2.9.17](https://github.com/laurent22/joplin/releases/tag/v2.9.17) | 2022-11-15T10:28:37Z | 335,188 | 108,776 | 83,340 | 527,304 | +| [v2.9.12](https://github.com/laurent22/joplin/releases/tag/v2.9.12) (p) | 2022-11-01T17:06:05Z | 11,163 | 612 | 541 | 12,316 | +| [v2.9.11](https://github.com/laurent22/joplin/releases/tag/v2.9.11) (p) | 2022-10-23T16:09:58Z | 3,313 | 530 | 756 | 4,599 | +| [v2.9.4](https://github.com/laurent22/joplin/releases/tag/v2.9.4) (p) | 2022-08-18T16:52:26Z | 8,356 | 1,868 | 2,194 | 12,418 | +| [v2.9.3](https://github.com/laurent22/joplin/releases/tag/v2.9.3) (p) | 2022-08-18T13:11:09Z | 363 | 92 | 270 | 725 | +| [v2.9.2](https://github.com/laurent22/joplin/releases/tag/v2.9.2) (p) | 2022-08-12T18:12:12Z | 1,533 | 447 | 0 | 1,980 | +| [v2.9.1](https://github.com/laurent22/joplin/releases/tag/v2.9.1) (p) | 2022-07-11T09:59:32Z | 7,797 | 1,343 | 1,405 | 10,545 | +| [v2.8.8](https://github.com/laurent22/joplin/releases/tag/v2.8.8) | 2022-05-17T14:48:06Z | 351,304 | 114,355 | 113,564 | 579,223 | +| [v2.8.7](https://github.com/laurent22/joplin/releases/tag/v2.8.7) (p) | 2022-05-06T11:34:27Z | 4,301 | 366 | 423 | 5,090 | +| [v2.8.6](https://github.com/laurent22/joplin/releases/tag/v2.8.6) (p) | 2022-05-03T10:08:25Z | 3,929 | 403 | 329 | 4,661 | +| [v2.8.5](https://github.com/laurent22/joplin/releases/tag/v2.8.5) (p) | 2022-04-27T13:51:50Z | 4,018 | 370 | 352 | 4,740 | +| [v2.8.4](https://github.com/laurent22/joplin/releases/tag/v2.8.4) (p) | 2022-04-19T18:00:09Z | 4,507 | 590 | 328 | 5,425 | +| [v2.8.2](https://github.com/laurent22/joplin/releases/tag/v2.8.2) (p) | 2022-04-14T11:35:45Z | 3,907 | 280 | 267 | 4,454 | +| [v2.7.15](https://github.com/laurent22/joplin/releases/tag/v2.7.15) | 2022-03-17T13:03:23Z | 156,153 | 56,777 | 51,265 | 264,195 | +| [v2.7.14](https://github.com/laurent22/joplin/releases/tag/v2.7.14) | 2022-02-27T11:30:53Z | 34,476 | 16,783 | 4,803 | 56,062 | +| [v2.7.13](https://github.com/laurent22/joplin/releases/tag/v2.7.13) | 2022-02-24T17:42:12Z | 54,850 | 25,725 | 11,713 | 92,288 | +| [v2.7.12](https://github.com/laurent22/joplin/releases/tag/v2.7.12) (p) | 2022-02-14T15:06:14Z | 4,697 | 465 | 483 | 5,645 | +| [v2.7.11](https://github.com/laurent22/joplin/releases/tag/v2.7.11) (p) | 2022-02-12T13:00:02Z | 3,837 | 195 | 169 | 4,201 | +| [v2.7.10](https://github.com/laurent22/joplin/releases/tag/v2.7.10) (p) | 2022-02-11T18:19:09Z | 3,345 | 126 | 83 | 3,554 | +| [v2.7.8](https://github.com/laurent22/joplin/releases/tag/v2.7.8) (p) | 2022-01-19T09:35:27Z | 5,570 | 771 | 825 | 7,166 | +| [v2.7.7](https://github.com/laurent22/joplin/releases/tag/v2.7.7) (p) | 2022-01-18T14:05:07Z | 3,668 | 157 | 136 | 3,961 | +| [v2.7.6](https://github.com/laurent22/joplin/releases/tag/v2.7.6) (p) | 2022-01-17T17:08:28Z | 3,590 | 183 | 115 | 3,888 | +| [v2.6.10](https://github.com/laurent22/joplin/releases/tag/v2.6.10) | 2021-12-19T11:31:16Z | 136,105 | 51,199 | 49,311 | 236,615 | +| [v2.6.9](https://github.com/laurent22/joplin/releases/tag/v2.6.9) | 2021-12-17T11:57:32Z | 19,116 | 9,498 | 3,187 | 31,801 | +| [v2.6.7](https://github.com/laurent22/joplin/releases/tag/v2.6.7) (p) | 2021-12-16T10:47:23Z | 3,811 | 180 | 104 | 4,095 | +| [v2.6.6](https://github.com/laurent22/joplin/releases/tag/v2.6.6) (p) | 2021-12-13T12:31:43Z | 3,803 | 257 | 167 | 4,227 | +| [v2.6.5](https://github.com/laurent22/joplin/releases/tag/v2.6.5) (p) | 2021-12-13T10:07:04Z | 3,138 | 51 | 31 | 3,220 | +| [v2.6.4](https://github.com/laurent22/joplin/releases/tag/v2.6.4) (p) | 2021-12-09T19:53:43Z | 3,882 | 291 | 202 | 4,375 | +| [v2.6.2](https://github.com/laurent22/joplin/releases/tag/v2.6.2) (p) | 2021-11-18T12:19:12Z | 5,672 | 793 | 702 | 7,167 | +| [v2.5.12](https://github.com/laurent22/joplin/releases/tag/v2.5.12) | 2021-11-08T11:07:11Z | 82,848 | 32,504 | 25,233 | 140,585 | +| [v2.5.10](https://github.com/laurent22/joplin/releases/tag/v2.5.10) | 2021-11-01T08:22:42Z | 47,059 | 19,049 | 10,096 | 76,204 | +| [v2.5.8](https://github.com/laurent22/joplin/releases/tag/v2.5.8) | 2021-10-31T11:38:03Z | 15,791 | 6,579 | 2,325 | 24,695 | +| [v2.5.7](https://github.com/laurent22/joplin/releases/tag/v2.5.7) (p) | 2021-10-29T14:47:33Z | 3,409 | 203 | 164 | 3,776 | +| [v2.5.6](https://github.com/laurent22/joplin/releases/tag/v2.5.6) (p) | 2021-10-28T22:03:09Z | 3,463 | 177 | 107 | 3,747 | +| [v2.5.4](https://github.com/laurent22/joplin/releases/tag/v2.5.4) (p) | 2021-10-19T10:10:54Z | 4,960 | 568 | 580 | 6,108 | +| [v2.4.12](https://github.com/laurent22/joplin/releases/tag/v2.4.12) | 2021-10-13T17:24:34Z | 47,473 | 19,980 | 9,786 | 77,239 | +| [v2.5.1](https://github.com/laurent22/joplin/releases/tag/v2.5.1) (p) | 2021-10-02T09:51:58Z | 5,997 | 907 | 947 | 7,851 | +| [v2.4.9](https://github.com/laurent22/joplin/releases/tag/v2.4.9) | 2021-09-29T19:08:58Z | 59,195 | 23,260 | 15,913 | 98,368 | +| [v2.4.8](https://github.com/laurent22/joplin/releases/tag/v2.4.8) (p) | 2021-09-22T19:01:46Z | 9,810 | 1,774 | 535 | 12,119 | +| [v2.4.7](https://github.com/laurent22/joplin/releases/tag/v2.4.7) (p) | 2021-09-19T12:53:22Z | 3,930 | 259 | 210 | 4,399 | +| [v2.4.6](https://github.com/laurent22/joplin/releases/tag/v2.4.6) (p) | 2021-09-09T18:57:17Z | 4,696 | 460 | 520 | 5,676 | +| [v2.4.5](https://github.com/laurent22/joplin/releases/tag/v2.4.5) (p) | 2021-09-06T18:03:28Z | 3,938 | 275 | 225 | 4,438 | +| [v2.4.4](https://github.com/laurent22/joplin/releases/tag/v2.4.4) (p) | 2021-08-30T16:02:51Z | 4,146 | 380 | 371 | 4,897 | +| [v2.4.3](https://github.com/laurent22/joplin/releases/tag/v2.4.3) (p) | 2021-08-28T15:27:32Z | 3,644 | 207 | 180 | 4,031 | +| [v2.4.2](https://github.com/laurent22/joplin/releases/tag/v2.4.2) (p) | 2021-08-27T17:13:21Z | 3,409 | 151 | 91 | 3,651 | +| [v2.4.1](https://github.com/laurent22/joplin/releases/tag/v2.4.1) (p) | 2021-08-21T11:52:30Z | 4,255 | 372 | 337 | 4,964 | +| [v2.3.5](https://github.com/laurent22/joplin/releases/tag/v2.3.5) | 2021-08-17T06:43:30Z | 85,158 | 31,436 | 33,142 | 149,736 | +| [v2.3.3](https://github.com/laurent22/joplin/releases/tag/v2.3.3) | 2021-08-14T09:19:40Z | 18,370 | 6,885 | 4,062 | 29,317 | +| [v2.2.7](https://github.com/laurent22/joplin/releases/tag/v2.2.7) | 2021-08-11T11:03:26Z | 18,246 | 7,524 | 2,607 | 28,377 | +| [v2.2.6](https://github.com/laurent22/joplin/releases/tag/v2.2.6) (p) | 2021-08-09T19:29:20Z | 10,670 | 4,619 | 958 | 16,247 | +| [v2.2.5](https://github.com/laurent22/joplin/releases/tag/v2.2.5) (p) | 2021-08-07T10:35:24Z | 3,986 | 278 | 208 | 4,472 | +| [v2.2.4](https://github.com/laurent22/joplin/releases/tag/v2.2.4) (p) | 2021-08-05T16:42:48Z | 3,650 | 208 | 133 | 3,991 | +| [v2.2.2](https://github.com/laurent22/joplin/releases/tag/v2.2.2) (p) | 2021-07-19T10:28:35Z | 5,559 | 737 | 648 | 6,944 | +| [v2.1.9](https://github.com/laurent22/joplin/releases/tag/v2.1.9) | 2021-07-19T10:28:43Z | 49,857 | 18,959 | 16,816 | 85,632 | +| [v2.2.1](https://github.com/laurent22/joplin/releases/tag/v2.2.1) (p) | 2021-07-09T17:38:25Z | 5,188 | 417 | 394 | 5,999 | +| [v2.1.8](https://github.com/laurent22/joplin/releases/tag/v2.1.8) | 2021-07-03T08:25:16Z | 33,448 | 12,205 | 12,736 | 58,389 | +| [v2.1.7](https://github.com/laurent22/joplin/releases/tag/v2.1.7) | 2021-06-26T19:48:55Z | 16,754 | 6,410 | 3,636 | 26,800 | +| [v2.1.5](https://github.com/laurent22/joplin/releases/tag/v2.1.5) (p) | 2021-06-23T15:08:52Z | 4,086 | 254 | 202 | 4,542 | +| [v2.1.3](https://github.com/laurent22/joplin/releases/tag/v2.1.3) (p) | 2021-06-19T16:32:51Z | 4,154 | 312 | 217 | 4,683 | +| [v2.0.11](https://github.com/laurent22/joplin/releases/tag/v2.0.11) | 2021-06-16T17:55:49Z | 26,458 | 9,279 | 9,903 | 45,640 | +| [v2.0.10](https://github.com/laurent22/joplin/releases/tag/v2.0.10) | 2021-06-16T07:58:29Z | 5,682 | 945 | 399 | 7,026 | +| [v2.0.9](https://github.com/laurent22/joplin/releases/tag/v2.0.9) (p) | 2021-06-12T09:30:30Z | 4,080 | 306 | 899 | 5,285 | +| [v2.0.8](https://github.com/laurent22/joplin/releases/tag/v2.0.8) (p) | 2021-06-10T16:15:08Z | 3,578 | 246 | 598 | 4,422 | | [v2.0.4](https://github.com/laurent22/joplin/releases/tag/v2.0.4) (p) | 2021-06-02T12:54:17Z | 1,642 | 404 | 392 | 2,438 | -| [v2.0.2](https://github.com/laurent22/joplin/releases/tag/v2.0.2) (p) | 2021-05-21T18:07:48Z | 5,586 | 503 | 1,681 | 7,770 | +| [v2.0.2](https://github.com/laurent22/joplin/releases/tag/v2.0.2) (p) | 2021-05-21T18:07:48Z | 5,667 | 503 | 1,681 | 7,851 | | [v2.0.1](https://github.com/laurent22/joplin/releases/tag/v2.0.1) (p) | 2021-05-15T13:22:58Z | 948 | 287 | 1,039 | 2,274 | -| [v1.8.5](https://github.com/laurent22/joplin/releases/tag/v1.8.5) | 2021-05-10T11:58:14Z | 41,432 | 16,301 | 19,436 | 77,169 | -| [v1.8.4](https://github.com/laurent22/joplin/releases/tag/v1.8.4) (p) | 2021-05-09T18:05:05Z | 3,467 | 152 | 473 | 4,092 | -| [v1.8.3](https://github.com/laurent22/joplin/releases/tag/v1.8.3) (p) | 2021-05-04T10:38:16Z | 4,486 | 320 | 951 | 5,757 | -| [v1.8.2](https://github.com/laurent22/joplin/releases/tag/v1.8.2) (p) | 2021-04-25T10:50:51Z | 4,782 | 451 | 1,300 | 6,533 | -| [v1.8.1](https://github.com/laurent22/joplin/releases/tag/v1.8.1) (p) | 2021-03-29T10:46:41Z | 5,791 | 840 | 2,466 | 9,097 | -| [v1.7.11](https://github.com/laurent22/joplin/releases/tag/v1.7.11) | 2021-02-03T12:50:01Z | 120,681 | 42,980 | 64,447 | 228,108 | -| [v1.7.10](https://github.com/laurent22/joplin/releases/tag/v1.7.10) | 2021-01-30T13:25:29Z | 14,581 | 4,882 | 4,528 | 23,991 | +| [v1.8.5](https://github.com/laurent22/joplin/releases/tag/v1.8.5) | 2021-05-10T11:58:14Z | 41,530 | 16,302 | 19,436 | 77,268 | +| [v1.8.4](https://github.com/laurent22/joplin/releases/tag/v1.8.4) (p) | 2021-05-09T18:05:05Z | 3,514 | 152 | 473 | 4,139 | +| [v1.8.3](https://github.com/laurent22/joplin/releases/tag/v1.8.3) (p) | 2021-05-04T10:38:16Z | 4,547 | 320 | 951 | 5,818 | +| [v1.8.2](https://github.com/laurent22/joplin/releases/tag/v1.8.2) (p) | 2021-04-25T10:50:51Z | 4,828 | 451 | 1,300 | 6,579 | +| [v1.8.1](https://github.com/laurent22/joplin/releases/tag/v1.8.1) (p) | 2021-03-29T10:46:41Z | 5,839 | 840 | 2,466 | 9,145 | +| [v1.7.11](https://github.com/laurent22/joplin/releases/tag/v1.7.11) | 2021-02-03T12:50:01Z | 120,782 | 42,980 | 64,450 | 228,212 | +| [v1.7.10](https://github.com/laurent22/joplin/releases/tag/v1.7.10) | 2021-01-30T13:25:29Z | 14,587 | 4,883 | 4,528 | 23,998 | | [v1.7.9](https://github.com/laurent22/joplin/releases/tag/v1.7.9) (p) | 2021-01-28T09:50:21Z | 531 | 148 | 514 | 1,193 | | [v1.7.6](https://github.com/laurent22/joplin/releases/tag/v1.7.6) (p) | 2021-01-27T10:36:05Z | 346 | 108 | 304 | 758 | | [v1.7.5](https://github.com/laurent22/joplin/releases/tag/v1.7.5) (p) | 2021-01-26T09:53:05Z | 439 | 219 | 468 | 1,126 | | [v1.7.4](https://github.com/laurent22/joplin/releases/tag/v1.7.4) (p) | 2021-01-22T17:58:38Z | 729 | 219 | 641 | 1,589 | -| [v1.6.8](https://github.com/laurent22/joplin/releases/tag/v1.6.8) | 2021-01-20T18:11:34Z | 23,029 | 7,731 | 7,635 | 38,395 | +| [v1.6.8](https://github.com/laurent22/joplin/releases/tag/v1.6.8) | 2021-01-20T18:11:34Z | 23,104 | 7,731 | 7,635 | 38,470 | | [v1.7.3](https://github.com/laurent22/joplin/releases/tag/v1.7.3) (p) | 2021-01-20T11:23:50Z | 383 | 95 | 459 | 937 | -| [v1.6.7](https://github.com/laurent22/joplin/releases/tag/v1.6.7) | 2021-01-11T23:20:33Z | 14,619 | 4,663 | 4,572 | 23,854 | -| [v1.6.6](https://github.com/laurent22/joplin/releases/tag/v1.6.6) | 2021-01-09T16:15:31Z | 12,860 | 3,440 | 4,818 | 21,118 | -| [v1.6.5](https://github.com/laurent22/joplin/releases/tag/v1.6.5) (p) | 2021-01-09T01:24:32Z | 3,745 | 91 | 324 | 4,160 | +| [v1.6.7](https://github.com/laurent22/joplin/releases/tag/v1.6.7) | 2021-01-11T23:20:33Z | 14,705 | 4,663 | 4,572 | 23,940 | +| [v1.6.6](https://github.com/laurent22/joplin/releases/tag/v1.6.6) | 2021-01-09T16:15:31Z | 12,861 | 3,440 | 4,818 | 21,119 | +| [v1.6.5](https://github.com/laurent22/joplin/releases/tag/v1.6.5) (p) | 2021-01-09T01:24:32Z | 3,791 | 91 | 324 | 4,206 | | [v1.6.4](https://github.com/laurent22/joplin/releases/tag/v1.6.4) (p) | 2021-01-07T19:11:32Z | 422 | 93 | 220 | 735 | | [v1.6.2](https://github.com/laurent22/joplin/releases/tag/v1.6.2) (p) | 2021-01-04T22:34:55Z | 704 | 242 | 606 | 1,552 | -| [v1.5.14](https://github.com/laurent22/joplin/releases/tag/v1.5.14) | 2020-12-30T01:48:46Z | 15,118 | 5,233 | 5,551 | 25,902 | +| [v1.5.14](https://github.com/laurent22/joplin/releases/tag/v1.5.14) | 2020-12-30T01:48:46Z | 15,208 | 5,233 | 5,551 | 25,992 | | [v1.6.1](https://github.com/laurent22/joplin/releases/tag/v1.6.1) (p) | 2020-12-29T19:37:45Z | 202 | 53 | 184 | 439 | -| [v1.5.13](https://github.com/laurent22/joplin/releases/tag/v1.5.13) | 2020-12-29T18:29:15Z | 781 | 242 | 228 | 1,251 | -| [v1.5.12](https://github.com/laurent22/joplin/releases/tag/v1.5.12) | 2020-12-28T15:14:08Z | 2,562 | 1,796 | 943 | 5,301 | -| [v1.5.11](https://github.com/laurent22/joplin/releases/tag/v1.5.11) | 2020-12-27T19:54:07Z | 14,356 | 4,659 | 4,307 | 23,322 | +| [v1.5.13](https://github.com/laurent22/joplin/releases/tag/v1.5.13) | 2020-12-29T18:29:15Z | 782 | 242 | 228 | 1,252 | +| [v1.5.12](https://github.com/laurent22/joplin/releases/tag/v1.5.12) | 2020-12-28T15:14:08Z | 2,563 | 1,796 | 943 | 5,302 | +| [v1.5.11](https://github.com/laurent22/joplin/releases/tag/v1.5.11) | 2020-12-27T19:54:07Z | 14,357 | 4,660 | 4,308 | 23,325 | | [v1.5.10](https://github.com/laurent22/joplin/releases/tag/v1.5.10) (p) | 2020-12-26T12:35:36Z | 324 | 124 | 286 | 734 | | [v1.5.9](https://github.com/laurent22/joplin/releases/tag/v1.5.9) (p) | 2020-12-23T18:01:08Z | 358 | 386 | 427 | 1,171 | | [v1.5.8](https://github.com/laurent22/joplin/releases/tag/v1.5.8) (p) | 2020-12-20T09:45:19Z | 594 | 179 | 660 | 1,433 | | [v1.5.7](https://github.com/laurent22/joplin/releases/tag/v1.5.7) (p) | 2020-12-10T12:58:33Z | 920 | 269 | 1,010 | 2,199 | | [v1.5.4](https://github.com/laurent22/joplin/releases/tag/v1.5.4) (p) | 2020-12-05T12:07:49Z | 732 | 182 | 652 | 1,566 | -| [v1.4.19](https://github.com/laurent22/joplin/releases/tag/v1.4.19) | 2020-12-01T11:11:16Z | 29,514 | 13,616 | 11,714 | 54,844 | -| [v1.4.18](https://github.com/laurent22/joplin/releases/tag/v1.4.18) | 2020-11-28T12:21:41Z | 11,749 | 3,910 | 3,162 | 18,821 | -| [v1.4.16](https://github.com/laurent22/joplin/releases/tag/v1.4.16) | 2020-11-27T19:40:16Z | 1,641 | 861 | 621 | 3,123 | -| [v1.4.15](https://github.com/laurent22/joplin/releases/tag/v1.4.15) | 2020-11-27T13:25:43Z | 1,031 | 513 | 296 | 1,840 | -| [v1.4.12](https://github.com/laurent22/joplin/releases/tag/v1.4.12) | 2020-11-23T18:58:07Z | 3,214 | 1,375 | 1,328 | 5,917 | -| [v1.4.11](https://github.com/laurent22/joplin/releases/tag/v1.4.11) (p) | 2020-11-19T23:06:51Z | 4,528 | 191 | 611 | 5,330 | +| [v1.4.19](https://github.com/laurent22/joplin/releases/tag/v1.4.19) | 2020-12-01T11:11:16Z | 29,577 | 13,619 | 11,714 | 54,910 | +| [v1.4.18](https://github.com/laurent22/joplin/releases/tag/v1.4.18) | 2020-11-28T12:21:41Z | 11,750 | 3,910 | 3,162 | 18,822 | +| [v1.4.16](https://github.com/laurent22/joplin/releases/tag/v1.4.16) | 2020-11-27T19:40:16Z | 1,642 | 861 | 621 | 3,124 | +| [v1.4.15](https://github.com/laurent22/joplin/releases/tag/v1.4.15) | 2020-11-27T13:25:43Z | 1,032 | 513 | 296 | 1,841 | +| [v1.4.12](https://github.com/laurent22/joplin/releases/tag/v1.4.12) | 2020-11-23T18:58:07Z | 3,215 | 1,376 | 1,328 | 5,919 | +| [v1.4.11](https://github.com/laurent22/joplin/releases/tag/v1.4.11) (p) | 2020-11-19T23:06:51Z | 4,579 | 191 | 611 | 5,381 | | [v1.4.10](https://github.com/laurent22/joplin/releases/tag/v1.4.10) (p) | 2020-11-14T09:53:15Z | 693 | 232 | 703 | 1,628 | | [v1.4.9](https://github.com/laurent22/joplin/releases/tag/v1.4.9) (p) | 2020-11-11T14:23:17Z | 873 | 177 | 420 | 1,470 | | [v1.4.7](https://github.com/laurent22/joplin/releases/tag/v1.4.7) (p) | 2020-11-07T18:23:29Z | 559 | 208 | 534 | 1,301 | -| [v1.3.18](https://github.com/laurent22/joplin/releases/tag/v1.3.18) | 2020-11-06T12:07:02Z | 35,066 | 11,387 | 10,548 | 57,001 | +| [v1.3.18](https://github.com/laurent22/joplin/releases/tag/v1.3.18) | 2020-11-06T12:07:02Z | 35,147 | 11,387 | 10,548 | 57,082 | | [v1.3.17](https://github.com/laurent22/joplin/releases/tag/v1.3.17) (p) | 2020-11-06T11:35:15Z | 86 | 64 | 43 | 193 | -| [v1.4.6](https://github.com/laurent22/joplin/releases/tag/v1.4.6) (p) | 2020-11-05T22:44:12Z | 748 | 128 | 70 | 946 | -| [v1.3.15](https://github.com/laurent22/joplin/releases/tag/v1.3.15) | 2020-11-04T12:22:50Z | 2,782 | 1,343 | 871 | 4,996 | +| [v1.4.6](https://github.com/laurent22/joplin/releases/tag/v1.4.6) (p) | 2020-11-05T22:44:12Z | 750 | 128 | 70 | 948 | +| [v1.3.15](https://github.com/laurent22/joplin/releases/tag/v1.3.15) | 2020-11-04T12:22:50Z | 2,784 | 1,343 | 871 | 4,998 | | [v1.3.11](https://github.com/laurent22/joplin/releases/tag/v1.3.11) (p) | 2020-10-31T13:22:20Z | 740 | 220 | 499 | 1,459 | -| [v1.3.10](https://github.com/laurent22/joplin/releases/tag/v1.3.10) (p) | 2020-10-29T13:27:14Z | 412 | 150 | 334 | 896 | +| [v1.3.10](https://github.com/laurent22/joplin/releases/tag/v1.3.10) (p) | 2020-10-29T13:27:14Z | 413 | 151 | 334 | 898 | | [v1.3.9](https://github.com/laurent22/joplin/releases/tag/v1.3.9) (p) | 2020-10-23T16:04:26Z | 894 | 278 | 652 | 1,824 | | [v1.3.8](https://github.com/laurent22/joplin/releases/tag/v1.3.8) (p) | 2020-10-21T18:46:29Z | 559 | 153 | 350 | 1,062 | | [v1.3.7](https://github.com/laurent22/joplin/releases/tag/v1.3.7) (p) | 2020-10-20T11:35:55Z | 333 | 121 | 362 | 816 | @@ -231,7 +234,7 @@ updated: 2025-02-01T00:53:21Z | [v1.3.3](https://github.com/laurent22/joplin/releases/tag/v1.3.3) (p) | 2020-10-17T10:56:57Z | 156 | 81 | 52 | 289 | | [v1.3.2](https://github.com/laurent22/joplin/releases/tag/v1.3.2) (p) | 2020-10-11T20:39:49Z | 709 | 217 | 587 | 1,513 | | [v1.3.1](https://github.com/laurent22/joplin/releases/tag/v1.3.1) (p) | 2020-10-11T15:10:18Z | 121 | 87 | 63 | 271 | -| [v1.2.6](https://github.com/laurent22/joplin/releases/tag/v1.2.6) | 2020-10-09T13:56:59Z | 49,034 | 17,792 | 14,090 | 80,916 | +| [v1.2.6](https://github.com/laurent22/joplin/releases/tag/v1.2.6) | 2020-10-09T13:56:59Z | 49,114 | 17,792 | 14,090 | 80,996 | | [v1.2.4](https://github.com/laurent22/joplin/releases/tag/v1.2.4) (p) | 2020-09-30T07:34:29Z | 860 | 288 | 821 | 1,969 | | [v1.2.3](https://github.com/laurent22/joplin/releases/tag/v1.2.3) (p) | 2020-09-29T15:13:02Z | 258 | 100 | 102 | 460 | | [v1.2.2](https://github.com/laurent22/joplin/releases/tag/v1.2.2) (p) | 2020-09-22T20:31:55Z | 1,155 | 242 | 658 | 2,055 | @@ -239,61 +242,61 @@ updated: 2025-02-01T00:53:21Z | [v1.1.3](https://github.com/laurent22/joplin/releases/tag/v1.1.3) (p) | 2020-09-17T10:30:37Z | 626 | 189 | 484 | 1,299 | | [v1.1.2](https://github.com/laurent22/joplin/releases/tag/v1.1.2) (p) | 2020-09-15T12:58:38Z | 420 | 152 | 271 | 843 | | [v1.1.1](https://github.com/laurent22/joplin/releases/tag/v1.1.1) (p) | 2020-09-11T23:32:47Z | 597 | 232 | 371 | 1,200 | -| [v1.0.245](https://github.com/laurent22/joplin/releases/tag/v1.0.245) | 2020-09-09T12:56:10Z | 22,918 | 10,064 | 5,676 | 38,658 | +| [v1.0.245](https://github.com/laurent22/joplin/releases/tag/v1.0.245) | 2020-09-09T12:56:10Z | 22,942 | 10,064 | 5,676 | 38,682 | | [v1.0.242](https://github.com/laurent22/joplin/releases/tag/v1.0.242) | 2020-09-04T22:00:34Z | 12,904 | 6,463 | 3,046 | 22,413 | -| [v1.0.241](https://github.com/laurent22/joplin/releases/tag/v1.0.241) | 2020-09-04T18:06:00Z | 26,639 | 5,987 | 5,146 | 37,772 | +| [v1.0.241](https://github.com/laurent22/joplin/releases/tag/v1.0.241) | 2020-09-04T18:06:00Z | 26,650 | 5,987 | 5,147 | 37,784 | | [v1.0.239](https://github.com/laurent22/joplin/releases/tag/v1.0.239) (p) | 2020-09-01T21:56:36Z | 988 | 268 | 425 | 1,681 | | [v1.0.237](https://github.com/laurent22/joplin/releases/tag/v1.0.237) (p) | 2020-08-29T15:38:04Z | 637 | 963 | 360 | 1,960 | | [v1.0.236](https://github.com/laurent22/joplin/releases/tag/v1.0.236) (p) | 2020-08-28T09:16:54Z | 360 | 150 | 126 | 636 | | [v1.0.235](https://github.com/laurent22/joplin/releases/tag/v1.0.235) (p) | 2020-08-18T22:08:01Z | 2,063 | 528 | 944 | 3,535 | | [v1.0.234](https://github.com/laurent22/joplin/releases/tag/v1.0.234) (p) | 2020-08-17T23:13:02Z | 696 | 164 | 123 | 983 | -| [v1.0.233](https://github.com/laurent22/joplin/releases/tag/v1.0.233) | 2020-08-01T14:51:15Z | 47,641 | 18,246 | 12,387 | 78,274 | +| [v1.0.233](https://github.com/laurent22/joplin/releases/tag/v1.0.233) | 2020-08-01T14:51:15Z | 47,724 | 18,246 | 12,387 | 78,357 | | [v1.0.232](https://github.com/laurent22/joplin/releases/tag/v1.0.232) (p) | 2020-07-28T22:34:40Z | 703 | 262 | 201 | 1,166 | -| [v1.0.227](https://github.com/laurent22/joplin/releases/tag/v1.0.227) | 2020-07-07T20:44:54Z | 41,729 | 15,324 | 9,672 | 66,725 | +| [v1.0.227](https://github.com/laurent22/joplin/releases/tag/v1.0.227) | 2020-07-07T20:44:54Z | 41,753 | 15,324 | 9,672 | 66,749 | | [v1.0.226](https://github.com/laurent22/joplin/releases/tag/v1.0.226) (p) | 2020-07-04T10:21:26Z | 4,970 | 2,293 | 710 | 7,973 | -| [v1.0.224](https://github.com/laurent22/joplin/releases/tag/v1.0.224) | 2020-06-20T22:26:08Z | 25,266 | 11,049 | 6,031 | 42,346 | +| [v1.0.224](https://github.com/laurent22/joplin/releases/tag/v1.0.224) | 2020-06-20T22:26:08Z | 25,289 | 11,049 | 6,031 | 42,369 | | [v1.0.223](https://github.com/laurent22/joplin/releases/tag/v1.0.223) (p) | 2020-06-20T11:51:27Z | 231 | 152 | 101 | 484 | | [v1.0.221](https://github.com/laurent22/joplin/releases/tag/v1.0.221) (p) | 2020-06-20T01:44:20Z | 898 | 247 | 235 | 1,380 | -| [v1.0.220](https://github.com/laurent22/joplin/releases/tag/v1.0.220) | 2020-06-13T18:26:22Z | 32,819 | 9,969 | 6,444 | 49,232 | +| [v1.0.220](https://github.com/laurent22/joplin/releases/tag/v1.0.220) | 2020-06-13T18:26:22Z | 32,821 | 9,970 | 6,445 | 49,236 | | [v1.0.218](https://github.com/laurent22/joplin/releases/tag/v1.0.218) | 2020-06-07T10:43:34Z | 14,638 | 7,018 | 3,154 | 24,810 | | [v1.0.217](https://github.com/laurent22/joplin/releases/tag/v1.0.217) (p) | 2020-06-06T15:17:27Z | 280 | 138 | 85 | 503 | -| [v1.0.216](https://github.com/laurent22/joplin/releases/tag/v1.0.216) | 2020-05-24T14:21:01Z | 41,402 | 14,352 | 10,217 | 65,971 | -| [v1.0.214](https://github.com/laurent22/joplin/releases/tag/v1.0.214) (p) | 2020-05-21T17:15:15Z | 7,080 | 3,513 | 789 | 11,382 | +| [v1.0.216](https://github.com/laurent22/joplin/releases/tag/v1.0.216) | 2020-05-24T14:21:01Z | 41,491 | 14,355 | 10,218 | 66,064 | +| [v1.0.214](https://github.com/laurent22/joplin/releases/tag/v1.0.214) (p) | 2020-05-21T17:15:15Z | 7,103 | 3,513 | 789 | 11,405 | | [v1.0.212](https://github.com/laurent22/joplin/releases/tag/v1.0.212) (p) | 2020-05-21T07:48:39Z | 255 | 112 | 72 | 439 | | [v1.0.211](https://github.com/laurent22/joplin/releases/tag/v1.0.211) (p) | 2020-05-20T08:59:16Z | 354 | 174 | 113 | 641 | | [v1.0.209](https://github.com/laurent22/joplin/releases/tag/v1.0.209) (p) | 2020-05-17T18:32:51Z | 1,449 | 894 | 173 | 2,516 | | [v1.0.207](https://github.com/laurent22/joplin/releases/tag/v1.0.207) (p) | 2020-05-10T16:37:35Z | 1,252 | 305 | 1,044 | 2,601 | -| [v1.0.201](https://github.com/laurent22/joplin/releases/tag/v1.0.201) | 2020-04-15T22:55:13Z | 54,403 | 20,100 | 18,214 | 92,717 | -| [v1.0.200](https://github.com/laurent22/joplin/releases/tag/v1.0.200) | 2020-04-12T12:17:46Z | 9,631 | 4,935 | 1,931 | 16,497 | -| [v1.0.199](https://github.com/laurent22/joplin/releases/tag/v1.0.199) | 2020-04-10T18:41:58Z | 19,841 | 5,931 | 3,827 | 29,599 | -| [v1.0.197](https://github.com/laurent22/joplin/releases/tag/v1.0.197) | 2020-03-30T17:21:22Z | 23,476 | 9,870 | 6,588 | 39,934 | -| [v1.0.195](https://github.com/laurent22/joplin/releases/tag/v1.0.195) | 2020-03-22T19:56:12Z | 19,171 | 7,993 | 4,535 | 31,699 | -| [v1.0.194](https://github.com/laurent22/joplin/releases/tag/v1.0.194) (p) | 2020-03-14T00:00:32Z | 1,339 | 1,429 | 543 | 3,311 | -| [v1.0.193](https://github.com/laurent22/joplin/releases/tag/v1.0.193) | 2020-03-08T08:58:53Z | 28,842 | 10,967 | 7,444 | 47,253 | -| [v1.0.192](https://github.com/laurent22/joplin/releases/tag/v1.0.192) (p) | 2020-03-06T23:27:52Z | 558 | 164 | 113 | 835 | +| [v1.0.201](https://github.com/laurent22/joplin/releases/tag/v1.0.201) | 2020-04-15T22:55:13Z | 54,404 | 20,100 | 18,214 | 92,718 | +| [v1.0.200](https://github.com/laurent22/joplin/releases/tag/v1.0.200) | 2020-04-12T12:17:46Z | 9,634 | 4,935 | 1,931 | 16,500 | +| [v1.0.199](https://github.com/laurent22/joplin/releases/tag/v1.0.199) | 2020-04-10T18:41:58Z | 19,860 | 5,931 | 3,827 | 29,618 | +| [v1.0.197](https://github.com/laurent22/joplin/releases/tag/v1.0.197) | 2020-03-30T17:21:22Z | 23,478 | 9,870 | 6,599 | 39,947 | +| [v1.0.195](https://github.com/laurent22/joplin/releases/tag/v1.0.195) | 2020-03-22T19:56:12Z | 19,172 | 7,993 | 4,535 | 31,700 | +| [v1.0.194](https://github.com/laurent22/joplin/releases/tag/v1.0.194) (p) | 2020-03-14T00:00:32Z | 1,339 | 1,430 | 543 | 3,312 | +| [v1.0.193](https://github.com/laurent22/joplin/releases/tag/v1.0.193) | 2020-03-08T08:58:53Z | 28,842 | 10,968 | 7,445 | 47,255 | +| [v1.0.192](https://github.com/laurent22/joplin/releases/tag/v1.0.192) (p) | 2020-03-06T23:27:52Z | 559 | 164 | 113 | 836 | | [v1.0.190](https://github.com/laurent22/joplin/releases/tag/v1.0.190) (p) | 2020-03-06T01:22:22Z | 439 | 133 | 110 | 682 | | [v1.0.189](https://github.com/laurent22/joplin/releases/tag/v1.0.189) (p) | 2020-03-04T17:27:15Z | 427 | 136 | 121 | 684 | | [v1.0.187](https://github.com/laurent22/joplin/releases/tag/v1.0.187) (p) | 2020-03-01T12:31:06Z | 983 | 277 | 298 | 1,558 | -| [v1.0.179](https://github.com/laurent22/joplin/releases/tag/v1.0.179) | 2020-01-24T22:42:41Z | 71,728 | 29,097 | 22,595 | 123,420 | +| [v1.0.179](https://github.com/laurent22/joplin/releases/tag/v1.0.179) | 2020-01-24T22:42:41Z | 71,741 | 29,106 | 22,596 | 123,443 | | [v1.0.178](https://github.com/laurent22/joplin/releases/tag/v1.0.178) | 2020-01-20T19:06:45Z | 17,677 | 6,006 | 2,620 | 26,303 | | [v1.0.177](https://github.com/laurent22/joplin/releases/tag/v1.0.177) (p) | 2019-12-30T14:40:40Z | 2,011 | 478 | 748 | 3,237 | | [v1.0.176](https://github.com/laurent22/joplin/releases/tag/v1.0.176) (p) | 2019-12-14T10:36:44Z | 3,176 | 2,579 | 496 | 6,251 | -| [v1.0.175](https://github.com/laurent22/joplin/releases/tag/v1.0.175) | 2019-12-08T11:48:47Z | 73,780 | 17,022 | 16,625 | 107,427 | -| [v1.0.174](https://github.com/laurent22/joplin/releases/tag/v1.0.174) | 2019-11-12T18:20:58Z | 30,740 | 11,802 | 8,253 | 50,795 | +| [v1.0.175](https://github.com/laurent22/joplin/releases/tag/v1.0.175) | 2019-12-08T11:48:47Z | 73,782 | 17,022 | 16,625 | 107,429 | +| [v1.0.174](https://github.com/laurent22/joplin/releases/tag/v1.0.174) | 2019-11-12T18:20:58Z | 30,744 | 11,803 | 8,253 | 50,800 | | [v1.0.173](https://github.com/laurent22/joplin/releases/tag/v1.0.173) | 2019-11-11T08:33:35Z | 5,152 | 2,122 | 772 | 8,046 | -| [v1.0.170](https://github.com/laurent22/joplin/releases/tag/v1.0.170) | 2019-10-13T22:13:04Z | 27,856 | 8,821 | 7,714 | 44,391 | -| [v1.0.169](https://github.com/laurent22/joplin/releases/tag/v1.0.169) | 2019-09-27T18:35:13Z | 17,274 | 5,971 | 3,784 | 27,029 | +| [v1.0.170](https://github.com/laurent22/joplin/releases/tag/v1.0.170) | 2019-10-13T22:13:04Z | 27,859 | 8,821 | 7,715 | 44,395 | +| [v1.0.169](https://github.com/laurent22/joplin/releases/tag/v1.0.169) | 2019-09-27T18:35:13Z | 17,279 | 5,971 | 3,784 | 27,034 | | [v1.0.168](https://github.com/laurent22/joplin/releases/tag/v1.0.168) | 2019-09-25T21:21:38Z | 5,394 | 2,316 | 745 | 8,455 | -| [v1.0.167](https://github.com/laurent22/joplin/releases/tag/v1.0.167) | 2019-09-10T08:48:37Z | 17,000 | 5,747 | 3,740 | 26,487 | +| [v1.0.167](https://github.com/laurent22/joplin/releases/tag/v1.0.167) | 2019-09-10T08:48:37Z | 17,005 | 5,747 | 3,740 | 26,492 | | [v1.0.166](https://github.com/laurent22/joplin/releases/tag/v1.0.166) | 2019-09-09T17:35:54Z | 2,006 | 601 | 261 | 2,868 | -| [v1.0.165](https://github.com/laurent22/joplin/releases/tag/v1.0.165) | 2019-08-14T21:46:29Z | 19,119 | 7,022 | 5,491 | 31,632 | -| [v1.0.161](https://github.com/laurent22/joplin/releases/tag/v1.0.161) | 2019-07-13T18:30:00Z | 19,445 | 6,391 | 4,161 | 29,997 | -| [v1.0.160](https://github.com/laurent22/joplin/releases/tag/v1.0.160) | 2019-06-15T00:21:40Z | 30,852 | 7,795 | 8,132 | 46,779 | -| [v1.0.159](https://github.com/laurent22/joplin/releases/tag/v1.0.159) | 2019-06-08T00:00:19Z | 5,272 | 2,220 | 1,289 | 8,781 | +| [v1.0.165](https://github.com/laurent22/joplin/releases/tag/v1.0.165) | 2019-08-14T21:46:29Z | 19,120 | 7,022 | 5,491 | 31,633 | +| [v1.0.161](https://github.com/laurent22/joplin/releases/tag/v1.0.161) | 2019-07-13T18:30:00Z | 19,446 | 6,391 | 4,161 | 29,998 | +| [v1.0.160](https://github.com/laurent22/joplin/releases/tag/v1.0.160) | 2019-06-15T00:21:40Z | 30,853 | 7,795 | 8,132 | 46,780 | +| [v1.0.159](https://github.com/laurent22/joplin/releases/tag/v1.0.159) | 2019-06-08T00:00:19Z | 5,272 | 2,220 | 1,293 | 8,785 | | [v1.0.158](https://github.com/laurent22/joplin/releases/tag/v1.0.158) | 2019-05-27T19:01:18Z | 9,890 | 3,588 | 1,961 | 15,439 | | [v1.0.157](https://github.com/laurent22/joplin/releases/tag/v1.0.157) | 2019-05-26T17:55:53Z | 2,248 | 881 | 314 | 3,443 | | [v1.0.153](https://github.com/laurent22/joplin/releases/tag/v1.0.153) (p) | 2019-05-15T06:27:29Z | 916 | 143 | 131 | 1,190 | -| [v1.0.152](https://github.com/laurent22/joplin/releases/tag/v1.0.152) | 2019-05-13T09:08:07Z | 13,946 | 4,475 | 4,091 | 22,512 | +| [v1.0.152](https://github.com/laurent22/joplin/releases/tag/v1.0.152) | 2019-05-13T09:08:07Z | 13,947 | 4,475 | 4,091 | 22,513 | | [v1.0.151](https://github.com/laurent22/joplin/releases/tag/v1.0.151) | 2019-05-12T15:14:32Z | 2,002 | 574 | 984 | 3,560 | | [v1.0.150](https://github.com/laurent22/joplin/releases/tag/v1.0.150) | 2019-05-12T11:27:48Z | 496 | 175 | 94 | 765 | | [v1.0.148](https://github.com/laurent22/joplin/releases/tag/v1.0.148) (p) | 2019-05-08T19:12:24Z | 186 | 93 | 120 | 399 | @@ -302,14 +305,14 @@ updated: 2025-02-01T00:53:21Z | [v1.0.142](https://github.com/laurent22/joplin/releases/tag/v1.0.142) | 2019-04-02T16:44:51Z | 14,863 | 4,607 | 4,757 | 24,227 | | [v1.0.140](https://github.com/laurent22/joplin/releases/tag/v1.0.140) | 2019-03-10T20:59:58Z | 13,723 | 4,217 | 3,406 | 21,346 | | [v1.0.139](https://github.com/laurent22/joplin/releases/tag/v1.0.139) (p) | 2019-03-09T10:06:48Z | 186 | 104 | 69 | 359 | -| [v1.0.138](https://github.com/laurent22/joplin/releases/tag/v1.0.138) (p) | 2019-03-03T17:23:00Z | 223 | 128 | 107 | 458 | +| [v1.0.138](https://github.com/laurent22/joplin/releases/tag/v1.0.138) (p) | 2019-03-03T17:23:00Z | 225 | 128 | 107 | 460 | | [v1.0.137](https://github.com/laurent22/joplin/releases/tag/v1.0.137) (p) | 2019-03-03T01:12:51Z | 650 | 95 | 107 | 852 | | [v1.0.135](https://github.com/laurent22/joplin/releases/tag/v1.0.135) | 2019-02-27T23:36:57Z | 12,704 | 3,996 | 4,106 | 20,806 | | [v1.0.134](https://github.com/laurent22/joplin/releases/tag/v1.0.134) | 2019-02-27T10:21:44Z | 1,512 | 610 | 244 | 2,366 | | [v1.0.132](https://github.com/laurent22/joplin/releases/tag/v1.0.132) | 2019-02-26T23:02:05Z | 1,150 | 491 | 119 | 1,760 | | [v1.0.127](https://github.com/laurent22/joplin/releases/tag/v1.0.127) | 2019-02-14T23:12:48Z | 10,023 | 3,212 | 2,957 | 16,192 | | [v1.0.126](https://github.com/laurent22/joplin/releases/tag/v1.0.126) (p) | 2019-02-09T19:46:16Z | 1,001 | 115 | 138 | 1,254 | -| [v1.0.125](https://github.com/laurent22/joplin/releases/tag/v1.0.125) | 2019-01-26T18:14:33Z | 10,392 | 3,596 | 1,726 | 15,714 | +| [v1.0.125](https://github.com/laurent22/joplin/releases/tag/v1.0.125) | 2019-01-26T18:14:33Z | 10,397 | 3,596 | 1,726 | 15,719 | | [v1.0.120](https://github.com/laurent22/joplin/releases/tag/v1.0.120) | 2019-01-10T21:42:53Z | 15,705 | 5,251 | 6,544 | 27,500 | | [v1.0.119](https://github.com/laurent22/joplin/releases/tag/v1.0.119) | 2018-12-18T12:40:22Z | 9,006 | 3,301 | 2,040 | 14,347 | | [v1.0.118](https://github.com/laurent22/joplin/releases/tag/v1.0.118) | 2019-01-11T08:34:13Z | 763 | 288 | 115 | 1,166 | @@ -317,7 +320,7 @@ updated: 2025-02-01T00:53:21Z | [v1.0.116](https://github.com/laurent22/joplin/releases/tag/v1.0.116) | 2018-11-20T19:09:24Z | 4,069 | 1,165 | 740 | 5,974 | | [v1.0.115](https://github.com/laurent22/joplin/releases/tag/v1.0.115) | 2018-11-16T16:52:02Z | 3,723 | 1,341 | 827 | 5,891 | | [v1.0.114](https://github.com/laurent22/joplin/releases/tag/v1.0.114) | 2018-10-24T20:14:10Z | 11,470 | 3,540 | 3,855 | 18,865 | -| [v1.0.111](https://github.com/laurent22/joplin/releases/tag/v1.0.111) | 2018-09-30T20:15:09Z | 12,486 | 3,526 | 3,707 | 19,719 | +| [v1.0.111](https://github.com/laurent22/joplin/releases/tag/v1.0.111) | 2018-09-30T20:15:09Z | 12,504 | 3,531 | 3,707 | 19,742 | | [v1.0.110](https://github.com/laurent22/joplin/releases/tag/v1.0.110) | 2018-09-29T12:29:21Z | 1,010 | 449 | 142 | 1,601 | | [v1.0.109](https://github.com/laurent22/joplin/releases/tag/v1.0.109) | 2018-09-27T18:01:41Z | 2,146 | 743 | 356 | 3,245 | | [v1.0.108](https://github.com/laurent22/joplin/releases/tag/v1.0.108) (p) | 2018-09-29T18:49:29Z | 66 | 60 | 38 | 164 | @@ -328,7 +331,7 @@ updated: 2025-02-01T00:53:21Z | [v1.0.103](https://github.com/laurent22/joplin/releases/tag/v1.0.103) | 2018-06-21T19:38:13Z | 2,128 | 926 | 703 | 3,757 | | [v1.0.101](https://github.com/laurent22/joplin/releases/tag/v1.0.101) | 2018-06-17T18:35:11Z | 1,374 | 648 | 434 | 2,456 | | [v1.0.100](https://github.com/laurent22/joplin/releases/tag/v1.0.100) | 2018-06-14T17:41:43Z | 959 | 477 | 272 | 1,708 | -| [v1.0.99](https://github.com/laurent22/joplin/releases/tag/v1.0.99) | 2018-06-10T13:18:23Z | 1,325 | 638 | 406 | 2,369 | +| [v1.0.99](https://github.com/laurent22/joplin/releases/tag/v1.0.99) | 2018-06-10T13:18:23Z | 1,325 | 638 | 408 | 2,371 | | [v1.0.97](https://github.com/laurent22/joplin/releases/tag/v1.0.97) | 2018-06-09T19:23:34Z | 357 | 193 | 86 | 636 | | [v1.0.96](https://github.com/laurent22/joplin/releases/tag/v1.0.96) | 2018-05-26T16:36:39Z | 2,800 | 1,267 | 1,748 | 5,815 | | [v1.0.95](https://github.com/laurent22/joplin/releases/tag/v1.0.95) | 2018-05-25T13:04:30Z | 466 | 258 | 163 | 887 | @@ -344,24 +347,24 @@ updated: 2025-02-01T00:53:21Z | [v1.0.78](https://github.com/laurent22/joplin/releases/tag/v1.0.78) | 2018-03-17T15:27:18Z | 1,354 | 943 | 915 | 3,212 | | [v1.0.77](https://github.com/laurent22/joplin/releases/tag/v1.0.77) | 2018-03-16T15:12:35Z | 202 | 144 | 88 | 434 | | [v1.0.72](https://github.com/laurent22/joplin/releases/tag/v1.0.72) | 2018-03-14T09:44:35Z | 451 | 296 | 98 | 845 | -| [v1.0.70](https://github.com/laurent22/joplin/releases/tag/v1.0.70) | 2018-02-28T20:04:30Z | 2,003 | 1,093 | 1,296 | 4,392 | -| [v1.0.67](https://github.com/laurent22/joplin/releases/tag/v1.0.67) | 2018-02-19T22:51:08Z | 1,945 | 645 | 0 | 2,590 | -| [v1.0.66](https://github.com/laurent22/joplin/releases/tag/v1.0.66) | 2018-02-18T23:09:09Z | 449 | 174 | 108 | 731 | -| [v1.0.65](https://github.com/laurent22/joplin/releases/tag/v1.0.65) | 2018-02-17T20:02:25Z | 348 | 170 | 156 | 674 | -| [v1.0.64](https://github.com/laurent22/joplin/releases/tag/v1.0.64) | 2018-02-16T00:58:20Z | 1,194 | 583 | 1,146 | 2,923 | -| [v1.0.63](https://github.com/laurent22/joplin/releases/tag/v1.0.63) | 2018-02-14T19:40:36Z | 412 | 200 | 115 | 727 | -| [v1.0.62](https://github.com/laurent22/joplin/releases/tag/v1.0.62) | 2018-02-12T20:19:58Z | 713 | 345 | 399 | 1,457 | -| [v0.10.61](https://github.com/laurent22/joplin/releases/tag/v0.10.61) | 2018-02-08T18:27:39Z | 1,122 | 678 | 987 | 2,787 | +| [v1.0.70](https://github.com/laurent22/joplin/releases/tag/v1.0.70) | 2018-02-28T20:04:30Z | 2,004 | 1,093 | 1,296 | 4,393 | +| [v1.0.67](https://github.com/laurent22/joplin/releases/tag/v1.0.67) | 2018-02-19T22:51:08Z | 1,946 | 645 | 0 | 2,591 | +| [v1.0.66](https://github.com/laurent22/joplin/releases/tag/v1.0.66) | 2018-02-18T23:09:09Z | 450 | 174 | 108 | 732 | +| [v1.0.65](https://github.com/laurent22/joplin/releases/tag/v1.0.65) | 2018-02-17T20:02:25Z | 349 | 171 | 156 | 676 | +| [v1.0.64](https://github.com/laurent22/joplin/releases/tag/v1.0.64) | 2018-02-16T00:58:20Z | 1,195 | 583 | 1,147 | 2,925 | +| [v1.0.63](https://github.com/laurent22/joplin/releases/tag/v1.0.63) | 2018-02-14T19:40:36Z | 413 | 200 | 115 | 728 | +| [v1.0.62](https://github.com/laurent22/joplin/releases/tag/v1.0.62) | 2018-02-12T20:19:58Z | 714 | 345 | 400 | 1,459 | +| [v0.10.61](https://github.com/laurent22/joplin/releases/tag/v0.10.61) | 2018-02-08T18:27:39Z | 1,123 | 678 | 987 | 2,788 | | [v0.10.60](https://github.com/laurent22/joplin/releases/tag/v0.10.60) | 2018-02-06T13:09:56Z | 770 | 565 | 577 | 1,912 | -| [v0.10.54](https://github.com/laurent22/joplin/releases/tag/v0.10.54) | 2018-01-31T20:21:30Z | 1,958 | 1,503 | 347 | 3,808 | -| [v0.10.52](https://github.com/laurent22/joplin/releases/tag/v0.10.52) | 2018-01-31T19:25:18Z | 163 | 677 | 41 | 881 | -| [v0.10.51](https://github.com/laurent22/joplin/releases/tag/v0.10.51) | 2018-01-28T18:47:02Z | 1,429 | 1,643 | 352 | 3,424 | -| [v0.10.48](https://github.com/laurent22/joplin/releases/tag/v0.10.48) | 2018-01-23T11:19:51Z | 2,111 | 1,795 | 56 | 3,962 | -| [v0.10.47](https://github.com/laurent22/joplin/releases/tag/v0.10.47) | 2018-01-16T17:27:17Z | 1,333 | 1,317 | 91 | 2,741 | +| [v0.10.54](https://github.com/laurent22/joplin/releases/tag/v0.10.54) | 2018-01-31T20:21:30Z | 1,959 | 1,503 | 347 | 3,809 | +| [v0.10.52](https://github.com/laurent22/joplin/releases/tag/v0.10.52) | 2018-01-31T19:25:18Z | 164 | 677 | 41 | 882 | +| [v0.10.51](https://github.com/laurent22/joplin/releases/tag/v0.10.51) | 2018-01-28T18:47:02Z | 1,430 | 1,643 | 352 | 3,425 | +| [v0.10.48](https://github.com/laurent22/joplin/releases/tag/v0.10.48) | 2018-01-23T11:19:51Z | 2,112 | 1,795 | 56 | 3,963 | +| [v0.10.47](https://github.com/laurent22/joplin/releases/tag/v0.10.47) | 2018-01-16T17:27:17Z | 1,334 | 1,317 | 91 | 2,742 | | [v0.10.43](https://github.com/laurent22/joplin/releases/tag/v0.10.43) | 2018-01-08T10:12:10Z | 3,486 | 2,401 | 1,237 | 7,124 | -| [v0.10.41](https://github.com/laurent22/joplin/releases/tag/v0.10.41) | 2018-01-05T20:38:12Z | 1,243 | 1,597 | 266 | 3,106 | +| [v0.10.41](https://github.com/laurent22/joplin/releases/tag/v0.10.41) | 2018-01-05T20:38:12Z | 1,245 | 1,597 | 266 | 3,108 | | [v0.10.40](https://github.com/laurent22/joplin/releases/tag/v0.10.40) | 2018-01-02T23:16:57Z | 1,638 | 1,832 | 362 | 3,832 | -| [v0.10.39](https://github.com/laurent22/joplin/releases/tag/v0.10.39) | 2017-12-11T21:19:44Z | 5,994 | 4,442 | 3,323 | 13,759 | +| [v0.10.39](https://github.com/laurent22/joplin/releases/tag/v0.10.39) | 2017-12-11T21:19:44Z | 5,995 | 4,443 | 3,324 | 13,762 | | [v0.10.38](https://github.com/laurent22/joplin/releases/tag/v0.10.38) | 2017-12-08T10:12:06Z | 1,089 | 1,274 | 330 | 2,693 | | [v0.10.37](https://github.com/laurent22/joplin/releases/tag/v0.10.37) | 2017-12-07T19:38:05Z | 291 | 892 | 109 | 1,292 | | [v0.10.36](https://github.com/laurent22/joplin/releases/tag/v0.10.36) | 2017-12-05T09:34:40Z | 1,052 | 1,405 | 465 | 2,922 | @@ -369,12 +372,12 @@ updated: 2025-02-01T00:53:21Z | [v0.10.34](https://github.com/laurent22/joplin/releases/tag/v0.10.34) | 2017-12-02T14:50:28Z | 117 | 717 | 85 | 919 | | [v0.10.33](https://github.com/laurent22/joplin/releases/tag/v0.10.33) | 2017-12-02T13:20:39Z | 95 | 711 | 51 | 857 | | [v0.10.31](https://github.com/laurent22/joplin/releases/tag/v0.10.31) | 2017-12-01T09:56:44Z | 918 | 1,499 | 435 | 2,852 | -| [v0.10.30](https://github.com/laurent22/joplin/releases/tag/v0.10.30) | 2017-11-30T20:28:16Z | 841 | 1,428 | 452 | 2,721 | -| [v0.10.28](https://github.com/laurent22/joplin/releases/tag/v0.10.28) | 2017-11-30T01:07:46Z | 1,490 | 1,761 | 906 | 4,157 | -| [v0.10.26](https://github.com/laurent22/joplin/releases/tag/v0.10.26) | 2017-11-29T16:02:17Z | 306 | 756 | 291 | 1,353 | -| [v0.10.25](https://github.com/laurent22/joplin/releases/tag/v0.10.25) | 2017-11-24T14:27:49Z | 258 | 752 | 6,769 | 7,779 | -| [v0.10.23](https://github.com/laurent22/joplin/releases/tag/v0.10.23) | 2017-11-21T19:38:41Z | 246 | 714 | 65 | 1,025 | -| [v0.10.22](https://github.com/laurent22/joplin/releases/tag/v0.10.22) | 2017-11-20T21:45:57Z | 191 | 700 | 49 | 940 | -| [v0.10.21](https://github.com/laurent22/joplin/releases/tag/v0.10.21) | 2017-11-18T00:53:15Z | 169 | 693 | 44 | 906 | -| [v0.10.20](https://github.com/laurent22/joplin/releases/tag/v0.10.20) | 2017-11-17T17:18:25Z | 160 | 706 | 56 | 922 | -| [v0.10.19](https://github.com/laurent22/joplin/releases/tag/v0.10.19) | 2017-11-20T18:59:48Z | 179 | 707 | 54 | 940 | \ No newline at end of file +| [v0.10.30](https://github.com/laurent22/joplin/releases/tag/v0.10.30) | 2017-11-30T20:28:16Z | 842 | 1,428 | 452 | 2,722 | +| [v0.10.28](https://github.com/laurent22/joplin/releases/tag/v0.10.28) | 2017-11-30T01:07:46Z | 1,491 | 1,761 | 906 | 4,158 | +| [v0.10.26](https://github.com/laurent22/joplin/releases/tag/v0.10.26) | 2017-11-29T16:02:17Z | 307 | 756 | 291 | 1,354 | +| [v0.10.25](https://github.com/laurent22/joplin/releases/tag/v0.10.25) | 2017-11-24T14:27:49Z | 259 | 752 | 6,769 | 7,780 | +| [v0.10.23](https://github.com/laurent22/joplin/releases/tag/v0.10.23) | 2017-11-21T19:38:41Z | 247 | 714 | 65 | 1,026 | +| [v0.10.22](https://github.com/laurent22/joplin/releases/tag/v0.10.22) | 2017-11-20T21:45:57Z | 192 | 700 | 49 | 941 | +| [v0.10.21](https://github.com/laurent22/joplin/releases/tag/v0.10.21) | 2017-11-18T00:53:15Z | 170 | 693 | 44 | 907 | +| [v0.10.20](https://github.com/laurent22/joplin/releases/tag/v0.10.20) | 2017-11-17T17:18:25Z | 161 | 706 | 56 | 923 | +| [v0.10.19](https://github.com/laurent22/joplin/releases/tag/v0.10.19) | 2017-11-20T18:59:48Z | 180 | 707 | 55 | 942 | \ No newline at end of file From 0cc0fec8c3f1430af4a2e2bfb4ba13cf78bb86fe Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sat, 1 Mar 2025 13:04:28 +0000 Subject: [PATCH 002/158] lock file --- packages/app-mobile/ios/Podfile.lock | 146 +++++++++++++-------------- 1 file changed, 73 insertions(+), 73 deletions(-) diff --git a/packages/app-mobile/ios/Podfile.lock b/packages/app-mobile/ios/Podfile.lock index 4f188a7406..abe680bbc6 100644 --- a/packages/app-mobile/ios/Podfile.lock +++ b/packages/app-mobile/ios/Podfile.lock @@ -1030,7 +1030,7 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - react-native-image-resizer (3.0.10): + - react-native-image-resizer (3.0.11): - React-Core - react-native-netinfo (11.3.3): - React-Core @@ -1686,20 +1686,20 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: boost: d3f49c53809116a5d38da093a8aa78bf551aed09 DoubleConversion: 76ab83afb40bddeeee456813d9c04f67f78771b5 - EXAV: afa491e598334bbbb92a92a2f4dd33d7149ad37f - EXConstants: 409690fbfd5afea964e5e9d6c4eb2c2b59222c59 - Expo: f3e39cddde295c79d206e972a59693cbb329ef46 - ExpoAsset: 323700f291684f110fb55f0d4022a3362ea9f875 - ExpoCamera: 929be541d1c1319fcf32f9f5d9df8b97804346b5 - ExpoFileSystem: 80bfe850b1f9922c16905822ecbf97acd711dc51 - ExpoFont: 00756e6c796d8f7ee8d211e29c8b619e75cbf238 - ExpoModulesCore: 5440e96a8ee014f4fd88e77264985fd0a65f5f8c + EXAV: 64e72329d2f8c2ba13608fed4a713af4e793242d + EXConstants: 89d35611505a8ce02550e64e43cd05565da35f9a + Expo: 647dd60db7a75898e3148258fb018b8fdb686291 + ExpoAsset: 286fee7ba711ce66bf20b315e68106b13b8629fc + ExpoCamera: cf49d2d121a9f883be0f98dde15a2185a1dd42be + ExpoFileSystem: 2988caaf68b7cb706e36d382829d99811d9d76a5 + ExpoFont: 38dddf823e32740c2a9f37c926a33aeca736b5c4 + ExpoModulesCore: cad1227f619a67c82c52e0e71fc70514cd93def8 FBLazyVector: 898d14d17bf19e2435cafd9ea2a1033efe445709 fmt: 4c2741a687cc09f0634a2e2c72a838b99f1ff120 glog: c5d68082e772fa1c511173d6b30a9de2c05a69a2 hermes-engine: 16b8530de1b383cdada1476cf52d1b52f0692cbc JoplinCommonShareExtension: a8b60b02704d85a7305627912c0240e94af78db7 - JoplinRNShareExtension: 485f3e6dad83b7b77f1572eabc249f869ee55c02 + JoplinRNShareExtension: e158a4b53ee0aa9cd3037a16221dc8adbd6f7860 OpenSSL-Universal: b60a3702c9fea8b3145549d421fdb018e53ab7b4 RCT-Folly: 02617c592a293bd6d418e0a88ff4ee1f88329b47 RCTDeprecation: efb313d8126259e9294dc4ee0002f44a6f676aba @@ -1707,76 +1707,76 @@ SPEC CHECKSUMS: RCTTypeSafety: a11979ff0570d230d74de9f604f7d19692157bc4 React: 88794fad7f460349dbc9df8a274d95f37a009f5d React-callinvoker: 7a7023e34a55c89ea2aa62486bb3c1164ab0be0c - React-Codegen: af31a9323ce23988c255c9afd0ae9415ff894939 - React-Core: 60075333bc22b5a793d3f62e207368b79bff2e64 - React-CoreModules: 147c314d6b3b1e069c9ad64cbbbeba604854ff86 - React-cxxreact: 5de27fd8bff4764acb2eac3ee66001e0e2b910e7 + React-Codegen: 118828b0731a9ecf9021270b788f958f9ccb2e19 + React-Core: 74cc07109071b230de904d394c2bf15b9f886bff + React-CoreModules: 8beb4863375aafeac52c49a3962b81d137577585 + React-cxxreact: d0b0d575214ba236dff569e14dd4411ac82b3566 React-debug: 6397f0baf751b40511d01e984b01467d7e6d8127 - React-Fabric: 6fa475e16e0a37b38d462cec32b70fd5cf886305 - React-FabricImage: 7e09b3704e3fa084b4d44b5b5ef6e2e3d3334ec0 + React-Fabric: 37f29709a9caefd2a9fece6f695bc88a0af77f40 + React-FabricImage: 9c3f6125b2f5908a2e7d0947cfb74022c1a0b294 React-featureflags: 2eb79dd9df4095bff519379f2a4c915069e330bb - React-graphics: 82a482a3aa5d9659b74cdf2c8b57faf67eaa10fb - React-hermes: d93936b02de2fd7e67c11e92c16d4278a14d0134 - React-ImageManager: ebb3c4812e2c5acba5a89728c2d77729471329ad - React-jserrorhandler: a08e0adcf1612900dde82b8bf8e93e7d2ad953b3 - React-jsi: f46d09ee5079a4f3b637d30d0e59b8ea6470632c - React-jsiexecutor: e73579560957aa3ca9dc02ab90e163454279d48c - React-jsinspector: e8ba20dde269c7c1d45784b858fa1cf4383f0bbb - React-jsitracing: 233d1a798fe0ff33b8e630b8f00f62c4a8115fbc - React-logger: 7e7403a2b14c97f847d90763af76b84b152b6fce - React-Mapbuffer: 11029dcd47c5c9e057a4092ab9c2a8d10a496a33 - react-native-alarm-notification: 0c7c6b84a4b73da3cd594c2008bd289fdda4296c - react-native-document-picker: 5b97e24a7f1a1e4a50a72c540a043f32d29a70a2 - react-native-fingerprint-scanner: ac6656f18c8e45a7459302b84da41a44ad96dbbe - react-native-geolocation: 5c5dd5de4571c55014e9e98214b273eed854f293 - react-native-get-random-values: 21325b2244dfa6b58878f51f9aa42821e7ba3d06 - react-native-image-picker: d3a65af2538ac5407e5329e50f057fb2456f15f8 - react-native-image-resizer: fd0c333eca55147bd55c5e054cac95dcd0da6814 - react-native-netinfo: 9af975c142e5673d643093aa5afdfa26f46b71b4 - react-native-quick-crypto: 7085e4e4607e7e8fa57f4193f994d5262d351e45 - react-native-rsa-native: 12132eb627797529fdb1f0d22fd0f8f9678df64a - react-native-saf-x: b868b5334ba23684a89a5b86749ee359c8bb6932 - react-native-safe-area-context: b7daa1a8df36095a032dff095a1ea8963cb48371 - react-native-slider: 03f213d3ffbf919b16298c7896c1b60101d8e137 - react-native-sqlite-storage: f6d515e1c446d1e6d026aa5352908a25d4de3261 - react-native-version-info: a106f23009ac0db4ee00de39574eb546682579b9 - react-native-webview: 553abd09f58e340fdc7746c9e2ae096839e99911 + React-graphics: d0b9a0a174fb86bfed50bf4fb7c835183a546ab5 + React-hermes: 06e8316213d56ab914afb9a829763123fcfacf22 + React-ImageManager: 821a1182139cc986598868d0e9a00b3a021feddb + React-jserrorhandler: 1dd2a75b24dd9a318ee88fa6792e98524879af24 + React-jsi: e381545475da5ea77777e7b5513031a434ced04b + React-jsiexecutor: ce91dde1a61efd519a5ff7ac0f64b61a14217072 + React-jsinspector: 627ac44b1d090fc6a8039b1df723677bc7d86fe4 + React-jsitracing: dd0e541a34027b3ab668ad94cf268482ad6f82fb + React-logger: 6070f362a1657bb53335eb1fc903d3f49fd79842 + React-Mapbuffer: 2c95cbabc3d75a17747452381e998c35208ea3ee + react-native-alarm-notification: e0ec4c4041f705cdd27281dac168e5e26e5671e9 + react-native-document-picker: 6b08d834d4e4252bb8aad13d852e27666294b5b9 + react-native-fingerprint-scanner: 91bf6825709dd7bd3abc4588a4772eb097a2b2d8 + react-native-geolocation: 29755191062842d349d7a5160d0638f25b9bd168 + react-native-get-random-values: d16467cf726c618e9c7a8c3c39c31faa2244bbba + react-native-image-picker: 10f58d521d8da62b9747cd107045bce399cf5a1e + react-native-image-resizer: 24c5d06fae2176dc0caed4b6396e02befb44064a + react-native-netinfo: 28c2462c85067fe653615f6f595673bdca93a287 + react-native-quick-crypto: 08ecf18a70a8a49dbd0b5d983afbd56bdd809f86 + react-native-rsa-native: a7931cdda1f73a8576a46d7f431378c5550f0c38 + react-native-saf-x: 318d0cdb38f4618bd7ef5840d4f5c12e097dfbe7 + react-native-safe-area-context: b72c4611af2e86d80a59ac76279043d8f75f454c + react-native-slider: 921ce51608bfd0680d64617bfff286f747e27160 + react-native-sqlite-storage: 0c84826214baaa498796c7e46a5ccc9a82e114ed + react-native-version-info: f0b04e16111c4016749235ff6d9a757039189141 + react-native-webview: a71525b1ab760230fbf37303d8371fbe72051c7d React-nativeconfig: b0073a590774e8b35192fead188a36d1dca23dec - React-NativeModulesApple: df46ff3e3de5b842b30b4ca8a6caae6d7c8ab09f + React-NativeModulesApple: 61b07ab32af3ea4910ba553932c0a779e853c082 React-perflogger: 3d31e0d1e8ad891e43a09ac70b7b17a79773003a React-RCTActionSheet: c4a3a134f3434c9d7b0c1054f1a8cfed30c7a093 - React-RCTAnimation: 0e5d15320eeece667fcceb6c785acf9a184e9da1 - React-RCTAppDelegate: c4f6c0700b8950a8b18c2e004996eec1807d430a - React-RCTBlob: c46aaaee693d371a1c7cae2a8c8ee2aa7fbc1adb - React-RCTFabric: 0dbf28ce96c7f2843483e32a725a5b5793584ff3 - React-RCTImage: a04dba5fcc823244f5822192c130ecf09623a57f - React-RCTLinking: 533bf13c745fcb2a0c14e0e49fd149586a7f0d14 - React-RCTNetwork: a29e371e0d363d7b4c10ab907bc4d6ae610541e9 - React-RCTSettings: 127813224780861d0d30ecda17a40d1dfebe7d73 - React-RCTText: 8a823f245ecf82edb7569646e3c4d8041deb800a - React-RCTVibration: 46b5fae74e63f240f22f39de16ad6433da3b65d9 - React-rendererdebug: 4653f8da6ab1d7b01af796bdf8ca47a927539e39 + React-RCTAnimation: dab04683056694845eb7a9e283f4c63eec7fa633 + React-RCTAppDelegate: 1785d42459138c45175b2fa18e86cd2aee829a93 + React-RCTBlob: a0a8f6bfd8926bff0e2814ec3f8cd5514f2db243 + React-RCTFabric: f69d856b74b6d385c4cf4bd128c330161ce18306 + React-RCTImage: 51db983bcc5075fa9bf3e094e5c6c1f5b5575472 + React-RCTLinking: 3430cd1023a5ac86a96ed6d4fbf7a8ed7b2e44d5 + React-RCTNetwork: 52198f8a8c823639dcc8f6725ca5b360d66ea1a0 + React-RCTSettings: c127440c2c538128f92fb45524e976e25cb69bd6 + React-RCTText: 640b2d0bfb51d88d8a76c6a1a7ea1f94667bf231 + React-RCTVibration: bd20c8156b649cd745c70db3341c409ae3b42821 + React-rendererdebug: 16394ffe0d852967123b3b76a630233b90ec8e63 React-rncore: 4f1e645acb5107bd4b4cf29eff17b04a7cd422f3 - React-RuntimeApple: 013b606e743efb5ee14ef03c32379b78bfe74354 - React-RuntimeCore: 7205be45a25713b5418bbf2db91ddfcca0761d8b + React-RuntimeApple: 97d0a5c655467c57b88076434427ec32413e7802 + React-RuntimeCore: a55443ddb73e6666b441963d8951a16ba5cfc223 React-runtimeexecutor: a278d4249921853d4a3f24e4d6e0ff30688f3c16 - React-RuntimeHermes: 44c628568ce8feedc3acfbd48fc07b7f0f6d2731 - React-runtimescheduler: e2152ed146b6a35c07386fc2ac4827b27e6aad12 - React-utils: 3285151c9d1e3a28a9586571fc81d521678c196d - ReactCommon: f42444e384d82ab89184aed5d6f3142748b54768 - rn-fetch-blob: f065bb7ab7fb48dd002629f8bdcb0336602d3cba - RNCClipboard: 2821ac938ef46f736a8de0c8814845dde2dcbdfb - RNCPushNotificationIOS: 64218f3c776c03d7408284a819b2abfda1834bc8 - RNDateTimePicker: 40ffda97d071a98a10fdca4fa97e3977102ccd14 - RNDeviceInfo: 59344c19152c4b2b32283005f9737c5c64b42fba - RNExitApp: 00036cabe7bacbb413d276d5520bf74ba39afa6a - RNFileViewer: ce7ca3ac370e18554d35d6355cffd7c30437c592 - RNFS: 4ac0f0ea233904cb798630b3c077808c06931688 - RNLocalize: 4f22418187ecd5ca693231093ff1d912d1b3c9bc - RNQuickAction: 6d404a869dc872cde841ad3147416a670d13fa93 - RNSecureRandom: 07efbdf2cd99efe13497433668e54acd7df49fef - RNShare: 0fad69ae2d71de9d1f7b9a43acf876886a6cb99c - RNVectorIcons: 2a2f79274248390b80684ea3c4400bd374a15c90 + React-RuntimeHermes: 6273f0755fef304453fc3c356b25abf17e915b83 + React-runtimescheduler: 87b14969bb0b10538014fb8407d472f9904bc8cd + React-utils: 67574b07bff4429fd6c4d43a7fad8254d814ee20 + ReactCommon: 64c64f4ae1f2debe3fab1800e00cb8466a4477b7 + rn-fetch-blob: 25612b6d6f6e980c6f17ed98ba2f58f5696a51ca + RNCClipboard: 7c3e3b5f71d84ef61690ad377b6c50cf27864ff5 + RNCPushNotificationIOS: 6c4ca3388c7434e4a662b92e4dfeeee858e6f440 + RNDateTimePicker: 818460dc31b0dc5ec58289003e27dd8d022fb79c + RNDeviceInfo: 98bb51ba1519cd3f19f14e7236b5bb1c312c780f + RNExitApp: 4432b9b7cc5ccec9f91c94e507849891282befd4 + RNFileViewer: 4b5d83358214347e4ab2d4ca8d5c1c90d869e251 + RNFS: 89de7d7f4c0f6bafa05343c578f61118c8282ed8 + RNLocalize: e7378161f0b6a6365407eb2377aab46cc38047d8 + RNQuickAction: c2c8f379e614428be0babe4d53a575739667744d + RNSecureRandom: b64d263529492a6897e236a22a2c4249aa1b53dc + RNShare: 694e19d7f74ac4c04de3a8af0649e9ccc03bd8b1 + RNVectorIcons: f733cb2133a8e1f7dc723b97a1d70dad681124c3 SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d Yoga: 348f8b538c3ed4423eb58a8e5730feec50bce372 ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5 From 06359834d680472b9f02e79995b3f2989c21e425 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 2 Mar 2025 22:20:47 +0000 Subject: [PATCH 003/158] Desktop: Add a button to collapse or expand all folders (#11905) --- .eslintignore | 4 +++ .gitignore | 4 +++ .../gui/Sidebar/FolderAndTagList.tsx | 7 +++- .../Sidebar/hooks/useOnRenderListWrapper.tsx | 34 +++++++++++++++--- packages/app-desktop/gui/Sidebar/style.scss | 2 +- ...button.scss => sidebar-header-button.scss} | 8 +++-- packages/lib/commands/index.ts | 2 ++ packages/lib/commands/toggleAllFolders.ts | 19 ++++++++++ .../utils/areAllFoldersCollapsed.test.ts | 35 +++++++++++++++++++ .../models/utils/areAllFoldersCollapsed.ts | 10 ++++++ .../utils/getCanBeCollapsedFolderIds.ts | 21 +++++++++++ packages/lib/reducer.ts | 5 +++ packages/tools/cspell/dictionary4.txt | 2 ++ 13 files changed, 144 insertions(+), 9 deletions(-) rename packages/app-desktop/gui/Sidebar/styles/{new-folder-button.scss => sidebar-header-button.scss} (81%) create mode 100644 packages/lib/commands/toggleAllFolders.ts create mode 100644 packages/lib/models/utils/areAllFoldersCollapsed.test.ts create mode 100644 packages/lib/models/utils/areAllFoldersCollapsed.ts create mode 100644 packages/lib/models/utils/getCanBeCollapsedFolderIds.ts diff --git a/.eslintignore b/.eslintignore index 240a7bd184..2d70731d42 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1026,6 +1026,7 @@ packages/lib/commands/renderMarkup.test.js packages/lib/commands/renderMarkup.js packages/lib/commands/showEditorPlugin.js packages/lib/commands/synchronize.js +packages/lib/commands/toggleAllFolders.js packages/lib/commands/toggleEditorPlugin.js packages/lib/components/EncryptionConfigScreen/utils.test.js packages/lib/components/EncryptionConfigScreen/utils.js @@ -1120,6 +1121,9 @@ packages/lib/models/settings/builtInMetadata.js packages/lib/models/settings/settingValidations.test.js packages/lib/models/settings/settingValidations.js packages/lib/models/settings/types.js +packages/lib/models/utils/areAllFoldersCollapsed.test.js +packages/lib/models/utils/areAllFoldersCollapsed.js +packages/lib/models/utils/getCanBeCollapsedFolderIds.js packages/lib/models/utils/getCollator.js packages/lib/models/utils/getConflictFolderId.js packages/lib/models/utils/isItemId.js diff --git a/.gitignore b/.gitignore index e67e37a2c0..27d9bcd48e 100644 --- a/.gitignore +++ b/.gitignore @@ -1001,6 +1001,7 @@ packages/lib/commands/renderMarkup.test.js packages/lib/commands/renderMarkup.js packages/lib/commands/showEditorPlugin.js packages/lib/commands/synchronize.js +packages/lib/commands/toggleAllFolders.js packages/lib/commands/toggleEditorPlugin.js packages/lib/components/EncryptionConfigScreen/utils.test.js packages/lib/components/EncryptionConfigScreen/utils.js @@ -1095,6 +1096,9 @@ packages/lib/models/settings/builtInMetadata.js packages/lib/models/settings/settingValidations.test.js packages/lib/models/settings/settingValidations.js packages/lib/models/settings/types.js +packages/lib/models/utils/areAllFoldersCollapsed.test.js +packages/lib/models/utils/areAllFoldersCollapsed.js +packages/lib/models/utils/getCanBeCollapsedFolderIds.js packages/lib/models/utils/getCollator.js packages/lib/models/utils/getConflictFolderId.js packages/lib/models/utils/isItemId.js diff --git a/packages/app-desktop/gui/Sidebar/FolderAndTagList.tsx b/packages/app-desktop/gui/Sidebar/FolderAndTagList.tsx index 5de96ca0da..1499c50867 100644 --- a/packages/app-desktop/gui/Sidebar/FolderAndTagList.tsx +++ b/packages/app-desktop/gui/Sidebar/FolderAndTagList.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { AppState } from '../../app.reducer'; import { FolderEntity, TagsWithNoteCountEntity } from '@joplin/lib/services/database/types'; +import areAllFoldersCollapsed from '@joplin/lib/models/utils/areAllFoldersCollapsed'; import { PluginStates } from '@joplin/lib/services/plugins/reducer'; import { connect } from 'react-redux'; import { Dispatch } from 'redux'; @@ -41,6 +42,10 @@ const FolderAndTagList: React.FC = props => { listItems: listItems, }); + const allFoldersCollapsed = useMemo(() => { + return areAllFoldersCollapsed(props.folders, props.collapsedFolderIds); + }, [props.collapsedFolderIds, props.folders]); + const listContainerRef = useRef(null); const onRenderItem = useOnRenderItem({ ...props, @@ -67,7 +72,7 @@ const FolderAndTagList: React.FC = props => { const listHeight = useElementHeight(itemListContainer); const listStyle = useMemo(() => ({ height: listHeight }), [listHeight]); - const onRenderContentWrapper = useOnRenderListWrapper({ selectedIndex, onKeyDown: onKeyEventHandler }); + const onRenderContentWrapper = useOnRenderListWrapper({ allFoldersCollapsed, selectedIndex, onKeyDown: onKeyEventHandler }); return (
{ void CommandService.instance().execute('newFolder'); }; +const onToggleAllFolders = (allFoldersCollapsed: boolean) => { + void CommandService.instance().execute('toggleAllFolders', !allFoldersCollapsed); +}; + +interface CollapseExpandAllButtonProps { + allFoldersCollapsed: boolean; +} + +const CollapseExpandAllButton = (props: CollapseExpandAllButtonProps) => { + // To allow it to be accessed by accessibility tools, the new folder button + // is not included in the portion of the list with role='tree'. + const icon = props.allFoldersCollapsed ? 'far fa-caret-square-right' : 'far fa-caret-square-down'; + + return ; +}; + const NewFolderButton = () => { // To allow it to be accessed by accessibility tools, the new folder button // is not included in the portion of the list with role='tree'. - return ; }; -const useOnRenderListWrapper = ({ selectedIndex, onKeyDown }: Props) => { +const useOnRenderListWrapper = (props: Props) => { return useCallback((listItems: React.ReactNode[]) => { - const listHasValidSelection = selectedIndex >= 0; + const listHasValidSelection = props.selectedIndex >= 0; const allowContainerFocus = !listHasValidSelection; return <> +
{...listItems}
; - }, [selectedIndex, onKeyDown]); + }, [props.selectedIndex, props.onKeyDown, props.allFoldersCollapsed]); }; export default useOnRenderListWrapper; diff --git a/packages/app-desktop/gui/Sidebar/style.scss b/packages/app-desktop/gui/Sidebar/style.scss index f1598f1889..206281f564 100644 --- a/packages/app-desktop/gui/Sidebar/style.scss +++ b/packages/app-desktop/gui/Sidebar/style.scss @@ -5,4 +5,4 @@ @use 'styles/sidebar-expand-link.scss'; @use 'styles/sidebar-header-container.scss'; @use 'styles/sidebar-spacer-item.scss'; -@use 'styles/new-folder-button.scss'; \ No newline at end of file +@use 'styles/sidebar-header-button.scss'; \ No newline at end of file diff --git a/packages/app-desktop/gui/Sidebar/styles/new-folder-button.scss b/packages/app-desktop/gui/Sidebar/styles/sidebar-header-button.scss similarity index 81% rename from packages/app-desktop/gui/Sidebar/styles/new-folder-button.scss rename to packages/app-desktop/gui/Sidebar/styles/sidebar-header-button.scss index 2bfcb379de..90f851e717 100644 --- a/packages/app-desktop/gui/Sidebar/styles/new-folder-button.scss +++ b/packages/app-desktop/gui/Sidebar/styles/sidebar-header-button.scss @@ -1,11 +1,11 @@ -.new-folder-button { +.sidebar-header-button { position: absolute; top: 0; inset-inline-end: 0; padding-inline-end: 15px; - padding-top: 4px; + padding-top: 8px; height: 30px; border: none; @@ -22,4 +22,8 @@ color: var(--joplin-color-active2); background: none; } + + &.-collapseall { + right: 25px; + } } diff --git a/packages/lib/commands/index.ts b/packages/lib/commands/index.ts index f3bef142e7..38403bb83c 100644 --- a/packages/lib/commands/index.ts +++ b/packages/lib/commands/index.ts @@ -7,6 +7,7 @@ import * as permanentlyDeleteNote from './permanentlyDeleteNote'; import * as renderMarkup from './renderMarkup'; import * as showEditorPlugin from './showEditorPlugin'; import * as synchronize from './synchronize'; +import * as toggleAllFolders from './toggleAllFolders'; import * as toggleEditorPlugin from './toggleEditorPlugin'; const index: any[] = [ @@ -18,6 +19,7 @@ const index: any[] = [ renderMarkup, showEditorPlugin, synchronize, + toggleAllFolders, toggleEditorPlugin, ]; diff --git a/packages/lib/commands/toggleAllFolders.ts b/packages/lib/commands/toggleAllFolders.ts new file mode 100644 index 0000000000..eabe50f287 --- /dev/null +++ b/packages/lib/commands/toggleAllFolders.ts @@ -0,0 +1,19 @@ +import { CommandRuntime, CommandDeclaration, CommandContext } from '../services/CommandService'; +import { _ } from '../locale'; +import getCanBeCollapsedFolderIds from '../models/utils/getCanBeCollapsedFolderIds'; + +export const declaration: CommandDeclaration = { + name: 'toggleAllFolders', + label: () => _('Toggle all notebooks'), +}; + +export const runtime = (): CommandRuntime => { + return { + execute: async (context: CommandContext, collapseAll: boolean) => { + context.dispatch({ + type: 'FOLDER_SET_COLLAPSED', + ids: collapseAll ? getCanBeCollapsedFolderIds(context.state.folders) : [], + }); + }, + }; +}; diff --git a/packages/lib/models/utils/areAllFoldersCollapsed.test.ts b/packages/lib/models/utils/areAllFoldersCollapsed.test.ts new file mode 100644 index 0000000000..204abe19a3 --- /dev/null +++ b/packages/lib/models/utils/areAllFoldersCollapsed.test.ts @@ -0,0 +1,35 @@ +import { setupDatabaseAndSynchronizer, switchClient } from '../../testing/test-utils'; +import Folder from '../Folder'; +import areAllFoldersCollapsed from './areAllFoldersCollapsed'; + +describe('areAllFoldersCollapsed', () => { + + beforeEach(async () => { + await setupDatabaseAndSynchronizer(1); + await switchClient(1); + }); + + it('should tell if all folders are collapsed', async () => { + const folder1 = await Folder.save({}); + await Folder.save({ parent_id: folder1.id }); + await Folder.save({ parent_id: folder1.id }); + + const folder2 = await Folder.save({ }); + const folder2a = await Folder.save({ parent_id: folder2.id }); + await Folder.save({ parent_id: folder2a.id }); + + expect(areAllFoldersCollapsed(await Folder.all(), [])).toBe(false); + + expect(areAllFoldersCollapsed(await Folder.all(), [ + folder1.id, + folder2.id, + ])).toBe(false); + + expect(areAllFoldersCollapsed(await Folder.all(), [ + folder1.id, + folder2.id, + folder2a.id, + ])).toBe(true); + }); + +}); diff --git a/packages/lib/models/utils/areAllFoldersCollapsed.ts b/packages/lib/models/utils/areAllFoldersCollapsed.ts new file mode 100644 index 0000000000..146d6cdc99 --- /dev/null +++ b/packages/lib/models/utils/areAllFoldersCollapsed.ts @@ -0,0 +1,10 @@ +import { FolderEntity } from '../../services/database/types'; +import getCanBeCollapsedFolderIds from './getCanBeCollapsedFolderIds'; + +export default (folders: FolderEntity[], collapsedFolderIds: string[]) => { + const canBeCollapsedIds = getCanBeCollapsedFolderIds(folders); + if (collapsedFolderIds.length !== canBeCollapsedIds.length) return false; + collapsedFolderIds = collapsedFolderIds.slice().sort(); + canBeCollapsedIds.sort(); + return JSON.stringify(collapsedFolderIds) === JSON.stringify(canBeCollapsedIds); +}; diff --git a/packages/lib/models/utils/getCanBeCollapsedFolderIds.ts b/packages/lib/models/utils/getCanBeCollapsedFolderIds.ts new file mode 100644 index 0000000000..cfa4ea9688 --- /dev/null +++ b/packages/lib/models/utils/getCanBeCollapsedFolderIds.ts @@ -0,0 +1,21 @@ +import { FolderEntity } from '../../services/database/types'; +import Folder, { FolderEntityWithChildren } from '../Folder'; + +export default (folders: FolderEntity[]) => { + const tree = Folder.buildTree(folders); + + const canBeCollapsedIds: string[] = []; + + const processTree = (folders: FolderEntityWithChildren[]) => { + for (const folder of folders) { + if (folder.children.length) { + canBeCollapsedIds.push(folder.id); + processTree(folder.children); + } + } + }; + + processTree(tree); + + return canBeCollapsedIds; +}; diff --git a/packages/lib/reducer.ts b/packages/lib/reducer.ts index 1e972efa77..9c6c3c7216 100644 --- a/packages/lib/reducer.ts +++ b/packages/lib/reducer.ts @@ -449,6 +449,11 @@ function stateHasEncryptedItems(state: State) { // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied function folderSetCollapsed(draft: Draft, action: any) { + if (action.ids) { + draft.collapsedFolderIds = action.ids; + return; + } + const collapsedFolderIds = draft.collapsedFolderIds.slice(); const idx = collapsedFolderIds.indexOf(action.id); diff --git a/packages/tools/cspell/dictionary4.txt b/packages/tools/cspell/dictionary4.txt index 3b25d44dd4..49aaa01bf9 100644 --- a/packages/tools/cspell/dictionary4.txt +++ b/packages/tools/cspell/dictionary4.txt @@ -171,3 +171,5 @@ millis sideloading ggml Minidump +collapseall +newfolder \ No newline at end of file From 975f16d21c6924c50dea00012e58df17161678f6 Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Mon, 3 Mar 2025 14:29:05 -0800 Subject: [PATCH 004/158] Server: Security: Improve request validation in default route (#11916) --- packages/server/src/utils/joplinUtils.test.ts | 20 ++++++++++++++++- packages/server/src/utils/joplinUtils.ts | 22 ++++++++++++++++--- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/packages/server/src/utils/joplinUtils.test.ts b/packages/server/src/utils/joplinUtils.test.ts index 8e5c155b45..07fc93eb5f 100644 --- a/packages/server/src/utils/joplinUtils.test.ts +++ b/packages/server/src/utils/joplinUtils.test.ts @@ -1,5 +1,6 @@ +import { basename } from '@joplin/utils/path'; import { Item } from '../services/database/types'; -import { itemIsEncrypted } from './joplinUtils'; +import { itemIsEncrypted, localFileFromUrl } from './joplinUtils'; import { expectThrow } from './testing/testUtils'; describe('joplinUtils', () => { @@ -21,4 +22,21 @@ describe('joplinUtils', () => { await expectThrow(async () => itemIsEncrypted({ name: 'missing props' })); }); + it.each([ + 'css/pluginAssets/../../../test', + 'css/pluginAssets/../../test', + 'js/pluginAssets/./../../test', + ])('localFileFromUrl should prevent access to paths outside the assets directory', async (url) => { + await expect(localFileFromUrl(url)).rejects.toThrow('Disallowed access:'); + }); + + it.each([ + 'css/pluginAssets/test.css', + 'js/pluginAssets/subfolder/test.js', + 'css/pluginAssets/testing/this-is-a-test.css', + ])('localFileFromUrl should allow access to paths inside the assets directory', async (url) => { + const resolvedPath = await localFileFromUrl(url); + // Should resolve to the same file + expect(basename(resolvedPath)).toBe(basename(url)); + }); }); diff --git a/packages/server/src/utils/joplinUtils.ts b/packages/server/src/utils/joplinUtils.ts index 9b649d1d27..178080c8e1 100644 --- a/packages/server/src/utils/joplinUtils.ts +++ b/packages/server/src/utils/joplinUtils.ts @@ -26,6 +26,7 @@ import MustacheService from '../services/MustacheService'; import Logger from '@joplin/utils/Logger'; import config from '../config'; import { TreeItem } from '../models/ItemResourceModel'; +import resolvePathWithinDir from '@joplin/lib/utils/resolvePathWithinDir'; const { substrWithEllipsis } = require('@joplin/lib/string-utils'); const logger = Logger.create('JoplinUtils'); @@ -116,11 +117,26 @@ export function isJoplinResourceBlobPath(path: string): boolean { return path.indexOf(resourceDirName) === 0; } -export async function localFileFromUrl(url: string): Promise { +const resolveUnsafeAssetPath = (relativeAssetPath: string) => { + const resolvedPath = resolvePathWithinDir(pluginAssetRootDir_, relativeAssetPath); + if (resolvedPath === null) { + throw new ErrorForbidden('Disallowed access: Item is not in the plugin asset directory'); + } + return resolvedPath; +}; + +export async function localFileFromUrl(urlPath: string): Promise { const cssPluginAssets = 'css/pluginAssets/'; const jsPluginAssets = 'js/pluginAssets/'; - if (url.indexOf(cssPluginAssets) === 0) return `${pluginAssetRootDir_}/${url.substr(cssPluginAssets.length)}`; - if (url.indexOf(jsPluginAssets) === 0) return `${pluginAssetRootDir_}/${url.substr(jsPluginAssets.length)}`; + const baseUrls = [cssPluginAssets, jsPluginAssets]; + + for (const baseUrl of baseUrls) { + if (urlPath.startsWith(baseUrl)) { + const pluginAssetPath = urlPath.substring(baseUrl.length); + return resolveUnsafeAssetPath(pluginAssetPath); + } + } + return null; } From 5f02af972433d277a01b9b1e248ddd19404361c4 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Mon, 3 Mar 2025 22:29:46 +0000 Subject: [PATCH 005/158] Server v3.3.4 --- packages/server/package.json | 2 +- readme/about/changelog/server.md | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/server/package.json b/packages/server/package.json index 3394003b4d..9436e76a6b 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@joplin/server", - "version": "3.3.3", + "version": "3.3.4", "private": true, "scripts": { "start-dev": "yarn build && JOPLIN_IS_TESTING=1 nodemon --config nodemon.json --ext ts,js,mustache,css,tsx dist/app.js --env dev", diff --git a/readme/about/changelog/server.md b/readme/about/changelog/server.md index c9aeef2240..608ceef370 100644 --- a/readme/about/changelog/server.md +++ b/readme/about/changelog/server.md @@ -1,5 +1,9 @@ # Joplin Server Changelog +## [server-v3.3.4](https://github.com/laurent22/joplin/releases/tag/server-v3.3.4) - 2025-03-03T22:29:29Z + +- Security: Improve request validation in default route (#11916 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) + ## [server-v3.3.3](https://github.com/laurent22/joplin/releases/tag/server-v3.3.3) - 2025-02-23T19:06:59Z - Security: Fixed patching user properties (12baa98) From 5c35569b5b9b4588d1c14dedf7963e5a83ecc8bb Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Mon, 3 Mar 2025 22:36:37 +0000 Subject: [PATCH 006/158] Android 3.3.2 --- packages/app-mobile/android/app/build.gradle | 4 ++-- packages/app-mobile/ios/Podfile.lock | 2 +- readme/about/changelog/android.md | 9 +++++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/app-mobile/android/app/build.gradle b/packages/app-mobile/android/app/build.gradle index 07b20cb839..96bba67344 100644 --- a/packages/app-mobile/android/app/build.gradle +++ b/packages/app-mobile/android/app/build.gradle @@ -86,8 +86,8 @@ android { applicationId "net.cozic.joplin" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 2097764 - versionName "3.3.1" + versionCode 2097765 + versionName "3.3.2" ndk { abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64" } diff --git a/packages/app-mobile/ios/Podfile.lock b/packages/app-mobile/ios/Podfile.lock index abe680bbc6..f297736307 100644 --- a/packages/app-mobile/ios/Podfile.lock +++ b/packages/app-mobile/ios/Podfile.lock @@ -1701,7 +1701,7 @@ SPEC CHECKSUMS: JoplinCommonShareExtension: a8b60b02704d85a7305627912c0240e94af78db7 JoplinRNShareExtension: e158a4b53ee0aa9cd3037a16221dc8adbd6f7860 OpenSSL-Universal: b60a3702c9fea8b3145549d421fdb018e53ab7b4 - RCT-Folly: 02617c592a293bd6d418e0a88ff4ee1f88329b47 + RCT-Folly: 5dc73daec3476616d19e8a53f0156176f7b55461 RCTDeprecation: efb313d8126259e9294dc4ee0002f44a6f676aba RCTRequired: f49ea29cece52aee20db633ae7edc4b271435562 RCTTypeSafety: a11979ff0570d230d74de9f604f7d19692157bc4 diff --git a/readme/about/changelog/android.md b/readme/about/changelog/android.md index 4da108b17b..a05dd88597 100644 --- a/readme/about/changelog/android.md +++ b/readme/about/changelog/android.md @@ -1,5 +1,14 @@ # Joplin Android Changelog +## [android-v3.3.2](https://github.com/laurent22/joplin/releases/tag/android-v3.3.2) (Pre-release) - 2025-03-03T22:35:08Z + +- Improved: Improve encryption config screen accessibility (#11874) (#11846 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Improved: Switch default library used for Whisper voice typing (#11881 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Improved: Updated packages @bam.tech/react-native-image-resizer (v3.0.11) +- Fixed: Accessibility: Fix "new note" and "new to-do" buttons are focusable even while invisible (#11899 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Fixed: Fix disabled encryption keys list showing enabled keys (#11861) (#11858 by [@pedr](https://github.com/pedr)) +- Fixed: Fix voice recorder crash (#11876) (#11864 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) + ## [android-v3.3.1](https://github.com/laurent22/joplin/releases/tag/android-v3.3.1) (Pre-release) - 2025-02-19T16:01:54Z - New: Add support for plugin editor views (#11831) From 0bdc38a6be1eea0e5c1496354a4e6529b82fa6c2 Mon Sep 17 00:00:00 2001 From: Eric Duarte Date: Tue, 4 Mar 2025 02:43:27 +0100 Subject: [PATCH 007/158] All: Translation: Update es_ES.po (#11913) --- packages/tools/locales/es_ES.po | 934 +++++++++++++++----------------- 1 file changed, 422 insertions(+), 512 deletions(-) diff --git a/packages/tools/locales/es_ES.po b/packages/tools/locales/es_ES.po index d5c1a99598..e6c8522d06 100644 --- a/packages/tools/locales/es_ES.po +++ b/packages/tools/locales/es_ES.po @@ -15,14 +15,16 @@ msgid "" msgstr "" "Project-Id-Version: Joplin-CLI 1.0.0\n" "Report-Msgid-Bugs-To: \n" -"Last-Translator: Francisco Villaverde \n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: Éric Duarte \n" "Language-Team: Spanish \n" "Language: es_ES\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 3.2.2\n" +"X-Generator: Poedit 3.5\n" "X-Poedit-SourceCharset: UTF-8\n" #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:593 @@ -57,7 +59,7 @@ msgstr "(En plugin: %s)" #: packages/app-mobile/components/side-menu-content.tsx:265 msgid "(level %d)" -msgstr "" +msgstr "(Nivel %d)" #: packages/lib/SyncTargetNone.ts:16 msgid "(None)" @@ -71,7 +73,7 @@ msgstr "(wysiwyg: %s)" #: packages/app-mobile/components/screens/Note/Note.tsx:712 #: packages/lib/shim-init-node.ts:264 msgid "(You may disable this prompt in the options)" -msgstr "" +msgstr "(Puede desactivar este aviso en las opciones)" #: packages/app-desktop/gui/MenuBar.tsx:1036 #: packages/app-desktop/gui/MenuBar.tsx:737 @@ -105,9 +107,8 @@ msgid "&View" msgstr "&Ver" #: packages/app-desktop/gui/MenuBar.tsx:903 -#, fuzzy msgid "&Window" -msgstr "Cerrar Ventana" +msgstr "&Ventana" #: packages/lib/models/settings/builtInMetadata.ts:1483 #: packages/lib/models/settings/builtInMetadata.ts:1735 @@ -158,15 +159,13 @@ msgid "%d notes match this pattern. Delete them?" msgstr "%d notas coinciden con el patrón. ¿Eliminarlas?" #: packages/app-cli/app/command-rmnote.ts:40 -#, fuzzy msgid "%d notes will be permanently deleted. Continue?" -msgstr "Borrar notas seleccionadas" +msgstr "%d notas se eliminarán de forma permanente. ¿Continuar?" #: packages/app-desktop/gui/NoteListControls/NoteListControls.tsx:228 #: packages/app-desktop/gui/NoteListControls/NoteListControls.tsx:238 -#, fuzzy msgid "%s" -msgstr "(%s)" +msgstr "%s" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/duplicateNote.ts:18 msgid "%s - Copy" @@ -216,10 +215,12 @@ msgid "" "%s is not optimised for synchronising many small files so your initial " "synchronisation will be slow." msgstr "" +"%s no está optimizado para sincronizar muchos archivos pequeños, por lo que " +"la sincronización inicial será lenta." #: packages/app-mobile/components/plugins/dialogs/PluginPanelViewer.tsx:75 msgid "%s tab opened" -msgstr "" +msgstr "%s pestaña abierta" #: packages/lib/services/ReportService.ts:286 #: packages/lib/services/ReportService.ts:287 @@ -243,9 +244,8 @@ msgstr "%s: %s" #: packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx:224 #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:265 -#, fuzzy msgid "%s: Missing password." -msgstr "Contraseña maestra" +msgstr "%s: Falta la contraseña." #: packages/app-cli/app/command-tag.js:14 msgid "" @@ -273,9 +273,8 @@ msgstr "" "tarea a una nota normal." #: packages/app-desktop/gui/UpdateNotification/UpdateNotification.tsx:62 -#, fuzzy msgid "A new update (%s) is available" -msgstr "Actualizar perfil" +msgstr "Una nueva actualización (%s) está disponible" #: packages/lib/models/settings/builtInMetadata.ts:1253 msgid "A3" @@ -292,7 +291,7 @@ msgstr "A5" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/index.tsx:75 #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginInfoModal.tsx:240 msgid "About" -msgstr "" +msgstr "Acerca de" #: packages/app-desktop/gui/MenuBar.tsx:620 #: packages/app-desktop/gui/MenuBar.tsx:955 @@ -322,17 +321,19 @@ msgid "Accept" msgstr "Aceptar" #: packages/app-mobile/components/screens/ShareManager/index.tsx:98 -#, fuzzy msgid "Accepted invitations" -msgstr "El destinatario ha aceptado la invitación" +msgstr "Invitaciones aceptadas" #: packages/lib/WebDavApi.js:451 msgid "Access denied: Please check your username and password" msgstr "" +"Acceso denegado: Por favor, compruebe su nombre de usuario y contraseña" #: packages/lib/WebDavApi.js:449 msgid "Access denied: Please re-enter your password and/or username" msgstr "" +"Acceso denegado: Por favor, vuelva a introducir su contraseña y/o nombre de " +"usuario" #: packages/server/src/routes/admin/users.ts:144 msgid "Account" @@ -340,15 +341,13 @@ msgstr "Cuenta" #: packages/app-desktop/gui/JoplinCloudConfigScreen.tsx:31 #: packages/app-mobile/components/screens/ConfigScreen/JoplinCloudConfig.tsx:48 -#, fuzzy msgid "Account information" -msgstr "Más información" +msgstr "Información de la Cuenta" #: packages/app-desktop/gui/JoplinCloudConfigScreen.tsx:35 #: packages/app-mobile/components/screens/ConfigScreen/JoplinCloudConfig.tsx:51 -#, fuzzy msgid "Account type" -msgstr "Cuenta" +msgstr "Tipo de Cuenta" #: packages/app-desktop/gui/ResourceScreen.tsx:113 msgid "Action" @@ -386,7 +385,7 @@ msgstr "Agregar destinatario:" #: packages/app-mobile/components/screens/NoteTagsDialog.tsx:94 msgid "Add tag %s to note" -msgstr "" +msgstr "Añadir etiqueta %s a la nota" #: packages/app-mobile/components/screens/Note/Note.tsx:1574 msgid "Add title" @@ -397,9 +396,8 @@ msgid "Add to dictionary" msgstr "Agregar al diccionario" #: packages/app-mobile/components/CameraView/ScannedBarcodes.tsx:98 -#, fuzzy msgid "Add to note" -msgstr "Añadir título" +msgstr "Añadir a la nota" #: packages/server/src/services/MustacheService.ts:162 #: packages/server/src/services/MustacheService.ts:286 @@ -415,18 +413,16 @@ msgid "Advanced options" msgstr "Opciones avanzadas" #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:653 -#, fuzzy msgid "Advanced settings" -msgstr "Mostrar Opciones Avanzadas" +msgstr "Ajustes avanzados" #: packages/app-desktop/gui/StatusScreen/StatusScreen.tsx:196 msgid "Advanced tools" msgstr "Herramientas avanzadas" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:18 -#, fuzzy msgid "all" -msgstr "Instalar" +msgstr "todo" #: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:109 msgid "" @@ -437,6 +433,8 @@ msgstr "" #: packages/lib/services/ReportService.ts:227 msgid "All item sync failures have been marked as \"ignored\"." msgstr "" +"Todos los errores de sincronización de elementos se han marcado como " +"\"ignorados\"." #: packages/app-desktop/gui/Sidebar/listItemComponents/AllNotesItem.tsx:71 #: packages/app-mobile/components/screens/Notes.tsx:208 @@ -453,6 +451,7 @@ msgstr "" #: packages/lib/models/settings/builtInMetadata.ts:910 msgid "Allows debugging mobile plugins. See %s for details." msgstr "" +"Permite depurar plugins móviles. Consulte %s para obtener más detalles." #: packages/app-cli/app/command-config.ts:19 msgid "Also displays unset and hidden config variables." @@ -467,18 +466,16 @@ msgid "Always" msgstr "Siempre" #: packages/lib/models/settings/builtInMetadata.ts:866 -#, fuzzy msgid "Always ask" -msgstr "Siempre" +msgstr "Pregunte siempre" #: packages/app-desktop/bridge.ts:450 msgid "Always open %s files without asking." -msgstr "" +msgstr "Abrir siempre los archivos %s sin preguntar." #: packages/lib/models/settings/builtInMetadata.ts:867 -#, fuzzy msgid "Always resize" -msgstr "Siempre" +msgstr "Redimensionar siempre" #: packages/app-cli/app/command-mv.ts:37 msgid "" @@ -500,10 +497,11 @@ msgstr "" #: packages/app-mobile/components/NoteEditor/ImageEditor/promptRestoreAutosave.ts:13 msgid "An autosaved drawing was found. Attach a copy of it to the note?" msgstr "" +"Se ha encontrado un dibujo autoguardado. ¿Adjuntar una copia a la nota?" #: packages/app-desktop/ElectronAppWrapper.ts:133 msgid "An error occurred: %s" -msgstr "" +msgstr "Se ha producido un error: %s" #: packages/app-desktop/checkForUpdates.ts:107 msgid "An update is available, do you want to download it now?" @@ -511,7 +509,7 @@ msgstr "Está disponible una actualización. ¿Quiere descargarla ahora?" #: packages/app-mobile/utils/getVersionInfoText.ts:22 msgid "Android API level: %d" -msgstr "" +msgstr "Nivel de API de Android: %d" #: packages/app-desktop/gui/JoplinCloudConfigScreen.tsx:48 #: packages/app-mobile/components/screens/ConfigScreen/JoplinCloudConfig.tsx:24 @@ -519,6 +517,9 @@ msgid "" "Any email sent to this address will be converted into a note and added to " "your collection. The note will be saved into the Inbox notebook" msgstr "" +"Cualquier correo electrónico enviado a esta dirección se convertirá en una " +"nota y se añadirá a tu colección. La nota se guardará en la libreta Bandeja " +"de entrada." #: packages/lib/models/Setting.ts:1174 msgid "Appearance" @@ -533,11 +534,13 @@ msgid "Apply" msgstr "Aplicar" #: packages/app-mobile/components/EditorToolbar/ToolbarEditorDialog.tsx:146 -#, fuzzy msgid "" "Are you sure that you want to restore the default toolbar layout?\n" "This cannot be undone." -msgstr "¿Está seguro de que desea renovar el token de autorización?" +msgstr "" +"¿Está seguro de que desea restaurar el diseño predeterminado de la barra de " +"herramientas?\n" +"Esto no se puede deshacer." #: packages/app-desktop/gui/ClipperConfigScreen.tsx:38 msgid "Are you sure you want to renew the authorisation token?" @@ -548,6 +551,8 @@ msgid "" "Are you sure you want to return to the default layout? The current layout " "configuration will be lost." msgstr "" +"¿Estás seguro de que quieres volver al diseño predeterminado? La " +"configuración de diseño actual se perderá." #: packages/app-desktop/gui/ConfigScreen/controls/SettingComponent.tsx:235 msgid "Arguments:" @@ -562,6 +567,8 @@ msgid "" "At present, Joplin Web can only be open in one tab at a time. Please close " "the other instance of Joplin." msgstr "" +"En la actualidad, Joplin Web solo se puede abrir en una pestaña a la vez. " +"Por favor, cierre la otra instancia de Joplin." #: packages/app-mobile/components/NoteEditor/ImageEditor/promptRestoreAutosave.ts:25 msgid "Attach" @@ -630,9 +637,8 @@ msgstr "Token de autorización:" #: packages/app-desktop/gui/JoplinCloudLoginScreen.tsx:88 #: packages/app-mobile/components/screens/JoplinCloudLoginScreen.tsx:162 -#, fuzzy msgid "Authorise" -msgstr "Token de autorización:" +msgstr "Autorizar" #: packages/lib/models/settings/builtInMetadata.ts:398 msgid "Auto" @@ -648,7 +654,7 @@ msgstr "Autoemparejar llaves, paréntesis, comillas, etc." #: packages/lib/models/settings/builtInMetadata.ts:656 msgid "Autocomplete Markdown and HTML" -msgstr "" +msgstr "Autocompletar Markdown y HTML" #: packages/lib/models/settings/builtInMetadata.ts:1198 msgid "Automatically check for updates" @@ -656,7 +662,7 @@ msgstr "Comprobar actualizaciones" #: packages/lib/models/settings/builtInMetadata.ts:1722 msgid "Automatically delete notes in the trash after a number of days" -msgstr "" +msgstr "Eliminar automáticamente notas en la papelera después de varios días" #: packages/lib/models/settings/builtInMetadata.ts:556 msgid "Automatically switch theme to match system theme" @@ -680,7 +686,7 @@ msgstr "Básico" #: packages/app-mobile/components/ScreenHeader/WebBetaButton.tsx:37 #: packages/app-mobile/components/ScreenHeader/WebBetaButton.tsx:45 msgid "Beta" -msgstr "" +msgstr "Beta" #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:55 #: packages/app-mobile/components/NoteEditor/commandDeclarations.ts:54 @@ -699,7 +705,7 @@ msgstr "Explorar..." #: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.tsx:223 #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/PluginChips.tsx:54 msgid "Built-in" -msgstr "" +msgstr "Integrado" #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:85 msgid "Bulleted List" @@ -707,11 +713,11 @@ msgstr "Lista con Viñetas" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginInfoModal.tsx:129 msgid "by %s" -msgstr "" +msgstr "por %s" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:20 msgid "by word" -msgstr "" +msgstr "por palabra" #: packages/server/src/routes/admin/users.ts:160 msgid "Can Share" @@ -719,11 +725,11 @@ msgstr "Puede compartir" #: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:120 msgid "Can view" -msgstr "" +msgstr "Puede ver" #: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:121 msgid "Can view and edit" -msgstr "" +msgstr "Puede ver y editar" #: packages/app-desktop/bridge.ts:373 packages/app-desktop/bridge.ts:389 #: packages/app-desktop/bridge.ts:452 @@ -782,9 +788,8 @@ msgid "Cannot copy note to \"%s\" notebook" msgstr "No se ha podido copiar la nota a la libreta «%s»" #: packages/app-mobile/components/screens/Notes.tsx:195 -#, fuzzy msgid "Cannot create a new note: %s" -msgstr "Crea una nueva nota." +msgstr "No se puede crear una nueva nota: %s" #: packages/app-cli/app/command-attach.ts:22 #: packages/app-cli/app/command-cat.ts:26 packages/app-cli/app/command-cp.ts:25 @@ -816,9 +821,8 @@ msgid "Cannot find \"%s\"." msgstr "No se puede encontrar «%s»." #: packages/app-cli/app/command-mkbook.ts:28 -#, fuzzy msgid "Cannot find: \"%s\"" -msgstr "No se puede encontrar «%s»." +msgstr "No se puede encontrar: «%s»" #: packages/app-cli/app/command-sync.ts:202 msgid "Cannot initialise synchroniser." @@ -888,13 +892,12 @@ msgid "Change language" msgstr "Cambiar idioma" #: packages/app-mobile/components/CameraView/ActionButtons.tsx:124 -#, fuzzy msgid "Change ratio" -msgstr "Configuración" +msgstr "Relación de cambio" #: packages/app-desktop/gui/KeymapConfig/KeymapConfigScreen.tsx:98 msgid "Change shortcut for \"%s\"" -msgstr "" +msgstr "Cambiar el atajo para \"%s\"" #: packages/app-desktop/gui/NoteContentPropertiesDialog.tsx:106 msgid "Characters" @@ -907,6 +910,7 @@ msgstr "Caracteres excluyendo espacios" #: packages/app-mobile/components/EditorToolbar/ToolbarEditorDialog.tsx:168 msgid "Check elements to display in the toolbar" msgstr "" +"Verifica los elementos que se van a mostrar en la barra de herramientas" #: packages/app-desktop/gui/MenuBar.tsx:634 #: packages/app-desktop/gui/MenuBar.tsx:929 @@ -951,9 +955,8 @@ msgstr "Quitar alarma" #: packages/app-desktop/gui/lib/SearchInput/SearchInput.tsx:62 #: packages/app-mobile/components/screens/ConfigScreen/plugins/SearchPlugins.tsx:140 -#, fuzzy msgid "Clear search" -msgstr "Quitar alarma" +msgstr "Borrar búsqueda" #: packages/app-desktop/gui/NoteRevisionViewer.tsx:205 msgid "" @@ -972,9 +975,8 @@ msgid "Client ID: %s" msgstr "ID del Cliente: %s" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:23 -#, fuzzy msgid "close" -msgstr "Cerrar" +msgstr "cerrar" #: packages/app-desktop/gui/MenuBar.tsx:359 #: packages/app-desktop/gui/NoteContentPropertiesDialog.tsx:175 @@ -994,13 +996,12 @@ msgid "Close dropdown" msgstr "Cerrar menú" #: packages/app-mobile/components/accessibility/AccessibleModalMenu.tsx:46 -#, fuzzy msgid "Close menu" -msgstr "Cerrar" +msgstr "Cerrar menú" #: packages/app-mobile/components/SideMenu.tsx:300 msgid "Close side menu" -msgstr "" +msgstr "Cerrar menú lateral" #: packages/lib/models/settings/settingValidations.ts:33 msgid "" @@ -1008,6 +1009,9 @@ msgid "" "application again. Make sure you create a backup first by exporting all your " "notes as JEX." msgstr "" +"Cierre la aplicación, luego elimine su perfil en \"%s\" y vuelva a iniciar " +"la aplicación. Asegúrate de crear una copia de seguridad primero exportando " +"todas tus notas como JEX." #: packages/app-desktop/gui/KeymapConfig/utils/getLabel.ts:26 #: packages/app-desktop/gui/MenuBar.tsx:699 @@ -1016,11 +1020,11 @@ msgstr "Cerrar Ventana" #: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useLinkTooltips.ts:39 msgid "Cmd-click to open" -msgstr "" +msgstr "Cmd-haga clic para abrir" #: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useLinkTooltips.ts:45 msgid "Cmd-click to open: %s" -msgstr "" +msgstr "Cmd-clic para abrir: %s" #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:70 #: packages/app-mobile/components/NoteEditor/commandDeclarations.ts:65 @@ -1036,9 +1040,8 @@ msgid "Code View" msgstr "Código" #: packages/lib/utils/joplinCloud/index.ts:173 -#, fuzzy msgid "Collaborate on a notebook with others" -msgstr "Colaborar en los cuadernos con otros" +msgstr "Colaborar en un cuaderno con otros usuarios" #: packages/app-desktop/gui/SyncWizard/Dialog.tsx:169 msgid "Collaborate on notebooks with others" @@ -1046,7 +1049,7 @@ msgstr "Colaborar en los cuadernos con otros" #: packages/app-desktop/gui/Sidebar/listItemComponents/ExpandIcon.tsx:28 msgid "Collapsed, press space to expand." -msgstr "" +msgstr "Contraído, presione espacio para expandir." #: packages/lib/services/ReportService.ts:351 msgid "Coming alarms" @@ -1055,9 +1058,9 @@ msgstr "Alarmas próximas" #: packages/lib/models/settings/builtInMetadata.ts:1379 msgid "" "Comma-separated list of paths to directories to load the certificates from, " -"or path to individual cert files. For example: /my/cert_dir, /other/" -"custom.pem. Note that if you make changes to the TLS settings, you must save " -"your changes before clicking on \"Check synchronisation configuration\"." +"or path to individual cert files. For example: /my/cert_dir, /other/custom." +"pem. Note that if you make changes to the TLS settings, you must save your " +"changes before clicking on \"Check synchronisation configuration\"." msgstr "" "Lista de rutas de directorios separados por comas de dónde cargar los " "certificados, o ruta a certificados individuales. Por ejemplo: /mi/" @@ -1082,19 +1085,16 @@ msgid "Command palette..." msgstr "Paleta de comandos..." #: packages/lib/services/noteList/defaultListRenderer.ts:24 -#, fuzzy msgid "Compact" -msgstr "Completada" +msgstr "Compacto" #: packages/app-desktop/gui/NoteList/utils/useOnKeyDown.ts:153 -#, fuzzy msgid "Complete" -msgstr "Completada" +msgstr "Completo" #: packages/app-desktop/gui/NoteListItem/utils/prepareViewProps.ts:40 -#, fuzzy msgid "Complete to-do" -msgstr "Completada" +msgstr "Tarea completas" #: packages/app-desktop/gui/NoteListHeader/utils/getColumnTitle.ts:12 #: packages/app-desktop/gui/NotePropertiesDialog.tsx:70 @@ -1110,6 +1110,8 @@ msgid "" "Completed with warnings:\n" "%s" msgstr "" +"Completado con advertencias:\n" +"%s" #: packages/lib/Synchronizer.ts:207 msgid "Completed: %s (%s)" @@ -1117,7 +1119,7 @@ msgstr "Completado: %s (%s)" #: packages/lib/models/Note.ts:66 msgid "completion date" -msgstr "" +msgstr "fecha de compleción" #: packages/server/src/services/TaskService.ts:28 msgid "Compress old changes" @@ -1157,38 +1159,34 @@ msgstr "Conflictos (adjuntos)" #: packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx:253 #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:462 -#, fuzzy msgid "Connect to Joplin Cloud" -msgstr "Joplin Cloud" +msgstr "Conéctese a Joplin Cloud" #: packages/lib/utils/joplinCloud/index.ts:208 msgid "Consolidated billing" msgstr "Facturación consolidada" #: packages/app-desktop/gui/Sidebar/listItemComponents/NoteCount.tsx:11 -#, fuzzy msgid "Contains %d note" msgid_plural "Contains %d notes" -msgstr[0] "Convertir en nota" -msgstr[1] "Convertir en nota" +msgstr[0] "Contiene %d nota" +msgstr[1] "Contiene %d notas" #: packages/app-desktop/gui/ConfigScreen/controls/plugins/SearchPlugins.tsx:106 msgid "Content provided by %s" msgstr "Contenido provisto por %s" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginStates.tsx:102 -#, fuzzy msgid "Content provided by: %s" -msgstr "Contenido provisto por %s" +msgstr "Contenido proporcionado por: %s" #: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:74 msgid "Continue" msgstr "Continuar" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:6 -#, fuzzy msgid "Control character" -msgstr "Caracteres" +msgstr "Carácter de control" #: packages/app-mobile/components/screens/Note/Note.tsx:1221 msgid "Convert to note" @@ -1199,9 +1197,8 @@ msgid "Convert to todo" msgstr "Convertir a tarea" #: packages/app-mobile/components/voiceTyping/VoiceTypingDialog.tsx:181 -#, fuzzy msgid "Converting speech to text..." -msgstr "Convertir en nota" +msgstr "Convertir voz en texto..." #: packages/app-desktop/gui/MenuBar.tsx:601 #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:35 @@ -1232,9 +1229,8 @@ msgstr "Copiar Enlace" #: packages/app-desktop/gui/JoplinCloudLoginScreen.tsx:94 #: packages/app-mobile/components/screens/JoplinCloudLoginScreen.tsx:169 -#, fuzzy msgid "Copy link to website" -msgstr "Sitio web de Joplin" +msgstr "Copiar enlace al sitio web" #: packages/app-desktop/gui/utils/NoteListUtils.ts:112 #: packages/app-mobile/components/screens/Note/Note.tsx:1230 @@ -1253,18 +1249,16 @@ msgstr[1] "Copiar Enlaces Compartible" #: packages/app-desktop/gui/JoplinCloudConfigScreen.tsx:52 #: packages/app-mobile/components/screens/ConfigScreen/JoplinCloudConfig.tsx:75 -#, fuzzy msgid "Copy to clipboard" -msgstr "Copiar la ruta al portapapeles" +msgstr "Copiar al portapapeles" #: packages/app-desktop/gui/ClipperConfigScreen.tsx:144 msgid "Copy token" msgstr "Copiar token" #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:611 -#, fuzzy msgid "Copy version info" -msgstr "Muestra información de la versión" +msgstr "Copiar información de la versión" #: packages/lib/components/shared/dropbox-login-shared.js:43 msgid "" @@ -1333,18 +1327,16 @@ msgstr "" "abortando. Por favor, inténtelo de nuevo cuando esté conectado a Internet." #: packages/app-mobile/components/biometrics/biometricAuthenticate.ts:30 -#, fuzzy msgid "Could not verify your identity: %s" -msgstr "No se pudo verificar su identidad" +msgstr "No se ha podido verificar su identidad: %s" #: packages/app-desktop/gui/PromptDialog.tsx:277 msgid "Create" msgstr "Crear" #: packages/app-cli/app/command-mkbook.ts:19 -#, fuzzy msgid "Create a new notebook under a parent notebook." -msgstr "Crea una nueva libreta." +msgstr "Cree una nueva libreta en una libreta principal." #: packages/app-mobile/components/NoteList.tsx:102 msgid "Create a notebook" @@ -1411,14 +1403,12 @@ msgid "Creates a new to-do." msgstr "Crea una nueva tarea." #: packages/app-desktop/gui/NoteEditor/NoteTitle/NoteTitleBar.tsx:123 -#, fuzzy msgid "Creating new note..." -msgstr "Creando nuevo %s..." +msgstr "Creando una nueva nota..." #: packages/app-desktop/gui/NoteEditor/NoteTitle/NoteTitleBar.tsx:123 -#, fuzzy msgid "Creating new to-do..." -msgstr "Creando nuevo %s..." +msgstr "Creando nueva tarea..." #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/ExportDebugReportButton.tsx:29 msgid "Creating report..." @@ -1426,21 +1416,19 @@ msgstr "Creando reporte..." #: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useLinkTooltips.ts:41 msgid "Ctrl-click to open" -msgstr "" +msgstr "Ctrl-clic para abrir" #: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useLinkTooltips.ts:47 msgid "Ctrl-click to open: %s" -msgstr "" +msgstr "Ctrl-clic para abrir: %s" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:24 -#, fuzzy msgid "current match" -msgstr "Siguiente coincidencia" +msgstr "Partido actual" #: packages/app-desktop/gui/MasterPasswordDialog/Dialog.tsx:153 -#, fuzzy msgid "Current password" -msgstr "Contraseña maestra" +msgstr "Contraseña actual" #: packages/app-desktop/checkForUpdates.ts:90 msgid "Current version is up-to-date." @@ -1468,7 +1456,7 @@ msgstr "Certificados TLS personalizados" #: packages/lib/utils/joplinCloud/index.ts:194 msgid "Customise the note publishing banner" -msgstr "" +msgstr "Personaliza el banner de publicación de notas" #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:40 #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useContextMenu.ts:85 @@ -1564,16 +1552,16 @@ msgid "" "Delete model and re-download?\n" "This cannot be undone." msgstr "" +"¿Eliminar el modelo y volver a descargarlo?\n" +"Esto no se puede deshacer." #: packages/lib/commands/deleteNote.ts:7 -#, fuzzy msgid "Delete note" -msgstr "¿Borrar nota?" +msgstr "Eliminar nota" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/deleteFolder.ts:9 -#, fuzzy msgid "Delete notebook" -msgstr "Eliminar libreta?" +msgstr "Eliminar libreta" #: packages/lib/components/shared/config/plugins/useOnDeleteHandler.ts:16 msgid "Delete plugin \"%s\"?" @@ -1595,6 +1583,10 @@ msgid "" "If you delete the inbox notebook, any email that's recently been sent to it " "may be lost." msgstr "" +"¿Eliminar la libreta de la bandeja de entrada?\n" +"\n" +"Si eliminas la libreta de la bandeja de entrada, es posible que se pierda " +"cualquier correo electrónico que se haya enviado recientemente." #: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:246 msgid "" @@ -1610,9 +1602,8 @@ msgstr "¿Borrar este perfil?" #: packages/app-desktop/gui/NotePropertiesDialog.tsx:69 #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginInfoModal.tsx:207 -#, fuzzy msgid "Deleted" -msgstr "Borrar" +msgstr "Eliminado" #: packages/lib/Synchronizer.ts:203 msgid "Deleted local items: %d." @@ -1624,7 +1615,7 @@ msgstr "Elementos remotos borrados: %d." #: packages/app-cli/app/command-rmnote.ts:20 msgid "Deletes notes permanently, skipping the trash." -msgstr "" +msgstr "Elimina notas de forma permanente, saltándose la papelera." #: packages/app-cli/app/command-rmbook.ts:14 msgid "Deletes the given notebook." @@ -1643,14 +1634,12 @@ msgid "Deletes the notes without asking for confirmation." msgstr "Elimina las notas sin pedir confirmación." #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:551 -#, fuzzy msgid "Deletion log" -msgstr "Borrar línea" +msgstr "Registro de eliminación" #: packages/app-mobile/components/NoteItem.tsx:144 -#, fuzzy msgid "Deselect" -msgstr "Seleccione" +msgstr "Deseleccionar" #: packages/app-cli/app/command-export.ts:24 msgid "Destination format: %s" @@ -1659,11 +1648,11 @@ msgstr "Formato de destino: %s" #: packages/lib/services/noteList/defaultLeftToRightListRenderer.ts:25 #: packages/lib/services/noteList/defaultMultiColumnsRenderer.ts:8 msgid "Detailed" -msgstr "" +msgstr "Detallado" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/PluginChips.tsx:99 msgid "Dev" -msgstr "" +msgstr "Desarrollador" #: packages/lib/services/interop/Module.ts:62 msgid "Directory" @@ -1700,9 +1689,8 @@ msgid "Disabled" msgstr "Deshabilitado" #: packages/app-mobile/components/screens/encryption-config.tsx:323 -#, fuzzy msgid "Disabled keys" -msgstr "Ocultar las claves desactivadas" +msgstr "Teclas deshabilitadas" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:200 #: packages/app-mobile/components/screens/encryption-config.tsx:251 @@ -1716,9 +1704,8 @@ msgstr "" "continuar?" #: packages/app-mobile/components/NoteEditor/ImageEditor/promptRestoreAutosave.ts:19 -#, fuzzy msgid "Discard" -msgstr "Descartar cambios" +msgstr "Descartar" #: packages/app-mobile/components/NoteEditor/ImageEditor/ImageEditor.tsx:105 #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:269 @@ -1796,9 +1783,8 @@ msgstr "" "introduzca su contraseña a continuación." #: packages/lib/models/Setting.ts:1220 -#, fuzzy msgid "Donate, website" -msgstr "Sitio web de Joplin" +msgstr "Donar, sitio web" #: packages/app-mobile/components/NoteEditor/EditLinkDialog.tsx:151 #: packages/app-mobile/components/voiceTyping/VoiceTypingDialog.tsx:245 @@ -1815,9 +1801,8 @@ msgid "Download and install the relevant extension for your browser:" msgstr "Descargue e instale la extensión apropiada para su navegador:" #: packages/app-mobile/components/voiceTyping/VoiceTypingDialog.tsx:206 -#, fuzzy msgid "Download updated model" -msgstr "Descargado" +msgstr "Descargar modelo actualizado" #: packages/lib/models/Resource.ts:409 msgid "Downloaded" @@ -1836,9 +1821,8 @@ msgid "Downloading" msgstr "Descargando" #: packages/app-mobile/components/voiceTyping/VoiceTypingDialog.tsx:182 -#, fuzzy msgid "Downloading %s language files..." -msgstr "Descargando recursos..." +msgstr "Descarga de archivos de idioma %s..." #: packages/app-cli/app/command-sync.ts:256 msgid "Downloading resources..." @@ -1850,11 +1834,11 @@ msgstr "Drácula" #: packages/app-mobile/components/screens/Note/Note.tsx:1162 msgid "Draw picture" -msgstr "" +msgstr "Dibujo" #: packages/app-mobile/components/screens/Note/Note.tsx:872 msgid "Drawing" -msgstr "" +msgstr "Dibujar" #: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx:1444 msgid "Drop notes or files here" @@ -1870,12 +1854,11 @@ msgstr "Inicio de sesión de Dropbox" #: packages/app-desktop/gui/NoteListHeader/utils/getColumnTitle.ts:13 msgid "Due" -msgstr "" +msgstr "Vencido" #: packages/lib/models/Note.ts:65 -#, fuzzy msgid "due date" -msgstr "fecha de actualización" +msgstr "fecha límite" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/duplicateNote.ts:7 #: packages/app-mobile/components/ScreenHeader/index.tsx:470 @@ -1916,12 +1899,11 @@ msgstr "Editar con un editor externo" #: packages/app-desktop/commands/openNoteInNewWindow.ts:10 msgid "Edit in new window" -msgstr "" +msgstr "Editar en ventana nueva" #: packages/app-desktop/gui/utils/NoteListUtils.ts:70 -#, fuzzy msgid "Edit in..." -msgstr "Editar enlace" +msgstr "Editar en..." #: packages/app-mobile/components/NoteEditor/EditLinkDialog.tsx:143 msgid "Edit link" @@ -1952,9 +1934,8 @@ msgid "Editor" msgstr "Editor" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/Toolbar.tsx:38 -#, fuzzy msgid "Editor actions" -msgstr "Fuente del editor" +msgstr "Acciones del editor" #: packages/lib/models/settings/builtInMetadata.ts:1074 msgid "Editor font" @@ -1998,18 +1979,16 @@ msgstr "Email" #: packages/app-desktop/gui/JoplinCloudConfigScreen.tsx:47 #: packages/app-mobile/components/screens/ConfigScreen/JoplinCloudConfig.tsx:23 -#, fuzzy msgid "Email to note" -msgstr "Editar nota." +msgstr "Correo electrónico a la nota" #: packages/lib/utils/joplinCloud/index.ts:187 msgid "Email to Note" -msgstr "" +msgstr "Enviar por correo electrónico a la nota" #: packages/lib/models/Setting.ts:1213 -#, fuzzy msgid "Email To Note, login information" -msgstr "Muestra información de la versión" +msgstr "Correo electrónico a la nota, información de inicio de sesión" #: packages/server/src/routes/admin/emails.ts:111 #: packages/server/src/services/MustacheService.ts:133 @@ -2025,7 +2004,7 @@ msgstr "texto en cursiva" #: packages/app-mobile/components/side-menu-content.tsx:338 #: packages/app-mobile/components/side-menu-content.tsx:342 msgid "Empty trash" -msgstr "" +msgstr "Vaciar papelera" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:144 #: packages/app-mobile/components/biometrics/BiometricPopup.tsx:86 @@ -2072,7 +2051,7 @@ msgstr "Habilitar cifrado" #: packages/lib/models/settings/builtInMetadata.ts:994 msgid "Enable file:// URLs for images and videos" -msgstr "" +msgstr "Habilitar URL de file:// para imágenes y videos" #: packages/lib/models/settings/builtInMetadata.ts:975 msgid "Enable footnotes" @@ -2108,12 +2087,11 @@ msgstr "Habilitar historial de notas" #: packages/lib/models/settings/builtInMetadata.ts:500 msgid "Enable optical character recognition (OCR)" -msgstr "" +msgstr "Habilitar el reconocimiento óptico de caracteres (OCR)" #: packages/lib/models/Setting.ts:1219 -#, fuzzy msgid "Enable or disable plugins" -msgstr "Administre sus plugins" +msgstr "Activar o desactivar plugins" #: packages/lib/models/settings/builtInMetadata.ts:973 msgid "Enable PDF viewer" @@ -2121,31 +2099,28 @@ msgstr "Activar visor de PDF" #: packages/app-mobile/components/screens/ConfigScreen/plugins/EnablePluginSupportPage.tsx:119 #: packages/lib/models/settings/builtInMetadata.ts:921 -#, fuzzy msgid "Enable plugin support" -msgstr "Activar el soporte de tipógrafo" +msgstr "Habilitar la compatibilidad con complementos" #: packages/lib/models/settings/builtInMetadata.ts:963 msgid "Enable soft breaks" msgstr "Activar saltos de línea" #: packages/lib/models/settings/builtInMetadata.ts:1303 -#, fuzzy msgid "Enable spell checking in Markdown editor" -msgstr "Activar sintaxis de emojis markdown" +msgstr "Habilitar la revisión ortográfica en el editor de Markdown" #: packages/lib/models/settings/builtInMetadata.ts:789 msgid "Enable spellcheck in the text editor" -msgstr "" +msgstr "Habilitar el corrector ortográfico en el editor de texto" #: packages/lib/models/settings/builtInMetadata.ts:976 msgid "Enable table of contents extension" msgstr "Activar extensión de tabla de contenidos" #: packages/lib/models/settings/builtInMetadata.ts:800 -#, fuzzy msgid "Enable the Markdown toolbar" -msgstr "Activar sintaxis de emojis markdown" +msgstr "Habilitar la barra de herramientas Markdown" #: packages/lib/models/settings/builtInMetadata.ts:964 msgid "Enable typographer support" @@ -2172,6 +2147,8 @@ msgid "" "Enables Markdown list continuation, auto-closing HTML tags, and other markup " "autocompletions." msgstr "" +"Activa la continuación de listas Markdown, el cierre automático de etiquetas " +"HTML y otros autocompletados de marcado." #: packages/lib/components/EncryptionConfigScreen/utils.ts:50 msgid "" @@ -2218,7 +2195,7 @@ msgstr "Cifrado de Extremo a Extremo" #: packages/app-mobile/components/voiceTyping/VoiceTypingDialog.tsx:244 msgid "Ends voice typing" -msgstr "" +msgstr "Finaliza la escritura por voz" #: packages/app-mobile/components/screens/dropbox-login.tsx:70 msgid "Enter code here" @@ -2234,13 +2211,12 @@ msgid "Enter notebook title" msgstr "Introduzca el título de la libreta" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:122 -#, fuzzy msgid "Enter password" -msgstr "Contraseña maestra" +msgstr "Introducir la contraseña" #: packages/app-mobile/components/NoteItem.tsx:120 msgid "Entering selection mode" -msgstr "" +msgstr "Entrando en el modo de selección" #: packages/app-cli/app/help-utils.js:56 msgid "Enum" @@ -2291,27 +2267,24 @@ msgid "Evernote Export File (as Markdown)" msgstr "Exportar como Archivo de Ever(como Markdown)" #: packages/lib/services/interop/InteropService.ts:94 -#, fuzzy msgid "Evernote Export Files (Directory, as HTML)" -msgstr "Exportar como Archivo de Ever(como HTML)" +msgstr "Archivos de exportación de Evernote (directorio, como HTML)" #: packages/lib/services/interop/InteropService.ts:103 -#, fuzzy msgid "Evernote Export Files (Directory, as Markdown)" -msgstr "Exportar como Archivo de Ever(como Markdown)" +msgstr "Archivos de exportación de Evernote (directorio, como Markdown)" #: packages/app-cli/app/command-exit.ts:11 msgid "Exits the application." msgstr "Sale de la aplicación." #: packages/app-mobile/components/side-menu-content.tsx:212 -#, fuzzy msgid "Expand %s" -msgstr "Expandir" +msgstr "Expandir %s" #: packages/app-desktop/gui/Sidebar/listItemComponents/ExpandIcon.tsx:26 msgid "Expanded, press space to collapse." -msgstr "" +msgstr "Expandido, presione espacio para contraer." #: packages/app-desktop/gui/KeymapConfig/KeymapConfigScreen.tsx:182 #: packages/app-desktop/gui/Sidebar/hooks/useOnRenderItem.tsx:213 @@ -2325,9 +2298,8 @@ msgid "Export all" msgstr "Exportar todo" #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteExportButton.tsx:20 -#, fuzzy msgid "Export all notes as JEX" -msgstr "Exportar todo" +msgstr "Exportar todas las notas como JEX" #: packages/app-desktop/gui/StatusScreen/StatusScreen.tsx:199 msgid "Export debug report" @@ -2338,9 +2310,8 @@ msgid "Export Debug Report" msgstr "Exportar Informe de Depuración" #: packages/app-desktop/commands/exportDeletionLog.ts:11 -#, fuzzy msgid "Export deletion log" -msgstr "Exportar todo" +msgstr "Exportar registro de eliminación" #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/ExportProfileButton.tsx:16 msgid "Export profile" @@ -2348,7 +2319,7 @@ msgstr "Exportar perfil" #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteExportButton.tsx:70 msgid "Exported successfully!" -msgstr "" +msgstr "¡Exportado con éxito!" #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/ExportProfileButton.tsx:36 msgid "Exporting profile..." @@ -2359,9 +2330,8 @@ msgid "Exporting to \"%s\" as \"%s\" format. Please wait..." msgstr "Exportando a «%s» como formato «%s». Por favor espere..." #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteExportButton.tsx:25 -#, fuzzy msgid "Exporting..." -msgstr "Exportando perfil..." +msgstr "Exportando..." #: packages/app-cli/app/command-export.ts:14 msgid "" @@ -2420,18 +2390,16 @@ msgstr "Sistema de archivos" #: packages/app-mobile/components/screens/LogScreen.tsx:207 #: packages/app-mobile/components/screens/LogScreen.tsx:208 -#, fuzzy msgid "Filter" -msgstr "Filtrar etiquetas" +msgstr "Filtro" #: packages/app-mobile/components/screens/NoteTagsDialog.tsx:227 msgid "Filter tags" msgstr "Filtrar etiquetas" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:14 -#, fuzzy msgid "Find" -msgstr "Buscar: " +msgstr "Encontrar" #: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:253 msgid "Find: " @@ -2469,7 +2437,7 @@ msgstr "Enfocar título" #: packages/app-mobile/components/CameraView/ScannedBarcodes.tsx:97 msgid "Follow link" -msgstr "" +msgstr "Seguir enlace" #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/ExportProfileButton.tsx:38 msgid "For debugging purpose only: export your profile to an external SD card." @@ -2541,6 +2509,8 @@ msgstr[1] "Creando enlaces..." #: packages/lib/models/Setting.ts:1215 msgid "Geolocation, spellcheck, editor toolbar, image resize" msgstr "" +"Geolocalización, corrector ortográfico, barra de herramientas del editor, " +"cambio de tamaño de imagen" #: packages/app-desktop/gui/ExtensionBadge.tsx:93 msgid "Get it now:" @@ -2562,21 +2532,20 @@ msgstr "" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:13 msgid "go" -msgstr "" +msgstr "ir" #: packages/app-mobile/components/CameraView/CameraView.tsx:165 msgid "Go back" -msgstr "" +msgstr "Volver" #: packages/app-desktop/gui/JoplinCloudConfigScreen.tsx:44 #: packages/app-mobile/components/screens/ConfigScreen/JoplinCloudConfig.tsx:59 -#, fuzzy msgid "Go to Joplin Cloud profile" -msgstr "Joplin Cloud" +msgstr "Ir al perfil de Joplin Cloud" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:12 msgid "Go to line" -msgstr "" +msgstr "Ir a la línea" #: packages/app-mobile/components/screens/Note/Note.tsx:1051 msgid "Go to source URL" @@ -2594,6 +2563,7 @@ msgstr "Conceder la autorización" #: packages/app-cli/app/command-sync.ts:116 msgid "Have you authorised the application login in the above URL?" msgstr "" +"¿Ha autorizado el inicio de sesión de la aplicación en la URL anterior?" #: packages/app-mobile/components/NoteEditor/commandDeclarations.ts:19 msgid "Header %d" @@ -2612,12 +2582,11 @@ msgstr "Ayuda" #: packages/app-mobile/components/screens/ConfigScreen/plugins/EnablePluginSupportPage.tsx:113 msgid "Here's what we do to make plugins safer:" -msgstr "" +msgstr "Esto es lo que hacemos para que los plugins sean más seguros:" #: packages/app-mobile/utils/getVersionInfoText.ts:49 -#, fuzzy msgid "Hermes enabled: %d" -msgstr "FTS activado: %d" +msgstr "Hermes habilitado: %d" #: packages/app-desktop/gui/MenuBar.tsx:670 msgid "Hide %s" @@ -2644,9 +2613,8 @@ msgid "Hide keyboard" msgstr "Ocultar teclado" #: packages/app-desktop/gui/PasswordInput/PasswordInput.tsx:21 -#, fuzzy msgid "Hide password" -msgstr "Contraseña inválida" +msgstr "Ocultar la contraseña" #: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/setupToolbarButtons.ts:14 msgid "Highlight" @@ -2667,7 +2635,7 @@ msgstr "Directorio HTML" #: packages/lib/services/interop/InteropService.ts:112 msgid "HTML document" -msgstr "" +msgstr "Documento HTML" #: packages/lib/services/interop/InteropService.ts:179 msgid "HTML File" @@ -2698,6 +2666,8 @@ msgid "" "If you have already authorised, please wait for the application to sync to " "Joplin Cloud." msgstr "" +"Si ya lo ha autorizado, espere a que la aplicación se sincronice con Joplin " +"Cloud." #: packages/app-desktop/ElectronAppWrapper.ts:127 #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:360 @@ -2711,9 +2681,8 @@ msgid "Ignore TLS certificate errors" msgstr "Ignorar errores en certificados TLS" #: packages/lib/services/ReportService.ts:236 -#, fuzzy msgid "Ignored items that cannot be synchronised" -msgstr "Elementos que no pueden ser sincronizados" +msgstr "Elementos ignorados que no se pueden sincronizar" #: packages/app-desktop/gui/EditFolderDialog/Dialog.tsx:106 msgid "Images" @@ -2727,32 +2696,32 @@ msgid "Import" msgstr "Importar" #: packages/lib/models/Setting.ts:1186 -#, fuzzy msgid "Import and Export" -msgstr "Exportar Informe de depuración" +msgstr "Importación / exportación .po" #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteImportButton.tsx:66 msgid "" "Import failed. Make sure a JEX file was selected.\n" "Details: %s" msgstr "" +"Error de importación. Asegúrese de que se haya seleccionado un archivo JEX.\n" +"Detalles: %s" #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteImportButton.tsx:21 msgid "Import from JEX" -msgstr "" +msgstr "Importar desde JEX" #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteImportButton.tsx:22 msgid "Import notes from a JEX (Joplin Export) file." -msgstr "" +msgstr "Importar notas de un archivo JEX (Joplin Export)." #: packages/lib/models/Setting.ts:1218 -#, fuzzy msgid "Import or export your data" -msgstr "Exportar todo" +msgstr "Importa o exporta tus datos" #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteImportButton.tsx:76 msgid "Imported successfully!" -msgstr "" +msgstr "¡Importado exitosamente!" #: packages/app-desktop/gui/MenuBar.tsx:319 msgid "Importing from \"%s\" as \"%s\" format. Please wait..." @@ -2763,9 +2732,8 @@ msgid "Importing notes..." msgstr "Importando notas..." #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteImportButton.tsx:26 -#, fuzzy msgid "Importing..." -msgstr "Exportando perfil..." +msgstr "Importando..." #: packages/app-cli/app/command-import.ts:16 msgid "Imports data into Joplin." @@ -2839,7 +2807,7 @@ msgstr "" #: packages/lib/services/synchronizer/syncInfoUtils.ts:466 msgid "In order to synchronise, please upgrade your application to version %s+" -msgstr "" +msgstr "Para sincronizar, actualice su aplicación a la versión %s+" #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:122 #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:224 @@ -2864,17 +2832,15 @@ msgstr "En: %s" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/PluginChips.tsx:69 msgid "Incompatible" -msgstr "" +msgstr "Incompatible" #: packages/app-desktop/gui/NoteList/utils/useOnKeyDown.ts:153 -#, fuzzy msgid "Incomplete" -msgstr "Completada" +msgstr "Incompleto" #: packages/app-desktop/gui/NoteListItem/utils/prepareViewProps.ts:40 -#, fuzzy msgid "Incomplete to-do" -msgstr "Mostrar tareas completadas" +msgstr "Tareas incompletas" #: packages/app-mobile/components/NoteEditor/commandDeclarations.ts:97 msgid "Increase indent level" @@ -2890,7 +2856,7 @@ msgstr "Aumentar sangría" #: packages/app-mobile/components/DialogManager/hooks/useDialogControl.ts:21 msgid "Info" -msgstr "" +msgstr "Información" #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:223 msgid "Information" @@ -2932,9 +2898,8 @@ msgid "Installed" msgstr "Instalado" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginStates.tsx:202 -#, fuzzy msgid "Installed (%d):" -msgstr "Instalado" +msgstr "Instalado (%d):" #: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.tsx:192 #: packages/app-mobile/components/screens/ConfigScreen/plugins/buttons/InstallButton.tsx:17 @@ -2967,9 +2932,8 @@ msgid "Invalid password" msgstr "Contraseña inválida" #: packages/app-mobile/utils/getVersionInfoText.ts:24 -#, fuzzy msgid "iOS version: %s" -msgstr "Nueva versión: %s" +msgstr "versión de iOS: %s" #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:60 #: packages/app-mobile/components/NoteEditor/commandDeclarations.ts:59 @@ -2995,7 +2959,7 @@ msgstr "Elementos que no pueden ser sincronizados" #: packages/app-desktop/gui/MenuBar.tsx:923 msgid "Join us on %s" -msgstr "" +msgstr "Únete a nosotros en %s" #: packages/app-desktop/gui/SyncWizard/Dialog.tsx:267 msgid "" @@ -3011,20 +2975,20 @@ msgstr "Joplin Cloud" #: packages/app-desktop/gui/Root.tsx:190 #: packages/app-mobile/components/screens/JoplinCloudLoginScreen.tsx:148 -#, fuzzy msgid "Joplin Cloud Login" -msgstr "Joplin Cloud" +msgstr "Inicio de sesión en Joplin Cloud" #: packages/lib/services/plugins/PluginService.ts:525 -#, fuzzy msgid "Joplin Desktop" -msgstr "Sitio web de Joplin" +msgstr "Escritorio Joplin" #: packages/app-desktop/bridge.ts:448 msgid "" "Joplin doesn't recognise the %s extension. Opening this file could be " "dangerous. What would you like to do?" msgstr "" +"Joplin no reconoce la extensión %s. Abrir este archivo podría ser peligroso. " +"¿Qué te gustaría hacer?" #: packages/lib/services/interop/InteropService.ts:159 #: packages/lib/services/interop/InteropService.ts:68 @@ -3051,14 +3015,12 @@ msgid "Joplin Forum" msgstr "Foro de Joplin" #: packages/app-mobile/utils/lockToSingleInstance.ts:16 -#, fuzzy msgid "Joplin is already running." -msgstr "El servidor ya esta ejecutándose en el puerto %d" +msgstr "Joplin ya se está ejecutando." #: packages/lib/services/plugins/PluginService.ts:523 -#, fuzzy msgid "Joplin Mobile" -msgstr "Sitio web de Joplin" +msgstr "Joplin Móvil" #: packages/lib/SyncTargetJoplinServer.ts:61 msgid "Joplin Server" @@ -3095,16 +3057,15 @@ msgid "" msgstr "" "El servicio de sincronización propio de Joplin. También da acceso a " "funciones específicas de Joplin, como la publicación de notas o la " -"colaboración en cuadernos con otras personas." +"colaboración en libretas con otras personas." #: packages/lib/models/settings/builtInMetadata.ts:1485 msgid "Keep note history for" msgstr "Mantener historial de la nota durante" #: packages/lib/models/settings/builtInMetadata.ts:1739 -#, fuzzy msgid "Keep notes in the trash for" -msgstr "Mantener historial de la nota durante" +msgstr "Guarda las notas en la papelera durante" #: packages/lib/models/settings/builtInMetadata.ts:1285 msgid "Keyboard Mode" @@ -3135,9 +3096,8 @@ msgid "Language" msgstr "Idioma" #: packages/lib/models/Setting.ts:1210 -#, fuzzy msgid "Language, date format" -msgstr "Formato de fecha" +msgstr "Idioma, formato de fecha" #: packages/lib/Synchronizer.ts:208 msgid "Last error: %s" @@ -3149,7 +3109,7 @@ msgstr "Luego" #: packages/app-desktop/gui/NoteListHeader/utils/getColumnTitle.ts:7 msgid "Latitude" -msgstr "" +msgstr "Latitud" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v5/CodeMirror.tsx:638 #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/CodeMirror.tsx:237 @@ -3163,18 +3123,18 @@ msgstr "Secuencia del botón de diseño" #: packages/app-desktop/bridge.ts:453 #: packages/app-mobile/components/screens/ConfigScreen/plugins/EnablePluginSupportPage.tsx:118 #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/RecommendedBadge.tsx:52 -#, fuzzy msgid "Learn more" -msgstr "Aumentar sangría" +msgstr "Saber más" #: packages/lib/models/settings/builtInMetadata.ts:1692 msgid "Leave it blank to download the language files from the default website" msgstr "" +"Déjelo en blanco para descargar los archivos de idioma del sitio web " +"predeterminado" #: packages/app-mobile/components/screens/ShareManager/AcceptedShareItem.tsx:90 -#, fuzzy msgid "Leave notebook" -msgstr "Abandonar libreta..." +msgstr "Dejar una libreta" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/leaveSharedFolder.ts:11 msgid "Leave notebook..." @@ -3197,6 +3157,8 @@ msgid "" "Like any software you install, plugins can potentially cause security issues " "or data loss." msgstr "" +"Al igual que cualquier software que instale, los complementos pueden causar " +"problemas de seguridad o pérdida de datos." #: packages/app-desktop/gui/NoteContentPropertiesDialog.tsx:108 msgid "Lines" @@ -3234,9 +3196,8 @@ msgstr "Cargado" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginStates.tsx:117 #: packages/app-mobile/components/voiceTyping/VoiceTypingDialog.tsx:179 #: packages/app-mobile/root.tsx:1247 -#, fuzzy msgid "Loading..." -msgstr "Actualizando..." +msgstr "Cargando..." #: packages/app-desktop/gui/NotePropertiesDialog.tsx:71 msgid "Location" @@ -3259,9 +3220,8 @@ msgid "Log" msgstr "Registro" #: packages/app-desktop/gui/MainScreen.tsx:563 -#, fuzzy msgid "Login to Joplin Cloud." -msgstr "Joplin Cloud" +msgstr "Acceder con Joplin Cloud." #: packages/app-mobile/components/screens/dropbox-login.tsx:59 msgid "Login with Dropbox" @@ -3277,11 +3237,11 @@ msgstr "Cerrar sesión" #: packages/lib/models/Setting.ts:1217 msgid "Logs, profiles, sync status" -msgstr "" +msgstr "Registros, perfiles, estado de sincronización" #: packages/app-desktop/gui/NoteListHeader/utils/getColumnTitle.ts:8 msgid "Longitude" -msgstr "" +msgstr "Longitud" #: packages/app-desktop/gui/MenuBar.tsx:926 #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:604 @@ -3305,14 +3265,12 @@ msgid "Manage profiles" msgstr "Administrar perfiles" #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:555 -#, fuzzy msgid "Manage shared notebooks" -msgstr "Administrar perfiles" +msgstr "Administrar libretas compartidas" #: packages/app-mobile/components/EditorToolbar/ToolbarEditorDialog.tsx:165 -#, fuzzy msgid "Manage toolbar options" -msgstr "Administre sus plugins" +msgstr "Administrar opciones de la barra de herramientas" #: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.tsx:331 msgid "Manage your plugins" @@ -3345,9 +3303,8 @@ msgstr "Markdown + Front Matter" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/CodeMirror.tsx:375 #: packages/app-mobile/components/NoteEditor/NoteEditor.tsx:352 -#, fuzzy msgid "Markdown editor" -msgstr "Markdown" +msgstr "Editor de Markdown" #: packages/app-cli/app/command-done.ts:15 msgid "Marks a to-do as done." @@ -3378,11 +3335,11 @@ msgstr "Contraseña maestra:" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:19 msgid "match case" -msgstr "" +msgstr "Caso de coincidencia" #: packages/app-mobile/components/NoteEditor/commandDeclarations.ts:72 msgid "Math" -msgstr "" +msgstr "Matemáticas" #: packages/lib/models/settings/builtInMetadata.ts:421 msgid "Max concurrent connections" @@ -3402,16 +3359,15 @@ msgstr "Tamaño original" #: packages/lib/models/Setting.ts:1214 msgid "Media player, math, diagrams, table of contents" -msgstr "" +msgstr "Reproductor multimedia, matemáticas, diagramas, tabla de contenido" #: packages/app-desktop/gui/KeymapConfig/utils/getLabel.ts:24 msgid "Minimise" -msgstr "" +msgstr "Minimizar" #: packages/app-mobile/components/CameraView/CameraView.tsx:163 -#, fuzzy msgid "Missing camera permission" -msgstr "Claves Maestras Faltantes" +msgstr "Falta el permiso de la cámara" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:320 msgid "Missing keys" @@ -3426,9 +3382,8 @@ msgid "Missing required argument: %s" msgstr "Falta un argumento requerido: %s" #: packages/app-cli/app/cli-utils.js:135 -#, fuzzy msgid "Missing required flag value: %s" -msgstr "Falta un argumento requerido: %s" +msgstr "Falta el valor de indicador obligatorio: %s" #: packages/app-mobile/components/side-menu-content.tsx:663 msgid "Mobile data - auto-sync disabled" @@ -3451,6 +3406,8 @@ msgstr "" msgid "" "Most plugins have source code available for review on the plugin website." msgstr "" +"La mayoría de los plugins tienen código fuente disponible para su revisión " +"en el sitio web del plugin." #: packages/app-mobile/components/ScreenHeader/index.tsx:546 msgid "Move %d notes to notebook \"%s\"?" @@ -3459,16 +3416,16 @@ msgstr "¿Desea mover %d notas a libreta «%s»?" #: packages/app-cli/app/command-rmbook.ts:38 #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/deleteFolder.ts:20 #: packages/app-mobile/components/side-menu-content.tsx:410 -#, fuzzy msgid "" "Move notebook \"%s\" to the trash?\n" "\n" "All notes and sub-notebooks within this notebook will also be moved to the " "trash." msgstr "" -"¿Borrar libreta «%s»?\n" +"¿Mover la libreta \"%s\" a la papelera?\n" "\n" -"Todas las notas y sublibretas de esta libreta serán borradas." +"Todas las notas y sublibretas dentro de esta libreta también se moverán a la " +"papelera." #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/moveToFolder.ts:14 msgid "Move to notebook" @@ -3497,22 +3454,19 @@ msgstr "N" #: packages/lib/models/settings/builtInMetadata.ts:868 msgid "Never resize" -msgstr "" +msgstr "Nunca cambiar el tamaño" #: packages/app-mobile/setupQuickActions.ts:33 -#, fuzzy msgid "New attachment" -msgstr "Adjuntos de las notas" +msgstr "Nuevo apego" #: packages/app-mobile/setupQuickActions.ts:34 -#, fuzzy msgid "New drawing" -msgstr "Nuevas etiquetas:" +msgstr "Nuevo dibujo" #: packages/app-mobile/components/screens/ShareManager/index.tsx:120 -#, fuzzy msgid "New invitations" -msgstr "Nueva versión: %s" +msgstr "Nuevas invitaciones" #: packages/app-desktop/gui/NoteListControls/NoteListControls.tsx:111 #: packages/app-desktop/gui/NoteListWrapper/NoteListWrapper.tsx:72 @@ -3537,9 +3491,8 @@ msgid "" msgstr "Se creará la libreta nueva «%s» y se importará en ella el archivo «%s»" #: packages/app-mobile/setupQuickActions.ts:32 -#, fuzzy msgid "New photo" -msgstr "Tomar una foto" +msgstr "Nueva foto" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/newSubFolder.ts:6 msgid "New sub-notebook" @@ -3563,7 +3516,7 @@ msgstr "Nueva versión: %s" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:16 msgid "next" -msgstr "" +msgstr "siguiente" #: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:271 msgid "Next match" @@ -3601,7 +3554,7 @@ msgstr "No hay libreta activa." #: packages/app-mobile/components/screens/ShareManager/index.tsx:92 msgid "No new invitations" -msgstr "" +msgstr "No hay nuevas invitaciones" #: packages/app-cli/app/app.ts:104 msgid "No notebook has been specified." @@ -3617,7 +3570,7 @@ msgstr "No hay ninguna nota. Cree una haciendo clic en «Nota nueva»." #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginStates.tsx:202 msgid "No plugins are installed." -msgstr "" +msgstr "No se instalan plugins." #: packages/app-desktop/gui/ResourceScreen.tsx:305 msgid "No resources!" @@ -3636,9 +3589,8 @@ msgid "No suggestions" msgstr "No hay sugerencias" #: packages/app-mobile/components/plugins/dialogs/PluginPanelViewer.tsx:120 -#, fuzzy msgid "No tab selected" -msgstr "Ninguna libreta ha sido seleccionada." +msgstr "No hay ninguna pestaña seleccionada" #: packages/app-cli/app/command-edit.ts:31 msgid "" @@ -3648,14 +3600,12 @@ msgstr "" "editor `" #: packages/app-desktop/gui/UpdateNotification/UpdateNotification.tsx:93 -#, fuzzy msgid "No updates available" -msgstr "Actualizar perfil" +msgstr "No hay actualizaciones disponibles" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/moveToFolder.ts:44 -#, fuzzy msgid "None" -msgstr "(Ninguno)" +msgstr "Ninguno" #: packages/lib/models/settings/builtInMetadata.ts:47 msgid "Nord" @@ -3738,9 +3688,8 @@ msgid "Note list growth factor" msgstr "Factor de crecimiento de la lista de notas" #: packages/app-desktop/gui/MenuBar.tsx:793 -#, fuzzy msgid "Note list style" -msgstr "Lista de notas" +msgstr "Estilo de lista de notas" #: packages/app-desktop/gui/NotePropertiesDialog.tsx:451 #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showNoteProperties.ts:7 @@ -3764,7 +3713,7 @@ msgstr "" #: packages/app-desktop/gui/MenuBar.tsx:872 msgid "Note&book" -msgstr "Libreta" +msgstr "Li&breta" #: packages/app-desktop/plugins/GotoAnything.tsx:570 #: packages/lib/models/Setting.ts:1176 @@ -3778,12 +3727,11 @@ msgstr "Factor de crecimiento de la lista de libretas" #: packages/app-desktop/gui/NoteListHeader/utils/getColumnTitle.ts:5 #: packages/app-mobile/components/side-menu-content.tsx:441 msgid "Notebook: %s" -msgstr "Libretas: %s" +msgstr "Libreta: %s" #: packages/app-mobile/components/screens/ShareManager/AcceptedShareItem.tsx:81 -#, fuzzy msgid "Notebook: %s (%s)" -msgstr "Libretas: %s" +msgstr "Cibreta: %s (%s)" #: packages/app-desktop/gui/Sidebar/hooks/useSidebarListData.ts:50 #: packages/app-mobile/components/side-menu-content.tsx:686 @@ -3817,12 +3765,11 @@ msgstr "Lista Numerada" #: packages/lib/models/settings/builtInMetadata.ts:531 msgid "OCR: Clear cache and re-download language data files" -msgstr "" +msgstr "OCR: Borrar caché y volver a descargar archivos de datos de idioma" #: packages/lib/models/settings/builtInMetadata.ts:512 -#, fuzzy msgid "OCR: Language data URL or path" -msgstr "Formato de fecha" +msgstr "OCR: URL o ruta de datos de idioma" #: packages/app-desktop/bridge.ts:360 packages/app-desktop/bridge.ts:373 #: packages/app-desktop/bridge.ts:387 packages/app-desktop/bridge.ts:403 @@ -3858,7 +3805,7 @@ msgstr "En %s: %s" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:27 msgid "on line" -msgstr "" +msgstr "En línea" #: packages/app-desktop/gui/MainScreen.tsx:525 msgid "One of your master keys use an obsolete encryption method." @@ -3889,9 +3836,8 @@ msgid "OneDrive Login" msgstr "Inicio de sesión de OneDrive" #: packages/lib/services/interop/InteropService.ts:144 -#, fuzzy msgid "OneNote Notebook" -msgstr "Nueva Libreta" +msgstr "Libreta de OneNote" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/print.ts:18 msgid "Only one note can be printed at a time." @@ -3906,9 +3852,8 @@ msgid "Open %s" msgstr "Abrir %s" #: packages/app-desktop/bridge.ts:454 -#, fuzzy msgid "Open it" -msgstr "Abrir" +msgstr "Ábrela" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/openPdfViewer.ts:7 msgid "Open PDF viewer" @@ -3919,14 +3864,12 @@ msgid "Open profile directory" msgstr "Abrir directorio de perfiles" #: packages/app-mobile/components/CameraView/CameraView.tsx:164 -#, fuzzy msgid "Open settings" -msgstr "Mostrar Opciones Avanzadas" +msgstr "Abrir configuración" #: packages/app-mobile/components/screens/ConfigScreen/plugins/EnablePluginSupportPage.tsx:115 -#, fuzzy msgid "Open Source" -msgstr "Origen" +msgstr "Open Source" #: packages/lib/models/settings/builtInMetadata.ts:73 msgid "Open Sync Wizard..." @@ -3938,22 +3881,19 @@ msgstr "Abrir..." #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:206 msgid "Opening section %s" -msgstr "" +msgstr "Apertura de la sección %s" #: packages/app-mobile/components/Dropdown.tsx:215 -#, fuzzy msgid "Opens dropdown" -msgstr "Cerrar menú" +msgstr "Abre el menú desplegable " #: packages/app-mobile/components/NoteItem.tsx:162 -#, fuzzy msgid "Opens note" -msgstr "Abrir" +msgstr "Abre la nota" #: packages/app-mobile/components/side-menu-content.tsx:273 -#, fuzzy msgid "Opens notebook" -msgstr "Nueva libreta" +msgstr "Abre la libreta" #: packages/app-cli/app/command-e2ee.ts:41 #: packages/app-cli/app/command-e2ee.ts:87 @@ -4014,7 +3954,7 @@ msgstr "Pegar" #: packages/app-desktop/gui/NoteEditor/commands/pasteAsText.ts:6 #: packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts:211 msgid "Paste as text" -msgstr "" +msgstr "Pegar como texto" #: packages/app-desktop/gui/ConfigScreen/controls/SettingComponent.tsx:261 #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/ExportProfileButton.tsx:54 @@ -4031,34 +3971,31 @@ msgid "Per user. Minimum of %d users." msgstr "Por usuario. Mínimo %d usuarios." #: packages/lib/commands/permanentlyDeleteNote.ts:8 -#, fuzzy msgid "Permanently delete note" -msgstr "Borrar notas seleccionadas" +msgstr "Eliminar nota de forma permanente" #: packages/lib/models/Note.ts:943 -#, fuzzy msgid "Permanently delete note \"%s\"?" -msgstr "¿Borrar nota «%s»?" +msgstr "¿Eliminar permanentemente la nota \"%s\"?" #: packages/app-cli/app/command-rmbook.ts:36 -#, fuzzy msgid "" "Permanently delete notebook \"%s\"?\n" "\n" "All notes and sub-notebooks within this notebook will be permanently deleted." msgstr "" -"¿Borrar libreta? Todas las notas y sublibretas dentro de esta libreta " -"también serán eliminadas." +"¿Eliminar permanentemente la libreta %s\"?\n" +"\n" +"Todas las notas y sublibretas de esta libreta se eliminarán de forma " +"permanente." #: packages/lib/models/Note.ts:945 -#, fuzzy msgid "Permanently delete these %d notes?" -msgstr "¿Borrar estas %d notas?" +msgstr "¿Eliminar permanentemente estas notas %d?" #: packages/app-cli/app/command-rmbook.ts:20 -#, fuzzy msgid "Permanently deletes the notebook, skipping the trash." -msgstr "¿Borrar estas %d notas?" +msgstr "Elimina permanentemente la libreta, omitiendo la papelera." #: packages/app-mobile/components/screens/Note/Note.tsx:504 msgid "Permission needed" @@ -4111,7 +4048,7 @@ msgstr "" #: packages/app-mobile/components/voiceTyping/VoiceTypingDialog.tsx:180 msgid "Please record your voice..." -msgstr "" +msgstr "Por favor, graba tu voz..." #: packages/app-cli/app/command-ls.ts:66 msgid "Please select a notebook first." @@ -4134,9 +4071,9 @@ msgid "Please specify the notebook where the notes should be imported to." msgstr "Por favor especifique la libreta donde las notas deben ser importadas." #: packages/lib/services/plugins/PluginService.ts:519 -#, fuzzy msgid "Please upgrade Joplin to version %s or later to use this plugin." -msgstr "Por favor, actualice Joplin para usar este plugin" +msgstr "" +"Actualice Joplin a la versión %s o posterior para usar este complemento." #: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx:1444 msgid "" @@ -4152,28 +4089,24 @@ msgid "Please wait..." msgstr "Por favor espere..." #: packages/app-mobile/services/plugins/PlatformImplementation.ts:51 -#, fuzzy msgid "Plugin message" -msgstr "Plugins" +msgstr "Mensaje del plugin" #: packages/app-mobile/components/ScreenHeader/index.tsx:400 -#, fuzzy msgid "Plugin panels" -msgstr "Herramientas de Plugin" +msgstr "Paneles de plugins" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginStates.tsx:111 msgid "Plugin repository failed to load" -msgstr "" +msgstr "El repositorio de complementos no se pudo cargar" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginStates.tsx:29 -#, fuzzy msgid "Plugin search" -msgstr "Plugins" +msgstr "Búsqueda de plugins" #: packages/app-mobile/components/screens/ConfigScreen/plugins/EnablePluginSupportPage.tsx:107 -#, fuzzy msgid "Plugin security" -msgstr "Plugins" +msgstr "Seguridad de los plugins" #: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.tsx:329 msgid "Plugin tools" @@ -4181,7 +4114,7 @@ msgstr "Herramientas de Plugin" #: packages/lib/models/settings/builtInMetadata.ts:909 msgid "Plugin WebView debugging" -msgstr "" +msgstr "Depuración de Plugin WebView" #: packages/app-desktop/gui/ConfigScreen/Sidebar.tsx:148 #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:523 @@ -4195,6 +4128,9 @@ msgid "" "Plugins extend Joplin with features that are not present by default. Plugins " "can extend Joplin's editor, viewer, and more." msgstr "" +"Los plugins amplían Joplin con características que no están presentes de " +"forma predeterminada. Los plugins pueden ampliar el editor, el visor y mucho " +"más de Joplin." #: packages/lib/models/settings/builtInMetadata.ts:1261 msgid "Portrait" @@ -4226,11 +4162,11 @@ msgstr "Tema claro preferido" #: packages/lib/models/settings/builtInMetadata.ts:1704 msgid "Preferred voice typing provider" -msgstr "" +msgstr "Proveedor de mecanografía por voz preferido" #: packages/lib/models/settings/builtInMetadata.ts:667 msgid "Preserve colours when pasting text in Rich Text Editor" -msgstr "" +msgstr "Conservar los colores al pegar texto en el Editor de texto enriquecido" #: packages/app-cli/app/app-gui.js:758 msgid "Press Ctrl+D or type \"exit\" to exit the application" @@ -4252,9 +4188,8 @@ msgid "Press to set the decryption password." msgstr "Pulse para establecer la contraseña de descifrado." #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:17 -#, fuzzy msgid "previous" -msgstr "Anterior coincidencia" +msgstr "anterior" #: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:281 msgid "Previous match" @@ -4294,12 +4229,11 @@ msgstr "Procesar eliminaciones de usuarios" #: packages/lib/models/Resource.ts:32 msgid "Processing" -msgstr "" +msgstr "Procesando" #: packages/app-mobile/components/CameraView/ActionButtons.tsx:111 -#, fuzzy msgid "Processing photo..." -msgstr "Creando reporte..." +msgstr "Procesando foto..." #: packages/server/src/routes/admin/users.ts:254 msgid "Profile" @@ -4355,9 +4289,8 @@ msgid "Publish notes to the internet" msgstr "Publicar notas en Internet" #: packages/app-mobile/components/CameraView/ScannedBarcodes.tsx:78 -#, fuzzy msgid "QR Code" -msgstr "Código" +msgstr "Código QR" #: packages/app-desktop/app.ts:219 #: packages/app-desktop/ElectronAppWrapper.ts:123 @@ -4368,7 +4301,7 @@ msgstr "Salir" #: packages/app-mobile/components/voiceTyping/VoiceTypingDialog.tsx:206 msgid "Re-download model" -msgstr "" +msgstr "Volver a descargar el modelo" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:342 msgid "Re-encrypt data" @@ -4379,9 +4312,8 @@ msgid "Re-encryption" msgstr "Recifrado" #: packages/app-desktop/gui/MasterPasswordDialog/Dialog.tsx:181 -#, fuzzy msgid "Re-enter password" -msgstr "Contraseña maestra" +msgstr "Escriba la contraseña otra vez" #: packages/lib/models/settings/builtInMetadata.ts:1180 msgid "Re-upload local data to sync target" @@ -4412,14 +4344,12 @@ msgid "Recipients:" msgstr "Destinatarios:" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/RecommendedBadge.tsx:72 -#, fuzzy msgid "Recommended" -msgstr "comando" +msgstr "Recomendado" #: packages/app-mobile/components/screens/ConfigScreen/plugins/EnablePluginSupportPage.tsx:114 -#, fuzzy msgid "Recommended plugins" -msgstr "comando" +msgstr "Plugins recomendados" #: packages/app-desktop/gui/MenuBar.tsx:754 #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:122 @@ -4449,9 +4379,8 @@ msgid "Remove" msgstr "Eliminar" #: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:330 -#, fuzzy msgid "Remove %s from share" -msgstr "¿Desea eliminar la etiqueta «%s» de todas las notas?" +msgstr "Eliminar %s del recurso compartido" #: packages/app-desktop/gui/Sidebar/hooks/useOnRenderItem.tsx:111 msgid "Remove tag \"%s\" from all notes?" @@ -4483,9 +4412,8 @@ msgid "Renew token" msgstr "Renovar token" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:21 -#, fuzzy msgid "replace" -msgstr "Reemplazar" +msgstr "reemplazar" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:15 #: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:291 @@ -4493,7 +4421,6 @@ msgid "Replace" msgstr "Reemplazar" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:22 -#, fuzzy msgid "replace all" msgstr "Reemplazar todo" @@ -4511,38 +4438,35 @@ msgstr "Reemplazar: " #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:25 msgid "replaced $ matches" -msgstr "" +msgstr "Coincidencias de $ reemplazadas" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:26 msgid "replaced match on line $" -msgstr "" +msgstr "Coincidencia reemplazada en línea $" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginInfoModal.tsx:162 msgid "Report an issue" -msgstr "" +msgstr "Informar de un problema" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginInfoModal.tsx:219 msgid "Report any issues concerning the plugin." -msgstr "" +msgstr "Informe cualquier problema relacionado con el complemento." #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginInfoModal.tsx:224 msgid "Report fraudulent plugin" -msgstr "" +msgstr "Denunciar un plugin fraudulento" #: packages/app-mobile/components/screens/ConfigScreen/plugins/EnablePluginSupportPage.tsx:116 -#, fuzzy msgid "Report system" -msgstr "Sistema de archivos" +msgstr "Sistema de informes" #: packages/server/src/services/MustacheService.ts:137 -#, fuzzy msgid "Reports" -msgstr "Sistema de archivos" +msgstr "Informes" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/resetLayout.ts:7 -#, fuzzy msgid "Reset application layout" -msgstr "Cambiar el diseño de la aplicación" +msgstr "Restablecer el diseño de la aplicación" #: packages/app-desktop/gui/MasterPasswordDialog/Dialog.tsx:221 #: packages/app-desktop/gui/MasterPasswordDialog/Dialog.tsx:222 @@ -4551,7 +4475,7 @@ msgstr "Restablecer contraseña maestra" #: packages/lib/models/settings/builtInMetadata.ts:862 msgid "Resize large images:" -msgstr "" +msgstr "Cambiar el tamaño de las imágenes grandes:" #: packages/app-cli/app/command-import.ts:54 #: packages/app-desktop/gui/ImportScreen.tsx:93 @@ -4563,9 +4487,8 @@ msgid "Restart and upgrade" msgstr "Reiniciar y actualizar" #: packages/app-desktop/ElectronAppWrapper.ts:130 -#, fuzzy msgid "Restart in safe mode" -msgstr "Reiniciar y actualizar" +msgstr "Reiniciar en modo seguro" #: packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx:405 #: packages/app-desktop/gui/UpdateNotification/UpdateNotification.tsx:64 @@ -4582,29 +4505,25 @@ msgid "Restore" msgstr "Restaurar" #: packages/app-mobile/components/EditorToolbar/ToolbarEditorDialog.tsx:156 -#, fuzzy msgid "Restore defaults" -msgstr "Notas Restauradas" +msgstr "Restaurar valores predeterminados" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/restoreNote.ts:10 -#, fuzzy msgid "Restore note" msgstr "Notas Restauradas" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/restoreFolder.ts:9 -#, fuzzy msgid "Restore notebook" -msgstr "Crea libreta" +msgstr "Restaurar libreta" #: packages/app-cli/app/command-restore.ts:12 -#, fuzzy msgid "Restore the items matching from the trash." -msgstr "Elimina las notas que coincidan con ." +msgstr "" +"Restaure los elementos que coincidan desde la papelera." #: packages/lib/services/trash/index.ts:88 -#, fuzzy msgid "Restored items" -msgstr "Notas Restauradas" +msgstr "Objetos restaurados" #: packages/lib/services/RevisionService.ts:248 msgid "Restored Notes" @@ -4612,7 +4531,7 @@ msgstr "Notas Restauradas" #: packages/app-mobile/components/screens/ConfigScreen/plugins/SearchPlugins.tsx:162 msgid "Results (%d):" -msgstr "" +msgstr "Resultados (%d):" #: packages/app-desktop/gui/StatusScreen/StatusScreen.tsx:133 #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginStates.tsx:112 @@ -4646,11 +4565,13 @@ msgstr "Revisión: %s (%s)" #: packages/app-desktop/gui/ToggleEditorsButton/ToggleEditorsButton.tsx:28 msgid "Rich Text" -msgstr "" +msgstr "Texto enriquecido" #: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx:686 msgid "Rich Text editor. Press Escape then Tab to escape focus." msgstr "" +"Editor de texto enriquecido. Presione Escape y luego Tab para escapar del " +"enfoque." #: packages/app-cli/app/command-batch.js:10 msgid "" @@ -4723,9 +4644,8 @@ msgid "Save changes" msgstr "Guardar cambios" #: packages/app-mobile/components/NoteEditor/ImageEditor/ImageEditor.tsx:103 -#, fuzzy msgid "Save changes?" -msgstr "Guardar cambios" +msgstr "¿Guardar Cambios?" #: packages/lib/models/settings/builtInMetadata.ts:768 msgid "Save geo-location with notes" @@ -4733,7 +4653,7 @@ msgstr "Guardar geolocalización en las notas" #: packages/app-mobile/components/CameraView/ScannedBarcodes.tsx:89 msgid "Scanned code" -msgstr "" +msgstr "Código escaneado" #: packages/app-desktop/gui/lib/SearchInput/SearchInput.tsx:62 #: packages/app-mobile/components/NoteEditor/commandDeclarations.ts:102 @@ -4754,9 +4674,8 @@ msgid "Search for..." msgstr "Buscar..." #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:170 -#, fuzzy msgid "Search hidden" -msgstr "Búsquedas" +msgstr "Búsqueda oculta" #: packages/app-desktop/gui/NoteListControls/commands/focusSearch.ts:6 msgid "Search in all the notes" @@ -4767,14 +4686,12 @@ msgid "Search in current note" msgstr "Buscar en la nota actual" #: packages/app-desktop/plugins/GotoAnything.tsx:665 -#, fuzzy msgid "Search results" -msgstr "Sin resultados" +msgstr "Resultados de la búsqueda" #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:170 -#, fuzzy msgid "Search shown" -msgstr "Búsquedas" +msgstr "Se muestra la búsqueda" #: packages/app-cli/app/gui/FolderListWidget.ts:56 msgid "Search:" @@ -4793,9 +4710,8 @@ msgid "Searches for the given in all the notes." msgstr "Busca el dado en todas las notas." #: packages/app-desktop/gui/UpdateNotification/UpdateNotification.tsx:63 -#, fuzzy msgid "See changelog" -msgstr "Registro de cambios completo" +msgstr "Historial de cambios" #: packages/lib/models/settings/builtInMetadata.ts:1199 msgid "See the pre-release page for more details: %s" @@ -4820,24 +4736,20 @@ msgid "Select file..." msgstr "Seleccionar archivo..." #: packages/app-mobile/components/screens/folder.js:109 -#, fuzzy msgid "Select parent notebook" -msgstr "Borrar libreta" +msgstr "Seleccionar libreta principal" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:9 -#, fuzzy msgid "Selection deleted" -msgstr "Por borrar: %d" +msgstr "Selección eliminada" #: packages/app-mobile/components/FolderPicker.tsx:68 -#, fuzzy msgid "Selects a notebook" -msgstr "Borrar libreta" +msgstr "Selecciona una libreta" #: packages/app-desktop/gui/MenuBar.tsx:359 -#, fuzzy msgid "Send bug report" -msgstr "Exportar Informe de depuración" +msgstr "Enviar informe de error" #: packages/app-cli/app/command-server.js:38 msgid "Server is already running on port %d" @@ -4889,7 +4801,7 @@ msgstr "" #: packages/app-mobile/components/EditorToolbar/EditorToolbar.tsx:47 msgid "Settings" -msgstr "" +msgstr "Ajustes" #: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:281 #: packages/app-mobile/components/NoteBodyViewer/hooks/useOnResourceLongPress.ts:44 @@ -4903,17 +4815,17 @@ msgid "" "Share a copy of all notes in a file format that can be imported by Joplin on " "a computer." msgstr "" +"Comparta una copia de todas las notas en un formato de archivo que Joplin " +"pueda importar en un ordenador." #: packages/lib/utils/joplinCloud/index.ts:125 -#, fuzzy msgid "Share a notebook with others" -msgstr "Colaborar en los cuadernos con otros" +msgstr "Compartir una libreta con otros usuarios" #: packages/app-mobile/components/screens/ShareManager/AcceptedShareItem.tsx:82 #: packages/app-mobile/components/screens/ShareManager/IncomingShareItem.tsx:33 -#, fuzzy msgid "Share from %s (%s)" -msgstr "%s = %s (%s)" +msgstr "Compartir de %s (%s)" #: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:400 msgid "Share Notebook" @@ -4925,17 +4837,15 @@ msgstr "Compartir libreta..." #: packages/lib/utils/joplinCloud/index.ts:215 msgid "Share permissions" -msgstr "" +msgstr "Permisos de uso compartido" #: packages/app-desktop/gui/Sidebar/listItemComponents/FolderItem.tsx:56 -#, fuzzy msgid "Shared" -msgstr "Compartir" +msgstr "Compartido" #: packages/app-mobile/components/screens/ShareManager/index.tsx:107 -#, fuzzy msgid "Shares" -msgstr "Compartir" +msgstr "Compartido" #: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:364 msgid "Sharing notebook..." @@ -4970,23 +4880,20 @@ msgid "Show disabled keys" msgstr "Mostrar claves desactivadas" #: packages/app-desktop/gui/ConfigScreen/controls/FontSearch.tsx:132 -#, fuzzy msgid "Show monospace fonts only." -msgstr "Familia de fuente monoespaciada del editor" +msgstr "Mostrar solo fuentes monoespaciadas." #: packages/lib/models/settings/builtInMetadata.ts:599 msgid "Show note counts" msgstr "Mostrar número de notas" #: packages/app-mobile/components/side-menu-content.tsx:258 -#, fuzzy msgid "Show notebook options" -msgstr "Mostrar número de notas" +msgstr "Mostrar opciones de libreta" #: packages/app-desktop/gui/PasswordInput/PasswordInput.tsx:21 -#, fuzzy msgid "Show password" -msgstr "Establecer la contraseña" +msgstr "Mostrar contraseña" #: packages/lib/models/settings/builtInMetadata.ts:698 msgid "Show sort order buttons" @@ -5001,22 +4908,20 @@ msgid "Show/hide the sidebar" msgstr "Mostrar/ocultar barra lateral" #: packages/app-mobile/components/screens/tags.tsx:76 -#, fuzzy msgid "Shows notes for tag" -msgstr "Mostrar número de notas" +msgstr "Muestra notas para la etiqueta" #: packages/lib/models/settings/builtInMetadata.ts:863 msgid "Shrink large images before adding them to notes." -msgstr "" +msgstr "Reduzca las imágenes grandes antes de agregarlas a las notas." #: packages/app-mobile/components/SideMenu.tsx:258 -#, fuzzy msgid "Side menu closed" -msgstr "Ocultar más acciones" +msgstr "Menú lateral cerrado" #: packages/app-mobile/components/SideMenu.tsx:258 msgid "Side menu opened" -msgstr "" +msgstr "Menú lateral abierto" #: packages/app-desktop/gui/Sidebar/commands/focusElementSideBar.ts:10 #: packages/app-desktop/gui/Sidebar/Sidebar.tsx:77 @@ -5055,12 +4960,16 @@ msgstr "Claro Solarizado" msgid "" "Some attachments could not be downloaded. Please try to download them again." msgstr "" +"No se han podido descargar algunos archivos adjuntos. Por favor, intente " +"descargarlos de nuevo." #: packages/lib/models/settings/settingValidations.ts:18 msgid "" "Some attachments need to be downloaded. Set the attachment download mode to " "\"always\" and try again." msgstr "" +"Algunos archivos adjuntos deben descargarse. Establezca el modo de descarga " +"de archivos adjuntos en \"siempre\" e inténtelo de nuevo." #: packages/app-desktop/gui/MainScreen.tsx:519 #: packages/app-mobile/components/ScreenHeader/WarningBanner.tsx:52 @@ -5078,20 +4987,19 @@ msgstr "" "información." #: packages/lib/models/settings/settingValidations.ts:24 -#, fuzzy msgid "" "Some items could not be synchronised. Please try to synchronise them first." msgstr "" -"No se han podido sincronizar algunos de los elementos. Pulsa para más " -"información." +"Algunos elementos no se han podido sincronizar. Por favor, intente " +"sincronizarlos primero." #: packages/app-desktop/gui/ResourceScreen.tsx:92 msgid "Sort \"%s\" in ascending order" -msgstr "" +msgstr "Ordene \"%s\" en orden ascendente" #: packages/app-desktop/gui/ResourceScreen.tsx:92 msgid "Sort \"%s\" in descending order" -msgstr "" +msgstr "Ordene \"%s\" en orden descendente" #: packages/lib/models/settings/builtInMetadata.ts:754 msgid "Sort notebooks by" @@ -5126,7 +5034,7 @@ msgstr "Origen: " #: packages/app-desktop/gui/Sidebar/hooks/useOnRenderItem.tsx:435 msgid "Spacer" -msgstr "" +msgstr "Espaciador" #: packages/lib/models/settings/builtInMetadata.ts:1463 msgid "" @@ -5276,12 +5184,11 @@ msgstr "Cambiar perfil" #: packages/app-mobile/components/CameraView/ActionButtons.tsx:101 msgid "Switch to back-facing camera" -msgstr "" +msgstr "Cambiar a la cámara trasera" #: packages/app-mobile/components/CameraView/ActionButtons.tsx:101 -#, fuzzy msgid "Switch to front-facing camera" -msgstr "Cambiar al perfil %d" +msgstr "Cambiar a la cámara frontal" #: packages/app-desktop/gui/utils/NoteListUtils.ts:93 msgid "Switch to note type" @@ -5294,14 +5201,12 @@ msgid "Switch to profile %d" msgstr "Cambiar al perfil %d" #: packages/app-desktop/gui/ToggleEditorsButton/ToggleEditorsButton.tsx:28 -#, fuzzy msgid "Switch to the %s Editor" -msgstr "Cambiar a nota" +msgstr "Cambiar al editor de %s" #: packages/app-desktop/gui/NoteEditor/WarningBanner/WarningBanner.tsx:78 -#, fuzzy msgid "Switch to the legacy editor" -msgstr "Cambiar a nota" +msgstr "Cambiar al editor heredado" #: packages/app-desktop/gui/utils/NoteListUtils.ts:102 msgid "Switch to to-do type" @@ -5353,9 +5258,8 @@ msgid "Sync your notes" msgstr "Sincroniza tus notas" #: packages/lib/models/Setting.ts:1212 -#, fuzzy msgid "Sync, encryption, proxy" -msgstr "Habilitar cifrado" +msgstr "Sincronización, cifrado, proxy" #: packages/lib/models/Setting.ts:1173 msgid "Synchronisation" @@ -5433,7 +5337,7 @@ msgstr "Tomar una foto" #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/TaskButton.tsx:73 msgid "Task \"%s\" failed with error: %s" -msgstr "" +msgstr "Error en la tarea \"%s\" con error: %s" #: packages/app-mobile/components/NoteEditor/commandDeclarations.ts:87 msgid "Task list" @@ -5449,22 +5353,20 @@ msgid "Teams" msgstr "Equipos" #: packages/lib/services/interop/InteropService.ts:136 -#, fuzzy msgid "Text document" -msgstr "Comando de editor de texto" +msgstr "Documento de texto" #: packages/lib/models/settings/builtInMetadata.ts:1248 msgid "Text editor command" msgstr "Comando de editor de texto" #: packages/lib/utils/joplinCloud/index.ts:167 -#, fuzzy msgid "" "The [Web Clipper](%s) is a browser extension that allows you to save web " "pages and screenshots from your browser." msgstr "" -"El Web Clipper de Joplin le permite guardar páginas web y capturas de " -"pantalla desde su navegador a la aplicación." +"El [Web Clipper](%s) es una extensión del navegador que le permite guardar " +"páginas web y capturas de pantalla desde su navegador." #: packages/lib/services/profileConfig/index.ts:106 msgid "" @@ -5569,11 +5471,11 @@ msgstr "" "los cambios." #: packages/app-desktop/gui/NoteEditor/NoteEditor.tsx:612 -#, fuzzy msgid "The following attachment matches your search query:" msgid_plural "The following attachments match your search query:" -msgstr[0] "Los adjuntos siguientes están siendo vigilados en busca de cambios:" -msgstr[1] "Los adjuntos siguientes están siendo vigilados en busca de cambios:" +msgstr[0] "El siguiente archivo adjunto coincide con su consulta de búsqueda:" +msgstr[1] "" +"Los siguientes archivos adjuntos coinciden con su consulta de búsqueda:" #: packages/app-desktop/gui/NoteEditor/NoteEditor.tsx:596 msgid "The following attachments are being watched for changes:" @@ -5592,6 +5494,8 @@ msgstr "" #: packages/app-desktop/gui/NoteEditor/WarningBanner/WarningBanner.tsx:83 msgid "The following plugins may not support the current markdown editor:" msgstr "" +"Es posible que los siguientes complementos no sean compatibles con el editor " +"de markdown actual:" #: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.tsx:257 #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/RecommendedBadge.tsx:49 @@ -5631,16 +5535,14 @@ msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"." msgstr "La nota «%s» se ha restaurado exitosamente a la libreta «%s»." #: packages/app-desktop/gui/TrashNotification/TrashNotification.tsx:68 -#, fuzzy msgid "The note was successfully moved to the trash." msgid_plural "The notes were successfully moved to the trash." -msgstr[0] "La nota «%s» se ha restaurado exitosamente a la libreta «%s»." -msgstr[1] "La nota «%s» se ha restaurado exitosamente a la libreta «%s»." +msgstr[0] "La nota se movió con éxito a la papelera." +msgstr[1] "Las notas se movieron con éxito a la papelera." #: packages/app-desktop/gui/TrashNotification/TrashNotification.tsx:66 -#, fuzzy msgid "The notebook and its content was successfully moved to the trash." -msgstr "La nota «%s» se ha restaurado exitosamente a la libreta «%s»." +msgstr "La libreta y su contenido se han movido correctamente a la papelera." #: packages/app-mobile/components/screens/folder.js:76 msgid "The notebook could not be saved: %s" @@ -5675,6 +5577,13 @@ msgid "" "\n" "%s" msgstr "" +"El destino de sincronización no se puede cambiar por el siguiente motivo: " +"%s\n" +"\n" +"Si el problema no se puede resolver, es posible que primero deba borrar sus " +"datos siguiendo estas instrucciones:\n" +"\n" +"%s" #: packages/app-desktop/gui/MainScreen.tsx:513 msgid "" @@ -5694,9 +5603,8 @@ msgstr "" "proceder." #: packages/app-desktop/gui/MainScreen.tsx:507 -#, fuzzy msgid "The synchronisation password is missing." -msgstr "Comprobar configuración de la sincronización" +msgstr "Falta la contraseña de sincronización." #: packages/lib/models/Tag.ts:233 msgid "The tag \"%s\" already exists. Please choose a different name." @@ -5718,6 +5626,11 @@ msgid "" "\n" "Error: \"%s\"" msgstr "" +"El cliente web no admite la aceptación de libretas compartidas cifradas. " +"Cambie a la aplicación de escritorio o móvil antes de aceptar el uso " +"compartido.\n" +"\n" +"Error: \"%s\"" #: packages/app-desktop/gui/Root.tsx:150 msgid "The Web Clipper needs your authorisation to access your data." @@ -5736,24 +5649,24 @@ msgid "" "The WebDAV implementation of %s is incompatible with Joplin, and as such is " "no longer supported. Please use a different sync method." msgstr "" +"La implementación de WebDAV de %s es incompatible con Joplin y, como tal, ya " +"no es compatible. Utilice un método de sincronización diferente." #: packages/lib/models/settings/builtInMetadata.ts:543 msgid "Theme" msgstr "Tema" #: packages/lib/models/Setting.ts:1211 -#, fuzzy msgid "Themes, editor font" -msgstr "Fuente del editor" +msgstr "Temas, fuente del editor" #: packages/lib/components/shared/NoteList/getEmptyFolderMessage.ts:17 msgid "There are currently no notes. Create one by clicking on the (+) button." msgstr "Actualmente, no hay notas. Cree una pulsando en el botón (+)." #: packages/lib/components/shared/NoteList/getEmptyFolderMessage.ts:9 -#, fuzzy msgid "There are no notes in the trash folder." -msgstr "Mantener historial de la nota durante" +msgstr "No hay notas en la papelera." #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:268 msgid "There are unsaved changes." @@ -5783,6 +5696,10 @@ msgid "" "cause the sync warning to appear, but still aren't synced. To unignore, " "click \"retry\"." msgstr "" +"Estos elementos no se han podido sincronizar, pero se han marcado como " +"\"ignorados\". No harán que aparezca la advertencia de sincronización, pero " +"aún así no se sincronizan. Para anular la ignoración, haga clic en " +"\"reintentar\"." #: packages/lib/services/ReportService.ts:187 msgid "" @@ -5818,10 +5735,13 @@ msgid "" "collaborate on it. It does not however allow you to share a notebook with " "someone else, unless you have the feature \"%s\"." msgstr "" +"Esto permite que otro usuario comparta una libreta con usted y, a " +"continuación, ambos pueden colaborar en él. Sin embargo, no le permite " +"compartir una libreta con otra persona, a menos que tenga la función \"%s\"." #: packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts:150 msgid "This attachment does not have OCR data (Status: %s)" -msgstr "" +msgstr "Este archivo adjunto no tiene datos de OCR (Estado: %s)" #: packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts:54 #: packages/lib/services/ResourceEditWatcher/index.ts:241 @@ -5837,9 +5757,8 @@ msgstr "" "aplicaciones de terceros acceder a Joplin." #: packages/app-mobile/components/NoteEditor/ImageEditor/ImageEditor.tsx:103 -#, fuzzy msgid "This drawing may have unsaved changes." -msgstr "Hay cambios sin guardar." +msgstr "Es posible que este dibujo tenga cambios no guardados." #: packages/app-desktop/gui/ResourceScreen.tsx:291 msgid "" @@ -5852,25 +5771,22 @@ msgstr "" "pueden ser recuperados después." #: packages/app-mobile/components/ScreenHeader/index.tsx:237 -#, fuzzy msgid "This note could not be deleted: %s" msgid_plural "These notes could not be deleted: %s" -msgstr[0] "No se ha podido abrir este archivo: %s" -msgstr[1] "No se ha podido abrir este archivo: %s" +msgstr[0] "Esta nota no pudo ser eliminada: %s" +msgstr[1] "Estas notas no pudieron ser eliminadas: %s" #: packages/app-mobile/components/ScreenHeader/index.tsx:224 -#, fuzzy msgid "This note could not be duplicated: %s" msgid_plural "These notes could not be duplicated: %s" -msgstr[0] "No se ha podido guardar la libreta: %s" -msgstr[1] "No se ha podido guardar la libreta: %s" +msgstr[0] "Esta nota no se ha podido duplicar: %s" +msgstr[1] "Estas notas no se han podido duplicar: %s" #: packages/app-mobile/components/ScreenHeader/index.tsx:563 -#, fuzzy msgid "This note could not be moved: %s" msgid_plural "These notes could not be moved: %s" -msgstr[0] "No se ha podido guardar la libreta: %s" -msgstr[1] "No se ha podido guardar la libreta: %s" +msgstr[0] "Esta nota no se pudo mover: %s" +msgstr[1] "Estas notas no se han podido mover: %s" #: packages/lib/models/Note.ts:130 msgid "This note does not have geolocation information." @@ -5895,7 +5811,7 @@ msgstr "Esta nota no tiene historial" #: packages/lib/services/plugins/PluginService.ts:527 msgid "This plugin doesn't support %s." -msgstr "" +msgstr "Este plugin no es compatible con %s." #: packages/app-desktop/gui/NoteEditor/WarningBanner/WarningBanner.tsx:52 msgid "" @@ -5917,7 +5833,7 @@ msgstr "" #: packages/lib/components/shared/NoteList/getEmptyFolderMessage.ts:11 msgid "This subfolder of the trash has no notes." -msgstr "" +msgstr "Esta subcarpeta de la papelera no tiene notas." #: packages/lib/models/settings/builtInMetadata.ts:1009 msgid "" @@ -5937,11 +5853,12 @@ msgstr "Esto abrirá una nueva pantalla. ¿Desea guardar los cambios actuales?" #: packages/app-mobile/components/side-menu-content.tsx:340 msgid "This will permanently delete all items in the trash. Continue?" msgstr "" +"Esto eliminará permanentemente todos los elementos de la papelera. " +"¿Continuar?" #: packages/app-cli/app/command-rmnote.ts:40 -#, fuzzy msgid "This will permanently delete the note \"%s\". Continue?" -msgstr "¿Borrar nota «%s»?" +msgstr "Esto eliminará permanentemente la nota \"%s\". ¿Continuar?" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/leaveSharedFolder.ts:17 #: packages/app-mobile/components/screens/ShareManager/AcceptedShareItem.tsx:60 @@ -5979,13 +5896,12 @@ msgstr "" #: packages/app-cli/app/command-sync.ts:110 #: packages/app-desktop/gui/JoplinCloudLoginScreen.tsx:84 #: packages/app-mobile/components/screens/JoplinCloudLoginScreen.tsx:153 -#, fuzzy msgid "" "To allow Joplin to synchronise with Joplin Cloud, please login using this " "URL:" msgstr "" -"Para permitir que Joplin se sincronice con Dropbox, por favor siga estos " -"pasos:" +"Para permitir que Joplin se sincronice con Joplin Cloud, inicie sesión con " +"esta URL:" #: packages/lib/components/EncryptionConfigScreen/utils.ts:53 msgid "To continue, please enter your master password below." @@ -6053,9 +5969,8 @@ msgid "to-do" msgstr "tarea" #: packages/app-desktop/gui/NoteListHeader/utils/getColumnTitle.ts:6 -#, fuzzy msgid "To-do" -msgstr "tarea" +msgstr "Tareas" #: packages/app-mobile/components/NoteItem.tsx:172 msgid "to-do: %s" @@ -6074,7 +5989,6 @@ msgid "Toggle editor layout" msgstr "Alternar el diseño del editor" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleEditorPlugin.ts:11 -#, fuzzy msgid "Toggle editor plugin" msgstr "Alternar el diseño del editor" @@ -6087,14 +6001,12 @@ msgid "Toggle external editing" msgstr "Alternar edición externa" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleMenuBar.ts:7 -#, fuzzy msgid "Toggle menu bar" msgstr "Alternar la barra lateral" #: packages/lib/models/Setting.ts:1216 -#, fuzzy msgid "Toggle note history, keep notes for" -msgstr "Mantener historial de la nota durante" +msgstr "Alternar el historial de notas, guardar notas para" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleNoteList.ts:9 msgid "Toggle note list" @@ -6134,7 +6046,7 @@ msgstr "Total: %d/%d" #: packages/lib/services/trash/index.ts:44 msgid "Trash" -msgstr "" +msgstr "Papelera" #: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.tsx:319 #: packages/app-mobile/components/biometrics/BiometricPopup.tsx:123 @@ -6180,11 +6092,11 @@ msgstr "Tipo: %s." #: packages/app-mobile/components/screens/Note/Note.tsx:946 msgid "Unable to edit resource of type %s" -msgstr "" +msgstr "No se puede editar el recurso de tipo %s" #: packages/app-mobile/components/screens/LogScreen.tsx:108 msgid "Unable to share log data. Reason: %s" -msgstr "" +msgstr "No se pueden compartir los datos de registro. Motivo: %s" #: packages/lib/models/settings/builtInMetadata.ts:616 msgid "Uncompleted to-dos on top" @@ -6202,6 +6114,9 @@ msgid "" "Uninstall and reinstall the application. Make sure you create a backup first " "by exporting all your notes as JEX from the desktop application." msgstr "" +"Desinstale y vuelva a instalar la aplicación. Asegúrate de crear una copia " +"de seguridad primero exportando todas tus notas como JEX desde la aplicación " +"de escritorio." #: packages/app-mobile/utils/getVersionInfoText.ts:13 #: packages/app-mobile/utils/getVersionInfoText.ts:14 @@ -6209,9 +6124,8 @@ msgid "Unknown" msgstr "Desconocido" #: packages/app-desktop/bridge.ts:446 -#, fuzzy msgid "Unknown file type" -msgstr "Flag desconocida: %s" +msgstr "Tipo de archivo desconocido" #: packages/lib/utils/processStartFlags.ts:185 msgid "Unknown flag: %s" @@ -6225,9 +6139,8 @@ msgstr "" "Joplin a la última versión" #: packages/app-mobile/utils/getVersionInfoText.ts:28 -#, fuzzy msgid "Unknown platform" -msgstr "Flag desconocida: %s" +msgstr "Plataforma desconocida" #: packages/app-mobile/components/NoteEditor/commandDeclarations.ts:82 msgid "Unordered list" @@ -6259,11 +6172,12 @@ msgid "Unsupported link or message: %s" msgstr "Enlace o mensaje no soportado: %s" #: packages/app-mobile/commands/openItem.ts:60 -#, fuzzy msgid "" "Unsupported link or message: %s.\n" "Error: %s" -msgstr "Enlace o mensaje no soportado: %s" +msgstr "" +"Enlace o mensaje no compatible: %s.\n" +"Error: %s" #: packages/app-desktop/gui/ResourceScreen.tsx:123 #: packages/lib/models/BaseItem.ts:921 packages/lib/path-utils.ts:27 @@ -6277,14 +6191,12 @@ msgid "Update" msgstr "Actualizar" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/PluginChips.tsx:77 -#, fuzzy msgid "Update available" -msgstr "Actualizar perfil" +msgstr "Actualización disponible" #: packages/app-desktop/gui/UpdateNotification/UpdateNotification.tsx:65 -#, fuzzy msgid "Update later" -msgstr "fecha de actualización" +msgstr "Actualizar más tarde" #: packages/server/src/routes/admin/users.ts:257 #: packages/server/src/routes/index/users.ts:91 @@ -6384,9 +6296,8 @@ msgstr "" "salir." #: packages/lib/models/settings/builtInMetadata.ts:1347 -#, fuzzy msgid "Use the legacy Markdown editor" -msgstr "Activar sintaxis de emojis markdown" +msgstr "Usar el editor Markdown heredado" #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:552 msgid "" @@ -6448,7 +6359,7 @@ msgstr "Ver" #: packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts:141 msgid "View OCR text" -msgstr "" +msgstr "Ver texto de OCR" #: packages/app-mobile/components/screens/Note/Note.tsx:1044 msgid "View on map" @@ -6473,21 +6384,20 @@ msgstr "Vim" #: packages/lib/models/settings/builtInMetadata.ts:1693 msgid "Voice typing language files (URL)" -msgstr "" +msgstr "Archivos de idioma de escritura por voz (URL)" #: packages/app-mobile/components/screens/Note/Note.tsx:1191 #: packages/app-mobile/components/voiceTyping/VoiceTypingDialog.tsx:225 msgid "Voice typing..." -msgstr "" +msgstr "Escritura por voz..." #: packages/lib/models/settings/builtInMetadata.ts:1712 msgid "Vosk" -msgstr "" +msgstr "Vosk" #: packages/lib/services/joplinCloudUtils.ts:27 -#, fuzzy msgid "Waiting for authorisation..." -msgstr "Conceder la autorización" +msgstr "A la espera de la autorización..." #: packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx:224 #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:122 @@ -6503,12 +6413,15 @@ msgstr "" #: packages/app-mobile/components/screens/ConfigScreen/plugins/EnablePluginSupportPage.tsx:116 msgid "We have a system for reporting and removing problematic plugins." msgstr "" +"Tenemos un sistema para informar y eliminar complementos problemáticos." #: packages/app-mobile/components/screens/ConfigScreen/plugins/EnablePluginSupportPage.tsx:114 msgid "" "We mark plugins developed by trusted Joplin community members as " "\"recommended\"." msgstr "" +"Marcamos los plugins desarrollados por miembros de confianza de la comunidad " +"de Joplin como \"recomendados\"." #: packages/lib/models/Setting.ts:1182 #: packages/lib/utils/joplinCloud/index.ts:166 @@ -6538,12 +6451,11 @@ msgstr "Sitio web y documentación" #: packages/app-mobile/utils/getVersionInfoText.ts:14 msgid "WebView package: %s" -msgstr "" +msgstr "Paquete WebView: %s" #: packages/app-mobile/utils/getVersionInfoText.ts:13 -#, fuzzy msgid "WebView version: %s" -msgstr "Nueva versión: %s" +msgstr "Versión de WebView: %s" #: packages/app-cli/app/gui/NoteWidget.js:36 msgid "" @@ -6563,14 +6475,12 @@ msgstr "" "`mn`." #: packages/lib/WelcomeUtils.ts:63 -#, fuzzy msgid "Welcome!" -msgstr "Bienvenido" +msgstr "¡Bienvenido!" #: packages/app-mobile/components/screens/ConfigScreen/plugins/EnablePluginSupportPage.tsx:100 -#, fuzzy msgid "What are plugins?" -msgstr "¿Borrar plugin «%s»?" +msgstr "¿Qué son los plugins?" #: packages/lib/models/settings/builtInMetadata.ts:845 msgid "When creating a new note:" @@ -6585,14 +6495,17 @@ msgid "" "When enabled, the application will scan your attachments and extract the " "text from it. This will allow you to search for text in these attachments." msgstr "" +"Cuando está habilitado, la aplicación escaneará sus archivos adjuntos y " +"extraerá el texto de ellos. Esto le permitirá buscar texto en estos archivos " +"adjuntos." #: packages/lib/models/settings/builtInMetadata.ts:1713 msgid "Whisper" -msgstr "" +msgstr "Susurro" #: packages/app-desktop/ElectronAppWrapper.ts:222 msgid "Window unresponsive." -msgstr "" +msgstr "La ventana no responde." #: packages/app-desktop/gui/NoteContentPropertiesDialog.tsx:105 msgid "Words" @@ -6629,6 +6542,7 @@ msgstr "" #: packages/lib/services/joplinCloudUtils.ts:45 msgid "You are logged in into Joplin Cloud, you can leave this screen now." msgstr "" +"Ha iniciado sesión en Joplin Cloud, puede salir de esta pantalla ahora." #: packages/app-mobile/components/NoteList.tsx:98 msgid "You currently have no notebooks." @@ -6652,21 +6566,17 @@ msgstr "" "cifrado obsoleto." #: packages/lib/services/joplinCloudUtils.ts:53 -#, fuzzy msgid "" "You were unable to connect to Joplin Cloud. Please check your credentials " "and try again. Error:" msgstr "" -"Se ha producido un error al configurar su cuenta de Joplin Cloud. Por favor, " -"verifique su correo electrónico y contraseña e inténtelo de nuevo. El error " -"fue:\n" -"\n" -"%s" +"No ha podido conectarse a Joplin Cloud. Compruebe sus credenciales y vuelva " +"a intentarlo. Error:" #: packages/app-desktop/gui/JoplinCloudConfigScreen.tsx:55 #: packages/app-mobile/components/screens/ConfigScreen/JoplinCloudConfig.tsx:70 msgid "Your account doesn't have access to this feature" -msgstr "" +msgstr "Tu cuenta no tiene acceso a esta función" #: packages/app-cli/app/cli-utils.js:160 msgid "Your choice: " @@ -6679,7 +6589,7 @@ msgstr "Sus datos van a ser cifrados y sincronizados nuevamente." #: packages/app-desktop/gui/MainScreen.tsx:562 #: packages/app-mobile/components/ScreenHeader/WarningBanner.tsx:55 msgid "Your Joplin Cloud credentials are invalid, please login." -msgstr "" +msgstr "Sus credenciales de Joplin Cloud no son válidas, inicie sesión." #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:259 msgid "Your password is needed to decrypt some of your data." @@ -6690,8 +6600,8 @@ msgid "" "Your password is needed to decrypt some of your data. Type `:e2ee decrypt` " "to set it." msgstr "" -"Su contraseña es necesaria para descrifrar algunos de sus datos. Escriba " -"`:e2ee decrypt` para establecerla." +"Su contraseña es necesaria para descrifrar algunos de sus datos. Escriba `:" +"e2ee decrypt` para establecerla." #: packages/app-desktop/checkForUpdates.ts:108 msgid "Your version: %s" From 0d6c1067e32b9f53d42b4798d5ab3b9596bd0a71 Mon Sep 17 00:00:00 2001 From: klxiang <39042920+klxiang@users.noreply.github.com> Date: Tue, 4 Mar 2025 10:01:55 +0800 Subject: [PATCH 008/158] All: Translation: Update zh_CN.po (#11920) --- packages/tools/locales/zh_CN.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/tools/locales/zh_CN.po b/packages/tools/locales/zh_CN.po index 98e4b0c658..d2f39c61f5 100644 --- a/packages/tools/locales/zh_CN.po +++ b/packages/tools/locales/zh_CN.po @@ -624,7 +624,7 @@ msgstr "自动检查更新" #: packages/lib/models/settings/builtInMetadata.ts:1722 msgid "Automatically delete notes in the trash after a number of days" -msgstr "一段时间后自动删除回收站中的笔记" +msgstr "几天后自动删除回收站中的笔记" #: packages/lib/models/settings/builtInMetadata.ts:556 msgid "Automatically switch theme to match system theme" @@ -4754,7 +4754,7 @@ msgstr "显示密码" #: packages/lib/models/settings/builtInMetadata.ts:698 msgid "Show sort order buttons" -msgstr "显示排序方法按钮" +msgstr "显示排序按钮" #: packages/lib/models/settings/builtInMetadata.ts:1007 msgid "Show tray icon" From 4ad1b49769b7740446a53235824601bc380d9161 Mon Sep 17 00:00:00 2001 From: Joplin Bot Date: Tue, 4 Mar 2025 02:03:53 +0000 Subject: [PATCH 009/158] Doc: Auto-update documentation Auto-updated using release-website.sh --- packages/tools/postPreReleasesToForum.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/tools/postPreReleasesToForum.json b/packages/tools/postPreReleasesToForum.json index e61c8245f4..f0a042381b 100644 --- a/packages/tools/postPreReleasesToForum.json +++ b/packages/tools/postPreReleasesToForum.json @@ -134,6 +134,7 @@ "v3.3.2": true, "android-v3.3.1": true, "ios-v13.3.1": true, - "v3.2.13": true + "v3.2.13": true, + "android-v3.3.2": true } } \ No newline at end of file From b831d8c068e4f7950e757814bb3b0ee34b7cbb58 Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Tue, 4 Mar 2025 03:57:11 -0800 Subject: [PATCH 010/158] Desktop: Accessibility: Improve "toggle all notebooks" accessibility (#11918) --- .../app-desktop/gui/Sidebar/hooks/useOnRenderListWrapper.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/app-desktop/gui/Sidebar/hooks/useOnRenderListWrapper.tsx b/packages/app-desktop/gui/Sidebar/hooks/useOnRenderListWrapper.tsx index 5dc05a0ca6..224c646271 100644 --- a/packages/app-desktop/gui/Sidebar/hooks/useOnRenderListWrapper.tsx +++ b/packages/app-desktop/gui/Sidebar/hooks/useOnRenderListWrapper.tsx @@ -22,13 +22,14 @@ interface CollapseExpandAllButtonProps { } const CollapseExpandAllButton = (props: CollapseExpandAllButtonProps) => { - // To allow it to be accessed by accessibility tools, the new folder button + // To allow it to be accessed by accessibility tools, the toggle button // is not included in the portion of the list with role='tree'. const icon = props.allFoldersCollapsed ? 'far fa-caret-square-right' : 'far fa-caret-square-down'; + const label = props.allFoldersCollapsed ? _('Expand all notebooks') : _('Collapse all notebooks'); return , ); } else { + if (!clipperEnabled) { + webClipperStatusComps.push( +

+ {_('The web clipper service cannot be enabled in this instance of Joplin.')} +

, + ); + } else { + webClipperStatusComps.push( +

+ {_('The web clipper service is not enabled.')} +

, + ); + } + webClipperStatusComps.push( -

- {_('The web clipper service is not enabled.')} -

, - ); - webClipperStatusComps.push( - , ); diff --git a/packages/app-desktop/gui/MenuBar.tsx b/packages/app-desktop/gui/MenuBar.tsx index 8204c6c88c..977a0a2c23 100644 --- a/packages/app-desktop/gui/MenuBar.tsx +++ b/packages/app-desktop/gui/MenuBar.tsx @@ -555,6 +555,7 @@ function useMenu(props: Props) { const newFolderItem = menuItemDic.newFolder; const newSubFolderItem = menuItemDic.newSubFolder; const printItem = menuItemDic.print; + const newAppInstance = menuItemDic.newAppInstance; const switchProfileItem = { label: _('Switch profile'), submenu: switchProfileMenuItems, @@ -718,8 +719,11 @@ function useMenu(props: Props) { }, { type: 'separator', }, - printItem, + printItem, { + type: 'separator', + }, switchProfileItem, + newAppInstance, ], }; diff --git a/packages/app-desktop/gui/menuCommandNames.ts b/packages/app-desktop/gui/menuCommandNames.ts index fa3144bd8c..e04b001ed0 100644 --- a/packages/app-desktop/gui/menuCommandNames.ts +++ b/packages/app-desktop/gui/menuCommandNames.ts @@ -48,6 +48,7 @@ export default function() { 'toggleTabMovesFocus', 'editor.deleteLine', 'editor.duplicateLine', + 'newAppInstance', // We cannot put the undo/redo commands in the menu because they are // editor-specific commands. If we put them there it will break the // undo/redo in regular text fields. diff --git a/packages/app-desktop/main.js b/packages/app-desktop/main.js index 8353febd78..32f1b1d99f 100644 --- a/packages/app-desktop/main.js +++ b/packages/app-desktop/main.js @@ -25,28 +25,27 @@ process.on('unhandledRejection', (reason, p) => { process.exit(1); }); -// Likewise, we want to know if a profile is specified early, in particular -// to save the window state data. -function getProfileFromArgs(args) { +const getFlagValueFromArgs = (args, flag, defaultValue) => { if (!args) return null; - const profileIndex = args.indexOf('--profile'); - if (profileIndex <= 0 || profileIndex >= args.length - 1) return null; - const profileValue = args[profileIndex + 1]; - return profileValue ? profileValue : null; -} + const index = args.indexOf(flag); + if (index <= 0 || index >= args.length - 1) return defaultValue; + const value = args[index + 1]; + return value ? value : defaultValue; +}; Logger.fsDriver_ = new FsDriverNode(); const env = envFromArgs(process.argv); -const profileFromArgs = getProfileFromArgs(process.argv); +const profileFromArgs = getFlagValueFromArgs(process.argv, '--profile', null); const isDebugMode = !!process.argv && process.argv.indexOf('--debug') >= 0; +const altInstanceId = getFlagValueFromArgs(process.argv, '--alt-instance-id', ''); // We initialize all these variables here because they are needed from the main process. They are // then passed to the renderer process via the bridge. const appId = `net.cozic.joplin${env === 'dev' ? 'dev' : ''}-desktop`; let appName = env === 'dev' ? 'joplindev' : 'joplin'; if (appId.indexOf('-desktop') >= 0) appName += '-desktop'; -const { rootProfileDir } = determineBaseAppDirs(profileFromArgs, appName); +const { rootProfileDir } = determineBaseAppDirs(profileFromArgs, appName, altInstanceId); const settingsPath = `${rootProfileDir}/settings.json`; let autoUploadCrashDumps = false; @@ -67,7 +66,7 @@ const initialCallbackUrl = process.argv.find((arg) => isCallbackUrl(arg)); const wrapper = new ElectronAppWrapper(electronApp, env, rootProfileDir, isDebugMode, initialCallbackUrl); -initBridge(wrapper, appId, appName, rootProfileDir, autoUploadCrashDumps); +initBridge(wrapper, appId, appName, rootProfileDir, autoUploadCrashDumps, altInstanceId); wrapper.start().catch((error) => { console.error('Electron App fatal error:'); diff --git a/packages/app-desktop/runForTesting.sh b/packages/app-desktop/runForTesting.sh index 549b143dce..20f1d0a62c 100755 --- a/packages/app-desktop/runForTesting.sh +++ b/packages/app-desktop/runForTesting.sh @@ -180,7 +180,7 @@ fi if [ "$IS_DESKTOP" = "1" ]; then cd "$ROOT_DIR/packages/app-desktop" - yarn start --profile "$PROFILE_DIR" + yarn start --profile "$PROFILE_DIR" --alt-instance-id $USER_NUM else cd "$ROOT_DIR/packages/app-cli" if [[ $CMD == "--" ]]; then diff --git a/packages/app-desktop/services/commands/stateToWhenClauseContext.ts b/packages/app-desktop/services/commands/stateToWhenClauseContext.ts index 761faaa859..21ac5b9fa8 100644 --- a/packages/app-desktop/services/commands/stateToWhenClauseContext.ts +++ b/packages/app-desktop/services/commands/stateToWhenClauseContext.ts @@ -12,6 +12,7 @@ export default function stateToWhenClauseContext(state: AppState, options: WhenC const windowId = options?.windowId ?? defaultWindowId; const isMainWindow = windowId === defaultWindowId; const windowState = stateUtils.windowStateById(state, windowId); + const isAltInstance = !!state.settings.altInstanceId; return { ...libStateToWhenClauseContext(state, options), @@ -26,6 +27,7 @@ export default function stateToWhenClauseContext(state: AppState, options: WhenC gotoAnythingVisible: !!state.visibleDialogs['gotoAnything'], sidebarVisible: isMainWindow && !!state.mainLayout && layoutItemProp(state.mainLayout, 'sideBar', 'visible'), noteListHasNotes: !!windowState.notes.length, + isAltInstance, // Deprecated sideBarVisible: !!state.mainLayout && layoutItemProp(state.mainLayout, 'sideBar', 'visible'), diff --git a/packages/app-desktop/services/restart.ts b/packages/app-desktop/services/restart.ts index c268037b13..e505045017 100644 --- a/packages/app-desktop/services/restart.ts +++ b/packages/app-desktop/services/restart.ts @@ -2,9 +2,9 @@ import Setting from '@joplin/lib/models/Setting'; import bridge from './bridge'; -export default async (linuxSafeRestart = true) => { +export default async () => { Setting.setValue('wasClosedSuccessfully', true); await Setting.saveAll(); - bridge().restart(linuxSafeRestart); + await bridge().restart(); }; diff --git a/packages/app-desktop/utils/restartInSafeModeFromMain.ts b/packages/app-desktop/utils/restartInSafeModeFromMain.ts index dd4b9d3cf7..2c37ac31f9 100644 --- a/packages/app-desktop/utils/restartInSafeModeFromMain.ts +++ b/packages/app-desktop/utils/restartInSafeModeFromMain.ts @@ -21,14 +21,14 @@ const restartInSafeModeFromMain = async () => { shimInit({}); const startFlags = await processStartFlags(bridge().processArgv()); - const { rootProfileDir } = determineBaseAppDirs(startFlags.matched.profileDir, appName); + const { rootProfileDir } = determineBaseAppDirs(startFlags.matched.profileDir, appName, Setting.value('altInstanceId')); const { profileDir } = await initProfile(rootProfileDir); // We can't access the database, so write to a file instead. const safeModeFlagFile = join(profileDir, safeModeFlagFilename); await writeFile(safeModeFlagFile, 'true', 'utf8'); - bridge().restart(); + await bridge().restart(); }; export default restartInSafeModeFromMain; diff --git a/packages/lib/BaseApplication.ts b/packages/lib/BaseApplication.ts index 074c7f3b6e..1358117001 100644 --- a/packages/lib/BaseApplication.ts +++ b/packages/lib/BaseApplication.ts @@ -687,7 +687,9 @@ export default class BaseApplication { // https://immerjs.github.io/immer/docs/freezing setAutoFreeze(initArgs.env === 'dev'); - const { rootProfileDir, homeDir } = determineProfileAndBaseDir(options.rootProfileDir ?? initArgs.profileDir, appName); + const altInstanceId = initArgs.altInstanceId || ''; + + const { rootProfileDir, homeDir } = determineProfileAndBaseDir(options.rootProfileDir ?? initArgs.profileDir, appName, altInstanceId); const { profileDir, profileConfig, isSubProfile } = await initProfile(rootProfileDir); this.profileConfig_ = profileConfig; @@ -781,6 +783,8 @@ export default class BaseApplication { Setting.setValue('isSafeMode', true); } + Setting.setValue('altInstanceId', altInstanceId); + const safeModeFlagFile = join(profileDir, safeModeFlagFilename); if (await fs.pathExists(safeModeFlagFile) && fs.readFileSync(safeModeFlagFile, 'utf8') === 'true') { appLogger.info(`Safe mode enabled because of file: ${safeModeFlagFile}`); diff --git a/packages/lib/ClipperServer.ts b/packages/lib/ClipperServer.ts index 683a0acca3..d720ea0d5e 100644 --- a/packages/lib/ClipperServer.ts +++ b/packages/lib/ClipperServer.ts @@ -23,6 +23,7 @@ export default class ClipperServer { private api_: Api = null; // eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied private dispatch_: Function; + private enabled_ = true; private static instance_: ClipperServer = null; @@ -40,6 +41,18 @@ export default class ClipperServer { return this.api_; } + public enabled() { + return this.enabled_; + } + + public setEnabled(v: boolean) { + this.enabled_ = v; + + if (!this.enabled_ && this.isRunning()) { + void this.stop(); + } + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied public initialize(actionApi: any = null) { this.api_ = new Api(() => { @@ -106,6 +119,8 @@ export default class ClipperServer { } public async start() { + if (!this.enabled()) throw new Error('Cannot start clipper server because it is disabled'); + this.setPort(null); this.setStartState(StartState.Starting); @@ -251,8 +266,11 @@ export default class ClipperServer { } public async stop() { - this.server_.destroy(); - this.server_ = null; + if (this.server_) { + this.server_.destroy(); + this.server_ = null; + } + this.setStartState(StartState.Idle); this.setPort(null); } diff --git a/packages/lib/determineBaseAppDirs.ts b/packages/lib/determineBaseAppDirs.ts index 92198e09ef..32d8652e48 100644 --- a/packages/lib/determineBaseAppDirs.ts +++ b/packages/lib/determineBaseAppDirs.ts @@ -1,7 +1,7 @@ import { homedir } from 'os'; import { toSystemSlashes } from './path-utils'; -export default (profileFromArgs: string, appName: string) => { +export default (profileFromArgs: string, appName: string, altInstanceId: string) => { let profileDir = ''; let homeDir = ''; @@ -12,7 +12,11 @@ export default (profileFromArgs: string, appName: string) => { profileDir = `${process.env.PORTABLE_EXECUTABLE_DIR}/JoplinProfile`; homeDir = process.env.PORTABLE_EXECUTABLE_DIR; } else { - profileDir = `${homedir()}/.config/${appName}`; + if (!altInstanceId) { + profileDir = `${homedir()}/.config/${appName}`; + } else { + profileDir = `${homedir()}/.config/${appName}-${altInstanceId}`; + } homeDir = homedir(); } diff --git a/packages/lib/models/settings/builtInMetadata.ts b/packages/lib/models/settings/builtInMetadata.ts index 795b234615..cbdd678802 100644 --- a/packages/lib/models/settings/builtInMetadata.ts +++ b/packages/lib/models/settings/builtInMetadata.ts @@ -62,6 +62,16 @@ const builtInMetadata = (Setting: typeof SettingType) => { type: SettingItemType.String, public: false, }, + + 'altInstanceId': { + value: '', + type: SettingItemType.String, + public: false, + appTypes: [AppType.Desktop], + storage: SettingStorage.File, + isGlobal: true, + }, + 'editor.codeView': { value: true, type: SettingItemType.Bool, diff --git a/packages/lib/utils/processStartFlags.ts b/packages/lib/utils/processStartFlags.ts index 18e2f3c71e..bda8456093 100644 --- a/packages/lib/utils/processStartFlags.ts +++ b/packages/lib/utils/processStartFlags.ts @@ -13,6 +13,7 @@ export interface MatchedStartFlags { logLevel?: LogLevel; allowOverridingDnsResultOrder?: boolean; devPlugins?: string[]; + altInstanceId?: string; } // Handles the initial flags passed to main script and @@ -118,6 +119,12 @@ const processStartFlags = async (argv: string[], setDefaults = true) => { continue; } + if (arg === '--alt-instance-id') { + matched.altInstanceId = nextArg; + argv.splice(0, 2); + continue; + } + if (arg.indexOf('--remote-debugging-port=') === 0) { // Electron-specific flag used for debugging - ignore it. Electron expects this flag in '--x=y' form, a single string. argv.splice(0, 1); diff --git a/packages/lib/versionInfo.ts b/packages/lib/versionInfo.ts index 037e340853..3b1f48ed73 100644 --- a/packages/lib/versionInfo.ts +++ b/packages/lib/versionInfo.ts @@ -89,6 +89,7 @@ export default function versionInfo(packageInfo: PackageInfo, plugins: Plugins) _('Sync Version: %s', Setting.value('syncVersion')), _('Profile Version: %s', reg.db().version()), _('Keychain Supported: %s', keychainSupported ? _('Yes') : _('No')), + _('Alternative instance ID: %s', Setting.value('altInstanceId') || '-'), ]; if (gitInfo) { diff --git a/packages/tools/cspell/dictionary4.txt b/packages/tools/cspell/dictionary4.txt index b2c1d8080c..96040b232c 100644 --- a/packages/tools/cspell/dictionary4.txt +++ b/packages/tools/cspell/dictionary4.txt @@ -174,3 +174,4 @@ Minidump collapseall newfolder unfocusable +unlocker diff --git a/packages/utils/execCommand.ts b/packages/utils/execCommand.ts index a46fa8eacb..458e5d7234 100644 --- a/packages/utils/execCommand.ts +++ b/packages/utils/execCommand.ts @@ -10,6 +10,7 @@ interface ExecCommandOptions { quiet?: boolean; // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied env?: Record; + detached?: boolean; } export default async (command: string | string[], options: ExecCommandOptions | null = null): Promise => { @@ -19,6 +20,7 @@ export default async (command: string | string[], options: ExecCommandOptions | showStderr: true, quiet: false, env: {}, + detached: false, ...options, }; @@ -39,7 +41,7 @@ export default async (command: string | string[], options: ExecCommandOptions | const args: string[] = typeof command === 'string' ? splitCommandString(command) : command as string[]; const executableName = args[0]; args.splice(0, 1); - const promise = execa(executableName, args, { env: options.env }); + const promise = execa(executableName, args, { env: options.env, detached: options.detached }); if (options.showStdout && promise.stdout) promise.stdout.pipe(process.stdout); if (options.showStderr && promise.stderr) promise.stderr.pipe(process.stderr); const result = await promise; diff --git a/packages/utils/fs.test.ts b/packages/utils/fs.test.ts new file mode 100644 index 0000000000..e24553c9d6 --- /dev/null +++ b/packages/utils/fs.test.ts @@ -0,0 +1,46 @@ +import { mkdirp } from 'fs-extra'; +import { FileLocker } from './fs'; +import { msleep, Second } from './time'; + +const baseTempDir = `${__dirname}/../app-cli/tests/tmp`; + +const createTempDir = async () => { + const p = `${baseTempDir}/${Date.now()}`; + await mkdirp(p); + return p; +}; + +describe('fs', () => { + + it('should lock files', async () => { + const dirPath = await createTempDir(); + const filePath = `${dirPath}/test.lock`; + + const locker1 = new FileLocker(filePath, { + interval: 10 * Second, + }); + + expect(await locker1.lock()).toBe(true); + expect(await locker1.lock()).toBe(false); + + locker1.unlockSync(); + + const locker2 = new FileLocker(filePath, { + interval: 1.5 * Second, + }); + + expect(await locker2.lock()).toBe(true); + locker2.stopMonitoring_(); + + const locker3 = new FileLocker(filePath, { + interval: 1.5 * Second, + }); + + await msleep(2 * Second); + + expect(await locker3.lock()).toBe(true); + + locker3.unlockSync(); + }); + +}); diff --git a/packages/utils/fs.ts b/packages/utils/fs.ts index a707362e80..c81a386a76 100644 --- a/packages/utils/fs.ts +++ b/packages/utils/fs.ts @@ -1,6 +1,7 @@ -/* eslint-disable import/prefer-default-export */ - import { GlobOptionsWithFileTypesFalse, sync } from 'glob'; +import { stat, utimes } from 'fs/promises'; +import { ensureFile, removeSync } from 'fs-extra'; +import { Second } from './time'; // Wraps glob.sync but with good default options so that it works across // platforms and with consistent sorting. @@ -10,3 +11,77 @@ export const globSync = (pattern: string | string[], options: GlobOptionsWithFil output.sort(); return output; }; + +// ------------------------------------------------------------------------------------------------ +// This is a relatively crude system for "locking" files. It does so by regularly updating the +// timestamp of a file. If the file hasn't been updated for more than x seconds, it means the lock +// is stale and the file can be considered unlocked. +// +// This is good enough for our use case, to detect if a profile is already being used by a running +// instance of Joplin. +// ------------------------------------------------------------------------------------------------ + +interface FileLockerOptions { + interval?: number; +} + +export class FileLocker { + + private filePath_ = ''; + private interval_: ReturnType | null = null; + private options_: FileLockerOptions; + + public constructor(filePath: string, options: FileLockerOptions|null = null) { + this.options_ = { + interval: 10 * Second, + ...options, + }; + + this.filePath_ = filePath; + } + + public async lock() { + if (!(await this.canLock())) return false; + + await this.updateLock(); + + this.interval_ = setInterval(() => { + void this.updateLock(); + }, this.options_.interval); + + return true; + } + + private async canLock() { + try { + const s = await stat(this.filePath_); + return Date.now() - s.mtime.getTime() > (this.options_.interval as number); + } catch (error) { + const e = error as NodeJS.ErrnoException; + if (e.code === 'ENOENT') return true; + e.message = `Could not find out if this file can be locked: ${this.filePath_}`; + return e; + } + } + + // We want the unlock operation to be synchronous because it may be performed when the app + // is closing. + public unlockSync() { + this.stopMonitoring_(); + removeSync(this.filePath_); + } + + private async updateLock() { + await ensureFile(this.filePath_); + const now = new Date(); + await utimes(this.filePath_, now, now); + } + + public stopMonitoring_() { + if (this.interval_) { + clearInterval(this.interval_); + this.interval_ = null; + } + } + +} diff --git a/packages/utils/ipc.test.ts b/packages/utils/ipc.test.ts new file mode 100644 index 0000000000..0c4c56cc03 --- /dev/null +++ b/packages/utils/ipc.test.ts @@ -0,0 +1,77 @@ +import { newHttpError, sendMessage, startServer, stopServer } from './ipc'; + +describe('ipc', () => { + + it('should send and receive messages', async () => { + const startPort = 41168; + + const server1 = await startServer(startPort, async (request) => { + if (request.action === 'testing') { + return { + text: 'hello1', + }; + } + + throw newHttpError(404); + }); + + const server2 = await startServer(startPort, async (request) => { + if (request.action === 'testing') { + return { + text: 'hello2', + }; + } + + if (request.action === 'ping') { + return { + text: 'pong', + }; + } + + throw newHttpError(404); + }); + + { + const responses = await sendMessage(startPort, { + action: 'testing', + data: { + test: 1234, + }, + }); + + expect(responses).toEqual([ + { port: 41168, response: { text: 'hello1' } }, + { port: 41169, response: { text: 'hello2' } }, + ]); + } + + { + const responses = await sendMessage(startPort, { + action: 'ping', + data: null, + }); + + expect(responses).toEqual([ + { port: 41169, response: { text: 'pong' } }, + ]); + } + + { + const responses = await sendMessage(startPort, { + action: 'testing', + data: { + test: 1234, + }, + sourcePort: 41168, + }); + + expect(responses).toEqual([ + { port: 41169, response: { text: 'hello2' } }, + ]); + } + + await stopServer(server1); + await stopServer(server2); + }); + +}); diff --git a/packages/utils/ipc.ts b/packages/utils/ipc.ts new file mode 100644 index 0000000000..480428db60 --- /dev/null +++ b/packages/utils/ipc.ts @@ -0,0 +1,170 @@ +import { createServer, IncomingMessage, ServerResponse } from 'http'; +import fetch from 'node-fetch'; +import { Server } from 'http'; +import Logger from './Logger'; + +const tcpPortUsed = require('tcp-port-used'); +const maxPorts = 10; + +const findAvailablePort = async (startPort: number) => { + for (let i = 0; i < 100; i++) { + const port = startPort + i; + const inUse = await tcpPortUsed.check(port); + if (!inUse) return port; + } + + throw new Error(`All potential ports are in use or not available. Starting from port: ${startPort}`); +}; + +const findListenerPorts = async (startPort: number) => { + const output: number[] = []; + for (let i = 0; i < maxPorts; i++) { + const port = startPort + i; + const inUse = await tcpPortUsed.check(port); + if (inUse) output.push(port); + } + + return output; +}; + +const parseJson = (req: IncomingMessage): Promise => { + return new Promise((resolve, reject) => { + let body = ''; + req.on('data', chunk => { + body += chunk; + }); + req.on('end', () => { + try { + resolve(JSON.parse(body)); + } catch (error) { + reject(error); + } + }); + }); +}; + +interface HttpError extends Error { + httpCode: number; +} + +export interface Message { + action: string; + data: object|number|string|null; + sourcePort?: number; +} + +type Response = string|number|object|boolean; + +export const newHttpError = (httpCode: number, message = '') => { + const error = (new Error(message) as HttpError); + error.httpCode = httpCode; + return error; +}; + +export type IpcMessageHandler = (message: Message)=> Promise; + +export interface IpcServer { + port: number; + httpServer: Server; +} + +interface StartServerOptions { + logger?: Logger; +} + +export const startServer = async (startPort: number, messageHandler: IpcMessageHandler, options: StartServerOptions|null = null): Promise => { + const port = await findAvailablePort(startPort); + const logger = options && options.logger ? options.logger : new Logger(); + + return new Promise((resolve, reject) => { + try { + const server = createServer(async (req: IncomingMessage, res: ServerResponse) => { + try { + const message = await parseJson(req) as Message; + if (!message.action) throw newHttpError(400, 'Missing "action" property in message'); + const response = await messageHandler(message); + res.writeHead(200, { 'Content-Type': 'application/json' }); + res.end(JSON.stringify(response)); + } catch (error) { + const httpError = error as HttpError; + const httpCode = httpError.httpCode || 500; + res.writeHead(httpCode, { 'Content-Type': 'text/plain' }); + res.end(`Error ${httpCode}: ${httpError.message}`); + } + }); + + server.on('error', error => { + if (logger) logger.error('Server error:', error); + }); + + server.listen(port, () => { + resolve({ + httpServer: server, + port, + }); + }); + } catch (error) { + reject(error); + } + }); +}; + +export const stopServer = async (server: IpcServer) => { + return new Promise((resolve, reject) => { + server.httpServer.close((error) => { + if (error) { + reject(error); + } else { + resolve(null); + } + }); + }); +}; + +interface SendMessageOutput { + port: number; + response: Response; +} + +export interface SendMessageOptions { + logger?: Logger; + sendToSpecificPortOnly?: boolean; +} + +export const sendMessage = async (startPort: number, message: Message, options: SendMessageOptions|null = null) => { + const output: SendMessageOutput[] = []; + const ports = await findListenerPorts(startPort); + const logger = options && options.logger ? options.logger : new Logger(); + const sendToSpecificPortOnly = !!options && !!options.sendToSpecificPortOnly; + + for (const port of ports) { + if (sendToSpecificPortOnly && port !== startPort) continue; + if (message.sourcePort === port) continue; + + try { + const response = await fetch(`http://localhost:${port}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(message), + }); + + if (!response.ok) { + // It means the server doesn't support this particular message - so just skip it + if (response.status === 404) continue; + const text = await response.text(); + throw new Error(`Request failed: on port ${port}: ${text}`); + } + + output.push({ + port, + response: await response.json(), + }); + } catch (error) { + logger.error(`Could not send message on port ${port}:`, error); + } + } + + return output; +}; diff --git a/packages/utils/package.json b/packages/utils/package.json index 09285e1ec8..44d4a9dc1d 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -17,6 +17,7 @@ "./time": "./dist/time.js", "./types": "./dist/types.js", "./url": "./dist/url.js", + "./ipc": "./dist/ipc.js", "./path": "./dist/path.js" }, "publishConfig": { @@ -42,7 +43,8 @@ "markdown-it": "13.0.2", "moment": "2.30.1", "node-fetch": "2.6.7", - "sprintf-js": "1.1.3" + "sprintf-js": "1.1.3", + "tcp-port-used": "1.0.2" }, "devDependencies": { "@types/fs-extra": "11.0.4", diff --git a/readme/apps/multiple_instances.md b/readme/apps/multiple_instances.md new file mode 100644 index 0000000000..e687a9a2fb --- /dev/null +++ b/readme/apps/multiple_instances.md @@ -0,0 +1,36 @@ +# Running multiple instances of Joplin + +Joplin Desktop offers the capability to run **multiple instances** of the application simultaneously. Each instance is a separate application with its own configuration, plugins, and settings, meaning changes made in one instance do not affect the other. This feature is particularly useful for users who wish to maintain a clear separation between work and personal notes or utilise Joplin in multi-desktop environments. + +## Key Features of Multiple Instances + +1. **Independent Applications**: + +Each instance is completely isolated, operating as a standalone version of Joplin. This ensures no overlap in settings, plugins, or notes between instances. + +2. **Use Case Scenarios**: + +- Maintain separate environments for work and personal notes. +- Use Joplin on multi-desktop setups, with an instance on each virtual desktop. + +## Supported Number of Instances + +Currently, Joplin supports up to **two running instances**: + +1. **Main Instance**: The primary application instance, with full access to all Joplin features. + +2. **Alternative Instance**: A secondary application instance that functions independently. However, it does not support the **Web Clipper service**, which can only run in the main instance. + +## How to Launch a Second Instance + +To start a second instance of Joplin: + +1. Open the main Joplin application. + +2. Navigate to the menu and select: + +**File** => **New application instance...** + +3. A new instance of Joplin will open with its own profile. + +This second instance operates independently, allowing you to customise it as needed. diff --git a/readme/dev/spec/multiple_instances.md b/readme/dev/spec/multiple_instances.md new file mode 100644 index 0000000000..4facfc3797 --- /dev/null +++ b/readme/dev/spec/multiple_instances.md @@ -0,0 +1,25 @@ +# Multiple instance support + +Joplin Desktop supports multiple instances through **profile locking** and **IPC messaging**. + +### Profile Locking + +- A lock file is updated every `x` seconds by each instance. + +- If a valid lock exists, the new instance sends a message to all running instances and closes. This message prompts the other active instance to move to the front. + +### IPC Messaging + +- IPC is implemented using lightweight HTTP servers in each instance, communicating via `POST` requests. + +- When a message is sent, the implementation automatically discovers running IPC servers. + +### Instance Differentiation + +- The `--alt-instance-id` flag must be used to launch an alternative instance. This disables services like the Web Clipper. + +- The `altInstanceId` setting is consulted by the application to determine its type (main or alternative instance). + +### Current Limitations + +The system is designed to handle multiple instances but currently supports only two through the UI: a **main instance** and an **alternative instance**. \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 8a37a30195..912a8847c2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8993,6 +8993,7 @@ __metadata: moment: 2.30.1 node-fetch: 2.6.7 sprintf-js: 1.1.3 + tcp-port-used: 1.0.2 ts-jest: 29.1.5 typescript: 5.4.5 languageName: unknown From eb8bfd5aecd5f3a72fb53049621ce0299e24ba08 Mon Sep 17 00:00:00 2001 From: Meow Date: Sun, 16 Mar 2025 06:21:58 -0400 Subject: [PATCH 049/158] iOS: Re-Add iOS Dark Icon (#11943) Co-authored-by: Laurent Cozic --- .eslintrc.js | 2 +- Assets/JoplinLetterBlue.svg | 77 ++ .../AppIcon.appiconset/Contents.json | 555 ++++++++++-- .../AppIcon.appiconset/ios1024x1024.png | Bin 0 -> 34418 bytes .../AppIcon.appiconset/ios20x20@2x.png | Bin 0 -> 2284 bytes .../AppIcon.appiconset/ios20x20@3x.png | Bin 0 -> 3220 bytes .../AppIcon.appiconset/ios29x29@2x.png | Bin 0 -> 3161 bytes .../AppIcon.appiconset/ios29x29@3x.png | Bin 0 -> 4836 bytes .../AppIcon.appiconset/ios38x38@2x.png | Bin 0 -> 3965 bytes .../AppIcon.appiconset/ios38x38@3x.png | Bin 0 -> 5382 bytes .../AppIcon.appiconset/ios40x40@2x.png | Bin 0 -> 3989 bytes .../AppIcon.appiconset/ios40x40@3x.png | Bin 0 -> 5443 bytes .../AppIcon.appiconset/ios60x60@2x.png | Bin 0 -> 5443 bytes .../AppIcon.appiconset/ios60x60@3x.png | Bin 0 -> 8091 bytes .../AppIcon.appiconset/ios64x64@2x.png | Bin 0 -> 4918 bytes .../AppIcon.appiconset/ios64x64@3x.png | Bin 0 -> 7394 bytes .../AppIcon.appiconset/ios68x68@2x.png | Bin 0 -> 6237 bytes .../AppIcon.appiconset/ios76x76@2x.png | Bin 0 -> 7023 bytes .../AppIcon.appiconset/ios83.5x83.5@2x.png | Bin 0 -> 7695 bytes .../AppIcon.appiconset/ios_dark1024x1024.png | Bin 0 -> 23443 bytes .../AppIcon.appiconset/ios_dark20x20@2x.png | Bin 0 -> 871 bytes .../AppIcon.appiconset/ios_dark20x20@3x.png | Bin 0 -> 1189 bytes .../AppIcon.appiconset/ios_dark29x29@2x.png | Bin 0 -> 1091 bytes .../AppIcon.appiconset/ios_dark29x29@3x.png | Bin 0 -> 1568 bytes .../AppIcon.appiconset/ios_dark38x38@2x.png | Bin 0 -> 1463 bytes .../AppIcon.appiconset/ios_dark38x38@3x.png | Bin 0 -> 2002 bytes .../AppIcon.appiconset/ios_dark40x40@2x.png | Bin 0 -> 1522 bytes .../AppIcon.appiconset/ios_dark40x40@3x.png | Bin 0 -> 2166 bytes .../AppIcon.appiconset/ios_dark60x60@2x.png | Bin 0 -> 2166 bytes .../AppIcon.appiconset/ios_dark60x60@3x.png | Bin 0 -> 3132 bytes .../AppIcon.appiconset/ios_dark64x64@2x.png | Bin 0 -> 2254 bytes .../AppIcon.appiconset/ios_dark64x64@3x.png | Bin 0 -> 3406 bytes .../AppIcon.appiconset/ios_dark68x68@2x.png | Bin 0 -> 2437 bytes .../AppIcon.appiconset/ios_dark76x76@2x.png | Bin 0 -> 2722 bytes .../ios_dark83.5x83.5@2x.png | Bin 0 -> 2824 bytes .../ios_marketing1024x1024.png | Bin 34413 -> 0 bytes .../AppIcon.appiconset/ipad_app76x76.png | Bin 3682 -> 0 bytes .../AppIcon.appiconset/ipad_app76x76@2x.png | Bin 6661 -> 0 bytes .../ipad_notification20x20.png | Bin 973 -> 0 bytes .../ipad_notification20x20@2x.png | Bin 2174 -> 0 bytes .../ipad_pro_app83.5x83.5@2x.png | Bin 7192 -> 0 bytes .../AppIcon.appiconset/ipad_settings29x29.png | Bin 1483 -> 0 bytes .../ipad_settings29x29@2x.png | Bin 3120 -> 0 bytes .../ipad_spotlight40x40.png | Bin 2174 -> 0 bytes .../ipad_spotlight40x40@2x.png | Bin 3866 -> 0 bytes .../AppIcon.appiconset/iphone_app60x60@2x.png | Bin 5173 -> 0 bytes .../AppIcon.appiconset/iphone_app60x60@3x.png | Bin 8016 -> 0 bytes .../iphone_notification20x20@2x.png | Bin 2174 -> 0 bytes .../iphone_notification20x20@3x.png | Bin 3087 -> 0 bytes .../iphone_settings29x29@2x.png | Bin 3120 -> 0 bytes .../iphone_settings29x29@3x.png | Bin 4539 -> 0 bytes .../iphone_spotlight40x40@2x.png | Bin 3866 -> 0 bytes .../iphone_spotlight40x40@3x.png | Bin 5173 -> 0 bytes .../ios/Joplin/Images.xcassets/Contents.json | 6 + packages/tools/generate-images.json | 52 +- packages/tools/generate-images.ts | 848 ++++++++---------- 56 files changed, 990 insertions(+), 550 deletions(-) create mode 100644 Assets/JoplinLetterBlue.svg create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios1024x1024.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios20x20@2x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios20x20@3x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios29x29@2x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios29x29@3x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios38x38@2x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios38x38@3x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios40x40@2x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios40x40@3x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios60x60@2x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios60x60@3x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios64x64@2x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios64x64@3x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios68x68@2x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios76x76@2x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios83.5x83.5@2x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark1024x1024.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark20x20@2x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark20x20@3x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark29x29@2x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark29x29@3x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark38x38@2x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark38x38@3x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark40x40@2x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark40x40@3x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark60x60@2x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark60x60@3x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark64x64@2x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark64x64@3x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark68x68@2x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark76x76@2x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark83.5x83.5@2x.png delete mode 100755 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_marketing1024x1024.png delete mode 100755 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_app76x76.png delete mode 100755 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_app76x76@2x.png delete mode 100755 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_notification20x20.png delete mode 100755 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_notification20x20@2x.png delete mode 100755 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_pro_app83.5x83.5@2x.png delete mode 100755 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_settings29x29.png delete mode 100755 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_settings29x29@2x.png delete mode 100755 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_spotlight40x40.png delete mode 100755 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_spotlight40x40@2x.png delete mode 100755 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_app60x60@2x.png delete mode 100755 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_app60x60@3x.png delete mode 100755 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_notification20x20@2x.png delete mode 100755 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_notification20x20@3x.png delete mode 100755 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_settings29x29@2x.png delete mode 100755 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_settings29x29@3x.png delete mode 100755 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_spotlight40x40@2x.png delete mode 100755 packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_spotlight40x40@3x.png create mode 100644 packages/app-mobile/ios/Joplin/Images.xcassets/Contents.json diff --git a/.eslintrc.js b/.eslintrc.js index 62ec97a053..3aeb75a9fc 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -311,7 +311,7 @@ module.exports = { selector: 'interface', format: null, 'filter': { - 'regex': '^(RSA|RSAKeyPair)$', + 'regex': '^(RSA|RSAKeyPair|iOS.*)$', 'match': true, }, }, diff --git a/Assets/JoplinLetterBlue.svg b/Assets/JoplinLetterBlue.svg new file mode 100644 index 0000000000..02a9369957 --- /dev/null +++ b/Assets/JoplinLetterBlue.svg @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/Contents.json b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/Contents.json index 523aa8211b..3c7e2a44da 100755 --- a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/Contents.json +++ b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/Contents.json @@ -1,116 +1,517 @@ { - "images": [ + "images" : [ { - "filename": "ios_marketing1024x1024.png", - "idiom": "ios-marketing", - "size": "1024x1024", - "scale": "1x" + "filename" : "ios20x20@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "20x20" }, { - "filename": "iphone_notification20x20@2x.png", - "idiom": "iphone", - "size": "20x20", - "scale": "2x" + "filename" : "ios20x20@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "20x20" }, { - "filename": "iphone_notification20x20@3x.png", - "idiom": "iphone", - "size": "20x20", - "scale": "3x" + "filename" : "ios29x29@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "29x29" }, { - "filename": "iphone_settings29x29@2x.png", - "idiom": "iphone", - "size": "29x29", - "scale": "2x" + "filename" : "ios29x29@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "29x29" }, { - "filename": "iphone_settings29x29@3x.png", - "idiom": "iphone", - "size": "29x29", - "scale": "3x" + "filename" : "ios38x38@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "38x38" }, { - "filename": "iphone_spotlight40x40@2x.png", - "idiom": "iphone", - "size": "40x40", - "scale": "2x" + "filename" : "ios38x38@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "38x38" }, { - "filename": "iphone_spotlight40x40@3x.png", - "idiom": "iphone", - "size": "40x40", - "scale": "3x" + "filename" : "ios40x40@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "40x40" }, { - "filename": "iphone_app60x60@2x.png", - "idiom": "iphone", - "size": "60x60", - "scale": "2x" + "filename" : "ios40x40@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "40x40" }, { - "filename": "iphone_app60x60@3x.png", - "idiom": "iphone", - "size": "60x60", - "scale": "3x" + "filename" : "ios60x60@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "60x60" }, { - "filename": "ipad_notification20x20.png", - "idiom": "ipad", - "size": "20x20", - "scale": "1x" + "filename" : "ios60x60@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "60x60" }, { - "filename": "ipad_notification20x20@2x.png", - "idiom": "ipad", - "size": "20x20", - "scale": "2x" + "filename" : "ios64x64@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "64x64" }, { - "filename": "ipad_settings29x29.png", - "idiom": "ipad", - "size": "29x29", - "scale": "1x" + "filename" : "ios64x64@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "64x64" }, { - "filename": "ipad_settings29x29@2x.png", - "idiom": "ipad", - "size": "29x29", - "scale": "2x" + "filename" : "ios68x68@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "68x68" }, { - "filename": "ipad_spotlight40x40.png", - "idiom": "ipad", - "size": "40x40", - "scale": "1x" + "filename" : "ios76x76@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "76x76" }, { - "filename": "ipad_spotlight40x40@2x.png", - "idiom": "ipad", - "size": "40x40", - "scale": "2x" + "filename" : "ios83.5x83.5@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "83.5x83.5" }, { - "filename": "ipad_app76x76.png", - "idiom": "ipad", - "size": "76x76", - "scale": "1x" + "filename" : "ios1024x1024.png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" }, { - "filename": "ipad_app76x76@2x.png", - "idiom": "ipad", - "size": "76x76", - "scale": "2x" + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "ios_dark20x20@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "20x20" }, { - "filename": "ipad_pro_app83.5x83.5@2x.png", - "idiom": "ipad", - "size": "83.5x83.5", - "scale": "2x" + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "ios_dark20x20@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "20x20" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "ios_dark29x29@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "29x29" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "ios_dark29x29@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "29x29" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "ios_dark38x38@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "38x38" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "ios_dark38x38@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "38x38" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "ios_dark40x40@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "40x40" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "ios_dark40x40@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "40x40" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "ios_dark60x60@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "60x60" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "ios_dark60x60@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "60x60" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "ios_dark64x64@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "64x64" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "ios_dark64x64@3x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "64x64" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "ios_dark68x68@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "68x68" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "ios_dark76x76@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "76x76" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "ios_dark83.5x83.5@2x.png", + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "ios_dark1024x1024.png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "tinted" + } + ], + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "20x20" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "tinted" + } + ], + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "20x20" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "tinted" + } + ], + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "29x29" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "tinted" + } + ], + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "29x29" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "tinted" + } + ], + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "38x38" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "tinted" + } + ], + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "38x38" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "tinted" + } + ], + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "40x40" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "tinted" + } + ], + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "40x40" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "tinted" + } + ], + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "60x60" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "tinted" + } + ], + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "60x60" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "tinted" + } + ], + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "64x64" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "tinted" + } + ], + "idiom" : "universal", + "platform" : "ios", + "scale" : "3x", + "size" : "64x64" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "tinted" + } + ], + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "68x68" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "tinted" + } + ], + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "76x76" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "tinted" + } + ], + "idiom" : "universal", + "platform" : "ios", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "tinted" + } + ], + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" } ], - "info": { - "version": 1, - "author": "xcode" + "info" : { + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios1024x1024.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios1024x1024.png new file mode 100644 index 0000000000000000000000000000000000000000..3a2f2ef03ac2223a74b8dfe90963ec76543f832b GIT binary patch literal 34418 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 literal 0 HcmV?d00001 diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios29x29@3x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios29x29@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..6941164577c52af78b8110c468e09cdc0c720ac5 GIT binary patch literal 4836 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 KMNUMnLSTX!P~8at literal 0 HcmV?d00001 diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios38x38@2x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios38x38@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..cff0e76e90f06db1590f128152b005c7d57043d7 GIT binary patch literal 3965 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 X2kBnA3-CZh00000NkvXXu0mjflGlpB literal 0 HcmV?d00001 diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios38x38@3x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios38x38@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..36f3a5c12afa75999d4b30e26ae00c22bcf5468a GIT binary patch literal 5382 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 literal 0 HcmV?d00001 diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios40x40@2x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0387879f1ab403c7a1cffe7bdd106b5e6360c5a0 GIT binary patch literal 3989 zcmV;G4{Gp9uXlTFGmBReNT^h$QB$RnqJD`QscMw83XrxCb__P)ecv|>j#)ym zfdC1C0BMuberckX1Ogbm;eFr6%h;Y7?>h#J7cd^vbKjd8&+^{9`{o%l`pZaTEX{Au zz31HXKlhzaX-cfrE)P&jCsuNYN0LGYN^HkUXp@5CTe0F=B%oNiB(@nD)6Ogbtqz!hRu8;L zJH$fU%S^kUi55`FXeBW^VC!iqU^3bfHdi+TBIRZO&0Y-wOFT5(h(;>c2;FRtX(X0ctBqeIQU$7dxE zn$h-|?OO^pL%q0f>DZ=qc^a)`3N@*nkd^{Ar#(Hjnr-Wn#Fhqr9K+#%Isfrbl{_JMnUT@k9>4_7_|NpXlVUK&>(2t*R%%KUFZj`JrC+z`xU77L(sV% z(5w3u;<#2BAKDe+b!eF@(8{cS_w>FGFO58V_H1F{nRPD>^@p1-_1T5XJrg;ylp(D< z1~#WXHM#1!LsO&;+UV;fG&JQz=T02Soj7!B zB0GPgV|32)3a5Xi8hdi$_E_e%;jHV!hprF5k=ZVaXq3cQ%E^$W3~4d&@^^gR8Qrop zwNrx9DZa}oq02U=G-_igq%U0llLoEWhhaU;%w14#1X|ai3iQG|KHqeuO_btf{sf)I*nrR9y{9cg1g8t_)-{f;D=3f#exV(oPkI-M zY&(^I&oc0ZyW@OvvO#QvsMrQpVC^eMOW5%dc#aG%oKIROiU8mVZs1_HoLt9Pfy`;O zz)RBc5v*iJKe@vv6@Xh$5=7W0xLy`(aV4A32Ak5l?kz(vzepDjdlx>b9Vna|_-+Z78Ja zMVCEi(Ehn4M>VO5)`W(Qq zb&T)&MOJt6k7Gdi_~`=O*)x9nQsuNubc>8K9K8}+q3PoU{vvM#1yo7GN$V}0lTB!y zcNHPw9Un|a#3?Fisw(N~*uaCQdIy8HWArADp*vHqnifUNW%1Zg2HOz@)}OdNN&s9b z39liqK<2bsU?H(xd9d3hN%`jS-n+_~XIf4yHv2+DefkRZj3^2NgTv|>FDC;YM*fwO zuo{My%s^X;X#-4YF|d%157Qr}ZlYA*(w+81spel<%DzxId$zXvrK_I>M@H3{3gSo^j1+ zF945N20n{{%P}w?S{Gwl=bZ(}x{eRBlsHxO#iKq0?gw#^j14lGr;OHjk>Cv8A zZs6O)Xji#7q)G^_69%@f-e#y*BrC7Ur^sW=033t83y;_)65unphtRGv02V^)v?Cu` zS8tsYl)L{m%;qziIIJ3@T>Xp&b`IA%tQa_;Cg&CxaPAQDD_arFQg7)j#YKyOt?BsE z@mZ?6_pxPQx-ywX82>C&PGR6^>|J=oG*ZCB+`v0aG4MXp3go=Yl$HkO*YWves9h4f zHe4R$q^0KrGfy-%Ju^33CiB`KDTW_Ep*BE;YRWmR9s@@-M>cjVi$ zd!q0L3FTeLq5-%n=OzL0j*=BY*6drX?U>e)1}5+LKptth0csj}!WLngcKV5C!-XC= zB)dk*#j$cJR`ZIeCa16lu%--sDOprK+Fg}%Yls8*76lwwPFQbEXdP*7yMuV$>hw-m zxhHkK^;!4itcGnGM1Q`_Ya?(%_D*b(#mVV<3n>bUkTkl{#FwIgD|2pg0uP|=#qNRD z#8ywM117%J>7A~0iSK;xY#$pf{pQqT&Fh&8H#jZFF;A<-2ELRmvJUOy2LAje1-!3J z2(9DR+lZIv2#Xmm5pB3Mz&`lG?=}z2dL^`oV|1~#I2n;*;EJ4^gWSN|?qXna+8x?` ztEbfg6Z^?rJjI-O(N|MX?A<%~7-aBg)-9 za@!YR7-y8IE_!GjJv^u~WY(PhXz$Re#fZucr>p;cWYv-)p}5jf#W7uuZf>VKD|0_Bs?+5<4*jL&dZ z;F;Lw5Fx)(dEavDPk+$5p6R!<1@=B<{L$PmV=8R77l?L~)>}%ZwDuq0K-N7)0p6;8Sku?V ztTRr-_|Tynn|ykud_3qMst>Z;-Z?D)AiE{69&1=%y;IbH}@3BCc(uTDfz9YkHb)0J?;CvhU_>L<8Gj)92 zEBRwBt^LNIk=4)f!Qs(9q~R}Ls;C$e-5q?YStMW3-L>SrMA|kmE!}(9aYuo(ACG#= zNJ{|=cxD6)M`&&nzaOAOL3lfMVL>a-7yWhkpKHb8-Brl90-4j=X@RYMjt|bsa9Xwt zsylXLSZBmrdnMTHMW=@URE*kg&3ExDu!eS%DXrax>qy9Rd~j@(U^UnV)*ie%V7^@i z(l+-_`39BPZ>NCyS0Hm*3@qe1K7BVYiL6I^Y632+A5f5mp{0NYJjZ9)@!>u`pz5~=n~M~a&kUxA9+5PPr67n3MNyi7{dB=U#EKE(kM;QpBBr6p8QV#X@mDiDr}^}1x2s>F z9cKYp4}VOP}HBf2JPKUnw4bE4d17 zyaOp}ao<{7ffi#+p@M8NupnBNjxV%Y1Xr>BN=1Pce>f^X@?&4I;^FAzoOv?@^YP&a zPjZ_kpf`9et`cp^v)z&}+Fj`Ew*(c)oYwZQKOv#9Wx3Vq9$YC7!E+#6zf!cL*xtYN z<;bevXEkm--Rgfq5qPO1;6nSx&s*L(SmzT`YO}2XZOnr;3}-2kb@i5QB^%RHz=CKw zZVH|tddo;_1Hi&6P~~#dZo0uMC!5exz&vuYpj(~1W_-fy vEh8-rEQGd#X9eQrIpzwfw~Vwl>;LzER)}aX!E(}i00000NkvXXu0mjf#So!U literal 0 HcmV?d00001 diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios40x40@3x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios40x40@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..a01426934476476a62518ecd15b5257ba33cbd7a GIT binary patch literal 5443 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 literal 0 HcmV?d00001 diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios60x60@2x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a01426934476476a62518ecd15b5257ba33cbd7a GIT binary patch literal 5443 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 literal 0 HcmV?d00001 diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios60x60@3x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..7f0a517afd265a3c0780f539e94bfd32d51d4929 GIT binary patch literal 8091 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 O1yEDgR;pF74*ws7LX>v^ literal 0 HcmV?d00001 diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios64x64@3x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios64x64@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..a11d1561ef436f901e7ea3009cd859ee864a01d8 GIT binary patch literal 7394 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 literal 0 HcmV?d00001 diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios68x68@2x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios68x68@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..5d891ffc210127b188a82b191ebcc6bf65b0e407 GIT binary patch literal 6237 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 Hu0mjf8p`w5 literal 0 HcmV?d00001 diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios76x76@2x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios76x76@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..29a95a07e3f14de3f34e3e3f848c5e3954da19db GIT binary patch literal 7023 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 literal 0 HcmV?d00001 diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark20x20@3x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..fdeb1d40cd246ad02f743abb94364a2086807fa2 GIT binary patch literal 1189 zcmV;W1X}xvP)tsfQj4 zyOb5Sk=aR;*iM}IGfiSAtp~mI)a_g-g^j`1?NAsy7BYj3s`um2^nf^oMuUgC9?N{}1VOT4M$EZ&M8mR#OFy&?xNG{(n}@;D zW4934`EY_RYepJfbe} zxphtit3vSDZB7J>%)Y$3z!n~i!BT;O3c=wLhr?3-yb8gg5{JW5zBObXUGu66Oz~hG zRsgT63>++Scx(=ty=?(T&(TxWm+0~8TXdw>O;6Nc)}28|8iQF5iyc`-q*B3Mk&2y( z)PqcvP^a)arq`Ug!@ zPpI@KoT^_JV>|x!tS{Hys4fO5hr^PtB>*qV2Zn+o(n9JvEoD#BP?p1C$-y-099Zzk z`2AL|NzJp(!syurH^34Di}He*$;u7!JX`$cKwu130H2i;JW>9xNuIqS9lXrputfg? zfK&2;>GASq(L4*cvF^ipCvz6%(Md+ z${2dy>|MF~tg-r@#P|H(ik(6mhi|!|>v{BSPBuQHbH)vdAHDM_2pWNzLtvl4YaEkW zn#vx8D}556Kaqn=k6Xezk~?}w;@hK+*>~FdpOLX|)(*MW1;zgrqJKVZIGg&lvv2+n zLvQN7p?7Xg??_(PL)mEf^yVu%Ews==3oW$JLe=p%V#mpdTbU5o00000NkvXXu0mjf DqM|{> literal 0 HcmV?d00001 diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark29x29@2x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..defd4a49b5f1b4508d959c8e6332d61d93667565 GIT binary patch literal 1091 zcmV-J1ibr+P)-%o?@s-hu3tHk&*pqm z%=jUK4s8;=({O#Rvdl9JOjl>}dF3@Qc1-8fod(AC6fm?U^XZxb`pc6*-#W3Bx|VUE zYfb>8Grn8+(2lvvVvsr}4m70!O;;9!)Rq*q2&C2-D;;PtNUbAU8ql4dX}PH*b<*Tc zn@z4{m7#5Fj0;II@i66xR#DEFnQDrjBpN1VC3oB8PMGT?$>vB!$zQ9x;OTI^u7n4y zFZ~802j%!CMFnL;iVBKCQcV#NK@mu*aZE%|1d_TmDjp~bN#>vgSSJoB0!cQ6MFd44 z$@&ptLXGWH`(USYL+?tyf{nm?cy(l!u8-D<&$^bxDEuC87J{-NHFd+nf*RXW2Mlc~ zKUagUb;e`Mp(vzqpm41Lr;t0w_GET7QwUWEia=^E4gu`OZH`%mu|55Q&!|N?Vk@Bt zr20Y#Hx#Uc$j5x=N%)$sfTED<+ChN1=%net8JY`15lF1ia^{^17M@Rhk$LFYN+<%U zs_D;SJk2D%Dx@tqPv`vvtnEep>g=!pK0cA%H02Lj?2Zg}rNTf6VonjKq@tiCTYz& zv;%hTaT}WXZar2Ciqp>*E$XvIod*-C?Y~E}TLhaBT+ijll2| z^5W30LeEgrfg`GO!9`XiOqsRo9#*K%8QD%bA`4tY^HMWVJD5?|4tQbFxvr!KXeHh6 zg1DE+lgytc*lhJ3$3Bmejbk;ONK`Yxfs|Q&Zw2#z1&F)-FOYI;7fi23INLCIuWIT? z94uOUW%hYw2y^&C$&Yd*B!Z-dEcDl1jTjyBsMy+xv|x!be|#) zdN&ec2t#$RMrrHatFZO#S6O@Zs4V_6ar~wtg%naqA;o_jKLNgzjV84`!QlV^002ov JPDHLkV1jVe^~L}I literal 0 HcmV?d00001 diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark29x29@3x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark29x29@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..3bff8a514ade24ceede29557a8a89729d80d9e5d GIT binary patch literal 1568 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 R$c6v_002ovPDHLkV1nAxw5R|8 literal 0 HcmV?d00001 diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark38x38@3x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark38x38@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..48f2fa8d533553f0941ce2b12a625f5567a85ba5 GIT binary patch literal 2002 zcmV;@2QB!CP)Gw1om~X$uqz`*4{t%eI?o zvajRQmQtp3wC_2mJ>)$9)u}|E_(0sFNOOr^(U)f-^FFMkf`ou)j6Lk+g!gUUbCsPrb^WwS*+<)wN3Ts zFP5q`Y()hIQq*(t&7z)5RI&>9Urg1$3yJDppbC=JHJ_@^D5Z&&Z7x;T*`-oMRmLFNk497IT_QrI>Bdd?7`l;&U`Dlm~A>aoJ^ z`R5Dv&23JW$~wDMV~f_qa@ztkh@rbmOX!Ho9NM95ncA#u2`rVYX}k~-SdOx1Azy8q zi_#s5Dsyl*-pw4Rz&fX+`8b`xyT}d5&GhDpp>Oamasje)wuIh1G4v(gMJ_60z_H87a`+_UGpEYzdtbzNJ7L!jUMGWVze_$yP{TvBu9kO^B7Xo zHTMcY-p$h1w)7xL5bH+y3%Sk~Db#e$|Cz1*iD^NSBJvp$5WmhMBBd||9u3*B2uXq% zE1l;E58qHPl)#G3y=)=ICi-bXk|OFyCqjr%l5;%zu|VLQ{;wggFlD6Mt#3lfe)*-rOy3Zt=(jcbcT5+d>r5)j+zAj0D` z9Q#(uCL|#uC8-(yls_*z*4g89-cFU~u!*f}i$Rhjy7&dDu||HNGsRGtgD>XYkha^Pg9i*y# z>J7RJ;Q7YDb8JD9BE}&rhYs@wQf>`v0PY^G(=&|z6RbfJB8sbq_%$LEzmwBmnx|(_ za${fz)7K@^dA5=w#vv=6hxrBB5c{$A-Imo>yqi+J4q46m4i^ugS>*& zSf)48LR@NDoCv^5kD9SZYpv%fIpQEC(hjx=_?CQ2*i8>{X}kA`#NeSlGSy9P1)$v| zMvVQfaPH(Cq{0$MyV^Z#))lou18wqI!*^sq;*olGW$jWA9o!C+6)7T$<~b9 zGQ(J}yuqW%7*XeHp^d0@UK0qYH3B{c`fN%WLR@OkkQuz!rFGr|^16{{R(vW{4{wB# z_!C{kIAn$Mgn-Y1Q-^tF-E*F!9NBa;CiWk^fhVi$g9vqTncD5iO%f+#CuF2 z#!9Rmc#GGN8cSdkEW6!e9Fg8vjEoS46$5_=ntm1v_#S9m)UQ@VQN;iyEO&e$z%2e= z8vUnMC1Qo+x?uO93I!Ll-aIUZ^G;o>2{BfAWp*>_{d*cv=PQCH;;B`GSnhBMN>8sv zxrZ&2!TPD9(HG)6qOiWY>G8@O;oJA~m+=W$~?I@K_w04o)F#bIk5k(dD zG6c#f)Eb##yk1^E_7_JUr++`O$G!_)2qUW>D~4sa^SOPov0o9Fo!f#M42({>!CMK- zZC7*fI6WyZ@7JIKlhJu4ux@IW=|--ykLd8>OAXs;iU_58_b%8ad`_x!-)D5~wA?We z|47Wzt}o30M64fvN?hZq6W6%<#MQ3r1c-Np+JR9Rh2433oX_GN<;t6GwX0ZEHT*Vg zs_7I}o&O5pPD88WS#jl1Kfv{gwa!yw?cgDycCZ2JWkIQ3hW8DF!C){L3V!Z literal 0 HcmV?d00001 diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark40x40@2x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..911738da854dcb4e349f5535b4c31d067377a9fa GIT binary patch literal 1522 zcmVFgFt?g-(t{+L0=A+f1c+_ciDEI+hiC#>>p?AWNrR&Q^llI9+JKp5|!*hM$$9r;~_j%ti3=Itp4Gj$q4Gj$q4bA`Z@P|oFwg1YC z)vv8IsMg@phB7JTNo_1w;=gh(yj0Uat1WrJ8vo^k5BM+3N=UR_R?W$03-2A4AB zlVr0}-bLB$Nu|r=PG)N0Vy0XP*{GCrK{h$#b!7usY`ip}L#!_g!0o^@_KR{=IRKjO z02Ud~P*#B3fM;;T%LLFT9o!DQ3}Cc80Jj6rV2_mt;9mdFtYt`Qv-p;HrOduX7vRn3 zju*ek*<)_5KgM%?Q1)26(H-K-vbnDI$8^vbOISS4Azm@MrSine7PC8b3jNyJW1my8 zbukVk1^jPb>=YGK1H^tX`Y50ZU_!utZ7EO_PBt`DaGV(_|WDWEE# zJtm;=(tu$Ks0xU}i^#fC1T+pw`;DHI!|X|Z0fT{{X&@=V-u4R;%GKN44%F#Tmpc6XqS0#$qAF>>$y&n zVGuf|3fLPJFnDP|>&!5*b~S^`4*^;@-!VM572pgsVjVqZ2aE_vJXyz2k^=~@?JLE?%K%2R17h$xrerNSfbxA7@1j^dJf+W@QwQvd z2q-+I+9%&7f)CIR=ZW_hfCZsW!}-M-Xp%+1yPfItHUY%o@ss4NK)8nSNls0&L%abi z&bOBju^Ya!)~FFC$tU1;OOn z9x;G=k7&-NNro1szA(T^0f|QjV0ujNN?b)>x9E+2S1=$BPp)hkB?HjlTKF1!-2!$P zYcS6{oHrmpc@l+p?1ED7kO9~)He;__D8o>F&)hO=i|xthSu7v?3W+CcT1H3Wa@pyO6Z6nK7*6?HK z*S9VBCLZs+%(jd?N(>;JqCE(Al5b)0{vAo#!hh?nq0cJ2=k_t1obIu0K_BdG*RXg{ zH<*UPTBe;}g?;mH<%D39>ws2eZAbB-b{`FV%9Kg~su9jGZtfu7S*9Vjn<=HRw#Xy8uCTP- zc<|8(F~=|HnNo~$P^7noPV21GYukd?c<%d>#k=d3=4TFRJEumA_O)#s`3=6f9m=^h zQ%-?_z_ZXGp8>R6`QSm5{HvxZ@HW#rZeq$gTyw+#TeMcTZTwrdb>gQ@@tV#rz^eOb zcT?bb;|^XO0A`s16Mc4Gj$q4Gj$q4ULk2 Y0LP*X8;WGzkN^Mx07*qoM6N<$f_TZ#0{{R3 literal 0 HcmV?d00001 diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark40x40@3x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark40x40@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..ee9f6b4b3a2825def8cbdc09823014db53ed550e GIT binary patch literal 2166 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 literal 0 HcmV?d00001 diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark60x60@2x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..ee9f6b4b3a2825def8cbdc09823014db53ed550e GIT binary patch literal 2166 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 literal 0 HcmV?d00001 diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark60x60@3x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..edeb87944983129520dcbb0af9d60627a38932b0 GIT binary patch literal 3132 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 G-2Va3q3uur literal 0 HcmV?d00001 diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark64x64@2x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark64x64@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..ceda99737f633325facafce5c4ec0e0ad1b1d31d GIT binary patch literal 2254 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 literal 0 HcmV?d00001 diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark68x68@2x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark68x68@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e0895654afe41bf8eb9f53bc1a12027d8e36a14f GIT binary patch literal 2437 zcmZ`*dpHx^AK%6{jG0>&!$OivQpp-=AyhBbnhh(rB}8oQA%?}`O(e;6uUnCj(neV_ zdZS!Jgkq=(@yjiY{O0{V&+otYJm-5Z-`n&3e9!ls=iEH&U@Ie~A_V{dWKP;y<3%%b zn0ct&bBThJJjG@+Xtjpw!zI;~a(IlY1W* ztBD==iT|F;TaI~bMTQvK@EPy@mHHrp)kdG__f zpuu%FO)_`URI#v?7;b*?D|2@b))T0C7zNO@Ko{|v9F^%z2y=>x@dRkp~la{Ocw8$xEQKctLvkH$byZTbC2SP9Qke;)rCa~nC^ez3FC67a$ z`ck9pfF=zcO{JDX z5Z^)k6f5ssFrpmf5hsQ#kt#8p^N7j6Lvt6KV7vFb@EwM=R3*^BRc8LwO2G zo${yr9v61;lTXP>h@o8IcEWaV+KEy~i`?Q9k&Zls2TEcGLvSVcPr*eBJJI*Xys6uA z^`G1Fe|)ehDmZNz0|*DC8>BhQ!cf^)a$mqmgx5ZK#tDT+YbM;_FP>DL7#vwKri}|E z_UG2!EiYIb{T}r#)_z%YlbbZ1i+wvHmn}-PF>ZCNyB6A$a2LxNCMnu@PoLuk^Y_%2 z`<4#c+h=~R@yk3~V+#ZFRG~_dY4W8HjxApsl3$b0Ke}#29Nwk>a-y+SSptRv;Ny`O zPRs5TW+ zv9ZfGqHKep^pPvnAy(uI0%po*#t~bxVy|bLdGu7^tsC=QcSBcpVNs3wFZ0jdU{}5S z24f&1oW=lY`U_{BcJtjyQSz_jDD#2EC0aXA|&rk@m41`e~f$T6}C?X`JINLIp(E2O8~h zNB=0-p#= zY}$1u0|oT$00+q3+B$Z`L|x#*Z1h_G}{JXXjWyiOtxc12zV@o!pP z^VBvBL}JBdOu+|!sXUv1H{=~94&?!oK)4`je3YQen4I}MadaOP@d^XbR!*B+gM^)4 z;fL;O%y|v;h_mX6I8y1eFbbD3z1g#~k@Z7}D%6mYVu0a#OK7vN5s_yce~pYfac8Y? z#Qu+;qQrq8W@8h;qUzw7e~6q5CA!(S61-cx42QGU!}U9Ur~E;^M2`So@7PS?$&!b-zvW1I+K2g}(N^a)&Y@t*gE|m@>WT>+ccN3fC6(*!z1^JJbT3LhXf1 z;m*G`9tB7f6_Oi8*Jf{T_b?(&_D)r+E*V8WZ1Nmzw0G#CMblRK3{TxLW9wHtwNLm# zNoO?JXEQqBAp2AC?xvrOc#b`{IsjHDi@8iVvH3c(I`3=)PaaAV+Bc8lW(1i_SFz+v zPZTi$5yB0^*rP|G3y&Y{-s-)j)Ik}=AHLmD^Y`)PSF@{SpsTETt?Hv88drVR!`rC- zQAvb;EdSy1UFExm89H9QtIG8hq+S`}TaQrj@)kvW9Muu7?JQ%*;r})KzI(=JnJ3$} zRe->Vl78L*u9ElQ*8p7oM2fNsHa~A@LgP@$yu84YoE{J!_1#*RJMl)lpGAP3Bnwp+zwAI4BdHjU7nd$!YD2Z_z!3( z)62(fw+F`PWncn4`2PZn&|y~q literal 0 HcmV?d00001 diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark76x76@2x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_dark76x76@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..1fdaf9c5bad8c14184b4b1acdd61b5a487dce7fc GIT binary patch literal 2722 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 literal 0 HcmV?d00001 diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_marketing1024x1024.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_marketing1024x1024.png deleted file mode 100755 index 711e64a4f7f0d96fa0fbdc8d4e5bdd2aa9740d6f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 34413 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 az_CF@*VG-yEA(T~Pw%Zp$C;J_cMIi)=S diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_app76x76.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_app76x76.png deleted file mode 100755 index f7556cf24751767f720460a11176ec4073e99c72..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3682 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 Ar~m)} diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_app76x76@2x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_app76x76@2x.png deleted file mode 100755 index bae6a354aeee23f4f4c7a89dc543e2a18f820e3e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6661 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 P00000NkvXXu0mjf7}DC5 diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_notification20x20.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_notification20x20.png deleted file mode 100755 index 5c818e8470ef658cf9d3ef513e64e7fc17d1f363..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 973 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 AYybcN diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_pro_app83.5x83.5@2x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_pro_app83.5x83.5@2x.png deleted file mode 100755 index 9ea41ab0a1788302336fea1feea91b9c9878c84c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7192 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 diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_settings29x29@2x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_settings29x29@2x.png deleted file mode 100755 index bed468976e4f83ff1f08aa407f02487b440261f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3120 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 KMNUMnLSTaOQ~D7A diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_spotlight40x40.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_spotlight40x40.png deleted file mode 100755 index c4b9e4c9e18e9539313eed04a71458a4d9314364..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2174 zcmV-^2!Z#BP)(;sy6czEq~)u zUWDttKfOZh%a^jN^Rh4IWS`F-xH5B~aysDhRKTT4X~l%Jd|Z0b?0>=JUuN_xHTae2 zB}HSBLalGXsBgZ;Cr|B@s}koZ#n~gkrPi!L6_M4eP<4@5y|#eK_b};F5gC9Wy=M|!J!(f-X7PLE7x(XLng|X6A7^|K!R-YU~6`dUd@2tK=878Z;$|>39 zNm<3jfr{}1<>r8krhp4ZX_-M8Z)8oUei+&mpOcZ`#xy`M-HzqD_NDsvr8{klA5`l2=as&M3X@Ez!i)hx zRlj0VuTnECDx3KA&6&5Gww;|F8+svq;dkKcCpAW|Oogv&YYA15-Vgq-SaIdReHE9Q ze_1{C>dm%g+qS-G+p_N1mkqD=O)Gr!jm7rcD!o_6ux~bTpoCd+VJ1=qX?=jG9J?BL zeR0n-Tse(Yd*#5RBrG-ms%C1I| z!cjSX7fivI&EbEYJ@NHSgK7;k&e!K-YoFDdPt==&3YGkxi;4Jugoi zc5jl%umg_!dYqj;M&hovPtSg*(GC$Q>-V;`DXDRSR) zWHq&ypVGs(tGqLvVE@V?)CvYwQmm5}YrW2^kKP@p!VgTW4ZX zBYNj(gt;33LJd1h8G45bN8dBJCH9G7$>M!=ZmmP*#K-xGgtq!%f>(6 zoy`2lT;9Lt(!QDbO_foSuV!Z|LT?)>a8$h>obDB8^rKiEr^%tVLzNr%959_>k_x;3 zp{wTFw&khit=&ggH*X0p(YU7#Gs6izqO?6#&Z$3&%NF`9*oukP zzq7OLfP;%wZYhJIx2SMr-57}L5~lQ!RTwUza$=eRW90;tn|(@+Kfhu!Eo|-}iPD4} zsV-8wCCfu=^;Gzd7M$u7CU=w7HclL&dPO$@#>$bEo7lPf%BKtVSV@<_(%WtI%mz$@ zdBGA=qy$L=M{0ExIO6swi0u$2b&*vVZVM+Csdkvwo1_;^eq~1gQbVtK1ILFy6n5VZed}|a$w+j+G$!aT(6)tvEBcRQQutgX}h5AFE zn^rf7TMuvQcSEZnby#>_0k1jO{XJ6TqAa<4V&CB!Dtxk51EQYu6FZR_=h|1N%8vLE z!qgcN#wy4k`}mp(drr9Q(JV+A^2<@+xk-$coOP!6aP=q^zNtp=X}a3Tj(i4H1k)x{ zgMW!$kgt9JiecR`+2C!iYkdWh2mP{Lw>s=itc0G!)fx&MenSl+TKNfWv{(t%^W+bJ z-u>Yq?o*(Zm1s4y7JRqk<2AXo8B{RBO^4Ucpupb!Md^L4gzi67shwxu0jt2tW*#ga zT86Re8U7T|?;JRVON&N5vQ!Vd7M-UWXZzcMB~ID^I~nz1aYmmcqYp%NB;40I{{X{B zu8$x%j&z!ElCkP};t8Oua0>S;(0H9yesaTTbuf zaQuz)@Z-2YEb0XjP2Q(k_EJ3%OjF_P52tWRp2{<0_;1~dyGt2|wYFhx7+$*GFnzCO zZhFb$Y%KVcU{>=}-HMp99%4Ulw)E9}2u|7SWlH+dxYhZGDoD3+afqH}O3mLmsG z1{XvLt?m(x5T?e8GkhGy3RU-Gj{!|3J=4K@6=w}_Q~S8dz47<;a`PHxe8)e|tyoIF z(ZfFM5!uL%vB%1^uTB-gG?nyBho?1RdY>Tm1-x+J{rbBvM#}za`g_;>)8WO(@`c+! zOvT(%$x=H&*fVx?lSBP+f0cFgKY*r^p6PZ^rlQmyL2?%>wjD&b!Hx(bTR}t%IN1ck z8$F|&d8e8=d!J#7ieQ>LOr8CmlPMY}I)#ay@Y)faX&0PshfR?m-^!0`;l?z1{iGUZ zSC1i;75W{ZsibE*<{5F1n~q#LPbsI#u0Dn&UO-G$2PrCVA2qgxS#`wfzK7~|kw;K<`}E)c1F3mg1*_<7H2?qr07*qoM6N<$g2re% AYybcN diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_spotlight40x40@2x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_spotlight40x40@2x.png deleted file mode 100755 index 2650ef5a5e394202a1d013ce15ce278d986424c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3866 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 diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_app60x60@2x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_app60x60@2x.png deleted file mode 100755 index 2241e825657c1ff9de6c0500d9cccf2b47a9e210..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5173 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

+}n7ho-llcqB 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 AYybcN diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_notification20x20@3x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_notification20x20@3x.png deleted file mode 100755 index 6d053189d7298633b09c85a4d2c81a42be29ff34..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3087 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 KMNUMnLSTaOQ~D7A diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_settings29x29@3x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_settings29x29@3x.png deleted file mode 100755 index ae72ab5e076bc008de4b0f4bf4e98ef92541133d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4539 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 Z{{T$-0IK1;zJLG#002ovPDHLkV1ljFK8XMT diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_spotlight40x40@2x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_spotlight40x40@2x.png deleted file mode 100755 index 2650ef5a5e394202a1d013ce15ce278d986424c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3866 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 diff --git a/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_spotlight40x40@3x.png b/packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_spotlight40x40@3x.png deleted file mode 100755 index 2241e825657c1ff9de6c0500d9cccf2b47a9e210..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5173 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

+}n7ho-llcqB zvzo(7@JsOG{BCn!)5|w}Dz*Pn)@&eTdFInAP9`r396-!?g>Ty7DnIEePrl*hh2%XZ z3@ISUZ~wYBN=6Yjbc`I@WWg#&PG!&bqtaJC@kdW5xlTLgwh3av3wDzS))@mZz8?6~D@NS;9 z|6KjTyv5)8Q`b%hW`N=!C~r(lTrcIFp0r8Sfa_*$Px@&RCq94V-d?WdhgXW3-%|7<}Rm6 z|9!|2N!#jYvRQZjX}Ng*oL=dp*?ekiH3j?gDUWEAQDfGuOzISSo^TUhQRZC_4%3?iltT`FYE z7XLkzQZ&~{ePxfV^dH4t2s%V%I#Gx@#2imujabFH?!ScON*BPHgb{z#nL~8l#5J@k RN&kQV107@SO5pQ1{{y{fGd}; } +interface iOSAppIconContents { + images: { + appearances?: [ + { + appearance: 'luminosity'; + value: 'dark' | 'tinted'; + }, + ]; + filename?: string; + idiom: 'universal'; + platform: 'ios'; + scale?: '2x' | '3x'; + size: string; + }[]; +} + const sources: Source[] = [ { id: 1, @@ -82,6 +98,10 @@ const sources: Source[] = [ id: 12, name: 'JoplinCloudIcon2.svg', }, + { + id: 13, + name: '../JoplinLetterBlue.svg', + }, ]; function sourceById(id: number) { @@ -91,475 +111,396 @@ function sourceById(id: number) { throw new Error(`Invalid source ID: ${id}`); } -const operations: Operation[] = [ +const iOSReadAppIcon = async (filePath: string): Promise => { + if (!(await pathExists(filePath))) return { images: [] }; + const content = await readFile(filePath, 'utf8'); + return JSON.parse(content) as iOSAppIconContents; +}; - // ============================================================================ - // iOS icons - // ============================================================================ +const getOperations = async (rootDir: string): Promise => { + const iOSAppIconSet = 'packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset'; + const iOSAppIconSetContents = await iOSReadAppIcon(`${rootDir}/${iOSAppIconSet}/Contents.json`); - { - source: 1, - dest: 'packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ios_marketing1024x1024.png', - width: 1024, - height: 1024, - }, - { - source: 1, - dest: 'packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_app76x76.png', - width: 76, - height: 76, - }, - { - source: 1, - dest: 'packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_app76x76@2x.png', - width: 152, - height: 152, - }, - { - source: 1, - dest: 'packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_notification20x20.png', - width: 20, - height: 20, - }, - { - source: 1, - dest: 'packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_notification20x20@2x.png', - width: 40, - height: 40, - }, - { - source: 1, - dest: 'packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_pro_app83.5x83.5@2x.png', - width: 167, - height: 167, - }, - { - source: 1, - dest: 'packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_settings29x29.png', - width: 29, - height: 29, - }, - { - source: 1, - dest: 'packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_settings29x29@2x.png', - width: 58, - height: 58, - }, - { - source: 1, - dest: 'packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_spotlight40x40.png', - width: 40, - height: 40, - }, - { - source: 1, - dest: 'packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/ipad_spotlight40x40@2x.png', - width: 80, - height: 80, - }, - { - source: 1, - dest: 'packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_app60x60@2x.png', - width: 120, - height: 120, - }, - { - source: 1, - dest: 'packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_app60x60@3x.png', - width: 180, - height: 180, - }, - { - source: 1, - dest: 'packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_notification20x20@2x.png', - width: 40, - height: 40, - }, - { - source: 1, - dest: 'packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_notification20x20@3x.png', - width: 60, - height: 60, - }, - { - source: 1, - dest: 'packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_settings29x29@2x.png', - width: 58, - height: 58, - }, - { - source: 1, - dest: 'packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_settings29x29@3x.png', - width: 87, - height: 87, - }, - { - source: 1, - dest: 'packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_spotlight40x40@2x.png', - width: 80, - height: 80, - }, - { - source: 1, - dest: 'packages/app-mobile/ios/Joplin/Images.xcassets/AppIcon.appiconset/iphone_spotlight40x40@3x.png', - width: 120, - height: 120, - }, + return [ + // ============================================================================ + // iOS icons + // ============================================================================ - // ============================================================================ - // macOS icons - // ============================================================================ + ...(iOSAppIconSetContents.images.map(icon => { + const size = icon.size.split('x').map(Number), + scale = parseInt(icon.scale, 10) || 1; + if (!size || !icon.filename) return null; + return [ + { + source: 1, + dest: `${iOSAppIconSet}/ios${icon.size}${icon.scale ? `@${icon.scale}` : ''}.png`, + width: size[0] * scale, + height: size[1] * scale, + }, + { + source: 13, + dest: `${iOSAppIconSet}/ios_dark${icon.size}${icon.scale ? `@${icon.scale}` : ''}.png`, + width: size[0] * scale, + height: size[1] * scale, + }, + ]; + }).filter(ico => ico !== null)).flat(1), - { - source: 2, - dest: 'Assets/macOs.iconset/icon_16x16.png', - width: 16, - height: 16, - }, - { - source: 3, - dest: 'Assets/macOs.iconset/icon_16x16@2x.png', - width: 32, - height: 32, - }, - { - source: 3, - dest: 'Assets/macOs.iconset/icon_32x32.png', - width: 32, - height: 32, - }, - { - source: 3, - dest: 'Assets/macOs.iconset/icon_32x32@2x.png', - width: 64, - height: 64, - }, - { - source: 7, - dest: 'Assets/macOs.iconset/icon_128x128.png', - width: 128, - height: 128, - }, - { - source: 7, - dest: 'Assets/macOs.iconset/icon_128x128@2x.png', - width: 256, - height: 256, - }, - { - source: 7, - dest: 'Assets/macOs.iconset/icon_256x256.png', - width: 256, - height: 256, - }, - { - source: 7, - dest: 'Assets/macOs.iconset/icon_256x256@2x.png', - width: 512, - height: 512, - }, - { - source: 7, - dest: 'Assets/macOs.iconset/icon_512x512.png', - width: 512, - height: 512, - }, - { - source: 7, - dest: 'Assets/macOs.iconset/icon_512x512@2x.png', - width: 1024, - height: 1024, - }, + // ============================================================================ + // macOS icons + // ============================================================================ - // ============================================================================ - // Linux icons - // ============================================================================ + { + source: 2, + dest: 'Assets/macOs.iconset/icon_16x16.png', + width: 16, + height: 16, + }, + { + source: 3, + dest: 'Assets/macOs.iconset/icon_16x16@2x.png', + width: 32, + height: 32, + }, + { + source: 3, + dest: 'Assets/macOs.iconset/icon_32x32.png', + width: 32, + height: 32, + }, + { + source: 3, + dest: 'Assets/macOs.iconset/icon_32x32@2x.png', + width: 64, + height: 64, + }, + { + source: 7, + dest: 'Assets/macOs.iconset/icon_128x128.png', + width: 128, + height: 128, + }, + { + source: 7, + dest: 'Assets/macOs.iconset/icon_128x128@2x.png', + width: 256, + height: 256, + }, + { + source: 7, + dest: 'Assets/macOs.iconset/icon_256x256.png', + width: 256, + height: 256, + }, + { + source: 7, + dest: 'Assets/macOs.iconset/icon_256x256@2x.png', + width: 512, + height: 512, + }, + { + source: 7, + dest: 'Assets/macOs.iconset/icon_512x512.png', + width: 512, + height: 512, + }, + { + source: 7, + dest: 'Assets/macOs.iconset/icon_512x512@2x.png', + width: 1024, + height: 1024, + }, - { - source: 2, - dest: 'Assets/LinuxIcons/16x16.png', - width: 16, - height: 16, - }, - { - source: 3, - dest: 'Assets/LinuxIcons/24x24.png', - width: 24, - height: 24, - }, - { - source: 3, - dest: 'Assets/LinuxIcons/32x32.png', - width: 32, - height: 32, - }, - { - source: 7, - dest: 'Assets/LinuxIcons/48x48.png', - width: 48, - height: 48, - }, - { - source: 7, - dest: 'Assets/LinuxIcons/72x72.png', - width: 72, - height: 72, - }, - { - source: 7, - dest: 'Assets/LinuxIcons/96x96.png', - width: 96, - height: 96, - }, - { - source: 7, - dest: 'Assets/LinuxIcons/128x128.png', - width: 128, - height: 128, - }, - { - source: 7, - dest: 'Assets/LinuxIcons/144x144.png', - width: 144, - height: 144, - }, - { - source: 7, - dest: 'Assets/LinuxIcons/256x256.png', - width: 256, - height: 256, - }, - { - source: 7, - dest: 'Assets/LinuxIcons/512x512.png', - width: 512, - height: 512, - }, - { - source: 7, - dest: 'Assets/LinuxIcons/1024x1024.png', - width: 1024, - height: 1024, - }, + // ============================================================================ + // Linux icons + // ============================================================================ - // ============================================================================ - // PortableApps launcher - // ============================================================================ + { + source: 2, + dest: 'Assets/LinuxIcons/16x16.png', + width: 16, + height: 16, + }, + { + source: 3, + dest: 'Assets/LinuxIcons/24x24.png', + width: 24, + height: 24, + }, + { + source: 3, + dest: 'Assets/LinuxIcons/32x32.png', + width: 32, + height: 32, + }, + { + source: 7, + dest: 'Assets/LinuxIcons/48x48.png', + width: 48, + height: 48, + }, + { + source: 7, + dest: 'Assets/LinuxIcons/72x72.png', + width: 72, + height: 72, + }, + { + source: 7, + dest: 'Assets/LinuxIcons/96x96.png', + width: 96, + height: 96, + }, + { + source: 7, + dest: 'Assets/LinuxIcons/128x128.png', + width: 128, + height: 128, + }, + { + source: 7, + dest: 'Assets/LinuxIcons/144x144.png', + width: 144, + height: 144, + }, + { + source: 7, + dest: 'Assets/LinuxIcons/256x256.png', + width: 256, + height: 256, + }, + { + source: 7, + dest: 'Assets/LinuxIcons/512x512.png', + width: 512, + height: 512, + }, + { + source: 7, + dest: 'Assets/LinuxIcons/1024x1024.png', + width: 1024, + height: 1024, + }, - { - source: 5, - dest: 'packages/tools/PortableAppsLauncher/App/AppInfo/appicon.ico', - }, - { - source: 2, - dest: 'packages/tools/PortableAppsLauncher/App/AppInfo/appicon_16.png', - }, - { - source: 3, - dest: 'packages/tools/PortableAppsLauncher/App/AppInfo/appicon_32.png', - width: 32, - height: 32, - }, - { - source: 4, - dest: 'packages/tools/PortableAppsLauncher/App/AppInfo/appicon_75.png', - width: 75, - height: 75, - }, - { - source: 4, - dest: 'packages/tools/PortableAppsLauncher/App/AppInfo/appicon_128.png', - width: 128, - height: 128, - }, - { - source: 4, - dest: 'packages/tools/PortableAppsLauncher/App/AppInfo/Launcher/splash.jpg', - width: 144, - height: 144, - }, + // ============================================================================ + // PortableApps launcher + // ============================================================================ - // ============================================================================ - // Windows tiles - // ============================================================================ + { + source: 5, + dest: 'packages/tools/PortableAppsLauncher/App/AppInfo/appicon.ico', + }, + { + source: 2, + dest: 'packages/tools/PortableAppsLauncher/App/AppInfo/appicon_16.png', + }, + { + source: 3, + dest: 'packages/tools/PortableAppsLauncher/App/AppInfo/appicon_32.png', + width: 32, + height: 32, + }, + { + source: 4, + dest: 'packages/tools/PortableAppsLauncher/App/AppInfo/appicon_75.png', + width: 75, + height: 75, + }, + { + source: 4, + dest: 'packages/tools/PortableAppsLauncher/App/AppInfo/appicon_128.png', + width: 128, + height: 128, + }, + { + source: 4, + dest: 'packages/tools/PortableAppsLauncher/App/AppInfo/Launcher/splash.jpg', + width: 144, + height: 144, + }, - { - source: 6, - dest: 'packages/app-desktop/build-win/icons/Square150x150Logo.png', - width: 150, - height: 150, - iconWidth: 99, - iconHeight: 75, - }, - { - source: 6, - dest: 'packages/app-desktop/build-win/icons/SmallTile.png', - width: 70, - height: 70, - iconWidth: 46, - iconHeight: 46, - }, + // ============================================================================ + // Windows tiles + // ============================================================================ - // ============================================================================ - // Website images - // ============================================================================ + { + source: 6, + dest: 'packages/app-desktop/build-win/icons/Square150x150Logo.png', + width: 150, + height: 150, + iconWidth: 99, + iconHeight: 75, + }, + { + source: 6, + dest: 'packages/app-desktop/build-win/icons/SmallTile.png', + width: 70, + height: 70, + iconWidth: 46, + iconHeight: 46, + }, - { - source: 8, - dest: 'Assets/WebsiteAssets/images/home-top-img-4x.webp', - width: 4820, - height: 2938, - }, - { - source: 8, - dest: 'Assets/WebsiteAssets/images/home-top-img-2x.png', - width: 2388, - height: 1456, - }, - { - source: 8, - dest: 'Assets/WebsiteAssets/images/home-top-img-2x.webp', - width: 2388, - height: 1456, - }, - { - source: 8, - dest: 'Assets/WebsiteAssets/images/home-top-img.png', - width: 1205, - height: 734, - }, - { - source: 8, - dest: 'Assets/WebsiteAssets/images/home-top-img.webp', - width: 1205, - height: 734, - }, + // ============================================================================ + // Website images + // ============================================================================ - // ============================================================================ - // Website images CN - // ============================================================================ + { + source: 8, + dest: 'Assets/WebsiteAssets/images/home-top-img-4x.webp', + width: 4820, + height: 2938, + }, + { + source: 8, + dest: 'Assets/WebsiteAssets/images/home-top-img-2x.png', + width: 2388, + height: 1456, + }, + { + source: 8, + dest: 'Assets/WebsiteAssets/images/home-top-img-2x.webp', + width: 2388, + height: 1456, + }, + { + source: 8, + dest: 'Assets/WebsiteAssets/images/home-top-img.png', + width: 1205, + height: 734, + }, + { + source: 8, + dest: 'Assets/WebsiteAssets/images/home-top-img.webp', + width: 1205, + height: 734, + }, - { - source: 9, - dest: 'Assets/WebsiteAssets/images/home-top-img-cn-4x.webp', - width: 4820, - height: 2938, - }, - { - source: 9, - dest: 'Assets/WebsiteAssets/images/home-top-img-cn-2x.png', - width: 2388, - height: 1456, - }, - { - source: 9, - dest: 'Assets/WebsiteAssets/images/home-top-img-cn-2x.webp', - width: 2388, - height: 1456, - }, - { - source: 9, - dest: 'Assets/WebsiteAssets/images/home-top-img-cn.png', - width: 1205, - height: 734, - }, - { - source: 9, - dest: 'Assets/WebsiteAssets/images/home-top-img-cn.webp', - width: 1205, - height: 734, - }, + // ============================================================================ + // Website images CN + // ============================================================================ - // ============================================================================ - // Joplin Server Icons - // ============================================================================ + { + source: 9, + dest: 'Assets/WebsiteAssets/images/home-top-img-cn-4x.webp', + width: 4820, + height: 2938, + }, + { + source: 9, + dest: 'Assets/WebsiteAssets/images/home-top-img-cn-2x.png', + width: 2388, + height: 1456, + }, + { + source: 9, + dest: 'Assets/WebsiteAssets/images/home-top-img-cn-2x.webp', + width: 2388, + height: 1456, + }, + { + source: 9, + dest: 'Assets/WebsiteAssets/images/home-top-img-cn.png', + width: 1205, + height: 734, + }, + { + source: 9, + dest: 'Assets/WebsiteAssets/images/home-top-img-cn.webp', + width: 1205, + height: 734, + }, - { - source: 10, - dest: 'packages/server/public/images/icons/server/icon-512.png', - width: 512, - height: 512, - }, - { - source: 10, - dest: 'packages/server/public/images/icons/server/icon-192.png', - width: 192, - height: 192, - }, - { - source: 10, - dest: 'packages/server/public/images/icons/server/icon-180.png', - width: 180, - height: 180, - }, - { - source: 10, - dest: 'packages/server/public/images/server_logo.png', - width: 512, - height: 512, - }, - { - source: 10, - dest: 'packages/server/public/images/icons/server/icon-32.png', - width: 32, - height: 32, - imageName: 'joplinServer32', - }, - { - source: 10, - dest: 'packages/server/public/images/icons/server/icon.svg', - }, - { - source: 10, - dest: 'packages/server/public/images/icons/server/favicon.ico', - images: ['joplinServer32'], - }, + // ============================================================================ + // Joplin Server Icons + // ============================================================================ - // ============================================================================ - // Joplin Cloud Icons - // ============================================================================ + { + source: 10, + dest: 'packages/server/public/images/icons/server/icon-512.png', + width: 512, + height: 512, + }, + { + source: 10, + dest: 'packages/server/public/images/icons/server/icon-192.png', + width: 192, + height: 192, + }, + { + source: 10, + dest: 'packages/server/public/images/icons/server/icon-180.png', + width: 180, + height: 180, + }, + { + source: 10, + dest: 'packages/server/public/images/server_logo.png', + width: 512, + height: 512, + }, + { + source: 10, + dest: 'packages/server/public/images/icons/server/icon-32.png', + width: 32, + height: 32, + imageName: 'joplinServer32', + }, + { + source: 10, + dest: 'packages/server/public/images/icons/server/icon.svg', + }, + { + source: 10, + dest: 'packages/server/public/images/icons/server/favicon.ico', + images: ['joplinServer32'], + }, - { - source: 11, - dest: 'packages/server/public/images/icons/cloud/icon-512.png', - width: 512, - height: 512, - }, - { - source: 11, - dest: 'packages/server/public/images/icons/cloud/icon-192.png', - width: 192, - height: 192, - }, - { - source: 11, - dest: 'packages/server/public/images/icons/cloud/icon-180.png', - width: 180, - height: 180, - }, - { - source: 11, - dest: 'packages/server/public/images/cloud_logo.png', - width: 512, - height: 512, - }, - { - source: 12, - dest: 'packages/server/public/images/icons/cloud/icon-32.png', - width: 32, - height: 32, - imageName: 'joplinCloud32', - }, - { - source: 12, - dest: 'packages/server/public/images/icons/cloud/icon.svg', - }, - { - source: 12, - dest: 'packages/server/public/images/icons/cloud/favicon.ico', - images: ['joplinCloud32'], - }, -]; + // ============================================================================ + // Joplin Cloud Icons + // ============================================================================ + + { + source: 11, + dest: 'packages/server/public/images/icons/cloud/icon-512.png', + width: 512, + height: 512, + }, + { + source: 11, + dest: 'packages/server/public/images/icons/cloud/icon-192.png', + width: 192, + height: 192, + }, + { + source: 11, + dest: 'packages/server/public/images/icons/cloud/icon-180.png', + width: 180, + height: 180, + }, + { + source: 11, + dest: 'packages/server/public/images/cloud_logo.png', + width: 512, + height: 512, + }, + { + source: 12, + dest: 'packages/server/public/images/icons/cloud/icon-32.png', + width: 32, + height: 32, + imageName: 'joplinCloud32', + }, + { + source: 12, + dest: 'packages/server/public/images/icons/cloud/icon.svg', + }, + { + source: 12, + dest: 'packages/server/public/images/icons/cloud/favicon.ico', + images: ['joplinCloud32'], + }, + ]; +}; const md5Dir = async (dirPath: string): Promise => { const files = await readdir(dirPath); @@ -601,6 +542,7 @@ async function main() { const sourceImageDir = `${rootDir}/Assets/ImageSources`; const resultFilePath = `${__dirname}/generate-images.json`; const results: Results = await readResults(resultFilePath); + const operations = await getOperations(rootDir); for (const operation of operations) { const source = sourceById(operation.source); From 23254e6ffd95ed36ca4ad9afa1ae1c72477b2d32 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 16 Mar 2025 10:25:28 +0000 Subject: [PATCH 050/158] Desktop release v3.3.3 --- packages/app-desktop/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/app-desktop/package.json b/packages/app-desktop/package.json index fc0f23b061..0a08a40689 100644 --- a/packages/app-desktop/package.json +++ b/packages/app-desktop/package.json @@ -1,6 +1,6 @@ { "name": "@joplin/app-desktop", - "version": "3.3.2", + "version": "3.3.3", "description": "Joplin for Desktop", "main": "main.js", "private": true, From d7d6fd5ccd9eb88f124126ec4c7256fab187a8c9 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 16 Mar 2025 10:49:01 +0000 Subject: [PATCH 051/158] Android 3.3.3 --- packages/app-mobile/android/app/build.gradle | 4 ++-- readme/about/changelog/android.md | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/app-mobile/android/app/build.gradle b/packages/app-mobile/android/app/build.gradle index 96bba67344..b1c4c40786 100644 --- a/packages/app-mobile/android/app/build.gradle +++ b/packages/app-mobile/android/app/build.gradle @@ -86,8 +86,8 @@ android { applicationId "net.cozic.joplin" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 2097765 - versionName "3.3.2" + versionCode 2097766 + versionName "3.3.3" ndk { abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64" } diff --git a/readme/about/changelog/android.md b/readme/about/changelog/android.md index a05dd88597..44bffe6d08 100644 --- a/readme/about/changelog/android.md +++ b/readme/about/changelog/android.md @@ -1,5 +1,15 @@ # Joplin Android Changelog +## [android-v3.3.3](https://github.com/laurent22/joplin/releases/tag/android-v3.3.3) (Pre-release) - 2025-03-16T10:29:52Z + +- New: Add setting migration for ocr.enabled (ab86b95) +- Improved: Accessibility: Improve focus handling in the note actions menu and modal dialogs (#11929 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Improved: Accessibility: Make default modal close button accessible (#11957 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Improved: Voice typing: Transcribe more unprocessed audio after pressing "done" (#11960) (#11956 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Fixed: Accessibility: Fix missing label on note actions menu dismiss button (#11954 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Fixed: Make tab size consistent between Markdown editor and viewer (and RTE) (#11940) (#11673) +- Fixed: Voice typing: Fix potential output duplication when finalizing voice typing (#11953 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) + ## [android-v3.3.2](https://github.com/laurent22/joplin/releases/tag/android-v3.3.2) (Pre-release) - 2025-03-03T22:35:08Z - Improved: Improve encryption config screen accessibility (#11874) (#11846 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) From d735cf64e0a0960095683f724ec4befb39b8dc0c Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 16 Mar 2025 11:46:09 +0000 Subject: [PATCH 052/158] Chore: Fixing iOS build --- packages/app-mobile/ios/.xcode.env | 5 ++++- packages/tools/release-ios.ts | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/app-mobile/ios/.xcode.env b/packages/app-mobile/ios/.xcode.env index b32032ca15..4d27f3bf56 100644 --- a/packages/app-mobile/ios/.xcode.env +++ b/packages/app-mobile/ios/.xcode.env @@ -7,4 +7,7 @@ # Customize the NODE_BINARY variable here. # For example, to use nvm with brew, add the following line # . "$(brew --prefix nvm)/nvm.sh" --no-use -export NODE_BINARY=$(command -v node) + +# Note: `$(command -v node)` doesn't work so hardcode the path here - but it means it needs to be +# manually updated when Node is upgraded. +export NODE_BINARY=/opt/homebrew/opt/node@20/bin/node diff --git a/packages/tools/release-ios.ts b/packages/tools/release-ios.ts index 55c9320609..5b0febd4cb 100644 --- a/packages/tools/release-ios.ts +++ b/packages/tools/release-ios.ts @@ -80,6 +80,13 @@ async function main() { await warningMessage(); + // React Native caches a path to Node in there, which appears to point to a copy of the + // executable in a temp folder. If those temp folders are deleted it will still try to use that + // path and fail. Running "Clean build" won't remove `.xcode.env.local` so it's safer to always + // delete it, since if there's an issue the error makes no sense whatsoever, and several hours + // will be lost trying to fix the issue. + await fs.remove(`${mobileDir}/ios/Pods/../.xcode.env.local`); + const pbxprojFilePath = `${mobileDir}/ios/Joplin.xcodeproj/project.pbxproj`; await checkDeploymentTargets(pbxprojFilePath); From 6a22ffbcb1a96a921cc5bc7148e0a345a39e7254 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 16 Mar 2025 11:47:09 +0000 Subject: [PATCH 053/158] iOS 13.3.2 --- .../ios/Joplin.xcodeproj/project.pbxproj | 16 ++++++++-------- readme/about/changelog/ios.md | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/packages/app-mobile/ios/Joplin.xcodeproj/project.pbxproj b/packages/app-mobile/ios/Joplin.xcodeproj/project.pbxproj index 0b9a7ba33c..1c687598fc 100644 --- a/packages/app-mobile/ios/Joplin.xcodeproj/project.pbxproj +++ b/packages/app-mobile/ios/Joplin.xcodeproj/project.pbxproj @@ -535,13 +535,13 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Joplin/Joplin.entitlements; - CURRENT_PROJECT_VERSION = 134; + CURRENT_PROJECT_VERSION = 135; DEVELOPMENT_TEAM = A9BXAFS6CT; ENABLE_BITCODE = NO; INFOPLIST_FILE = Joplin/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.4; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MARKETING_VERSION = 13.3.1; + MARKETING_VERSION = 13.3.2; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", @@ -567,12 +567,12 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Joplin/Joplin.entitlements; - CURRENT_PROJECT_VERSION = 134; + CURRENT_PROJECT_VERSION = 135; DEVELOPMENT_TEAM = A9BXAFS6CT; INFOPLIST_FILE = Joplin/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.4; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MARKETING_VERSION = 13.3.1; + MARKETING_VERSION = 13.3.2; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", @@ -758,14 +758,14 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 134; + CURRENT_PROJECT_VERSION = 135; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = A9BXAFS6CT; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = ShareExtension/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.4; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 13.3.1; + MARKETING_VERSION = 13.3.2; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; OTHER_LDFLAGS = ( @@ -797,14 +797,14 @@ CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 134; + CURRENT_PROJECT_VERSION = 135; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = A9BXAFS6CT; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = ShareExtension/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.4; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 13.3.1; + MARKETING_VERSION = 13.3.2; MTL_FAST_MATH = YES; OTHER_LDFLAGS = ( "$(inherited)", diff --git a/readme/about/changelog/ios.md b/readme/about/changelog/ios.md index fd222b784d..e433bc8bb4 100644 --- a/readme/about/changelog/ios.md +++ b/readme/about/changelog/ios.md @@ -1,5 +1,21 @@ # Joplin iOS Changelog +## [ios-v13.3.2](https://github.com/laurent22/joplin/releases/tag/ios-v13.3.2) - 2025-03-16T11:47:05Z + +- New: Add setting migration for ocr.enabled (ab86b95) +- Improved: Accessibility: Improve focus handling in the note actions menu and modal dialogs (#11929 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Improved: Accessibility: Make default modal close button accessible (#11957 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Improved: Improve encryption config screen accessibility (#11874) (#11846 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Improved: Re-Add iOS Dark Icon (#11943 by [@itzTheMeow](https://github.com/itzTheMeow)) +- Improved: Updated packages @bam.tech/react-native-image-resizer (v3.0.11) +- Fixed: Accessibility: Fix "new note" and "new to-do" buttons are focusable even while invisible (#11899 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Fixed: Accessibility: Fix focus gets stuck on "Attach" in the note actions menu (#11958 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Fixed: Accessibility: Fix missing label on note actions menu dismiss button (#11954 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Fixed: Accessibility: Fix plugins can't be installed using VoiceOver (#11931 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Fixed: Fix disabled encryption keys list showing enabled keys (#11861) (#11858 by [@pedr](https://github.com/pedr)) +- Fixed: Fix voice recorder crash (#11876) (#11864 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Fixed: Make tab size consistent between Markdown editor and viewer (and RTE) (#11940) (#11673) + ## [ios-v13.3.1](https://github.com/laurent22/joplin/releases/tag/ios-v13.3.1) - 2025-02-19T16:04:34Z - New: Add support for plugin editor views (#11831) From 88d1d4b7d1b4c45793506597e5ca9b628075933f Mon Sep 17 00:00:00 2001 From: Joplin Bot Date: Sun, 16 Mar 2025 12:54:34 +0000 Subject: [PATCH 054/158] Doc: Auto-update documentation Auto-updated using release-website.sh --- packages/tools/postPreReleasesToForum.json | 5 ++++- readme/about/changelog/desktop.md | 26 ++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/packages/tools/postPreReleasesToForum.json b/packages/tools/postPreReleasesToForum.json index f0a042381b..3416982b4f 100644 --- a/packages/tools/postPreReleasesToForum.json +++ b/packages/tools/postPreReleasesToForum.json @@ -135,6 +135,9 @@ "android-v3.3.1": true, "ios-v13.3.1": true, "v3.2.13": true, - "android-v3.3.2": true + "android-v3.3.2": true, + "v3.3.3": true, + "android-v3.3.3": true, + "ios-v13.3.2": true } } \ No newline at end of file diff --git a/readme/about/changelog/desktop.md b/readme/about/changelog/desktop.md index c4be1f38c2..0320fa6bb4 100644 --- a/readme/about/changelog/desktop.md +++ b/readme/about/changelog/desktop.md @@ -1,5 +1,31 @@ # Joplin Desktop Changelog +## [v3.3.3](https://github.com/laurent22/joplin/releases/tag/v3.3.3) (Pre-release) - 2025-03-16T11:52:33Z + +- New: Accessibility: Add a menu item that moves focus to the note viewer ([#11967](https://github.com/laurent22/joplin/issues/11967) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- New: Accessibility: Add error indication on Note properties ([#11784](https://github.com/laurent22/joplin/issues/11784) by [@pedr](https://github.com/pedr)) +- New: Accessibility: Add more standard keyboard shortcuts for the notebook sidebar ([#11892](https://github.com/laurent22/joplin/issues/11892) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- New: Add a button to collapse or expand all folders ([#11905](https://github.com/laurent22/joplin/issues/11905)) +- New: Add dialog to select a note and link to it ([#11891](https://github.com/laurent22/joplin/issues/11891)) +- New: Add setting migration for ocr.enabled ([ab86b95](https://github.com/laurent22/joplin/commit/ab86b95)) +- New: Add support for multiple instances ([#11963](https://github.com/laurent22/joplin/issues/11963)) +- New: Added keyboard shortcut and menu item for toggleEditorPlugin command ([7e8dee4](https://github.com/laurent22/joplin/commit/7e8dee4)) +- New: Plugins: Add support for `joplin.shouldUseDarkColors` API ([fe67a44](https://github.com/laurent22/joplin/commit/fe67a44)) +- Improved: Accessibility: Improve "toggle all notebooks" accessibility ([#11918](https://github.com/laurent22/joplin/issues/11918) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Improved: Add "Disable synchronisation" to Joplin Cloud prompt message ([#11705](https://github.com/laurent22/joplin/issues/11705)) ([#11696](https://github.com/laurent22/joplin/issues/11696) by [@Vortrix5](https://github.com/Vortrix5)) +- Improved: Improve Rich Text Editor toolbar structure ([#11869](https://github.com/laurent22/joplin/issues/11869)) ([#11663](https://github.com/laurent22/joplin/issues/11663) by [@j-scheitler1](https://github.com/j-scheitler1)) +- Improved: Improve download in install script ([#11921](https://github.com/laurent22/joplin/issues/11921) by Helmut K. C. Tessarek) +- Improved: Make "toggle all folders" button also expand the folder list ([#11917](https://github.com/laurent22/joplin/issues/11917) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Improved: Plugins: Mark the LanguageTool Integration plugin as incompatible ([#11715](https://github.com/laurent22/joplin/issues/11715)) ([#11710](https://github.com/laurent22/joplin/issues/11710) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Improved: Upgrade to Electron 35.0.1 ([#11968](https://github.com/laurent22/joplin/issues/11968) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Fixed: Fix adding tags to a note through drag-and-drop ([#11911](https://github.com/laurent22/joplin/issues/11911) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Fixed: Fix ctrl-p doesn't open the goto anything dialog in the Rich Text Editor ([#11926](https://github.com/laurent22/joplin/issues/11926)) ([#11894](https://github.com/laurent22/joplin/issues/11894) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Fixed: Fix issue with GotoAnything that would prevent it from highlighting search results in note titles ([#11888](https://github.com/laurent22/joplin/issues/11888)) +- Fixed: Import audio from OneNote as file links ([#11942](https://github.com/laurent22/joplin/issues/11942)) ([#11939](https://github.com/laurent22/joplin/issues/11939) by [@pedr](https://github.com/pedr)) +- Fixed: Make tab size consistent between Markdown editor and viewer (and RTE) ([#11940](https://github.com/laurent22/joplin/issues/11940)) ([#11673](https://github.com/laurent22/joplin/issues/11673)) +- Fixed: Preserve attachment file extensions regardless of the mime type ([#11852](https://github.com/laurent22/joplin/issues/11852)) ([#11759](https://github.com/laurent22/joplin/issues/11759) by [@pedr](https://github.com/pedr)) +- Fixed: Sharing a notebook with nobody prints "No user with ID public_key" ([#11932](https://github.com/laurent22/joplin/issues/11932)) ([#11923](https://github.com/laurent22/joplin/issues/11923) by [@Paramesh-T-S](https://github.com/Paramesh-T-S)) + ## [v3.2.13](https://github.com/laurent22/joplin/releases/tag/v3.2.13) - 2025-02-28T14:38:21Z - Improved: Plugins: Mark the LanguageTool Integration plugin as incompatible ([#11715](https://github.com/laurent22/joplin/issues/11715)) ([#11710](https://github.com/laurent22/joplin/issues/11710) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) From 224b4f619ab5dfffc3c913457227317041d44a97 Mon Sep 17 00:00:00 2001 From: marph91 Date: Sun, 16 Mar 2025 23:22:57 +0100 Subject: [PATCH 055/158] Docs: update "Importing from other applications" help section (#11969) Co-authored-by: Laurent Cozic --- readme/apps/import_export.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/readme/apps/import_export.md b/readme/apps/import_export.md index 2274c01d8e..e4e9995ab5 100644 --- a/readme/apps/import_export.md +++ b/readme/apps/import_export.md @@ -48,15 +48,10 @@ Joplin can also import OneNote notebooks. To do this: ### Importing from other applications -In general the way to import notes from any application into Joplin is to convert the notes to ENEX files (Evernote format) and to import these ENEX files into Joplin using the method above. Most note-taking applications support ENEX files so it should be relatively straightforward. For help about specific applications, see below: - -* Standard Notes: Please see [this tutorial](https://programadorwebvalencia.com/migrate-notes-from-standard-notes-to-joplin/) -* Tomboy Notes: Export the notes to ENEX files [as described here](https://askubuntu.com/questions/243691/how-can-i-export-my-tomboy-notes-into-evernote/608551) for example, and import these ENEX files into Joplin. -* OneNote: First [import the notes from OneNote into Evernote](https://discussion.evernote.com/topic/107736-is-there-a-way-to-import-from-onenote-into-evernote-on-the-mac/). Then export the ENEX file from Evernote and import it into Joplin. -* NixNote: Synchronise with Evernote, then export the ENEX files and import them into Joplin. More info [in this thread](https://discourse.joplinapp.org/t/import-from-nixnote/183/3). +In general the way to import notes from other applications into Joplin is to convert the notes to ENEX files (Evernote format), HTML or Markdown, and to import these files into Joplin. For help about specific applications, see this wiki document: [Importing notes from other notebook applications](https://discourse.joplinapp.org/t/importing-notes-from-other-notebook-applications/22425). ## Exporting Joplin can export to the JEX format (Joplin Export file), which is a tar file that can contain multiple notes, notebooks, etc. This is a lossless format in that all the notes, but also metadata such as geo-location, updated time, tags, etc. are preserved. This format is convenient for backup purposes and can be re-imported into Joplin. A "raw" format is also available. This is the same as the JEX format except that the data is saved to a directory and each item represented by a single file. -Joplin is also capable of exporting to a number of other formats including HTML and PDF which can be done for single notes, notebooks or everything. \ No newline at end of file +Joplin is also capable of exporting to a number of other formats including HTML and PDF which can be done for single notes, notebooks or everything. From d40c9d3ff946fb6dd827d9c511ced99d64f4ecb4 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Tue, 18 Mar 2025 16:08:38 +0000 Subject: [PATCH 056/158] Doc: Add YouTube link to doc --- README.md | 3 ++- packages/doc-builder/docusaurus.config.js | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5a0fe08e3b..1c16c02afe 100644 --- a/README.md +++ b/README.md @@ -50,9 +50,10 @@ Please see the [donation page](https://github.com/laurent22/joplin/blob/dev/read Name | Description --- | --- [Support Forum](https://discourse.joplinapp.org/) | This is the main place for general discussion about Joplin, user support, software development questions, and to discuss new features. Also where the latest beta versions are released and discussed. +[Patreon page](https://www.patreon.com/joplin) |The latest news are often posted there [Bluesky feed](https://bsky.app/profile/joplinapp.bsky.social) | Follow us on Bluesky [Mastodon feed](https://mastodon.social/@joplinapp) | Follow us on Mastodon -[Patreon page](https://www.patreon.com/joplin) |The latest news are often posted there +[YouTube](https://www.youtube.com/@joplinapp) | Discover information and tutorials on how to use the apps [Discord server](https://discord.gg/VSj7AFHvpq) | Our chat server [LinkedIn](https://www.linkedin.com/company/joplin) | Our LinkedIn page [Lemmy Community](https://sopuli.xyz/c/joplinapp) | Also a good place to get help diff --git a/packages/doc-builder/docusaurus.config.js b/packages/doc-builder/docusaurus.config.js index 7d163e13c0..5a0f5e5586 100644 --- a/packages/doc-builder/docusaurus.config.js +++ b/packages/doc-builder/docusaurus.config.js @@ -252,6 +252,10 @@ const config = { label: 'Patreon', href: 'https://www.patreon.com/joplin', }, + { + label: 'YouTube', + href: 'https://www.youtube.com/@joplinapp', + }, { label: 'LinkedIn', href: 'https://www.linkedin.com/company/joplin', From 04fc634092068020b79e2aa2746c944685dae01b Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Tue, 18 Mar 2025 16:09:52 +0000 Subject: [PATCH 057/158] Server: Added links to social networks --- packages/server/src/routes/index/home.ts | 39 +++++++++++++++++++ packages/server/src/views/index/home.mustache | 16 ++++++++ 2 files changed, 55 insertions(+) diff --git a/packages/server/src/routes/index/home.ts b/packages/server/src/routes/index/home.ts index edba94f713..2a7e3df99d 100644 --- a/packages/server/src/routes/index/home.ts +++ b/packages/server/src/routes/index/home.ts @@ -22,6 +22,44 @@ function setupMessageHtml() { } } +// Note: Take the list from `packages/doc-builder/docusaurus.config.js` +const socialFeeds = () => { + return [ + { + label: 'Bluesky', + href: 'https://bsky.app/profile/joplinapp.bsky.social', + }, + { + label: 'Patreon', + href: 'https://www.patreon.com/joplin', + }, + { + label: 'YouTube', + href: 'https://www.youtube.com/@joplinapp', + }, + { + label: 'LinkedIn', + href: 'https://www.linkedin.com/company/joplin', + }, + { + label: 'Discord', + href: 'https://discord.gg/VSj7AFHvpq', + }, + { + label: 'Mastodon', + href: 'https://mastodon.social/@joplinapp', + }, + { + label: 'Lemmy', + href: 'https://sopuli.xyz/c/joplinapp', + }, + { + label: 'GitHub', + href: 'https://github.com/laurent22/joplin/', + }, + ]; +}; + router.get('home', async (_path: SubPath, ctx: AppContext) => { contextSessionId(ctx); @@ -79,6 +117,7 @@ router.get('home', async (_path: SubPath, ctx: AppContext) => { betaExpiredDays: betaUserTrialPeriodDays(user.created_time, 0, 0), betaStartSubUrl: betaStartSubUrl(user.email, user.account_type), setupMessageHtml: setupMessageHtml(), + socialFeeds: socialFeeds(), }; view.cssFiles = ['index/home']; diff --git a/packages/server/src/views/index/home.mustache b/packages/server/src/views/index/home.mustache index d8698ac82f..9e6343314e 100644 --- a/packages/server/src/views/index/home.mustache +++ b/packages/server/src/views/index/home.mustache @@ -38,3 +38,19 @@ Upgrade to a Pro account to collaborate on notebooks with other people, to increase the max note size, or the max total size.

{{/showUpgradeProButton}} + +

Follow us on social media

+ +

Get the latest updates about {{global.appName}} on our social feeds!

+ + + + {{#socialFeeds}} + + + + {{/socialFeeds}} + +
+ {{label}} +
From 20f7f37b499fda1b01def6eb44beccc6e91b382f Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Thu, 20 Mar 2025 17:05:09 +0100 Subject: [PATCH 058/158] Update config.yml --- .github/ISSUE_TEMPLATE/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 65349818fa..b02e16a9dc 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,8 +1,8 @@ -blank_issues_enabled: false +blank_issues_enabled: true contact_links: - name: Feature Requests url: https://discourse.joplinapp.org/c/features/ about: Discuss ideas for new features or changes - name: Support url: https://discourse.joplinapp.org/c/support/ - about: Please ask for help here \ No newline at end of file + about: Please ask for help here From 2142373fffae0b3539bac2d6191026fec85482bd Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Fri, 21 Mar 2025 11:55:53 +0100 Subject: [PATCH 059/158] Desktop: Fixes #11989: Joplin became unusably slow on MacOS due to incorrect detection of architecture --- packages/app-desktop/gui/MainScreen.tsx | 16 ++++++++++++- .../app-mobile/utils/shim-init-react/index.ts | 8 +++++++ packages/lib/shim-init-node.ts | 9 ++++++++ packages/lib/shim.ts | 23 +++++++++++++++++++ packages/lib/versionInfo.ts | 1 + 5 files changed, 56 insertions(+), 1 deletion(-) diff --git a/packages/app-desktop/gui/MainScreen.tsx b/packages/app-desktop/gui/MainScreen.tsx index 8ad97ab806..7d9505c967 100644 --- a/packages/app-desktop/gui/MainScreen.tsx +++ b/packages/app-desktop/gui/MainScreen.tsx @@ -83,6 +83,7 @@ interface Props { notesColumns: NoteListColumns; showInvalidJoplinCloudCredential: boolean; toast: Toast; + shouldSwitchToAppleSiliconVersion: boolean; } interface ShareFolderDialogOptions { @@ -492,6 +493,11 @@ class MainScreenComponent extends React.Component { }); }; + const onDownloadAppleSiliconVersion = () => { + // The website should redirect to the correct version + shim.openUrl('https://joplinapp.org/download/'); + }; + const onRestartAndUpgrade = async () => { Setting.setValue('sync.upgradeState', Setting.SYNC_UPGRADE_STATE_MUST_DO); await Setting.saveAll(); @@ -574,6 +580,12 @@ class MainScreenComponent extends React.Component { ); } else if (this.props.mustUpgradeAppMessage) { msg = this.renderNotificationMessage(this.props.mustUpgradeAppMessage); + } else if (this.props.shouldSwitchToAppleSiliconVersion) { + msg = this.renderNotificationMessage( + _('You are running the Intel version of Joplin on an Apple Silicon processor. Download the Apple Silicon one for better performance.'), + _('Download it now'), + onDownloadAppleSiliconVersion, + ); } else if (this.props.showInvalidJoplinCloudCredential) { msg = this.renderNotificationMessage( _('Your Joplin Cloud credentials are invalid, please login.'), @@ -611,7 +623,8 @@ class MainScreenComponent extends React.Component { this.showShareInvitationNotification(props) || this.props.needApiAuth || !!this.props.mustUpgradeAppMessage || - props.showInvalidJoplinCloudCredential; + props.showInvalidJoplinCloudCredential || + props.shouldSwitchToAppleSiliconVersion; } // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied @@ -839,6 +852,7 @@ const mapStateToProps = (state: AppState) => { notesColumns: validateColumns(state.settings['notes.columns']), showInvalidJoplinCloudCredential: state.settings['sync.target'] === 10 && state.mustAuthenticate, toast: state.toast, + shouldSwitchToAppleSiliconVersion: shim.isAppleSilicon() && process.arch !== 'arm64', }; }; diff --git a/packages/app-mobile/utils/shim-init-react/index.ts b/packages/app-mobile/utils/shim-init-react/index.ts index bd57fd54ec..a47ca585fb 100644 --- a/packages/app-mobile/utils/shim-init-react/index.ts +++ b/packages/app-mobile/utils/shim-init-react/index.ts @@ -168,6 +168,14 @@ export default function shimInit() { return Platform.OS; }; + shim.isAppleSilicon = () => { + return false; + }; + + shim.platformArch = () => { + return ''; // Not supported + }; + shim.appVersion = () => { const p = require('react-native-version-info').default; return p.appVersion; diff --git a/packages/lib/shim-init-node.ts b/packages/lib/shim-init-node.ts index 0086323eeb..160868709e 100644 --- a/packages/lib/shim-init-node.ts +++ b/packages/lib/shim-init-node.ts @@ -19,6 +19,7 @@ import FileApiDriverLocal from './file-api-driver-local'; import * as mimeUtils from './mime-utils'; import BaseItem from './models/BaseItem'; import { Size } from '@joplin/utils/types'; +import { arch } from 'os'; const { _ } = require('./locale'); const http = require('http'); const https = require('https'); @@ -170,6 +171,14 @@ function shimInit(options: ShimInitOptions = null) { return Array.from(buffer); }; + shim.isAppleSilicon = () => { + return shim.isMac() && arch() === 'arm64'; + }; + + shim.platformArch = () => { + return arch(); + }; + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied shim.detectAndSetLocale = function(Setting: any) { let locale = shim.isElectron() ? shim.electronBridge().getLocale() : process.env.LANG; diff --git a/packages/lib/shim.ts b/packages/lib/shim.ts index 68d690a4be..39dfdb99f0 100644 --- a/packages/lib/shim.ts +++ b/packages/lib/shim.ts @@ -156,6 +156,12 @@ const shim = { return typeof process !== 'undefined' && process.platform === 'darwin'; }, + // Tells whether the computer **CPU** is an Apple Silicon (not whether the running version was + // built for ARM64) + isAppleSilicon: (): boolean => { + throw new Error('Not implemented: isAppleSilicon'); + }, + platformName: () => { if (shim.isReactNative()) return shim.mobilePlatform(); if (shim.isMac()) return 'darwin'; @@ -166,6 +172,23 @@ const shim = { throw new Error('Cannot determine platform'); }, + // Tells the computer CPU architecture. Which if different from the architecture the running + // version was built for. For example, the laptop CPU may be an ARM64, while the version was + // built for x64 architecture. Here we want to know the laptop CPU. + platformArch: (): string => { + throw new Error('Not implemented: platformArch'); + }, + + deviceString: () => { + const output: string[] = []; + + output.push(shim.platformName()); + + if (shim.platformArch()) output.push(shim.platformArch()); + + return output.join(', '); + }, + // "ios" or "android", or "" if not on mobile mobilePlatform: () => { return ''; // Default if we're not on mobile (React Native) diff --git a/packages/lib/versionInfo.ts b/packages/lib/versionInfo.ts index 3b1f48ed73..7c111ebaf1 100644 --- a/packages/lib/versionInfo.ts +++ b/packages/lib/versionInfo.ts @@ -85,6 +85,7 @@ export default function versionInfo(packageInfo: PackageInfo, plugins: Plugins) const body = [ _('%s %s (%s, %s)', p.name, p.version, Setting.value('env'), shim.platformName()), '', + _('Device: %s', shim.deviceString()), _('Client ID: %s', Setting.value('clientId')), _('Sync Version: %s', Setting.value('syncVersion')), _('Profile Version: %s', reg.db().version()), From 808eb7d49abaad4baf657486f71fec9f986daec3 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Fri, 21 Mar 2025 12:08:09 +0100 Subject: [PATCH 060/158] Chore: Resolves #11993: Display a message explaining why the app did not start in dev mode --- packages/app-desktop/ElectronAppWrapper.ts | 3 ++- packages/utils/fs.ts | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/app-desktop/ElectronAppWrapper.ts b/packages/app-desktop/ElectronAppWrapper.ts index 40eca9ad3f..c175376d5c 100644 --- a/packages/app-desktop/ElectronAppWrapper.ts +++ b/packages/app-desktop/ElectronAppWrapper.ts @@ -20,7 +20,7 @@ import handleCustomProtocols, { CustomProtocolHandler } from './utils/customProt import { clearTimeout, setTimeout } from 'timers'; import { resolve } from 'path'; import { defaultWindowId } from '@joplin/lib/reducer'; -import { msleep } from '@joplin/utils/time'; +import { msleep, Second } from '@joplin/utils/time'; interface RendererProcessQuitReply { canClose: boolean; @@ -674,6 +674,7 @@ export default class ElectronAppWrapper { await this.sendCrossAppIpcMessage(message); this.quit(); + if (this.env() === 'dev') console.warn(`Closing the application because another instance is already running, or the previous instance was force-quit within the last ${Math.round(this.profileLocker_.options.interval / Second)} seconds.`); return true; } diff --git a/packages/utils/fs.ts b/packages/utils/fs.ts index c81a386a76..d1153dea77 100644 --- a/packages/utils/fs.ts +++ b/packages/utils/fs.ts @@ -40,6 +40,10 @@ export class FileLocker { this.filePath_ = filePath; } + public get options() { + return this.options_; + } + public async lock() { if (!(await this.canLock())) return false; From 5d7c78c3619ecaa79d3533bb4a334e9a4bff7429 Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Fri, 21 Mar 2025 11:00:38 -0700 Subject: [PATCH 061/158] Android: Voice typing: Improve processing with larger models (#11983) --- .../app/src/main/cpp/utils/WhisperSession.cpp | 163 ++++++++++++++---- .../app/src/main/cpp/utils/WhisperSession.h | 18 +- .../src/main/cpp/utils/findLongestSilence.cpp | 30 +++- .../src/main/cpp/utils/findLongestSilence.h | 23 ++- .../cpp/utils/findLongestSilence_test.cpp | 18 +- .../app/src/main/cpp/whisperWrapper.cpp | 55 ++++-- .../net/cozic/joplin/audio/AudioRecorder.kt | 4 +- .../cozic/joplin/audio/NativeWhisperLib.kt | 29 +++- .../joplin/audio/SpeechToTextConverter.kt | 8 +- .../cozic/joplin/audio/SpeechToTextPackage.kt | 4 +- .../audio/SpeechToTextSessionManager.kt | 3 +- .../voiceTyping/SpeechToTextBanner.tsx | 3 + .../services/voiceTyping/whisper.test.ts | 1 + .../services/voiceTyping/whisper.ts | 34 +++- 14 files changed, 308 insertions(+), 85 deletions(-) diff --git a/packages/app-mobile/android/app/src/main/cpp/utils/WhisperSession.cpp b/packages/app-mobile/android/app/src/main/cpp/utils/WhisperSession.cpp index 4f6f0fd214..6a73978edf 100644 --- a/packages/app-mobile/android/app/src/main/cpp/utils/WhisperSession.cpp +++ b/packages/app-mobile/android/app/src/main/cpp/utils/WhisperSession.cpp @@ -7,8 +7,8 @@ #include "findLongestSilence.h" #include "androidUtil.h" -WhisperSession::WhisperSession(const std::string& modelPath, std::string lang, std::string prompt) - : lang_ {std::move(lang)}, prompt_ {std::move(prompt)} { +WhisperSession::WhisperSession(const std::string& modelPath, std::string lang, std::string prompt, bool shortAudioContext) + : lang_ {std::move(lang)}, prompt_ {std::move(prompt)}, shortAudioContext_ {shortAudioContext} { whisper_context_params contextParams = whisper_context_default_params(); // Lifetime(pModelPath): Whisper.cpp creates a copy of pModelPath and stores it in a std::string. @@ -34,9 +34,9 @@ WhisperSession::buildWhisperParams_() { // WHISPER_SAMPLING_BEAM_SEARCH is an alternative to greedy: // params.beam_search = { .beam_size = 2 }; params.print_realtime = false; - // Disable timestamps: They make creating custom Whisper models more difficult: + // Disable timestamps: They make creating custom Whisper models more difficult: params.print_timestamps = false; - params.no_timestamps = true; + params.no_timestamps = true; params.print_progress = false; params.translate = false; @@ -54,6 +54,7 @@ WhisperSession::buildWhisperParams_() { params.initial_prompt = prompt_.c_str(); params.prompt_tokens = nullptr; params.prompt_n_tokens = 0; + params.audio_ctx = 0; // Lifetime: lifetime(params) < lifetime(lang_) = lifetime(this). params.language = lang_.c_str(); @@ -68,7 +69,26 @@ WhisperSession::transcribe_(const std::vector& audio, size_t transcribeCo return ""; } + float seconds = static_cast(audio.size()) / WHISPER_SAMPLE_RATE; + if (seconds > 30.0f) { + LOGW("Warning: Audio is longer than 30 seconds. Not all audio will be transcribed"); + } + whisper_full_params params = buildWhisperParams_(); + + // If supported by the model, allow shortening the transcription. This can significantly + // improve performance, but requires a fine-tuned model. + // See https://github.com/futo-org/whisper-acft + if (this->shortAudioContext_) { + // audio_ctx: 1500 every 30 seconds (50 units in one second). + // See https://github.com/futo-org/whisper-acft/issues/6 + float padding = 64.0f; + params.audio_ctx = static_cast(seconds * (1500.0f / 30.0f) + padding); + + if (params.audio_ctx > 1500) { + params.audio_ctx = 1500; + } + } whisper_reset_timings(pContext_); transcribeCount = std::min(audio.size(), transcribeCount); @@ -104,51 +124,130 @@ WhisperSession::splitAndTranscribeBefore_(int transcribeUpTo, int trimTo) { return result; } -std::string -WhisperSession::transcribeNextChunk(const float *pAudio, int sizeAudio) { - std::string finalizedContent; +bool WhisperSession::isBufferSilent_() { + int toleranceSamples = WHISPER_SAMPLE_RATE / 8; // 0.125s + auto silence = findLongestSilence( + audioBuffer_, + LongestSilenceOptions { + .sampleRate = WHISPER_SAMPLE_RATE, + .minSilenceLengthSeconds = 0.0f, + .maximumSilenceStartSamples = toleranceSamples, // 0.5s + .returnFirstMatch = true + } + ); + return silence.end >= audioBuffer_.size() - toleranceSamples; +} - // Update the local audio buffer - for (int i = 0; i < sizeAudio; i++) { - audioBuffer_.push_back(pAudio[i]); +std::string +WhisperSession::transcribeNextChunkNoPreview_() { + std::stringstream result; + + // Handles a silence detected between (splitStart, splitEnd). + auto splitAndProcess = [&] (int splitStart, int splitEnd) { + int tolerance = WHISPER_SAMPLE_RATE / 20; // 0.05s + bool isCompletelySilent = splitStart < tolerance && splitEnd > audioBuffer_.size() - tolerance; + LOGD("WhisperSession: Found silence range from %.2f -> %.2f", splitStart / (float) WHISPER_SAMPLE_RATE, splitEnd / (float) WHISPER_SAMPLE_RATE); + + if (isCompletelySilent) { + audioBuffer_.clear(); + return false; + } else if (splitEnd > tolerance) { // Anything to transcribe? + result << splitAndTranscribeBefore_(splitStart, splitEnd) << "\n\n"; + return true; + } + + return false; + }; + + int maximumSamples = WHISPER_SAMPLE_RATE * 25; + + // Handle paragraph breaks indicated by long pauses + while (audioBuffer_.size() > WHISPER_SAMPLE_RATE * 3) { + LOGD("WhisperSession: Checking for a longer pauses."); + // Allow brief pauses to create new paragraphs: + float minSilenceSeconds = 1.5f; + auto splitPoint = findLongestSilence( + audioBuffer_, + LongestSilenceOptions { + .sampleRate = WHISPER_SAMPLE_RATE, + .minSilenceLengthSeconds = minSilenceSeconds, + .maximumSilenceStartSamples = maximumSamples, + .returnFirstMatch = true + } + ); + if (!splitPoint.isValid) { + break; + } + if (!splitAndProcess(splitPoint.start, splitPoint.end)) { + break; + } } - // Does the audio buffer need to be split somewhere? - int maximumSamples = WHISPER_SAMPLE_RATE * 25; + // If there are no long pauses, force a paragraph break somewhere if (audioBuffer_.size() >= maximumSamples) { + LOGD("WhisperSession: Allowing shorter pauses to break."); float minSilenceSeconds = 0.3f; auto silenceRange = findLongestSilence( - audioBuffer_, WHISPER_SAMPLE_RATE, minSilenceSeconds, maximumSamples + audioBuffer_, + LongestSilenceOptions { + .sampleRate = WHISPER_SAMPLE_RATE, + .minSilenceLengthSeconds = minSilenceSeconds, + .maximumSilenceStartSamples = maximumSamples, + .returnFirstMatch = false + } ); // In this case, the audio is long enough that it needs to be split somewhere. If there's // no suitable pause available, default to splitting in the middle. int halfBufferSize = audioBuffer_.size() / 2; - int transcribeTo = silenceRange.isValid ? silenceRange.start : halfBufferSize; - int trimTo = silenceRange.isValid ? silenceRange.end : halfBufferSize; - - finalizedContent = splitAndTranscribeBefore_(transcribeTo, trimTo); - } else if (audioBuffer_.size() > WHISPER_SAMPLE_RATE * 3) { - // Allow brief pauses to create new paragraphs: - float minSilenceSeconds = 2.0f; - auto splitPoint = findLongestSilence( - audioBuffer_, WHISPER_SAMPLE_RATE, minSilenceSeconds, maximumSamples - ); - if (splitPoint.isValid) { - int tolerance = WHISPER_SAMPLE_RATE / 20; // 0.05s - bool isCompletelySilent = splitPoint.start < tolerance && splitPoint.end > audioBuffer_.size() - tolerance; - if (isCompletelySilent) { - audioBuffer_.clear(); - } else { - finalizedContent = splitAndTranscribeBefore_(splitPoint.start, splitPoint.end); - } - } + int splitStart = silenceRange.isValid ? silenceRange.start : halfBufferSize; + int splitEnd = silenceRange.isValid ? silenceRange.end : halfBufferSize; + splitAndProcess(splitStart, splitEnd); } + return result.str(); +} + + +void WhisperSession::addAudio(const float *pAudio, int sizeAudio) { + // Update the local audio buffer + for (int i = 0; i < sizeAudio; i++) { + audioBuffer_.push_back(pAudio[i]); + } +} + +std::string WhisperSession::transcribeNextChunk() { + std::string finalizedContent = transcribeNextChunkNoPreview_(); previewText_ = transcribe_(audioBuffer_, audioBuffer_.size()); return finalizedContent; } +std::string WhisperSession::transcribeAll() { + if (isBufferSilent_()) { + return ""; + } + + std::stringstream result; + + std::string transcribed; + auto update_transcribed = [&] { + transcribed = transcribeNextChunkNoPreview_(); + return !transcribed.empty(); + }; + while (update_transcribed()) { + result << transcribed << "\n\n"; + } + + // Transcribe content considered by transcribeNextChunk as partial: + if (!isBufferSilent_()) { + result << transcribe_(audioBuffer_, audioBuffer_.size()); + } + audioBuffer_.clear(); + + previewText_ = ""; + return result.str(); +} + std::string WhisperSession::getPreview() { return previewText_; } diff --git a/packages/app-mobile/android/app/src/main/cpp/utils/WhisperSession.h b/packages/app-mobile/android/app/src/main/cpp/utils/WhisperSession.h index 17a7d71b5a..4934a83974 100644 --- a/packages/app-mobile/android/app/src/main/cpp/utils/WhisperSession.h +++ b/packages/app-mobile/android/app/src/main/cpp/utils/WhisperSession.h @@ -5,9 +5,15 @@ class WhisperSession { public: - WhisperSession(const std::string& modelPath, std::string lang, std::string prompt); + WhisperSession(const std::string& modelPath, std::string lang, std::string prompt, bool shortAudioContext); ~WhisperSession(); - std::string transcribeNextChunk(const float *pAudio, int sizeAudio); + // Adds to the buffer + void addAudio(const float *pAudio, int sizeAudio); + // Returns the next finalized slice of audio (if any) and updates the preview. + std::string transcribeNextChunk(); + // Transcribes all buffered audio data that hasn't been finalized yet + std::string transcribeAll(); + // Returns the transcription of any unfinalized audio std::string getPreview(); private: @@ -17,10 +23,18 @@ private: whisper_full_params buildWhisperParams_(); std::string transcribe_(const std::vector& audio, size_t samplesToTranscribe); std::string splitAndTranscribeBefore_(int transcribeUpTo, int trimTo); + // Like transcribeNextChunk, but does not update the preview state + // and does not add a new chunk to the buffer. + // Since updating the preview state can be slow, this may be preferred + // for internal operations where the preview does not need to be kept up-to-date. + std::string transcribeNextChunkNoPreview_(); + + bool isBufferSilent_(); whisper_context *pContext_; const std::string lang_; const std::string prompt_; + const bool shortAudioContext_; std::vector audioBuffer_; }; diff --git a/packages/app-mobile/android/app/src/main/cpp/utils/findLongestSilence.cpp b/packages/app-mobile/android/app/src/main/cpp/utils/findLongestSilence.cpp index 876f5dde60..22f646ffb0 100644 --- a/packages/app-mobile/android/app/src/main/cpp/utils/findLongestSilence.cpp +++ b/packages/app-mobile/android/app/src/main/cpp/utils/findLongestSilence.cpp @@ -19,14 +19,18 @@ static void highpass(std::vector& data, int sampleRate) { SilenceRange findLongestSilence( const std::vector& audioData, - int sampleRate, - float minSilenceLengthSeconds, - int maxSilencePosition + LongestSilenceOptions options ) { + // Options variables + int sampleRate = options.sampleRate; + int maxSilencePosition = options.maximumSilenceStartSamples; + float minSilenceLengthSeconds = options.minSilenceLengthSeconds; + bool returnFirstMatch = options.returnFirstMatch; + + // State int bestCandidateLength = 0; int bestCandidateStart = -1; int bestCandidateEnd = -1; - int currentCandidateStart = -1; std::vector processedAudio { audioData }; @@ -35,7 +39,7 @@ SilenceRange findLongestSilence( // Break into windows of size `windowSize`: int windowSize = 256; int windowsPerSecond = sampleRate / windowSize; - int quietWindows = 0; + int quietWindows = 0; // Number of relatively quiet windows encountered // Finishes the current candidate for longest silence auto finalizeCandidate = [&] (int currentOffset) { @@ -86,12 +90,20 @@ SilenceRange findLongestSilence( } int minQuietWindows = static_cast(windowsPerSecond * minSilenceLengthSeconds); - if (quietWindows >= minQuietWindows && currentCandidateStart == -1) { - // Found a candidate. Start it. - currentCandidateStart = windowOffset; - } else if (quietWindows == 0) { + if (quietWindows >= minQuietWindows && currentCandidateStart == -1) { // Found silence + // Ignore the first window, which probably contains some of the start of the audio + // and the most recent window, which came after windowOffset. + int windowsToIgnore = 2; + int estimatedQuietSamples = std::max(0, quietWindows - windowsToIgnore) * windowSize; + currentCandidateStart = windowOffset - estimatedQuietSamples; + } else if (quietWindows == 0) { // Silence ended // Ended a candidate. Is it better than the best? finalizeCandidate(windowOffset); + + // Search for more candidates or return now? + if (returnFirstMatch && bestCandidateLength > 0) { + break; + } } } diff --git a/packages/app-mobile/android/app/src/main/cpp/utils/findLongestSilence.h b/packages/app-mobile/android/app/src/main/cpp/utils/findLongestSilence.h index b30a28556b..4bec6a5c1e 100644 --- a/packages/app-mobile/android/app/src/main/cpp/utils/findLongestSilence.h +++ b/packages/app-mobile/android/app/src/main/cpp/utils/findLongestSilence.h @@ -10,15 +10,24 @@ struct SilenceRange { int end; }; +struct LongestSilenceOptions { + int sampleRate; + + // Minimum length of a silence range (e.g. 3.0 seconds) + float minSilenceLengthSeconds; + + // The maximum position for a silence range to start (ignore + // all silences after this position). + int maximumSilenceStartSamples; + + // Return the first silence satisfying the conditions instead of + // the longest. + bool returnFirstMatch; +}; + SilenceRange findLongestSilence( const std::vector& audioData, - int sampleRate, - - // Minimum length of silence in seconds - float minSilenceLengthSeconds, - - // Doesn't check for silence at a position greater than maximumSilenceStart - int maximumSilenceStart + LongestSilenceOptions options ); diff --git a/packages/app-mobile/android/app/src/main/cpp/utils/findLongestSilence_test.cpp b/packages/app-mobile/android/app/src/main/cpp/utils/findLongestSilence_test.cpp index 0a8096eb90..fb91e6dd94 100644 --- a/packages/app-mobile/android/app/src/main/cpp/utils/findLongestSilence_test.cpp +++ b/packages/app-mobile/android/app/src/main/cpp/utils/findLongestSilence_test.cpp @@ -122,9 +122,12 @@ static float samplesToSeconds(int samples, int sampleRate) { static void expectNoSilence(const GeneratedAudio& audio, const std::string& testLabel) { auto silence = findLongestSilence( audio.data, - audio.sampleRate, - 0.02f, - audio.sampleCount + LongestSilenceOptions { + .sampleRate = audio.sampleRate, + .minSilenceLengthSeconds = 0.02f, + .maximumSilenceStartSamples = audio.sampleCount, + .returnFirstMatch = false, + } ); if (silence.isValid) { std::stringstream errorBuilder; @@ -141,9 +144,12 @@ static void expectNoSilence(const GeneratedAudio& audio, const std::string& test static void expectSilenceBetween(const GeneratedAudio& audio, float startTimeSeconds, float stopTimeSeconds, const std::string& testLabel) { auto silenceResult = findLongestSilence( audio.data, - audio.sampleRate, - 0.02f, - audio.sampleCount + LongestSilenceOptions { + .sampleRate = audio.sampleRate, + .minSilenceLengthSeconds = 0.02f, + .maximumSilenceStartSamples = audio.sampleCount, + .returnFirstMatch = false, + } ); if (!silenceResult.isValid) { diff --git a/packages/app-mobile/android/app/src/main/cpp/whisperWrapper.cpp b/packages/app-mobile/android/app/src/main/cpp/whisperWrapper.cpp index 4d054cbc2f..d597d39c94 100644 --- a/packages/app-mobile/android/app/src/main/cpp/whisperWrapper.cpp +++ b/packages/app-mobile/android/app/src/main/cpp/whisperWrapper.cpp @@ -54,13 +54,14 @@ Java_net_cozic_joplin_audio_NativeWhisperLib_00024Companion_init( jobject thiz, jstring modelPath, jstring language, - jstring prompt + jstring prompt, + jboolean useShortAudioContext ) { whisper_log_set(log_android, nullptr); try { auto *pSession = new WhisperSession( - stringToCXX(env, modelPath), stringToCXX(env, language), stringToCXX(env, prompt) + stringToCXX(env, modelPath), stringToCXX(env, language), stringToCXX(env, prompt), useShortAudioContext ); return (jlong) pSession; } catch (const std::exception& exception) { @@ -78,8 +79,8 @@ Java_net_cozic_joplin_audio_NativeWhisperLib_00024Companion_free(JNIEnv *env, jo } extern "C" -JNIEXPORT jstring JNICALL -Java_net_cozic_joplin_audio_NativeWhisperLib_00024Companion_fullTranscribe(JNIEnv *env, +JNIEXPORT void JNICALL +Java_net_cozic_joplin_audio_NativeWhisperLib_00024Companion_addAudio(JNIEnv *env, jobject thiz, jlong pointer, jfloatArray audio_data) { @@ -89,21 +90,55 @@ Java_net_cozic_joplin_audio_NativeWhisperLib_00024Companion_fullTranscribe(JNIEn std::string result; try { - LOGD("Starting Whisper, transcribe %d", lenAudioData); - result = pSession->transcribeNextChunk(pAudioData, lenAudioData); - auto preview = pSession->getPreview(); - LOGD("Ran Whisper. Got %s (preview %s)", result.c_str(), preview.c_str()); + pSession->addAudio(pAudioData, lenAudioData); } catch (const std::exception& exception) { - LOGW("Failed to run whisper: %s", exception.what()); + LOGW("Failed to add to audio buffer: %s", exception.what()); throwException(env, exception.what()); } // JNI_ABORT: "free the buffer without copying back the possible changes", pass 0 to copy // changes (there should be no changes) env->ReleaseFloatArrayElements(audio_data, pAudioData, JNI_ABORT); +} + +extern "C" +JNIEXPORT jstring JNICALL +Java_net_cozic_joplin_audio_NativeWhisperLib_00024Companion_transcribeNextChunk(JNIEnv *env, + jobject thiz, + jlong pointer) { + auto *pSession = reinterpret_cast (pointer); + std::string result; + + try { + result = pSession->transcribeNextChunk(); + } catch (const std::exception& exception) { + LOGW("Failed to run whisper: %s", exception.what()); + throwException(env, exception.what()); + return nullptr; + } return stringToJava(env, result); } + +extern "C" +JNIEXPORT jstring JNICALL +Java_net_cozic_joplin_audio_NativeWhisperLib_00024Companion_transcribeRemaining(JNIEnv *env, + jobject thiz, + jlong pointer) { + auto *pSession = reinterpret_cast (pointer); + std::string result; + + try { + result = pSession->transcribeAll(); + } catch (const std::exception& exception) { + LOGW("Failed to run whisper: %s", exception.what()); + throwException(env, exception.what()); + return nullptr; + } + + return stringToJava(env, result); +} + extern "C" JNIEXPORT jstring JNICALL Java_net_cozic_joplin_audio_NativeWhisperLib_00024Companion_getPreview( @@ -122,4 +157,4 @@ Java_net_cozic_joplin_audio_NativeWhisperLib_00024Companion_runTests(JNIEnv *env LOGW("Failed to run tests: %s", exception.what()); throwException(env, exception.what()); } -} \ No newline at end of file +} diff --git a/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/AudioRecorder.kt b/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/AudioRecorder.kt index 174bd0bfcd..a6f848687c 100644 --- a/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/AudioRecorder.kt +++ b/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/AudioRecorder.kt @@ -15,7 +15,9 @@ typealias AudioRecorderFactory = (context: Context)->AudioRecorder; class AudioRecorder(context: Context) : Closeable { private val sampleRate = 16_000 - private val maxLengthSeconds = 30 // Whisper supports a maximum of 30s + // Don't allow the unprocessed audio buffer to grow indefinitely -- discard + // data if longer than this: + private val maxLengthSeconds = 120 private val maxBufferSize = sampleRate * maxLengthSeconds private val buffer = FloatArray(maxBufferSize) private var bufferWriteOffset = 0 diff --git a/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/NativeWhisperLib.kt b/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/NativeWhisperLib.kt index 5cc9db59a4..0e12eaf5b6 100644 --- a/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/NativeWhisperLib.kt +++ b/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/NativeWhisperLib.kt @@ -6,6 +6,7 @@ class NativeWhisperLib( modelPath: String, languageCode: String, prompt: String, + shortAudioContext: Boolean, ) : Closeable { companion object { init { @@ -16,22 +17,40 @@ class NativeWhisperLib( // TODO: The example whisper.cpp project transfers pointers as Longs to the Kotlin code. // This seems unsafe. Try changing how this is managed. - private external fun init(modelPath: String, languageCode: String, prompt: String): Long; + private external fun init(modelPath: String, languageCode: String, prompt: String, shortAudioContext: Boolean): Long; private external fun free(pointer: Long): Unit; - private external fun fullTranscribe(pointer: Long, audioData: FloatArray): String; + private external fun addAudio(pointer: Long, audioData: FloatArray): Unit; + private external fun transcribeNextChunk(pointer: Long): String; + private external fun transcribeRemaining(pointer: Long): String; private external fun getPreview(pointer: Long): String; } private var closed = false - private val pointer: Long = init(modelPath, languageCode, prompt) + private val pointer: Long = init(modelPath, languageCode, prompt, shortAudioContext) - fun transcribe(audioData: FloatArray): String { + fun addAudio(audioData: FloatArray) { + if (closed) { + throw Exception("Cannot add audio data to a closed session") + } + + Companion.addAudio(pointer, audioData) + } + + fun transcribeNextChunk(): String { if (closed) { throw Exception("Cannot transcribe using a closed session") } - return fullTranscribe(pointer, audioData) + return Companion.transcribeNextChunk(pointer) + } + + fun transcribeRemaining(): String { + if (closed) { + throw Exception("Cannot transcribeAll using a closed session") + } + + return Companion.transcribeRemaining(pointer) } fun getPreview(): String { diff --git a/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/SpeechToTextConverter.kt b/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/SpeechToTextConverter.kt index 2988c7ad6e..84ca9fed4c 100644 --- a/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/SpeechToTextConverter.kt +++ b/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/SpeechToTextConverter.kt @@ -8,6 +8,7 @@ class SpeechToTextConverter( modelPath: String, locale: String, prompt: String, + useShortAudioCtx: Boolean, recorderFactory: AudioRecorderFactory, context: Context, ) : Closeable { @@ -17,6 +18,7 @@ class SpeechToTextConverter( modelPath, languageCode, prompt, + useShortAudioCtx, ) fun start() { @@ -25,7 +27,8 @@ class SpeechToTextConverter( private fun convert(data: FloatArray): String { Log.d("Whisper", "Pre-transcribe data of size ${data.size}") - val result = whisper.transcribe(data) + whisper.addAudio(data) + val result = whisper.transcribeNextChunk() Log.d("Whisper", "Post transcribe. Got $result") return result; } @@ -47,7 +50,8 @@ class SpeechToTextConverter( // Converts as many seconds of buffered data as possible, without waiting fun convertRemaining(): String { val buffer = recorder.pullAvailable() - return convert(buffer) + whisper.addAudio(buffer) + return whisper.transcribeRemaining() } fun getPreview(): String { diff --git a/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/SpeechToTextPackage.kt b/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/SpeechToTextPackage.kt index 12ed9c29ce..1e29d7a6e9 100644 --- a/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/SpeechToTextPackage.kt +++ b/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/SpeechToTextPackage.kt @@ -43,11 +43,11 @@ class SpeechToTextPackage : ReactPackage { } @ReactMethod - fun openSession(modelPath: String, locale: String, prompt: String, promise: Promise) { + fun openSession(modelPath: String, locale: String, prompt: String, useShortAudioCtx: Boolean, promise: Promise) { val appContext = context.applicationContext try { - val sessionId = sessionManager.openSession(modelPath, locale, prompt, appContext) + val sessionId = sessionManager.openSession(modelPath, locale, prompt, useShortAudioCtx, appContext) promise.resolve(sessionId) } catch (exception: Throwable) { promise.reject(exception) diff --git a/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/SpeechToTextSessionManager.kt b/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/SpeechToTextSessionManager.kt index bd1cdcb27c..94fca284c7 100644 --- a/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/SpeechToTextSessionManager.kt +++ b/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/SpeechToTextSessionManager.kt @@ -21,12 +21,13 @@ class SpeechToTextSessionManager( modelPath: String, locale: String, prompt: String, + useShortAudioCtx: Boolean, context: Context, ): Int { val sessionId = nextSessionId++ sessions[sessionId] = SpeechToTextSession( SpeechToTextConverter( - modelPath, locale, prompt, recorderFactory = AudioRecorder.factory, context, + modelPath, locale, prompt, useShortAudioCtx, recorderFactory = AudioRecorder.factory, context, ) ) return sessionId diff --git a/packages/app-mobile/components/voiceTyping/SpeechToTextBanner.tsx b/packages/app-mobile/components/voiceTyping/SpeechToTextBanner.tsx index 4ad5cdc509..f6980b9fd7 100644 --- a/packages/app-mobile/components/voiceTyping/SpeechToTextBanner.tsx +++ b/packages/app-mobile/components/voiceTyping/SpeechToTextBanner.tsx @@ -165,6 +165,9 @@ const SpeechToTextComponent: React.FC = props => { }; const renderPreview = () => { + if (recorderState !== RecorderState.Recording) { + return null; + } return {preview}; }; diff --git a/packages/app-mobile/services/voiceTyping/whisper.test.ts b/packages/app-mobile/services/voiceTyping/whisper.test.ts index 26628bd5a5..c032481fe3 100644 --- a/packages/app-mobile/services/voiceTyping/whisper.test.ts +++ b/packages/app-mobile/services/voiceTyping/whisper.test.ts @@ -19,6 +19,7 @@ jest.mock('react-native', () => { }), closeSession: jest.fn(), startRecording: jest.fn(), + convertAvailable: jest.fn(() => ''), }; return reactNative; diff --git a/packages/app-mobile/services/voiceTyping/whisper.ts b/packages/app-mobile/services/voiceTyping/whisper.ts index b3e662b063..698fcc5f63 100644 --- a/packages/app-mobile/services/voiceTyping/whisper.ts +++ b/packages/app-mobile/services/voiceTyping/whisper.ts @@ -13,6 +13,7 @@ const { SpeechToTextModule } = NativeModules; class WhisperConfig { public prompts: Map = new Map(); + public supportsShortAudioCtx = false; public stringReplacements: [string, string][] = []; public regexReplacements: [RegExp, string][] = []; @@ -69,6 +70,12 @@ class WhisperConfig { } }; + // Models fine-tuned as per https://github.com/futo-org/whisper-acft should have + // "shortAudioContext": true in their config.json. + if ('shortAudioContext' in json) { + this.supportsShortAudioCtx = !!json.shortAudioContext; + } + processPrompts(); processOutputSettings(); } @@ -86,15 +93,25 @@ class Whisper implements VoiceTypingSession { } private postProcessSpeech(data: string) { - data = data.trim(); + const paragraphs = data.split('\n\n'); - for (const [key, value] of this.config.stringReplacements) { - data = data.split(key).join(value); + const result = []; + for (let paragraph of paragraphs) { + paragraph = paragraph.trim(); + + for (const [key, value] of this.config.stringReplacements) { + paragraph = paragraph.split(key).join(value); + } + for (const [key, value] of this.config.regexReplacements) { + paragraph = paragraph.replace(key, value); + } + + if (paragraph) { + result.push(paragraph); + } } - for (const [key, value] of this.config.regexReplacements) { - data = data.replace(key, value); - } - return data; + + return result.join('\n\n'); } private onDataFinalize(data: string) { @@ -235,8 +252,9 @@ const whisper: VoiceTypingProvider = { throw new Error(`Model not found at path ${modelPath}`); } + logger.debug('Starting whisper session', config.supportsShortAudioCtx ? '(short audio context)' : ''); const sessionId = await SpeechToTextModule.openSession( - modelPath, locale, getPrompt(locale, config.prompts), + modelPath, locale, getPrompt(locale, config.prompts), config.supportsShortAudioCtx, ); return new Whisper(sessionId, callbacks, config); }, From c5bb88ddf4305a7ff4c42a54c3a2f05d34b5c66d Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Fri, 21 Mar 2025 11:00:49 -0700 Subject: [PATCH 062/158] Android: Resolves #11955: Voice typing: Improve re-download button UI (#11979) --- .../voiceTyping/SpeechToTextBanner.tsx | 23 ++++++++++++++++--- .../services/voiceTyping/VoiceTyping.ts | 8 +------ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/packages/app-mobile/components/voiceTyping/SpeechToTextBanner.tsx b/packages/app-mobile/components/voiceTyping/SpeechToTextBanner.tsx index f6980b9fd7..7084a4a06f 100644 --- a/packages/app-mobile/components/voiceTyping/SpeechToTextBanner.tsx +++ b/packages/app-mobile/components/voiceTyping/SpeechToTextBanner.tsx @@ -35,6 +35,7 @@ const useVoiceTyping = ({ locale, provider, onSetPreview, onText }: UseVoiceTypi const [error, setError] = useState(null); const [mustDownloadModel, setMustDownloadModel] = useState(null); const [modelIsOutdated, setModelIsOutdated] = useState(false); + const [stoppingSession, setIsStoppingSession] = useState(false); const onTextRef = useRef(onText); onTextRef.current = onText; @@ -95,14 +96,16 @@ const useVoiceTyping = ({ locale, provider, onSetPreview, onText }: UseVoiceTypi }, []); const onRequestRedownload = useCallback(async () => { + setIsStoppingSession(true); await voiceTypingRef.current?.cancel(); await builder.clearDownloads(); setMustDownloadModel(true); + setIsStoppingSession(false); setRedownloadCounter(value => value + 1); }, [builder]); return { - error, mustDownloadModel, voiceTyping, onRequestRedownload, modelIsOutdated, + error, mustDownloadModel, stoppingSession, voiceTyping, onRequestRedownload, modelIsOutdated, }; }; @@ -113,6 +116,7 @@ const SpeechToTextComponent: React.FC = props => { error: modelError, mustDownloadModel, voiceTyping, + stoppingSession, onRequestRedownload, modelIsOutdated, } = useVoiceTyping({ @@ -136,6 +140,12 @@ const SpeechToTextComponent: React.FC = props => { } }, [mustDownloadModel]); + useEffect(() => { + if (stoppingSession) { + setRecorderState(RecorderState.Processing); + } + }, [stoppingSession]); + useEffect(() => { if (recorderState === RecorderState.Recording) { void voiceTyping.start(); @@ -156,7 +166,9 @@ const SpeechToTextComponent: React.FC = props => { [RecorderState.Loading]: () => _('Loading...'), [RecorderState.Idle]: () => 'Waiting...', // Not used for now [RecorderState.Recording]: () => _('Please record your voice...'), - [RecorderState.Processing]: () => _('Converting speech to text...'), + [RecorderState.Processing]: () => ( + stoppingSession ? _('Closing session...') : _('Converting speech to text...') + ), [RecorderState.Downloading]: () => _('Downloading %s language files...', languageName(props.locale)), [RecorderState.Error]: () => _('Error: %s', modelError?.message), }; @@ -171,7 +183,12 @@ const SpeechToTextComponent: React.FC = props => { return {preview}; }; - const reDownloadButton = ; const allowReDownload = recorderState === RecorderState.Error || modelIsOutdated; diff --git a/packages/app-mobile/services/voiceTyping/VoiceTyping.ts b/packages/app-mobile/services/voiceTyping/VoiceTyping.ts index ed248fa97c..f108d5e9f4 100644 --- a/packages/app-mobile/services/voiceTyping/VoiceTyping.ts +++ b/packages/app-mobile/services/voiceTyping/VoiceTyping.ts @@ -2,7 +2,6 @@ import shim from '@joplin/lib/shim'; import Logger from '@joplin/utils/Logger'; import { PermissionsAndroid, Platform } from 'react-native'; import unzip from './utils/unzip'; -import { _ } from '@joplin/lib/locale'; const md5 = require('md5'); const logger = Logger.create('voiceTyping'); @@ -87,12 +86,7 @@ export default class VoiceTyping { } public async clearDownloads() { - const confirmed = await shim.showConfirmationDialog( - _('Delete model and re-download?\nThis cannot be undone.'), - ); - if (confirmed) { - await this.provider.deleteCachedModels(this.locale); - } + await this.provider.deleteCachedModels(this.locale); } public async download() { From 2fdbb22481be4ef76ff684ec9966b7a344e40934 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Fri, 21 Mar 2025 19:35:20 +0100 Subject: [PATCH 063/158] Android 3.3.4 --- packages/app-mobile/android/app/build.gradle | 4 ++-- readme/about/changelog/android.md | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/app-mobile/android/app/build.gradle b/packages/app-mobile/android/app/build.gradle index b1c4c40786..38d41b4968 100644 --- a/packages/app-mobile/android/app/build.gradle +++ b/packages/app-mobile/android/app/build.gradle @@ -86,8 +86,8 @@ android { applicationId "net.cozic.joplin" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 2097766 - versionName "3.3.3" + versionCode 2097767 + versionName "3.3.4" ndk { abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64" } diff --git a/readme/about/changelog/android.md b/readme/about/changelog/android.md index 44bffe6d08..383d067be6 100644 --- a/readme/about/changelog/android.md +++ b/readme/about/changelog/android.md @@ -1,5 +1,10 @@ # Joplin Android Changelog +## [android-v3.3.4](https://github.com/laurent22/joplin/releases/tag/android-v3.3.4) (Pre-release) - 2025-03-21T18:07:00Z + +- Improved: Voice typing: Improve processing with larger models (#11983 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Improved: Voice typing: Improve re-download button UI (#11979) (#11955 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) + ## [android-v3.3.3](https://github.com/laurent22/joplin/releases/tag/android-v3.3.3) (Pre-release) - 2025-03-16T10:29:52Z - New: Add setting migration for ocr.enabled (ab86b95) From a6079869bc88e55b234e5f5e7f9f72d284407f63 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Fri, 21 Mar 2025 23:26:54 +0100 Subject: [PATCH 064/158] Desktop: Fixes #11975: Regression: Restarting app is broken --- packages/app-desktop/ElectronAppWrapper.ts | 3 +++ packages/app-desktop/bridge.ts | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/app-desktop/ElectronAppWrapper.ts b/packages/app-desktop/ElectronAppWrapper.ts index c175376d5c..989c5be9b0 100644 --- a/packages/app-desktop/ElectronAppWrapper.ts +++ b/packages/app-desktop/ElectronAppWrapper.ts @@ -632,6 +632,9 @@ export default class ElectronAppWrapper { } if (callingAppGone) { + // Wait a bit more because even if the app is not responding, the process + // might still be there for a short while. + await msleep(1000); this.ipcLogger_.warn('restartAltInstance: App is gone - restarting it'); void bridge().launchNewAppInstance(this.env()); } else { diff --git a/packages/app-desktop/bridge.ts b/packages/app-desktop/bridge.ts index 8a758fca09..9d4302673e 100644 --- a/packages/app-desktop/bridge.ts +++ b/packages/app-desktop/bridge.ts @@ -572,7 +572,7 @@ export class Bridge { app.relaunch(); } - app.exit(); + this.electronApp().exit(); } public createImageFromPath(path: string) { From d07f3b5f16a8eef3b33ef27c4a1b9ceef7b5894a Mon Sep 17 00:00:00 2001 From: Joplin Bot Date: Sat, 22 Mar 2025 02:03:52 +0000 Subject: [PATCH 065/158] Doc: Auto-update documentation Auto-updated using release-website.sh --- packages/tools/postPreReleasesToForum.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/tools/postPreReleasesToForum.json b/packages/tools/postPreReleasesToForum.json index 3416982b4f..a8f5cca92a 100644 --- a/packages/tools/postPreReleasesToForum.json +++ b/packages/tools/postPreReleasesToForum.json @@ -138,6 +138,7 @@ "android-v3.3.2": true, "v3.3.3": true, "android-v3.3.3": true, - "ios-v13.3.2": true + "ios-v13.3.2": true, + "android-v3.3.4": true } } \ No newline at end of file From ef513862a99e40542516f408a49052efdbddd389 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 23 Mar 2025 13:14:02 +0100 Subject: [PATCH 066/158] Plugins: Add `setting.globalValues` and deprecate `setting.globalValue` --- .../lib/services/plugins/api/JoplinSettings.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/lib/services/plugins/api/JoplinSettings.ts b/packages/lib/services/plugins/api/JoplinSettings.ts index 1624141d33..c6c8d93f48 100644 --- a/packages/lib/services/plugins/api/JoplinSettings.ts +++ b/packages/lib/services/plugins/api/JoplinSettings.ts @@ -177,11 +177,23 @@ export default class JoplinSettings { } /** - * Gets a global setting value, including app-specific settings and those set by other plugins. + * Gets global setting values, including app-specific settings and those set by other plugins. * * The list of available settings is not documented yet, but can be found by looking at the source code: * - * https://github.com/laurent22/joplin/blob/dev/packages/lib/models/Setting.ts#L142 + * https://github.com/laurent22/joplin/blob/dev/packages/lib/models/settings/builtInMetadata.ts + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied + public async globalValues(keys: string[]): Promise { + const output: (string|number|boolean)[] = []; + for (const key of keys) { + output.push(Setting.value(key)); + } + return output; + } + + /** + * @deprecated Use joplin.settings.globalValues() */ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied public async globalValue(key: string): Promise { From cc2cf5f5212f4ec5cf5657188fb67c082b6b7d85 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Mon, 24 Mar 2025 15:34:58 +0100 Subject: [PATCH 067/158] Doc: added sponsor --- packages/tools/sponsors.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/tools/sponsors.json b/packages/tools/sponsors.json index aaa219b4b8..5e88b57d76 100644 --- a/packages/tools/sponsors.json +++ b/packages/tools/sponsors.json @@ -35,6 +35,9 @@ }, { "name": "Akhil-CM" + }, + { + "name": "ugoertz" } ], "orgs": [ From de6c5d448f4453bf7bb40672480064243adae0d7 Mon Sep 17 00:00:00 2001 From: Joplin Bot Date: Mon, 24 Mar 2025 18:45:45 +0000 Subject: [PATCH 068/158] Doc: Auto-update documentation Auto-updated using release-website.sh --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1c16c02afe..1ed1420f0a 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Please see the [donation page](https://github.com/laurent22/joplin/blob/dev/read |
[Akhil-CM](https://github.com/Akhil-CM) |
[andypiper](https://github.com/andypiper) |
[avanderberg](https://github.com/avanderberg) |
[chr15m](https://github.com/chr15m) | |
[felixstorm](https://github.com/felixstorm) |
[Galliver7](https://github.com/Galliver7) |
[Hegghammer](https://github.com/Hegghammer) |
[KentBrockman](https://github.com/KentBrockman) | |
[marcdw1289](https://github.com/marcdw1289) |
[maxtruxa](https://github.com/maxtruxa) |
[sif](https://github.com/sif) |
[taskcruncher](https://github.com/taskcruncher) | -| | | | | +|
[ugoertz](https://github.com/ugoertz) | | | | # Community From baaeea13070447863f211266a378f95955cf4fd8 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Tue, 25 Mar 2025 12:06:00 +0100 Subject: [PATCH 069/158] Server: Fixes #11910: Disable faulty dark theme to prevent published notes from being unreadable --- packages/server/package.json | 1 - packages/server/src/routes/default.ts | 21 +++++++++++++++++++-- yarn.lock | 8 -------- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index 9436e76a6b..364807e286 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -31,7 +31,6 @@ "@types/uuid": "9.0.7", "bcryptjs": "2.4.3", "bulma": "1.0.2", - "bulma-prefers-dark": "0.1.0-beta.1", "compare-versions": "6.1.1", "dayjs": "1.11.12", "formidable": "2.1.2", diff --git a/packages/server/src/routes/default.ts b/packages/server/src/routes/default.ts index ab8c568bd3..11b71884eb 100644 --- a/packages/server/src/routes/default.ts +++ b/packages/server/src/routes/default.ts @@ -19,7 +19,6 @@ interface PathToFileMap { // example if they are in node_modules, use the map below. const pathToFileMap: PathToFileMap = { 'css/bulma.min.css': 'node_modules/bulma/css/bulma.min.css', - 'css/bulma-prefers-dark.min.css': 'node_modules/bulma-prefers-dark/css/bulma-prefers-dark.min.css', 'css/fontawesome/css/all.min.css': 'node_modules/@fortawesome/fontawesome-free/css/all.min.css', 'js/zxcvbn.js': 'node_modules/zxcvbn/dist/zxcvbn.js', 'js/zxcvbn.js.map': 'node_modules/zxcvbn/dist/zxcvbn.js.map', @@ -49,6 +48,23 @@ async function findLocalFile(path: string): Promise { return localPath; } +const patchFile = (path: string, fileContent: Buffer): Buffer => { + const patches: Record Buffer> = { + 'css/bulma.min.css': fileContent => { + // We apply the patch here rather than with `yarn patch` because that would mean + // modifying a minified file, which is likely to break on each new update of Bulma. Dark + // theme is disabled mostly because we don't want it in published notes, which may have + // their own style inherited from clipped web pages. Having dark theme in the web UI is + // not that useful because it's not frequently accessed by users. + return Buffer.from(fileContent.toString().replace('prefers-color-scheme:dark', 'prefers-color-scheme:dark-disabled-by-patch'), 'utf-8'); + }, + }; + + if (patches[path]) return patches[path](fileContent); + + return fileContent; +}; + const router = new Router(RouteType.Web); router.public = true; @@ -70,7 +86,8 @@ router.get('', async (path: SubPath, ctx: AppContext) => { let mimeType: string = mime.fromFilename(localPath); if (!mimeType) mimeType = 'application/octet-stream'; - const fileContent: Buffer = await fs.readFile(localPath); + let fileContent: Buffer = await fs.readFile(localPath); + fileContent = patchFile(path.raw, fileContent); const koaResponse = ctx.response; koaResponse.body = fileContent; diff --git a/yarn.lock b/yarn.lock index 912a8847c2..6f6e22c2f7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8841,7 +8841,6 @@ __metadata: "@types/zxcvbn": 4.4.5 bcryptjs: 2.4.3 bulma: 1.0.2 - bulma-prefers-dark: 0.1.0-beta.1 compare-versions: 6.1.1 dayjs: 1.11.12 formidable: 2.1.2 @@ -18081,13 +18080,6 @@ __metadata: languageName: node linkType: hard -"bulma-prefers-dark@npm:0.1.0-beta.1": - version: 0.1.0-beta.1 - resolution: "bulma-prefers-dark@npm:0.1.0-beta.1" - checksum: 26a88776a97ed0b57307a1aee60380a1b484ebd27d101c9995b5d220ff79fe909b060577c42c674c2863c52d4de85396c6f36031b3f7828386e21c1eda1e4445 - languageName: node - linkType: hard - "bulma@npm:1.0.2": version: 1.0.2 resolution: "bulma@npm:1.0.2" From 93219575b4d986b88d3160e2daa5e0ca9963a9a6 Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Tue, 25 Mar 2025 04:12:38 -0700 Subject: [PATCH 070/158] Chore: Desktop: Update Playwright, allow debugging Playwright tests from VSCode (#12003) --- .../app-desktop/integration-tests/README.md | 2 ++ .../util/createStartupArgs.ts | 7 ++++- packages/app-desktop/package.json | 2 +- yarn.lock | 30 +++++++++---------- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/packages/app-desktop/integration-tests/README.md b/packages/app-desktop/integration-tests/README.md index 7b405b1fab..a298b920cd 100644 --- a/packages/app-desktop/integration-tests/README.md +++ b/packages/app-desktop/integration-tests/README.md @@ -17,6 +17,7 @@ with Playwright: - [The Playwright ElectronApp docs](https://playwright.dev/docs/api/class-electronapplication) - [Electron Playwright example repository](https://github.com/spaceagetv/electron-playwright-example) - [Playwright best practices](https://playwright.dev/docs/best-practices) +- [Running and debugging tests from VSCode](https://playwright.dev/docs/getting-started-vscode#running-tests). # FAQ @@ -25,3 +26,4 @@ with Playwright: If Playwright tests are timing out, consider modifying `playwright.config.ts` in the `app-desktop` folder. For example, increase the `timeout` option to `120_000` (2 minutes). Alternatively, try temporarily disabling `fullyParallel` (which disables running tests in parallel). + diff --git a/packages/app-desktop/integration-tests/util/createStartupArgs.ts b/packages/app-desktop/integration-tests/util/createStartupArgs.ts index b79d467d40..60fcd5fad2 100644 --- a/packages/app-desktop/integration-tests/util/createStartupArgs.ts +++ b/packages/app-desktop/integration-tests/util/createStartupArgs.ts @@ -1,8 +1,13 @@ +import { dirname, resolve } from 'path'; const createStartupArgs = (profileDirectory: string) => { + // Input paths need to be absolute when running from VSCode + const baseDirectory = dirname(dirname(__dirname)); + const mainPath = resolve(baseDirectory, 'main.js'); + // We need to run with --env dev to disable the single instance check. return [ - 'main.js', '--env', 'dev', '--no-welcome', '--profile', profileDirectory, + mainPath, '--env', 'dev', '--no-welcome', '--profile', resolve(profileDirectory), ]; }; diff --git a/packages/app-desktop/package.json b/packages/app-desktop/package.json index 0a08a40689..cef8d59529 100644 --- a/packages/app-desktop/package.json +++ b/packages/app-desktop/package.json @@ -134,7 +134,7 @@ "@electron/rebuild": "3.6.0", "@joplin/default-plugins": "~3.3", "@joplin/tools": "~3.3", - "@playwright/test": "1.45.3", + "@playwright/test": "1.51.1", "@testing-library/react-hooks": "8.0.1", "@types/jest": "29.5.12", "@types/node": "18.19.67", diff --git a/yarn.lock b/yarn.lock index 6f6e22c2f7..1983c03bce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8279,7 +8279,7 @@ __metadata: "@joplin/renderer": ~3.3 "@joplin/tools": ~3.3 "@joplin/utils": ~3.3 - "@playwright/test": 1.45.3 + "@playwright/test": 1.51.1 "@sentry/electron": 4.24.0 "@testing-library/react-hooks": 8.0.1 "@types/jest": 29.5.12 @@ -10675,14 +10675,14 @@ __metadata: languageName: node linkType: hard -"@playwright/test@npm:1.45.3": - version: 1.45.3 - resolution: "@playwright/test@npm:1.45.3" +"@playwright/test@npm:1.51.1": + version: 1.51.1 + resolution: "@playwright/test@npm:1.51.1" dependencies: - playwright: 1.45.3 + playwright: 1.51.1 bin: playwright: cli.js - checksum: 3e2c88d40f98cf94ab7947263804d1ee78c4bb21a35c8dbb64855eed5565ffc688509c5f07bda5438cba6c354374981448dcba3dbe326d1699b4fef75c9ce43d + checksum: c3c14f37451cc0323234e37fa559a075e5aee9f5e6ca06fa3b4a132ec6c809909b22877daca1fa48c95a1112d859346c10111e7003f44582a05100dd5385bbef languageName: node linkType: hard @@ -37993,27 +37993,27 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.45.3": - version: 1.45.3 - resolution: "playwright-core@npm:1.45.3" +"playwright-core@npm:1.51.1": + version: 1.51.1 + resolution: "playwright-core@npm:1.51.1" bin: playwright-core: cli.js - checksum: cecb58877b2c643403d7a72c24a7aa0fdd087a3c7f9a5ea5403851336ea831d8e304b1f159aacbbabd12e5c47eaac054333746c9e5431ec07b13d64dbf3b50ec + checksum: 1eb37e22e97435a5ed6389b4caa666fbe618348861cae97e67586e20c8fed9ac3d3dc899ff3b9237d0ddfcf087d5b552b80be247e246fc45b75282f96be714bb languageName: node linkType: hard -"playwright@npm:1.45.3": - version: 1.45.3 - resolution: "playwright@npm:1.45.3" +"playwright@npm:1.51.1": + version: 1.51.1 + resolution: "playwright@npm:1.51.1" dependencies: fsevents: 2.3.2 - playwright-core: 1.45.3 + playwright-core: 1.51.1 dependenciesMeta: fsevents: optional: true bin: playwright: cli.js - checksum: d9d23b155ccd001553214f710561b01e48eb409676102f8ab94c0b4aa5ac5f398becc1a96528b0554944e07e34189503d891913e0e0a4aa58ad36b9c08747983 + checksum: 2d78f53eed438d26df9743f98227d2e33bb5a378c8d0144a4ed75b4010c9c517d5a6ee6c1c9245ad61dc615054c5e19d2ded5a6e285e35d2bca39b05bc9c4a35 languageName: node linkType: hard From 0959a19d65c671b981e12dea5cf626dc640206f9 Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Tue, 25 Mar 2025 10:50:16 -0700 Subject: [PATCH 071/158] Chore: Desktop: Fix tests in IPC pull request (#12004) --- packages/app-desktop/ElectronAppWrapper.ts | 16 ++++++++++++++-- .../integration-tests/util/createStartupArgs.ts | 2 +- packages/app-desktop/main.js | 5 ++++- packages/lib/utils/processStartFlags.ts | 6 ++++++ 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/packages/app-desktop/ElectronAppWrapper.ts b/packages/app-desktop/ElectronAppWrapper.ts index 989c5be9b0..ba76b492bc 100644 --- a/packages/app-desktop/ElectronAppWrapper.ts +++ b/packages/app-desktop/ElectronAppWrapper.ts @@ -36,12 +36,21 @@ interface SecondaryWindowData { electronId: number; } +export interface Options { + env: string; + profilePath: string|null; + isDebugMode: boolean; + isEndToEndTesting: boolean; + initialCallbackUrl: string; +} + export default class ElectronAppWrapper { private logger_: Logger = null; private electronApp_: App; private env_: string; private isDebugMode_: boolean; private profilePath_: string; + private isEndToEndTesting_: boolean; private win_: BrowserWindow = null; private mainWindowHidden_ = true; @@ -65,12 +74,13 @@ export default class ElectronAppWrapper { private ipcLogger_: Logger; - public constructor(electronApp: App, env: string, profilePath: string|null, isDebugMode: boolean, initialCallbackUrl: string) { + public constructor(electronApp: App, { env, profilePath, isDebugMode, initialCallbackUrl, isEndToEndTesting }: Options) { this.electronApp_ = electronApp; this.env_ = env; this.isDebugMode_ = isDebugMode; this.profilePath_ = profilePath; this.initialCallbackUrl_ = initialCallbackUrl; + this.isEndToEndTesting_ = isEndToEndTesting; this.profileLocker_ = new FileLocker(`${this.profilePath_}/lock`); @@ -576,7 +586,9 @@ export default class ElectronAppWrapper { } public async ensureSingleInstance() { - // if (this.env_ === 'dev') return false; + // When end-to-end testing, multiple instances of Joplin are intentionally created at the same time, + // or very close to one another. The single instance handling logic can interfere with this, so disable it. + if (this.isEndToEndTesting_) return false; interface OnSecondInstanceMessageData { profilePath: string; diff --git a/packages/app-desktop/integration-tests/util/createStartupArgs.ts b/packages/app-desktop/integration-tests/util/createStartupArgs.ts index 60fcd5fad2..e499861a8a 100644 --- a/packages/app-desktop/integration-tests/util/createStartupArgs.ts +++ b/packages/app-desktop/integration-tests/util/createStartupArgs.ts @@ -7,7 +7,7 @@ const createStartupArgs = (profileDirectory: string) => { // We need to run with --env dev to disable the single instance check. return [ - mainPath, '--env', 'dev', '--no-welcome', '--profile', resolve(profileDirectory), + mainPath, '--env', 'dev', '--no-welcome', '--running-tests', '--profile', resolve(profileDirectory), ]; }; diff --git a/packages/app-desktop/main.js b/packages/app-desktop/main.js index 32f1b1d99f..4d2f129f58 100644 --- a/packages/app-desktop/main.js +++ b/packages/app-desktop/main.js @@ -38,6 +38,7 @@ Logger.fsDriver_ = new FsDriverNode(); const env = envFromArgs(process.argv); const profileFromArgs = getFlagValueFromArgs(process.argv, '--profile', null); const isDebugMode = !!process.argv && process.argv.indexOf('--debug') >= 0; +const isEndToEndTesting = !!process.argv?.includes('--running-tests'); const altInstanceId = getFlagValueFromArgs(process.argv, '--alt-instance-id', ''); // We initialize all these variables here because they are needed from the main process. They are @@ -64,7 +65,9 @@ void registerCustomProtocols(); const initialCallbackUrl = process.argv.find((arg) => isCallbackUrl(arg)); -const wrapper = new ElectronAppWrapper(electronApp, env, rootProfileDir, isDebugMode, initialCallbackUrl); +const wrapper = new ElectronAppWrapper(electronApp, { + env, profilePath: rootProfileDir, isDebugMode, initialCallbackUrl, isEndToEndTesting, +}); initBridge(wrapper, appId, appName, rootProfileDir, autoUploadCrashDumps, altInstanceId); diff --git a/packages/lib/utils/processStartFlags.ts b/packages/lib/utils/processStartFlags.ts index bda8456093..4f437cc7f6 100644 --- a/packages/lib/utils/processStartFlags.ts +++ b/packages/lib/utils/processStartFlags.ts @@ -188,6 +188,12 @@ const processStartFlags = async (argv: string[], setDefaults = true) => { continue; } + if (arg === '--running-tests') { + // Used by the desktop app to indicate that the app is running end-to-end tests. + argv.splice(0, 1); + continue; + } + if (arg.length && arg[0] === '-') { throw new JoplinError(_('Unknown flag: %s', arg), 'flagError'); } else { From e3762dc3f8ff03452261db9acab1a0df401eb571 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Tue, 25 Mar 2025 19:48:11 +0100 Subject: [PATCH 072/158] Desktop: Resolves #11992: Multiple instances: Secure local server (#11999) --- .eslintignore | 2 + .gitignore | 2 + packages/app-desktop/ElectronAppWrapper.ts | 17 ++++++- packages/lib/BaseApplication.ts | 4 +- packages/lib/getAppName.test.ts | 12 +++++ packages/lib/getAppName.ts | 5 ++ packages/utils/crypto.ts | 9 ++++ packages/utils/fs.test.ts | 4 +- packages/utils/ipc.test.ts | 53 +++++++++++++++++++++- packages/utils/ipc.ts | 41 ++++++++++++++++- readme/dev/spec/multiple_instances.md | 2 + 11 files changed, 142 insertions(+), 9 deletions(-) create mode 100644 packages/lib/getAppName.test.ts create mode 100644 packages/lib/getAppName.ts create mode 100644 packages/utils/crypto.ts diff --git a/.eslintignore b/.eslintignore index 0b3ae6f5df..27c673cf51 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1073,6 +1073,8 @@ packages/lib/fs-driver-base.js packages/lib/fs-driver-node.js packages/lib/fsDriver.test.js packages/lib/geolocation-node.js +packages/lib/getAppName.test.js +packages/lib/getAppName.js packages/lib/hooks/useAsyncEffect.js packages/lib/hooks/useElementSize.js packages/lib/hooks/useEventListener.js diff --git a/.gitignore b/.gitignore index 465a5a078d..35416946db 100644 --- a/.gitignore +++ b/.gitignore @@ -1048,6 +1048,8 @@ packages/lib/fs-driver-base.js packages/lib/fs-driver-node.js packages/lib/fsDriver.test.js packages/lib/geolocation-node.js +packages/lib/getAppName.test.js +packages/lib/getAppName.js packages/lib/hooks/useAsyncEffect.js packages/lib/hooks/useElementSize.js packages/lib/hooks/useEventListener.js diff --git a/packages/app-desktop/ElectronAppWrapper.ts b/packages/app-desktop/ElectronAppWrapper.ts index ba76b492bc..53c6aa7bf6 100644 --- a/packages/app-desktop/ElectronAppWrapper.ts +++ b/packages/app-desktop/ElectronAppWrapper.ts @@ -21,6 +21,8 @@ import { clearTimeout, setTimeout } from 'timers'; import { resolve } from 'path'; import { defaultWindowId } from '@joplin/lib/reducer'; import { msleep, Second } from '@joplin/utils/time'; +import determineBaseAppDirs from '@joplin/lib/determineBaseAppDirs'; +import getAppName from '@joplin/lib/getAppName'; interface RendererProcessQuitReply { canClose: boolean; @@ -579,7 +581,11 @@ export default class ElectronAppWrapper { if (port === null) port = this.ipcStartPort_; - return await sendMessage(port, { ...message, sourcePort: this.ipcServer_.port }, { + return await sendMessage(port, { + ...message, + sourcePort: this.ipcServer_.port, + secretKey: this.ipcServer_.secretKey, + }, { logger: this.ipcLogger_, ...options, }); @@ -631,6 +637,7 @@ export default class ElectronAppWrapper { const response = await this.sendCrossAppIpcMessage({ action: 'ping', data: null, + secretKey: this.ipcServer_.secretKey, }, message.sourcePort, { sendToSpecificPortOnly: true, }); @@ -662,7 +669,12 @@ export default class ElectronAppWrapper { }, }; - this.ipcServer_ = await startServer(this.ipcStartPort_, async (message) => { + const defaultProfileDir = determineBaseAppDirs('', getAppName(true, this.env() === 'dev'), '').rootProfileDir; + const secretKeyFilePath = `${defaultProfileDir}/ipc_secret_key.txt`; + + this.ipcLogger_.info('Starting server using secret key:', secretKeyFilePath); + + this.ipcServer_ = await startServer(this.ipcStartPort_, secretKeyFilePath, async (message) => { if (messageHandlers[message.action]) { this.ipcLogger_.info('Got message:', message); return messageHandlers[message.action](message); @@ -684,6 +696,7 @@ export default class ElectronAppWrapper { profilePath: this.profilePath_, argv: process.argv, }, + secretKey: this.ipcServer_.secretKey, }; await this.sendCrossAppIpcMessage(message); diff --git a/packages/lib/BaseApplication.ts b/packages/lib/BaseApplication.ts index 1358117001..bc00a6f526 100644 --- a/packages/lib/BaseApplication.ts +++ b/packages/lib/BaseApplication.ts @@ -65,6 +65,7 @@ import processStartFlags from './utils/processStartFlags'; import { setupAutoDeletion } from './services/trash/permanentlyDeleteOldItems'; import determineProfileAndBaseDir from './determineBaseAppDirs'; import NavService from './services/NavService'; +import getAppName from './getAppName'; const appLogger: LoggerWrapper = Logger.create('App'); @@ -679,8 +680,7 @@ export default class BaseApplication { let appName = options.appName; if (!appName) { - appName = initArgs.env === 'dev' ? 'joplindev' : 'joplin'; - if (Setting.value('appId').indexOf('-desktop') >= 0) appName += '-desktop'; + appName = getAppName(Setting.value('appId').indexOf('-desktop') >= 0, initArgs.env === 'dev'); } Setting.setConstant('appName', appName); diff --git a/packages/lib/getAppName.test.ts b/packages/lib/getAppName.test.ts new file mode 100644 index 0000000000..ae1c0280da --- /dev/null +++ b/packages/lib/getAppName.test.ts @@ -0,0 +1,12 @@ +import getAppName from './getAppName'; + +describe('getAppName', () => { + + it('should get the app name', () => { + expect(getAppName(true, true)).toBe('joplindev-desktop'); + expect(getAppName(true, false)).toBe('joplin-desktop'); + expect(getAppName(false, false)).toBe('joplin'); + expect(getAppName(false, true)).toBe('joplindev'); + }); + +}); diff --git a/packages/lib/getAppName.ts b/packages/lib/getAppName.ts new file mode 100644 index 0000000000..0b7a865fbe --- /dev/null +++ b/packages/lib/getAppName.ts @@ -0,0 +1,5 @@ +export default (isDesktop: boolean, isDev: boolean) => { + let appName = isDev ? 'joplindev' : 'joplin'; + if (isDesktop) appName += '-desktop'; + return appName; +}; diff --git a/packages/utils/crypto.ts b/packages/utils/crypto.ts new file mode 100644 index 0000000000..6c043926e0 --- /dev/null +++ b/packages/utils/crypto.ts @@ -0,0 +1,9 @@ +/* eslint-disable import/prefer-default-export */ + +import { randomBytes } from 'crypto'; + +export const getSecureRandomString = (length: number): string => { + const bytes = randomBytes(Math.ceil(length * 2)); + const randomString = bytes.toString('base64').replace(/[^a-zA-Z0-9]/g, ''); + return randomString.slice(0, length); +}; diff --git a/packages/utils/fs.test.ts b/packages/utils/fs.test.ts index e24553c9d6..b0e44742b4 100644 --- a/packages/utils/fs.test.ts +++ b/packages/utils/fs.test.ts @@ -1,10 +1,12 @@ +/* eslint-disable import/prefer-default-export */ + import { mkdirp } from 'fs-extra'; import { FileLocker } from './fs'; import { msleep, Second } from './time'; const baseTempDir = `${__dirname}/../app-cli/tests/tmp`; -const createTempDir = async () => { +export const createTempDir = async () => { const p = `${baseTempDir}/${Date.now()}`; await mkdirp(p); return p; diff --git a/packages/utils/ipc.test.ts b/packages/utils/ipc.test.ts index 0c4c56cc03..0fc572f926 100644 --- a/packages/utils/ipc.test.ts +++ b/packages/utils/ipc.test.ts @@ -1,11 +1,15 @@ +import { readFile } from 'fs/promises'; +import { createTempDir } from './fs.test'; import { newHttpError, sendMessage, startServer, stopServer } from './ipc'; describe('ipc', () => { it('should send and receive messages', async () => { + const tempDir = await createTempDir(); + const secretFilePath = `${tempDir}/secret.txt`; const startPort = 41168; - const server1 = await startServer(startPort, async (request) => { + const server1 = await startServer(startPort, secretFilePath, async (request) => { if (request.action === 'testing') { return { text: 'hello1', @@ -15,7 +19,7 @@ describe('ipc', () => { throw newHttpError(404); }); - const server2 = await startServer(startPort, async (request) => { + const server2 = await startServer(startPort, secretFilePath, async (request) => { if (request.action === 'testing') { return { text: 'hello2', @@ -31,12 +35,15 @@ describe('ipc', () => { throw newHttpError(404); }); + const secretKey = await readFile(secretFilePath, 'utf-8'); + { const responses = await sendMessage(startPort, { action: 'testing', data: { test: 1234, }, + secretKey, }); expect(responses).toEqual([ @@ -49,6 +56,7 @@ describe('ipc', () => { const responses = await sendMessage(startPort, { action: 'ping', data: null, + secretKey, }); expect(responses).toEqual([ @@ -63,6 +71,7 @@ describe('ipc', () => { test: 1234, }, sourcePort: 41168, + secretKey, }); expect(responses).toEqual([ @@ -74,4 +83,44 @@ describe('ipc', () => { await stopServer(server2); }); + it('should not process message if secret is invalid', async () => { + const tempDir = await createTempDir(); + const secretFilePath = `${tempDir}/secret.txt`; + const startPort = 41168; + + const server = await startServer(startPort, secretFilePath, async (request) => { + if (request.action === 'testing') { + return { + text: 'hello1', + }; + } + + throw newHttpError(404); + }); + + const secretKey = await readFile(secretFilePath, 'utf-8'); + + { + const responses = await sendMessage(startPort, { + action: 'testing', + data: null, + secretKey: 'wrong_key', + }); + + expect(responses.length).toBe(0); + } + + { + const responses = await sendMessage(startPort, { + action: 'testing', + data: null, + secretKey, + }); + + expect(responses.length).toBe(1); + } + + await stopServer(server); + }); + }); diff --git a/packages/utils/ipc.ts b/packages/utils/ipc.ts index 480428db60..344d669681 100644 --- a/packages/utils/ipc.ts +++ b/packages/utils/ipc.ts @@ -2,6 +2,9 @@ import { createServer, IncomingMessage, ServerResponse } from 'http'; import fetch from 'node-fetch'; import { Server } from 'http'; import Logger from './Logger'; +import { pathExists } from 'fs-extra'; +import { readFile, writeFile } from 'fs/promises'; +import { getSecureRandomString } from './crypto'; const tcpPortUsed = require('tcp-port-used'); const maxPorts = 10; @@ -51,6 +54,7 @@ export interface Message { action: string; data: object|number|string|null; sourcePort?: number; + secretKey?: string; } type Response = string|number|object|boolean; @@ -66,21 +70,52 @@ export type IpcMessageHandler = (message: Message)=> Promise; export interface IpcServer { port: number; httpServer: Server; + secretKey: string; } interface StartServerOptions { logger?: Logger; } -export const startServer = async (startPort: number, messageHandler: IpcMessageHandler, options: StartServerOptions|null = null): Promise => { +const getSecretKey = async (filePath: string) => { + try { + const keyLength = 64; + + const writeKeyToFile = async () => { + const key = getSecureRandomString(keyLength); + await writeFile(filePath, key, 'utf-8'); + return key; + }; + + if (!(await pathExists(filePath))) { + return await writeKeyToFile(); + } + + const key = await readFile(filePath, 'utf-8'); + if (key.length !== keyLength) return await writeKeyToFile(); + + return key; + } catch (error) { + const e = error as NodeJS.ErrnoException; + e.message = `Could not get secret key from file: ${filePath}`; + throw e; + } +}; + +// `secretKeyFilePath` must be the same for all the instances that can communicate with each others +export const startServer = async (startPort: number, secretKeyFilePath: string, messageHandler: IpcMessageHandler, options: StartServerOptions|null = null): Promise => { const port = await findAvailablePort(startPort); const logger = options && options.logger ? options.logger : new Logger(); + const secretKey = await getSecretKey(secretKeyFilePath); + return new Promise((resolve, reject) => { try { const server = createServer(async (req: IncomingMessage, res: ServerResponse) => { + let message: Message|null = null; try { - const message = await parseJson(req) as Message; + message = await parseJson(req) as Message; + if (message.secretKey !== secretKey) throw newHttpError(401, 'Invalid secret key'); if (!message.action) throw newHttpError(400, 'Missing "action" property in message'); const response = await messageHandler(message); res.writeHead(200, { 'Content-Type': 'application/json' }); @@ -88,6 +123,7 @@ export const startServer = async (startPort: number, messageHandler: IpcMessageH } catch (error) { const httpError = error as HttpError; const httpCode = httpError.httpCode || 500; + logger.error('Could not response to request:', message, 'Error', httpCode, httpError.message); res.writeHead(httpCode, { 'Content-Type': 'text/plain' }); res.end(`Error ${httpCode}: ${httpError.message}`); } @@ -101,6 +137,7 @@ export const startServer = async (startPort: number, messageHandler: IpcMessageH resolve({ httpServer: server, port, + secretKey, }); }); } catch (error) { diff --git a/readme/dev/spec/multiple_instances.md b/readme/dev/spec/multiple_instances.md index 4facfc3797..5dd4096ab5 100644 --- a/readme/dev/spec/multiple_instances.md +++ b/readme/dev/spec/multiple_instances.md @@ -14,6 +14,8 @@ Joplin Desktop supports multiple instances through **profile locking** and **IPC - When a message is sent, the implementation automatically discovers running IPC servers. +- Messages are secured using a secret that is shared by all applications. That secret is read from the profile directory of the main instance. It is created by the server if it doesn't exist. This ensures that, for example, a browser cannot send a valid message to the apps. + ### Instance Differentiation - The `--alt-instance-id` flag must be used to launch an alternative instance. This disables services like the Web Clipper. From 2a17301a9f4ad812f7ce01addb137321a3c6a574 Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Tue, 25 Mar 2025 13:07:27 -0700 Subject: [PATCH 073/158] Chore: Testing: Attach Playwright logs to CI results (#12007) --- .github/workflows/github-actions-main.yml | 65 +---------------- .../shared/setup-build-environment/action.yml | 72 +++++++++++++++++++ .github/workflows/ui-tests.yml | 29 ++++++++ .../app-desktop/integration-tests/run-ci.sh | 4 +- .../integration-tests/util/test.ts | 27 +++++-- packages/app-desktop/package.json | 2 +- packages/app-desktop/playwright.config.ts | 5 +- 7 files changed, 132 insertions(+), 72 deletions(-) create mode 100644 .github/workflows/shared/setup-build-environment/action.yml create mode 100644 .github/workflows/ui-tests.yml diff --git a/.github/workflows/github-actions-main.yml b/.github/workflows/github-actions-main.yml index be6141b5cb..b122839144 100644 --- a/.github/workflows/github-actions-main.yml +++ b/.github/workflows/github-actions-main.yml @@ -11,45 +11,10 @@ jobs: # https://github.com/actions/runner-images/issues/6709 os: [macos-13, ubuntu-22.04, windows-2019] steps: + - uses: actions/checkout@v4 - # Trying to fix random networking issues on Windows - # https://github.com/actions/runner-images/issues/1187#issuecomment-686735760 - - name: Disable TCP/UDP offload on Windows - if: runner.os == 'Windows' - run: Disable-NetAdapterChecksumOffload -Name * -TcpIPv4 -UdpIPv4 -TcpIPv6 -UdpIPv6 - - - name: Disable TCP/UDP offload on Linux - if: runner.os == 'Linux' - run: sudo ethtool -K eth0 tx off rx off - - - name: Disable TCP/UDP offload on macOS - if: runner.os == 'macOS' - run: | - sudo sysctl -w net.link.generic.system.hwcksum_tx=0 - sudo sysctl -w net.link.generic.system.hwcksum_rx=0 - - # Silence apt-get update errors (for example when a module doesn't - # exist) since otherwise it will make the whole build fails, even though - # it might work without update. libsecret-1-dev is required for keytar - - # https://github.com/atom/node-keytar - - - name: Install Linux dependencies - if: runner.os == 'Linux' - run: | - sudo apt-get update || true - sudo apt-get install -y gettext - sudo apt-get install -y libsecret-1-dev - sudo apt-get install -y translate-toolkit - sudo apt-get install -y rsync - # Provides a virtual display on Linux. Used for Playwright integration - # testing. - sudo apt-get install -y xvfb - - - name: Install macOs dependencies - if: runner.os == 'macOS' - run: | - # Required for building the canvas package - brew install pango + - name: Setup build environment + uses: ./.github/workflows/shared/setup-build-environment - name: Install Docker Engine # if: runner.os == 'Linux' && startsWith(github.ref, 'refs/tags/server-v') @@ -67,21 +32,6 @@ jobs: sudo apt-get update || true sudo apt-get install -y docker-ce docker-ce-cli containerd.io - - uses: actions/checkout@v4 - - uses: olegtarasov/get-tag@v2.1.3 - - uses: dtolnay/rust-toolchain@stable - - uses: actions/setup-node@v4 - with: - # We need to pin the version to 18.15, because 18.16+ fails with this error: - # https://github.com/facebook/react-native/issues/36440 - node-version: '18.15.0' - cache: 'yarn' - - - name: Install Yarn - run: | - # https://yarnpkg.com/getting-started/install - corepack enable - # Login to Docker only if we're on a server release tag. If we run this on # a pull request it will fail because the PR doesn't have access to # secrets @@ -91,15 +41,6 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - # macos-latest ships with Python 3.12 by default, but this removes a - # utility that's used by electron-builder (distutils) so we need to pin - # Python to an earlier version. - # Fixes error `ModuleNotFoundError: No module named 'distutils'` - # Ref: https://github.com/nodejs/node-gyp/issues/2869 - - uses: actions/setup-python@v5 - with: - python-version: '3.11' - - name: Run tests, build and publish Linux and macOS apps if: runner.os == 'Linux' || runner.os == 'macOs' env: diff --git a/.github/workflows/shared/setup-build-environment/action.yml b/.github/workflows/shared/setup-build-environment/action.yml new file mode 100644 index 0000000000..b9b6b08ed0 --- /dev/null +++ b/.github/workflows/shared/setup-build-environment/action.yml @@ -0,0 +1,72 @@ +name: 'Setup build environment' +description: 'Install Joplin build dependencies' +runs: + using: 'composite' + steps: + # Trying to fix random networking issues on Windows + # https://github.com/actions/runner-images/issues/1187#issuecomment-686735760 + - name: Disable TCP/UDP offload on Windows + if: runner.os == 'Windows' + shell: pwsh + run: Disable-NetAdapterChecksumOffload -Name * -TcpIPv4 -UdpIPv4 -TcpIPv6 -UdpIPv6 + + - name: Disable TCP/UDP offload on Linux + if: runner.os == 'Linux' + shell: bash + run: sudo ethtool -K eth0 tx off rx off + + - name: Disable TCP/UDP offload on macOS + if: runner.os == 'macOS' + shell: bash + run: | + sudo sysctl -w net.link.generic.system.hwcksum_tx=0 + sudo sysctl -w net.link.generic.system.hwcksum_rx=0 + + # Silence apt-get update errors (for example when a module doesn't + # exist) since otherwise it will make the whole build fails, even though + # it might work without update. libsecret-1-dev is required for keytar - + # https://github.com/atom/node-keytar + + - name: Install Linux dependencies + if: runner.os == 'Linux' + shell: bash + run: | + sudo apt-get update || true + sudo apt-get install -y gettext + sudo apt-get install -y libsecret-1-dev + sudo apt-get install -y translate-toolkit + sudo apt-get install -y rsync + # Provides a virtual display on Linux. Used for Playwright integration + # testing. + sudo apt-get install -y xvfb + + - name: Install macOs dependencies + if: runner.os == 'macOS' + shell: bash + run: | + # Required for building the canvas package + brew install pango + + - uses: olegtarasov/get-tag@v2.1.3 + - uses: dtolnay/rust-toolchain@stable + - uses: actions/setup-node@v4 + with: + # We need to pin the version to 18.15, because 18.16+ fails with this error: + # https://github.com/facebook/react-native/issues/36440 + node-version: '18.15.0' + cache: 'yarn' + + - name: Install Yarn + shell: bash + run: | + # https://yarnpkg.com/getting-started/install + corepack enable + + # macos-latest ships with Python 3.12 by default, but this removes a + # utility that's used by electron-builder (distutils) so we need to pin + # Python to an earlier version. + # Fixes error `ModuleNotFoundError: No module named 'distutils'` + # Ref: https://github.com/nodejs/node-gyp/issues/2869 + - uses: actions/setup-python@v5 + with: + python-version: '3.11' \ No newline at end of file diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml new file mode 100644 index 0000000000..0f31586d84 --- /dev/null +++ b/.github/workflows/ui-tests.yml @@ -0,0 +1,29 @@ +name: Joplin UI tests +on: [push, pull_request] +permissions: + contents: read +jobs: + Main: + # Don't run on forks + if: github.repository == 'laurent22/joplin' + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-13, ubuntu-22.04] + steps: + - uses: actions/checkout@v4 + - name: Setup build environment + uses: ./.github/workflows/shared/setup-build-environment + - name: Build + run: yarn install + - name: Run UI tests + run: | + cd ${GITHUB_WORKSPACE}/packages/app-desktop/ + bash ./integration-tests/run-ci.sh + # See https://playwright.dev/docs/ci-intro#setting-up-github-actions + - uses: actions/upload-artifact@v4 + if: ${{ !cancelled() }} + with: + name: playwright-report-${{ matrix.os }} + path: packages/app-desktop/playwright-report/ + retention-days: 7 diff --git a/packages/app-desktop/integration-tests/run-ci.sh b/packages/app-desktop/integration-tests/run-ci.sh index df63672ac7..78f3ace3fd 100755 --- a/packages/app-desktop/integration-tests/run-ci.sh +++ b/packages/app-desktop/integration-tests/run-ci.sh @@ -7,7 +7,7 @@ export CI=true if test "$RUNNER_OS" = "Linux" ; then # The Ubuntu Github CI doesn't have a display server. # Start a virtual one with xvfb-run. - xvfb-run -- yarn playwright test + xvfb-run -- yarn test-ui else - yarn playwright test + yarn test-ui fi diff --git a/packages/app-desktop/integration-tests/util/test.ts b/packages/app-desktop/integration-tests/util/test.ts index 548bd46658..167804a098 100644 --- a/packages/app-desktop/integration-tests/util/test.ts +++ b/packages/app-desktop/integration-tests/util/test.ts @@ -1,6 +1,6 @@ import { resolve, join, dirname } from 'path'; -import { remove, mkdirp } from 'fs-extra'; -import { _electron as electron, Page, ElectronApplication, test as base } from '@playwright/test'; +import { remove, mkdirp, readFile, pathExists } from 'fs-extra'; +import { _electron as electron, Page, ElectronApplication, test as base, TestInfo } from '@playwright/test'; import uuid from '@joplin/lib/uuid'; import createStartupArgs from './createStartupArgs'; import firstNonDevToolsWindow from './firstNonDevToolsWindow'; @@ -20,7 +20,7 @@ type JoplinFixtures = { // A custom fixture that loads an electron app. See // https://playwright.dev/docs/test-fixtures -const getAndResizeMainWindow = async (electronApp: ElectronApplication) => { +const initializeMainWindow = async (electronApp: ElectronApplication) => { const mainWindow = await firstNonDevToolsWindow(electronApp); // Setting the viewport size helps keep test environments consistent. @@ -48,6 +48,18 @@ const waitForStartupPlugins = async (electronApp: ElectronApplication) => { await waitForMainMessage(electronApp, 'startup-plugins-loaded'); }; +const attachJoplinLog = async (profileDirectory: string, testInfo: TestInfo) => { + const logFile = join(profileDirectory, 'log.txt'); + if (await pathExists(logFile)) { + await testInfo.attach('log.txt', { + body: await readFile(logFile, 'utf8'), + contentType: 'text/plain', + }); + } else { + console.warn('Missing log file'); + } +}; + const testDir = dirname(__dirname); export const test = base.extend({ @@ -67,7 +79,7 @@ export const test = base.extend({ await remove(profileSubdir); }, - electronApp: async ({ profileDirectory }, use) => { + electronApp: async ({ profileDirectory }, use, testInfo) => { const startupArgs = createStartupArgs(profileDirectory); const electronApp = await electron.launch({ args: startupArgs }); const startupPromise = waitForAppLoaded(electronApp); @@ -76,6 +88,9 @@ export const test = base.extend({ await use(electronApp); + // For debugging purposes, attach the Joplin log file to the test: + await attachJoplinLog(profileDirectory, testInfo); + await electronApp.firstWindow(); await electronApp.close(); }, @@ -96,7 +111,7 @@ export const test = base.extend({ ], }); const startupPromise = waitForAppLoaded(electronApp); - const mainWindowPromise = getAndResizeMainWindow(electronApp); + const mainWindowPromise = initializeMainWindow(electronApp); await waitForStartupPlugins(electronApp); await startupPromise; @@ -117,7 +132,7 @@ export const test = base.extend({ }, mainWindow: async ({ electronApp }, use) => { - await use(await getAndResizeMainWindow(electronApp)); + await use(await initializeMainWindow(electronApp)); }, }); diff --git a/packages/app-desktop/package.json b/packages/app-desktop/package.json index cef8d59529..44bdb9e1f6 100644 --- a/packages/app-desktop/package.json +++ b/packages/app-desktop/package.json @@ -14,7 +14,7 @@ "start": "gulp before-start && electron . --env dev --log-level debug --open-dev-tools --no-welcome", "test": "jest", "test-ui": "playwright test", - "test-ci": "yarn test && sh ./integration-tests/run-ci.sh", + "test-ci": "yarn test", "modifyReleaseAssets": "node tools/modifyReleaseAssets.js" }, "repository": { diff --git a/packages/app-desktop/playwright.config.ts b/packages/app-desktop/playwright.config.ts index e144ec969c..c9b48c5b6a 100644 --- a/packages/app-desktop/playwright.config.ts +++ b/packages/app-desktop/playwright.config.ts @@ -21,7 +21,10 @@ export default defineConfig({ workers: process.env.CI ? 1 : undefined, // Reporter to use. See https://playwright.dev/docs/test-reporters - reporter: process.env.CI ? 'line' : 'html', + reporter: process.env.CI ? [ + ['dot'], // Give realtime workflow progress in CI + ['html'], + ] : 'html', // The CI machines can sometimes be very slow. Increase per-test timeout in CI. timeout: process.env.CI ? 70_000 : 60_000, // milliseconds From cfd98d2723cf790949a5526bff861dd74f1f6c3b Mon Sep 17 00:00:00 2001 From: PARAMESH T S <42896229+Paramesh-T-S@users.noreply.github.com> Date: Thu, 27 Mar 2025 19:55:12 +0530 Subject: [PATCH 074/158] Desktop, Mobile: Fixes #11971: Changing the type of one list changes it for all the lists (#11986) --- ...rkdownCommands.bulletedVsChecklist.test.ts | 8 ++++---- .../markdownCommands.toggleList.test.ts | 20 +++++++++---------- .../CodeMirror/markdown/markdownCommands.ts | 13 ------------ 3 files changed, 14 insertions(+), 27 deletions(-) diff --git a/packages/editor/CodeMirror/markdown/markdownCommands.bulletedVsChecklist.test.ts b/packages/editor/CodeMirror/markdown/markdownCommands.bulletedVsChecklist.test.ts index 5da09a5c58..98d4544a10 100644 --- a/packages/editor/CodeMirror/markdown/markdownCommands.bulletedVsChecklist.test.ts +++ b/packages/editor/CodeMirror/markdown/markdownCommands.bulletedVsChecklist.test.ts @@ -12,25 +12,25 @@ describe('markdownCommands.bulletedVsChecklist', () => { const initialDocText = `${bulletedListPart}\n\n${checklistPart}`; const expectedTags = ['BulletList', 'Task']; - it('should remove a checklist following a bulleted list without modifying the bulleted list', async () => { + it('should remove a checklist following a bulleted list without modifying the bulleted list only at the selected line', async () => { const editor = await createTestEditor( initialDocText, EditorSelection.cursor(bulletedListPart.length + 5), expectedTags, ); toggleList(ListType.CheckList)(editor); expect(editor.state.doc.toString()).toBe( - `${bulletedListPart}\n\nThis is a checklist\nwith multiple items.\n☑`, + `${bulletedListPart}\n\nThis is a checklist\n- [ ] with multiple items.\n- [ ] ☑`, ); }); - it('should remove an unordered list following a checklist without modifying the checklist', async () => { + it('should remove an unordered list only at the selected line following a checklist without modifying the checklist', async () => { const editor = await createTestEditor( initialDocText, EditorSelection.cursor(bulletedListPart.length - 5), expectedTags, ); toggleList(ListType.UnorderedList)(editor); expect(editor.state.doc.toString()).toBe( - `Test\nThis is a test.\n3\n4\n5\n\n${checklistPart}`, + `- Test\n- This is a test.\n- 3\n4\n- 5\n\n${checklistPart}`, ); }); diff --git a/packages/editor/CodeMirror/markdown/markdownCommands.toggleList.test.ts b/packages/editor/CodeMirror/markdown/markdownCommands.toggleList.test.ts index a8e57bd90a..d4275c96ee 100644 --- a/packages/editor/CodeMirror/markdown/markdownCommands.toggleList.test.ts +++ b/packages/editor/CodeMirror/markdown/markdownCommands.toggleList.test.ts @@ -9,7 +9,7 @@ describe('markdownCommands.toggleList', () => { jest.retryTimes(2); - it('should remove the same type of list', async () => { + it('should remove the list only at the selected line', async () => { const initialDocText = '- testing\n- this is a `test`\n'; const editor = await createTestEditor( @@ -20,11 +20,11 @@ describe('markdownCommands.toggleList', () => { toggleList(ListType.UnorderedList)(editor); expect(editor.state.doc.toString()).toBe( - 'testing\nthis is a `test`\n', + 'testing\n- this is a `test`\n', ); }); - it('should insert a numbered list with correct numbering', async () => { + it('should insert a numbered list with correct numbering only at the selected line', async () => { const initialDocText = 'Testing...\nThis is a test\nof list toggling...'; const editor = await createTestEditor( initialDocText, @@ -50,7 +50,7 @@ describe('markdownCommands.toggleList', () => { const unorderedListText = '- 1\n- 2\n- 3\n- 4\n- 5\n- 6\n- 7'; - it('should correctly replace an unordered list with a numbered list', async () => { + it('should correctly replace an unordered list with a numbered list only at the selected line', async () => { const editor = await createTestEditor( unorderedListText, EditorSelection.cursor(unorderedListText.length), @@ -59,7 +59,7 @@ describe('markdownCommands.toggleList', () => { toggleList(ListType.OrderedList)(editor); expect(editor.state.doc.toString()).toBe( - '1. 1\n2. 2\n3. 3\n4. 4\n5. 5\n6. 6\n7. 7', + '- 1\n- 2\n- 3\n- 4\n- 5\n- 6\n1. 7', ); }); @@ -180,7 +180,7 @@ describe('markdownCommands.toggleList', () => { // ); // }); - it('should toggle a numbered list without changing its sublists', async () => { + it('should toggle only a numbered list at selected line without changing its sublists', async () => { const initialDocText = '1. Foo\n2. Bar\n3. Baz\n\t- Test\n\t- of\n\t- sublists\n4. Foo'; const editor = await createTestEditor( @@ -191,7 +191,7 @@ describe('markdownCommands.toggleList', () => { toggleList(ListType.CheckList)(editor); expect(editor.state.doc.toString()).toBe( - '- [ ] Foo\n- [ ] Bar\n- [ ] Baz\n\t- Test\n\t- of\n\t- sublists\n- [ ] Foo', + '- [ ] Foo\n2. Bar\n3. Baz\n\t- Test\n\t- of\n\t- sublists\n4. Foo', ); }); @@ -218,7 +218,7 @@ describe('markdownCommands.toggleList', () => { ); }); - it('should toggle lists properly within block quotes', async () => { + it('should toggle only list on the selected line properly within block quotes', async () => { const preSubListText = '> # List test\n> * This\n> * is\n'; const initialDocText = `${preSubListText}> \t* a\n> \t* test\n> * of list toggling`; const editor = await createTestEditor( @@ -228,9 +228,9 @@ describe('markdownCommands.toggleList', () => { toggleList(ListType.OrderedList)(editor); expect(editor.state.doc.toString()).toBe( - '> # List test\n> * This\n> * is\n> \t1. a\n> \t2. test\n> * of list toggling', + '> # List test\n> * This\n> * is\n> \t1. a\n> \t* test\n> * of list toggling', ); - expect(editor.state.selection.main.from).toBe(preSubListText.length); + expect(editor.state.selection.main.from).toBe(preSubListText.length + 7); }); it('should not treat a list of IP addresses as a numbered list', async () => { diff --git a/packages/editor/CodeMirror/markdown/markdownCommands.ts b/packages/editor/CodeMirror/markdown/markdownCommands.ts index a230d50c32..70961be99a 100644 --- a/packages/editor/CodeMirror/markdown/markdownCommands.ts +++ b/packages/editor/CodeMirror/markdown/markdownCommands.ts @@ -13,7 +13,6 @@ import { RegionSpec } from '../utils/formatting/RegionSpec'; import toggleInlineFormatGlobally from '../utils/formatting/toggleInlineFormatGlobally'; import stripBlockquote from './utils/stripBlockquote'; import isIndentationEquivalent from '../utils/formatting/isIndentationEquivalent'; -import growSelectionToNode from '../utils/growSelectionToNode'; import tabsToSpaces from '../utils/formatting/tabsToSpaces'; import renumberSelectedLists from './utils/renumberSelectedLists'; import toggleSelectedLinesStartWith from '../utils/formatting/toggleSelectedLinesStartWith'; @@ -126,9 +125,6 @@ export const toggleList = (listType: ListType): Command => { let state = view.state; let doc = state.doc; - const orderedListTag = 'OrderedList'; - const unorderedListTag = 'BulletList'; - // RegExps for different list types. The regular expressions MUST // be mutually exclusive. // `(?!\[[ xX]+\])` means "not followed by [x] or [ ]". @@ -188,15 +184,6 @@ export const toggleList = (listType: ListType): Command => { const origFirstLineIndentation = firstLineIndentation; const origContainerType = containerType; - // Grow `sel` to the smallest containing list, unless the - // cursor is on an empty line, in which case, the user - // probably wants to add a list item (and not select the entire - // list). - if (sel.empty && fromLine.text.trim() !== '') { - sel = growSelectionToNode(state, sel, [orderedListTag, unorderedListTag]); - computeSelectionProps(); - } - // Reset the selection if it seems likely the user didn't want the selection // to be expanded const isIndentationDiff = From ece7a4ccf0623858980c1524d9506318742928ec Mon Sep 17 00:00:00 2001 From: mrjo118 Date: Thu, 27 Mar 2025 14:33:00 +0000 Subject: [PATCH 075/158] Mobile: Fixes #11820: Fix cursor moves to incorrect position when revising TextInput value (#11821) --- .eslintignore | 1 + .gitignore | 1 + .../screens/ConfigScreen/SettingComponent.tsx | 33 ++++------- .../screens/ConfigScreen/SettingTextInput.tsx | 57 +++++++++++++++++++ 4 files changed, 70 insertions(+), 22 deletions(-) create mode 100644 packages/app-mobile/components/screens/ConfigScreen/SettingTextInput.tsx diff --git a/.eslintignore b/.eslintignore index 27c673cf51..08867b462c 100644 --- a/.eslintignore +++ b/.eslintignore @@ -747,6 +747,7 @@ packages/app-mobile/components/screens/ConfigScreen/SectionSelector/SectionTab.j packages/app-mobile/components/screens/ConfigScreen/SectionSelector/index.js packages/app-mobile/components/screens/ConfigScreen/SettingComponent.js packages/app-mobile/components/screens/ConfigScreen/SettingItem.js +packages/app-mobile/components/screens/ConfigScreen/SettingTextInput.js packages/app-mobile/components/screens/ConfigScreen/SettingsButton.js packages/app-mobile/components/screens/ConfigScreen/SettingsToggle.js packages/app-mobile/components/screens/ConfigScreen/configScreenStyles.js diff --git a/.gitignore b/.gitignore index 35416946db..e68e2dca79 100644 --- a/.gitignore +++ b/.gitignore @@ -722,6 +722,7 @@ packages/app-mobile/components/screens/ConfigScreen/SectionSelector/SectionTab.j packages/app-mobile/components/screens/ConfigScreen/SectionSelector/index.js packages/app-mobile/components/screens/ConfigScreen/SettingComponent.js packages/app-mobile/components/screens/ConfigScreen/SettingItem.js +packages/app-mobile/components/screens/ConfigScreen/SettingTextInput.js packages/app-mobile/components/screens/ConfigScreen/SettingsButton.js packages/app-mobile/components/screens/ConfigScreen/SettingsToggle.js packages/app-mobile/components/screens/ConfigScreen/configScreenStyles.js diff --git a/packages/app-mobile/components/screens/ConfigScreen/SettingComponent.tsx b/packages/app-mobile/components/screens/ConfigScreen/SettingComponent.tsx index 748ffdaace..4be5a49c71 100644 --- a/packages/app-mobile/components/screens/ConfigScreen/SettingComponent.tsx +++ b/packages/app-mobile/components/screens/ConfigScreen/SettingComponent.tsx @@ -1,13 +1,14 @@ import * as React from 'react'; import { UpdateSettingValueCallback } from './types'; -import { View, Text, TextInput } from 'react-native'; +import { View, Text } from 'react-native'; import Setting, { AppType } from '@joplin/lib/models/Setting'; import Dropdown from '../../Dropdown'; import { ConfigScreenStyles } from './configScreenStyles'; import Slider from '@react-native-community/slider'; import SettingsToggle from './SettingsToggle'; import FileSystemPathSelector from './FileSystemPathSelector'; +import SettingTextInput from './SettingTextInput'; import shim from '@joplin/lib/shim'; import { themeStyle } from '../../global-style'; import { useId } from 'react'; @@ -136,27 +137,15 @@ const SettingComponent: React.FunctionComponent = props => { } return ( - - - - {md.label()} - - void props.updateSettingValue(props.settingId, newValue)} - secureTextEntry={!!md.secure} - aria-labelledby={labelId} - /> - - {descriptionComp} - + ); } else if (md.type === Setting.TYPE_BUTTON) { // TODO: Not yet supported diff --git a/packages/app-mobile/components/screens/ConfigScreen/SettingTextInput.tsx b/packages/app-mobile/components/screens/ConfigScreen/SettingTextInput.tsx new file mode 100644 index 0000000000..785d2de228 --- /dev/null +++ b/packages/app-mobile/components/screens/ConfigScreen/SettingTextInput.tsx @@ -0,0 +1,57 @@ +import * as React from 'react'; +import { View, Text, TextInput } from 'react-native'; +import Setting, { AppType } from '@joplin/lib/models/Setting'; +import { ConfigScreenStyles } from './configScreenStyles'; +import { UpdateSettingValueCallback } from './types'; +import { themeStyle } from '../../global-style'; +import { FunctionComponent, ReactNode, useId, useState } from 'react'; + +interface Props { + settingId: string; + value: string; + styles: ConfigScreenStyles; + themeId: number; + label: string; + updateSettingValue: UpdateSettingValueCallback; + description?: ReactNode; +} + +const SettingTextInput: FunctionComponent = props => { + const [valueState, setValueState] = useState(props.value); + const md = Setting.settingMetadata(props.settingId); + const themeId = props.themeId; + const theme = themeStyle(themeId); + const settingDescription = md.description ? md.description(AppType.Mobile) : ''; + const styleSheet = props.styles.styleSheet; + const containerStyles = props.styles.getContainerStyle(!!settingDescription); + const labelId = useId(); + + return ( + + + + {md.label()} + + { + setValueState(newValue); + void props.updateSettingValue(props.settingId, newValue); + }} + secureTextEntry={!!md.secure} + aria-labelledby={labelId} + /> + + {props.description} + + ); +}; + +export default SettingTextInput; From b1edb84b49037840c733e5098c7f0f5a0ddf7cc2 Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Thu, 27 Mar 2025 07:44:19 -0700 Subject: [PATCH 076/158] Android: Voice typing: Default to a larger model (#12009) --- packages/app-mobile/services/voiceTyping/whisper.ts | 10 +++++----- readme/dev/spec/voice_typing.md | 2 +- readme/privacy.md | 2 +- readme/welcome/5_privacy.md | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/app-mobile/services/voiceTyping/whisper.ts b/packages/app-mobile/services/voiceTyping/whisper.ts index 698fcc5f63..a1ba1824dd 100644 --- a/packages/app-mobile/services/voiceTyping/whisper.ts +++ b/packages/app-mobile/services/voiceTyping/whisper.ts @@ -202,14 +202,14 @@ const whisper: VoiceTypingProvider = { let urlTemplate = rtrimSlashes(Setting.value('voiceTypingBaseUrl').trim()); if (!urlTemplate) { - urlTemplate = 'https://github.com/personalizedrefrigerator/joplin-voice-typing-test/releases/download/v0.0.3/{task}.zip'; + urlTemplate = 'https://github.com/joplin/voice-typing-models/releases/download/v0.2.0/{task}.zip'; } - // Note: whisper-base-q8_0 is also available and works on many Android devices. On some low - // resource devices, however, it will fail. - // TODO: Auto-select the model size? + // Note: whisper-base-q8_0.fr is also available and may have better performance on French-language + // input. + // TODO: Auto-select the model? return urlTemplate - .replace(/\{task\}/g, 'whisper-tiny-q8_0') + .replace(/\{task\}/g, 'whisper-base-q8_0') .replace(/\{lang\}/g, lang); }, deleteCachedModels: async (locale) => { diff --git a/readme/dev/spec/voice_typing.md b/readme/dev/spec/voice_typing.md index 8460fa2e58..a2ce83f716 100644 --- a/readme/dev/spec/voice_typing.md +++ b/readme/dev/spec/voice_typing.md @@ -12,7 +12,7 @@ Whisper.cpp provides a number of pre-trained models for transcribing speech in d ### Downloading the models -By default, Joplin downloads Whisper models from [this GitHub repository](https://github.com/personalizedrefrigerator/joplin-voice-typing-test/releases). It's possible to download models from a custom location by changing the **Voice typing language files (URL)** in from the "Note" tab of the configuration screen. +By default, Joplin downloads Whisper models from [this GitHub repository](https://github.com/joplin/voice-typing-models). It's possible to download models from a custom location by changing the **Voice typing language files (URL)** in from the "Note" tab of the configuration screen. ### Customizing Whisper diff --git a/readme/privacy.md b/readme/privacy.md index 638688e309..de45172d3f 100644 --- a/readme/privacy.md +++ b/readme/privacy.md @@ -12,7 +12,7 @@ In order to provide certain features, Joplin may need to connect to third-party | Wifi connection check | On mobile, Joplin checks for Wifi connectivity to give the option to synchronise data only when Wifi is enabled. | Enabled | No (1) | | Spellchecker dictionary | On Linux and Windows, the desktop application downloads the spellchecker dictionary from `redirector.gvt1.com`. | Enabled | Yes (2) | | Plugin repository | The desktop application downloads the list of available plugins from the [official GitHub repository](https://github.com/joplin/plugins). If this repository is not accessible (eg. in China) the app will try to get the plugin list from [various mirrors](https://github.com/laurent22/joplin/blob/8ac6017c02017b6efd59f5fcab7e0b07f8d44164/packages/lib/services/plugins/RepositoryApi.ts#L22), in which case the plugin screen [works slightly differently](https://github.com/laurent22/joplin/issues/5161#issuecomment-925226975). | Enabled | No -| Voice typing | If you use the voice typing feature on Android, the application will download the language files from https://alphacephei.com/vosk/models | Disabled | Yes +| Voice typing | If you use the voice typing feature on Android, the application will download the language files from https://github.com/joplin/voice-typing-models/ or https://alphacephei.com/vosk/models. | Disabled | Yes | OCR | If you have enabled optical character recognition on desktop, the application will download the language files from https://cdn.jsdelivr.net/npm/@tesseract.js-data/. | Disabled | Yes | Crash reports | If you have enabled crash auto-upload, the application will upload the report to Sentry when a crash happens. When Sentry is initialised it will also connect to `sentry.io`. | Disabled | Yes diff --git a/readme/welcome/5_privacy.md b/readme/welcome/5_privacy.md index 862659640b..581db62710 100644 --- a/readme/welcome/5_privacy.md +++ b/readme/welcome/5_privacy.md @@ -14,7 +14,7 @@ In order to provide certain features, Joplin may need to connect to third-party | Wifi connection check | On mobile, Joplin checks for Wifi connectivity to give the option to synchronise data only when Wifi is enabled. | Enabled | No (1) | | Spellchecker dictionary | On Linux and Windows, the desktop application downloads the spellchecker dictionary from `redirector.gvt1.com`. | Enabled | Yes (2) | | Plugin repository | The desktop application downloads the list of available plugins from the [official GitHub repository](https://github.com/joplin/plugins). If this repository is not accessible (eg. in China) the app will try to get the plugin list from [various mirrors](https://github.com/laurent22/joplin/blob/8ac6017c02017b6efd59f5fcab7e0b07f8d44164/packages/lib/services/plugins/RepositoryApi.ts#L22), in which case the plugin screen [works slightly differently](https://github.com/laurent22/joplin/issues/5161#issuecomment-925226975). | Enabled | No -| Voice typing | If you use the voice typing feature on Android, the application will download the language files from https://alphacephei.com/vosk/models | Disabled | Yes +| Voice typing | If you use the voice typing feature on Android, the application will download the language files from https://github.com/joplin/voice-typing-models/ or https://alphacephei.com/vosk/models. | Disabled | Yes (1) https://github.com/laurent22/joplin/issues/5705
(2) If the spellchecker is disabled, [it will not download the dictionary](https://discourse.joplinapp.org/t/new-version-of-joplin-contacting-google-servers-on-startup/23000/40?u=laurent). From 675f55d152dd18e427960af2334fd7bc459e05a2 Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Thu, 27 Mar 2025 07:53:59 -0700 Subject: [PATCH 077/158] Desktop: Resolves #11741: Accessibility: Add screen reader announcements when toggling the note list and/or sidebar (#11776) --- .../WindowCommandsAndDialogs/commands/toggleNoteList.ts | 7 +++++-- .../WindowCommandsAndDialogs/commands/toggleSideBar.ts | 7 +++++-- .../WindowCommandsAndDialogs/utils/useWindowControl.ts | 8 ++++++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleNoteList.ts b/packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleNoteList.ts index 7730634246..12d46b7288 100644 --- a/packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleNoteList.ts +++ b/packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleNoteList.ts @@ -3,6 +3,7 @@ import { _ } from '@joplin/lib/locale'; import setLayoutItemProps from '../../ResizableLayout/utils/setLayoutItemProps'; import layoutItemProp from '../../ResizableLayout/utils/layoutItemProp'; import { AppState } from '../../../app.reducer'; +import { WindowControl } from '../utils/useWindowControl'; export const declaration: CommandDeclaration = { name: 'toggleNoteList', @@ -10,14 +11,16 @@ export const declaration: CommandDeclaration = { iconName: 'fas fa-align-justify', }; -export const runtime = (): CommandRuntime => { +export const runtime = (control: WindowControl): CommandRuntime => { return { execute: async (context: CommandContext) => { const layout = (context.state as AppState).mainLayout; + const visible = !layoutItemProp(layout, 'noteList', 'visible'); const newLayout = setLayoutItemProps(layout, 'noteList', { - visible: !layoutItemProp(layout, 'noteList', 'visible'), + visible, }); + control.announcePanelVisibility(_('Note list'), visible); // Toggling the sidebar will affect the size of most other on-screen components. // Dispatching a window resize event is a bit of a hack, but it ensures that any diff --git a/packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleSideBar.ts b/packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleSideBar.ts index 698896ee1a..ae5bcebf0c 100644 --- a/packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleSideBar.ts +++ b/packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleSideBar.ts @@ -3,6 +3,7 @@ import { _ } from '@joplin/lib/locale'; import setLayoutItemProps from '../../ResizableLayout/utils/setLayoutItemProps'; import layoutItemProp from '../../ResizableLayout/utils/layoutItemProp'; import { AppState } from '../../../app.reducer'; +import { WindowControl } from '../utils/useWindowControl'; export const declaration: CommandDeclaration = { name: 'toggleSideBar', @@ -10,14 +11,16 @@ export const declaration: CommandDeclaration = { iconName: 'fas fa-bars', }; -export const runtime = (): CommandRuntime => { +export const runtime = (control: WindowControl): CommandRuntime => { return { execute: async (context: CommandContext) => { const layout = (context.state as AppState).mainLayout; + const visible = !layoutItemProp(layout, 'sideBar', 'visible'); const newLayout = setLayoutItemProps(layout, 'sideBar', { - visible: !layoutItemProp(layout, 'sideBar', 'visible'), + visible, }); + control.announcePanelVisibility(_('Sidebar'), visible); // Toggling the sidebar will affect the size of most other on-screen components. // Dispatching a window resize event is a bit of a hack, but it ensures that any diff --git a/packages/app-desktop/gui/WindowCommandsAndDialogs/utils/useWindowControl.ts b/packages/app-desktop/gui/WindowCommandsAndDialogs/utils/useWindowControl.ts index b5b50ba226..209095d9ab 100644 --- a/packages/app-desktop/gui/WindowCommandsAndDialogs/utils/useWindowControl.ts +++ b/packages/app-desktop/gui/WindowCommandsAndDialogs/utils/useWindowControl.ts @@ -2,10 +2,13 @@ import * as React from 'react'; import { useMemo, useRef } from 'react'; import { DialogState } from '../types'; import { PrintCallback } from './usePrintToCallback'; +import { _ } from '@joplin/lib/locale'; +import announceForAccessibility from '../../utils/announceForAccessibility'; export interface WindowControl { setState: (update: Partial)=> void; printTo: PrintCallback; + announcePanelVisibility(panelName: string, visible: boolean): void; } export type OnSetDialogState = React.Dispatch>; @@ -24,6 +27,11 @@ const useWindowControl = (setDialogState: OnSetDialogState, onPrint: PrintCallba })); }, printTo: (target, options) => onPrintRef.current(target, options), + announcePanelVisibility: (panelName, visible) => { + announceForAccessibility( + visible ? _('Panel "%s" is visible', panelName) : _('Panel %s is hidden', panelName), + ); + }, }; }, [setDialogState]); }; From 3e5acfbc09b0a8e0d7dd1ff3a5404effb9919cd2 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Thu, 27 Mar 2025 18:27:22 +0100 Subject: [PATCH 078/158] Doc: update sponsors --- packages/tools/sponsors.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/tools/sponsors.json b/packages/tools/sponsors.json index 5e88b57d76..cacc6cdbc1 100644 --- a/packages/tools/sponsors.json +++ b/packages/tools/sponsors.json @@ -100,11 +100,6 @@ "title": "Casino Reviews", "imageName": "CasinoReviews.png" }, - { - "url": "https://useviral.com.br/", - "title": "Comprar seguidores Instagram", - "imageName": "Useviral.png" - }, { "url": "https://ca.edubirdie.com/", "title": "Achieve academic success with Edubirdie — your trusted partner for expert writing assistance and resources!", From 0cef6cc6111d30ad3f61d83067ac44e51cd3553d Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Thu, 27 Mar 2025 10:57:55 -0700 Subject: [PATCH 079/158] Android: Voice typing: Fix incorrectly-calculated audio length (#12012) --- .../android/app/src/main/cpp/utils/WhisperSession.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/app-mobile/android/app/src/main/cpp/utils/WhisperSession.cpp b/packages/app-mobile/android/app/src/main/cpp/utils/WhisperSession.cpp index 6a73978edf..308035a0ff 100644 --- a/packages/app-mobile/android/app/src/main/cpp/utils/WhisperSession.cpp +++ b/packages/app-mobile/android/app/src/main/cpp/utils/WhisperSession.cpp @@ -69,10 +69,10 @@ WhisperSession::transcribe_(const std::vector& audio, size_t transcribeCo return ""; } - float seconds = static_cast(audio.size()) / WHISPER_SAMPLE_RATE; - if (seconds > 30.0f) { - LOGW("Warning: Audio is longer than 30 seconds. Not all audio will be transcribed"); - } + float seconds = static_cast(transcribeCount) / WHISPER_SAMPLE_RATE; + if (seconds > 30.0f) { + LOGW("Warning: Audio is longer than 30 seconds. Not all audio will be transcribed"); + } whisper_full_params params = buildWhisperParams_(); From 44d1e9e3ca0e56896f18a5b4d026e0143159c11e Mon Sep 17 00:00:00 2001 From: Joplin Bot Date: Thu, 27 Mar 2025 18:47:07 +0000 Subject: [PATCH 080/158] Doc: Auto-update documentation Auto-updated using release-website.sh --- README.md | 2 +- packages/lib/welcomeAssets.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1ed1420f0a..4543da127e 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Please see the [donation page](https://github.com/laurent22/joplin/blob/dev/read # Sponsors - EduBirdie web design agency RealGambling.ca write an essay online with EssayPro casino without making any upfront cost + EduBirdie web design agency RealGambling.ca write an essay online with EssayPro casino without making any upfront cost * * * diff --git a/packages/lib/welcomeAssets.js b/packages/lib/welcomeAssets.js index e802d6c61d..5a2c3c470d 100644 --- a/packages/lib/welcomeAssets.js +++ b/packages/lib/welcomeAssets.js @@ -46,7 +46,7 @@ module.exports = { { "id": "5ec2e7505ec2e7505ec2e7505ec2e750", "title": "5. Joplin Privacy Policy", - "body": "# Joplin Privacy Policy\n\nThe Joplin applications, including the Android, iOS, Windows, macOS and Linux applications, do not send any data to any service without your authorisation. Any data that Joplin saves, such as notes or images, are saved to your own device and you are free to delete this data at any time.\n\nIf you choose to synchronise with a third-party, such as OneDrive or Dropbox, the notes will be sent to that account, in which case the third-party privacy policy applies.\n\nIn order to provide certain features, Joplin may need to connect to third-party services. You can disable most of these features in the application settings:\n\n| Feature | Description | Default | Can be disabled |\n| -------- | ------------- | -------- | --- |\n| Auto-update | Joplin periodically connects to GitHub to check for new releases. | Enabled | Yes |\n| Geo-location | Joplin saves geo-location information in note properties when you create a note. | Enabled | Yes |\n| Synchronisation | Joplin supports synchronisation of your notes across multiple devices. If you choose to synchronise with a third-party, such as OneDrive, the notes will be sent to your OneDrive account, in which case the third-party privacy policy applies. | Disabled | Yes |\n| Wifi connection check | On mobile, Joplin checks for Wifi connectivity to give the option to synchronise data only when Wifi is enabled. | Enabled | No (1) |\n| Spellchecker dictionary | On Linux and Windows, the desktop application downloads the spellchecker dictionary from `redirector.gvt1.com`. | Enabled | Yes (2) |\n| Plugin repository | The desktop application downloads the list of available plugins from the [official GitHub repository](https://github.com/joplin/plugins). If this repository is not accessible (eg. in China) the app will try to get the plugin list from [various mirrors](https://github.com/laurent22/joplin/blob/8ac6017c02017b6efd59f5fcab7e0b07f8d44164/packages/lib/services/plugins/RepositoryApi.ts#L22), in which case the plugin screen [works slightly differently](https://github.com/laurent22/joplin/issues/5161#issuecomment-925226975). | Enabled | No\n| Voice typing | If you use the voice typing feature on Android, the application will download the language files from https://alphacephei.com/vosk/models | Disabled | Yes\n\n(1) https://github.com/laurent22/joplin/issues/5705
\n(2) If the spellchecker is disabled, [it will not download the dictionary](https://discourse.joplinapp.org/t/new-version-of-joplin-contacting-google-servers-on-startup/23000/40?u=laurent).\n\nFor any question about Joplin privacy policy, please leave a message [on the forum](https://discourse.joplinapp.org/).\n", + "body": "# Joplin Privacy Policy\n\nThe Joplin applications, including the Android, iOS, Windows, macOS and Linux applications, do not send any data to any service without your authorisation. Any data that Joplin saves, such as notes or images, are saved to your own device and you are free to delete this data at any time.\n\nIf you choose to synchronise with a third-party, such as OneDrive or Dropbox, the notes will be sent to that account, in which case the third-party privacy policy applies.\n\nIn order to provide certain features, Joplin may need to connect to third-party services. You can disable most of these features in the application settings:\n\n| Feature | Description | Default | Can be disabled |\n| -------- | ------------- | -------- | --- |\n| Auto-update | Joplin periodically connects to GitHub to check for new releases. | Enabled | Yes |\n| Geo-location | Joplin saves geo-location information in note properties when you create a note. | Enabled | Yes |\n| Synchronisation | Joplin supports synchronisation of your notes across multiple devices. If you choose to synchronise with a third-party, such as OneDrive, the notes will be sent to your OneDrive account, in which case the third-party privacy policy applies. | Disabled | Yes |\n| Wifi connection check | On mobile, Joplin checks for Wifi connectivity to give the option to synchronise data only when Wifi is enabled. | Enabled | No (1) |\n| Spellchecker dictionary | On Linux and Windows, the desktop application downloads the spellchecker dictionary from `redirector.gvt1.com`. | Enabled | Yes (2) |\n| Plugin repository | The desktop application downloads the list of available plugins from the [official GitHub repository](https://github.com/joplin/plugins). If this repository is not accessible (eg. in China) the app will try to get the plugin list from [various mirrors](https://github.com/laurent22/joplin/blob/8ac6017c02017b6efd59f5fcab7e0b07f8d44164/packages/lib/services/plugins/RepositoryApi.ts#L22), in which case the plugin screen [works slightly differently](https://github.com/laurent22/joplin/issues/5161#issuecomment-925226975). | Enabled | No\n| Voice typing | If you use the voice typing feature on Android, the application will download the language files from https://github.com/joplin/voice-typing-models/ or https://alphacephei.com/vosk/models. | Disabled | Yes\n\n(1) https://github.com/laurent22/joplin/issues/5705
\n(2) If the spellchecker is disabled, [it will not download the dictionary](https://discourse.joplinapp.org/t/new-version-of-joplin-contacting-google-servers-on-startup/23000/40?u=laurent).\n\nFor any question about Joplin privacy policy, please leave a message [on the forum](https://discourse.joplinapp.org/).\n", "resources": {}, "parent_id": "9bb5d498aba74cc6a047cfdc841e82a1" } From 0bc62aa05ed223389764d4ae5532c4a319cc56ff Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Thu, 27 Mar 2025 21:55:36 +0100 Subject: [PATCH 081/158] All: Fixes #11934: Restoring a note which was in a deleted notebook (#12016) --- .../commands/stateToWhenClauseContext.test.ts | 11 +++++++++++ .../lib/services/commands/stateToWhenClauseContext.ts | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/lib/services/commands/stateToWhenClauseContext.test.ts b/packages/lib/services/commands/stateToWhenClauseContext.test.ts index 2c0dc9922f..a772c9aa8b 100644 --- a/packages/lib/services/commands/stateToWhenClauseContext.test.ts +++ b/packages/lib/services/commands/stateToWhenClauseContext.test.ts @@ -50,6 +50,7 @@ describe('stateToWhenClauseContext', () => { it('should be in trash if command folder is deleted', async () => { const applicationState = { notes: [], + notesParentType: 'Folder', folders: [ { id: '1', deleted_time: 1722567036580, share_id: '', parent_id: '' }, ], @@ -71,4 +72,14 @@ describe('stateToWhenClauseContext', () => { expect(resultingState.inTrash).toBe(false); }); + it('should not be in trash if viewing all notes', async () => { + const applicationState = { + selectedFolderId: 'folder', + notesParentType: 'SmartFolder', + } as State; + const resultingState = stateToWhenClauseContext(applicationState); + + expect(resultingState.inTrash).toBe(false); + }); + }); diff --git a/packages/lib/services/commands/stateToWhenClauseContext.ts b/packages/lib/services/commands/stateToWhenClauseContext.ts index 0976249b1d..fa885ff77f 100644 --- a/packages/lib/services/commands/stateToWhenClauseContext.ts +++ b/packages/lib/services/commands/stateToWhenClauseContext.ts @@ -60,7 +60,7 @@ export default function stateToWhenClauseContext(state: State, options: WhenClau const selectedNote: NoteEntity = selectedNoteId ? BaseModel.byId(windowState.notes, selectedNoteId) : null; const selectedNotes = BaseModel.modelsByIds(windowState.notes ?? [], selectedNoteIds); - const commandFolderId = options.commandFolderId || windowState.selectedFolderId; + const commandFolderId = state.notesParentType === 'Folder' ? (options.commandFolderId || windowState.selectedFolderId) : ''; const commandFolder: FolderEntity = commandFolderId ? BaseModel.byId(state.folders, commandFolderId) : null; const { editorPlugin } = state.pluginService ? getActivePluginEditorView(state.pluginService.plugins) : { editorPlugin: null }; From 0a4c97c631c5d0d083fcf0b39eff02a4ac8c76ab Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Thu, 27 Mar 2025 13:56:56 -0700 Subject: [PATCH 082/158] Android: Voice typing: Performance: Disable preview generation logic (#12008) --- .../app/src/main/cpp/utils/WhisperSession.cpp | 41 +++++++------------ .../app/src/main/cpp/utils/WhisperSession.h | 12 +----- .../app/src/main/cpp/whisperWrapper.cpp | 9 ---- .../cozic/joplin/audio/NativeWhisperLib.kt | 9 ---- .../joplin/audio/SpeechToTextConverter.kt | 4 -- .../cozic/joplin/audio/SpeechToTextPackage.kt | 5 --- .../audio/SpeechToTextSessionManager.kt | 7 ---- .../services/voiceTyping/whisper.test.ts | 3 +- .../services/voiceTyping/whisper.ts | 4 -- 9 files changed, 17 insertions(+), 77 deletions(-) diff --git a/packages/app-mobile/android/app/src/main/cpp/utils/WhisperSession.cpp b/packages/app-mobile/android/app/src/main/cpp/utils/WhisperSession.cpp index 308035a0ff..53f48c931b 100644 --- a/packages/app-mobile/android/app/src/main/cpp/utils/WhisperSession.cpp +++ b/packages/app-mobile/android/app/src/main/cpp/utils/WhisperSession.cpp @@ -54,7 +54,7 @@ WhisperSession::buildWhisperParams_() { params.initial_prompt = prompt_.c_str(); params.prompt_tokens = nullptr; params.prompt_n_tokens = 0; - params.audio_ctx = 0; + params.audio_ctx = 0; // Lifetime: lifetime(params) < lifetime(lang_) = lifetime(this). params.language = lang_.c_str(); @@ -76,19 +76,19 @@ WhisperSession::transcribe_(const std::vector& audio, size_t transcribeCo whisper_full_params params = buildWhisperParams_(); - // If supported by the model, allow shortening the transcription. This can significantly - // improve performance, but requires a fine-tuned model. - // See https://github.com/futo-org/whisper-acft - if (this->shortAudioContext_) { - // audio_ctx: 1500 every 30 seconds (50 units in one second). - // See https://github.com/futo-org/whisper-acft/issues/6 - float padding = 64.0f; - params.audio_ctx = static_cast(seconds * (1500.0f / 30.0f) + padding); + // If supported by the model, allow shortening the transcription. This can significantly + // improve performance, but requires a fine-tuned model. + // See https://github.com/futo-org/whisper-acft + if (this->shortAudioContext_) { + // audio_ctx: 1500 every 30 seconds (50 units in one second). + // See https://github.com/futo-org/whisper-acft/issues/6 + float padding = 64.0f; + params.audio_ctx = static_cast(seconds * (1500.0f / 30.0f) + padding); - if (params.audio_ctx > 1500) { - params.audio_ctx = 1500; - } - } + if (params.audio_ctx > 1500) { + params.audio_ctx = 1500; + } + } whisper_reset_timings(pContext_); transcribeCount = std::min(audio.size(), transcribeCount); @@ -139,7 +139,7 @@ bool WhisperSession::isBufferSilent_() { } std::string -WhisperSession::transcribeNextChunkNoPreview_() { +WhisperSession::transcribeNextChunk() { std::stringstream result; // Handles a silence detected between (splitStart, splitEnd). @@ -216,12 +216,6 @@ void WhisperSession::addAudio(const float *pAudio, int sizeAudio) { } } -std::string WhisperSession::transcribeNextChunk() { - std::string finalizedContent = transcribeNextChunkNoPreview_(); - previewText_ = transcribe_(audioBuffer_, audioBuffer_.size()); - return finalizedContent; -} - std::string WhisperSession::transcribeAll() { if (isBufferSilent_()) { return ""; @@ -231,7 +225,7 @@ std::string WhisperSession::transcribeAll() { std::string transcribed; auto update_transcribed = [&] { - transcribed = transcribeNextChunkNoPreview_(); + transcribed = transcribeNextChunk(); return !transcribed.empty(); }; while (update_transcribed()) { @@ -244,10 +238,5 @@ std::string WhisperSession::transcribeAll() { } audioBuffer_.clear(); - previewText_ = ""; return result.str(); } - -std::string WhisperSession::getPreview() { - return previewText_; -} diff --git a/packages/app-mobile/android/app/src/main/cpp/utils/WhisperSession.h b/packages/app-mobile/android/app/src/main/cpp/utils/WhisperSession.h index 4934a83974..7eaa3c6866 100644 --- a/packages/app-mobile/android/app/src/main/cpp/utils/WhisperSession.h +++ b/packages/app-mobile/android/app/src/main/cpp/utils/WhisperSession.h @@ -13,28 +13,18 @@ public: std::string transcribeNextChunk(); // Transcribes all buffered audio data that hasn't been finalized yet std::string transcribeAll(); - // Returns the transcription of any unfinalized audio - std::string getPreview(); private: - // Current preview state - std::string previewText_; - whisper_full_params buildWhisperParams_(); std::string transcribe_(const std::vector& audio, size_t samplesToTranscribe); std::string splitAndTranscribeBefore_(int transcribeUpTo, int trimTo); - // Like transcribeNextChunk, but does not update the preview state - // and does not add a new chunk to the buffer. - // Since updating the preview state can be slow, this may be preferred - // for internal operations where the preview does not need to be kept up-to-date. - std::string transcribeNextChunkNoPreview_(); bool isBufferSilent_(); whisper_context *pContext_; const std::string lang_; const std::string prompt_; - const bool shortAudioContext_; + const bool shortAudioContext_; std::vector audioBuffer_; }; diff --git a/packages/app-mobile/android/app/src/main/cpp/whisperWrapper.cpp b/packages/app-mobile/android/app/src/main/cpp/whisperWrapper.cpp index d597d39c94..e6089ca3cd 100644 --- a/packages/app-mobile/android/app/src/main/cpp/whisperWrapper.cpp +++ b/packages/app-mobile/android/app/src/main/cpp/whisperWrapper.cpp @@ -139,15 +139,6 @@ Java_net_cozic_joplin_audio_NativeWhisperLib_00024Companion_transcribeRemaining( return stringToJava(env, result); } -extern "C" -JNIEXPORT jstring JNICALL -Java_net_cozic_joplin_audio_NativeWhisperLib_00024Companion_getPreview( - JNIEnv *env, jobject thiz, jlong pointer -) { - auto *pSession = reinterpret_cast (pointer); - return stringToJava(env, pSession->getPreview()); -} - extern "C" JNIEXPORT void JNICALL Java_net_cozic_joplin_audio_NativeWhisperLib_00024Companion_runTests(JNIEnv *env, jobject thiz) { diff --git a/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/NativeWhisperLib.kt b/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/NativeWhisperLib.kt index 0e12eaf5b6..a07af37099 100644 --- a/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/NativeWhisperLib.kt +++ b/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/NativeWhisperLib.kt @@ -23,7 +23,6 @@ class NativeWhisperLib( private external fun addAudio(pointer: Long, audioData: FloatArray): Unit; private external fun transcribeNextChunk(pointer: Long): String; private external fun transcribeRemaining(pointer: Long): String; - private external fun getPreview(pointer: Long): String; } private var closed = false @@ -53,14 +52,6 @@ class NativeWhisperLib( return Companion.transcribeRemaining(pointer) } - fun getPreview(): String { - if (closed) { - throw Exception("Cannot get preview from a closed session") - } - - return getPreview(pointer) - } - override fun close() { if (closed) { throw Exception("Cannot close a whisper session twice") diff --git a/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/SpeechToTextConverter.kt b/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/SpeechToTextConverter.kt index 84ca9fed4c..c2f752ae29 100644 --- a/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/SpeechToTextConverter.kt +++ b/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/SpeechToTextConverter.kt @@ -54,10 +54,6 @@ class SpeechToTextConverter( return whisper.transcribeRemaining() } - fun getPreview(): String { - return whisper.getPreview() - } - override fun close() { Log.d("Whisper", "Close") recorder.close() diff --git a/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/SpeechToTextPackage.kt b/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/SpeechToTextPackage.kt index 1e29d7a6e9..2e6f03e150 100644 --- a/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/SpeechToTextPackage.kt +++ b/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/SpeechToTextPackage.kt @@ -79,11 +79,6 @@ class SpeechToTextPackage : ReactPackage { sessionManager.convertAvailable(sessionId, promise) } - @ReactMethod - fun getPreview(sessionId: Int, promise: Promise) { - sessionManager.getPreview(sessionId, promise) - } - @ReactMethod fun closeSession(sessionId: Int, promise: Promise) { sessionManager.closeSession(sessionId, promise) diff --git a/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/SpeechToTextSessionManager.kt b/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/SpeechToTextSessionManager.kt index 94fca284c7..c770cc79af 100644 --- a/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/SpeechToTextSessionManager.kt +++ b/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/audio/SpeechToTextSessionManager.kt @@ -102,13 +102,6 @@ class SpeechToTextSessionManager( } } - fun getPreview(sessionId: Int, promise: Promise) { - this.concurrentWithSession(sessionId, promise::reject) { session -> - val result = session.converter.getPreview() - promise.resolve(result) - } - } - fun closeSession(sessionId: Int, promise: Promise) { this.concurrentWithSession(sessionId) { session -> session.converter.close() diff --git a/packages/app-mobile/services/voiceTyping/whisper.test.ts b/packages/app-mobile/services/voiceTyping/whisper.test.ts index c032481fe3..a4aa98ab9c 100644 --- a/packages/app-mobile/services/voiceTyping/whisper.test.ts +++ b/packages/app-mobile/services/voiceTyping/whisper.test.ts @@ -11,7 +11,6 @@ jest.mock('react-native', () => { // See https://github.com/facebook/react-native/issues/28839. reactNative.NativeModules.SpeechToTextModule = { convertNext: () => 'Test. This is test output. Test!', - getPreview: () => 'A preview of future output.', runTests: ()=> {}, openSession: jest.fn(() => { const someId = 1234; @@ -84,6 +83,6 @@ describe('whisper', () => { // Should have applied string, then regex replacements. expect( lastFinalizedText, - ).toBe('replaced again!. This is test output. replaced again!!'); + ).toBe('\n\nreplaced again!. This is test output. replaced again!!'); }); }); diff --git a/packages/app-mobile/services/voiceTyping/whisper.ts b/packages/app-mobile/services/voiceTyping/whisper.ts index a1ba1824dd..7be04f2c85 100644 --- a/packages/app-mobile/services/voiceTyping/whisper.ts +++ b/packages/app-mobile/services/voiceTyping/whisper.ts @@ -139,10 +139,6 @@ class Whisper implements VoiceTypingSession { this.onDataFinalize(data); logger.debug('done reading block. Length', data?.length); - if (this.sessionId !== null) { - const previewText = await SpeechToTextModule.getPreview(this.sessionId); - this.callbacks.onPreview(this.postProcessSpeech(previewText)); - } } } catch (error) { logger.error('Whisper error:', error); From 5198b598bbf7577b10488d9569a1782de1492a7c Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Thu, 27 Mar 2025 13:57:05 -0700 Subject: [PATCH 083/158] Android: Voice typing: Improve transcription at the end of paragraphs (#12013) --- .../android/app/src/main/cpp/utils/WhisperSession.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/app-mobile/android/app/src/main/cpp/utils/WhisperSession.cpp b/packages/app-mobile/android/app/src/main/cpp/utils/WhisperSession.cpp index 53f48c931b..13f10fb290 100644 --- a/packages/app-mobile/android/app/src/main/cpp/utils/WhisperSession.cpp +++ b/packages/app-mobile/android/app/src/main/cpp/utils/WhisperSession.cpp @@ -64,7 +64,8 @@ WhisperSession::buildWhisperParams_() { std::string WhisperSession::transcribe_(const std::vector& audio, size_t transcribeCount) { - int minTranscribeLength = WHISPER_SAMPLE_RATE / 2; // 0.5s + // Whisper won't transcribe anything shorter than 1s. + int minTranscribeLength = WHISPER_SAMPLE_RATE; // 1s if (transcribeCount < minTranscribeLength) { return ""; } @@ -152,6 +153,12 @@ WhisperSession::transcribeNextChunk() { audioBuffer_.clear(); return false; } else if (splitEnd > tolerance) { // Anything to transcribe? + // Include some of the silence between the start and the end. Excluding it + // seems to make Whisper more likely to omit trailing punctuation. + int maximumSilentSamples = WHISPER_SAMPLE_RATE; + int silentSamplesToAdd = std::min(maximumSilentSamples, (splitEnd - splitStart) / 2); + splitStart += silentSamplesToAdd; + result << splitAndTranscribeBefore_(splitStart, splitEnd) << "\n\n"; return true; } From 5966402d8b611b917acfaa9bdb0161a61d8963e0 Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Thu, 27 Mar 2025 13:57:28 -0700 Subject: [PATCH 084/158] Chore: Make useFormNote.test.ts less likely to fail in CI (#12014) --- .../app-desktop/gui/NoteEditor/utils/useFormNote.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/app-desktop/gui/NoteEditor/utils/useFormNote.ts b/packages/app-desktop/gui/NoteEditor/utils/useFormNote.ts index a4c35d70e0..d9d082bada 100644 --- a/packages/app-desktop/gui/NoteEditor/utils/useFormNote.ts +++ b/packages/app-desktop/gui/NoteEditor/utils/useFormNote.ts @@ -97,7 +97,15 @@ const useRefreshFormNoteOnChange = (formNoteRef: RefObject, editorId: await initNoteState(n, false); if (event.cancelled) return; - setFormNoteRefreshScheduled(0); + setFormNoteRefreshScheduled(oldValue => { + // If a new refresh was scheduled between initNoteState + // and now: + if (oldValue !== formNoteRefreshScheduled) { + return oldValue; + } + // A refresh is no longer scheduled + return 0; + }); }; await loadNote(); From 6a26ec8105421128f668a807bc14c8f18df475ec Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Thu, 27 Mar 2025 13:57:38 -0700 Subject: [PATCH 085/158] Android: Voice typing: Disable "Download update" button while downloading an updated model (#12015) --- .../app-mobile/components/voiceTyping/SpeechToTextBanner.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/app-mobile/components/voiceTyping/SpeechToTextBanner.tsx b/packages/app-mobile/components/voiceTyping/SpeechToTextBanner.tsx index 7084a4a06f..19e119f448 100644 --- a/packages/app-mobile/components/voiceTyping/SpeechToTextBanner.tsx +++ b/packages/app-mobile/components/voiceTyping/SpeechToTextBanner.tsx @@ -186,7 +186,7 @@ const SpeechToTextComponent: React.FC = props => { const reDownloadButton =
diff --git a/packages/app-desktop/integration-tests/wcag.spec.ts b/packages/app-desktop/integration-tests/wcag.spec.ts index 3f851dcf32..0604088fee 100644 --- a/packages/app-desktop/integration-tests/wcag.spec.ts +++ b/packages/app-desktop/integration-tests/wcag.spec.ts @@ -54,6 +54,12 @@ test.describe('wcag', () => { const mainScreen = await new MainScreen(mainWindow).setup(); await mainScreen.waitFor(); + // Ensure that there is at least one sub-folder in the sidebar + const folder1 = await mainScreen.sidebar.createNewFolder('Test folder 1'); + const folder2 = await mainScreen.sidebar.createNewFolder('Test folder 2'); + await folder2.dragTo(folder1); + await expect(folder2).toHaveJSProperty('ariaLevel', '3'); // Should be a sub-folder + await mainScreen.createNewNote('Test'); // Ensure that `:hover` styling is consistent between tests: From 1fed8751406aeacf6a8439abd3c1b92c77714cd6 Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Fri, 28 Mar 2025 05:40:36 -0700 Subject: [PATCH 092/158] Mobile: Plugins: Add command to hide the plugin panel viewer (#12018) --- .eslintignore | 1 + .gitignore | 1 + .../app-mobile/commands/dismissPluginPanels.ts | 16 ++++++++++++++++ packages/app-mobile/commands/index.ts | 2 ++ .../plugins/dialogs/PluginPanelViewer.tsx | 10 +++------- 5 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 packages/app-mobile/commands/dismissPluginPanels.ts diff --git a/.eslintignore b/.eslintignore index d3184257e8..0d741e902d 100644 --- a/.eslintignore +++ b/.eslintignore @@ -583,6 +583,7 @@ packages/app-desktop/utils/restartInSafeModeFromMain.test.js packages/app-desktop/utils/restartInSafeModeFromMain.js packages/app-desktop/utils/window/types.js packages/app-mobile/PluginAssetsLoader.js +packages/app-mobile/commands/dismissPluginPanels.js packages/app-mobile/commands/index.js packages/app-mobile/commands/newNote.test.js packages/app-mobile/commands/newNote.js diff --git a/.gitignore b/.gitignore index 37c02aeec1..e67719f994 100644 --- a/.gitignore +++ b/.gitignore @@ -558,6 +558,7 @@ packages/app-desktop/utils/restartInSafeModeFromMain.test.js packages/app-desktop/utils/restartInSafeModeFromMain.js packages/app-desktop/utils/window/types.js packages/app-mobile/PluginAssetsLoader.js +packages/app-mobile/commands/dismissPluginPanels.js packages/app-mobile/commands/index.js packages/app-mobile/commands/newNote.test.js packages/app-mobile/commands/newNote.js diff --git a/packages/app-mobile/commands/dismissPluginPanels.ts b/packages/app-mobile/commands/dismissPluginPanels.ts new file mode 100644 index 0000000000..744c007a9b --- /dev/null +++ b/packages/app-mobile/commands/dismissPluginPanels.ts @@ -0,0 +1,16 @@ +import { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/services/CommandService'; + +export const declaration: CommandDeclaration = { + name: 'dismissPluginPanels', +}; + +export const runtime = (): CommandRuntime => { + return { + execute: async (context: CommandContext) => { + context.dispatch({ + type: 'SET_PLUGIN_PANELS_DIALOG_VISIBLE', + visible: false, + }); + }, + }; +}; diff --git a/packages/app-mobile/commands/index.ts b/packages/app-mobile/commands/index.ts index 5a88342481..adc76ec48e 100644 --- a/packages/app-mobile/commands/index.ts +++ b/packages/app-mobile/commands/index.ts @@ -1,10 +1,12 @@ // AUTO-GENERATED using `gulp buildScriptIndexes` +import * as dismissPluginPanels from './dismissPluginPanels'; import * as newNote from './newNote'; import * as openItem from './openItem'; import * as openNote from './openNote'; import * as scrollToHash from './scrollToHash'; const index: any[] = [ + dismissPluginPanels, newNote, openItem, openNote, diff --git a/packages/app-mobile/components/plugins/dialogs/PluginPanelViewer.tsx b/packages/app-mobile/components/plugins/dialogs/PluginPanelViewer.tsx index df8c890c72..d0a9756d26 100644 --- a/packages/app-mobile/components/plugins/dialogs/PluginPanelViewer.tsx +++ b/packages/app-mobile/components/plugins/dialogs/PluginPanelViewer.tsx @@ -12,8 +12,8 @@ import PluginUserWebView from './PluginUserWebView'; import { View, StyleSheet, AccessibilityInfo } from 'react-native'; import { _ } from '@joplin/lib/locale'; import Setting from '@joplin/lib/models/Setting'; -import { Dispatch } from 'redux'; import DismissibleDialog, { DialogSize } from '../../../components/DismissibleDialog'; +import CommandService from '@joplin/lib/services/CommandService'; interface Props { themeId: number; @@ -21,7 +21,6 @@ interface Props { pluginHtmlContents: PluginHtmlContents; pluginStates: PluginStates; visible: boolean; - dispatch: Dispatch; } @@ -157,11 +156,8 @@ const PluginPanelViewer: React.FC = props => { }; const onClose = useCallback(() => { - props.dispatch({ - type: 'SET_PLUGIN_PANELS_DIALOG_VISIBLE', - visible: false, - }); - }, [props.dispatch]); + void CommandService.instance().execute('dismissPluginPanels'); + }, []); return ( From 6bc1965ec00905bb29b38d246514baefa8d883de Mon Sep 17 00:00:00 2001 From: Nick <84130654+NickWick13@users.noreply.github.com> Date: Fri, 28 Mar 2025 19:08:52 +0200 Subject: [PATCH 093/158] Update Swedish translation (#12023) --- packages/tools/locales/sv.po | 316 +++++++++++++++-------------------- 1 file changed, 132 insertions(+), 184 deletions(-) diff --git a/packages/tools/locales/sv.po b/packages/tools/locales/sv.po index 4af365700b..3989f52095 100644 --- a/packages/tools/locales/sv.po +++ b/packages/tools/locales/sv.po @@ -1,13 +1,15 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Laurent Cozic # This file is distributed under the same license as the Joplin-CLI package. -# FIRST AUTHOR , YEAR. +# Jonatan Nyberg, 2023, 2024, 2025. # msgid "" msgstr "" "Project-Id-Version: Joplin-CLI 1.0.0\n" "Report-Msgid-Bugs-To: \n" -"Last-Translator: Jonatan Nyberg \n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: Jonatan Nyberg\n" "Language-Team: \n" "Language: sv\n" "MIME-Version: 1.0\n" @@ -49,7 +51,7 @@ msgstr "(I insticksmodul: %s)" #: packages/app-mobile/components/side-menu-content.tsx:265 msgid "(level %d)" -msgstr "" +msgstr "(nivå %d)" #: packages/lib/SyncTargetNone.ts:16 msgid "(None)" @@ -263,9 +265,8 @@ msgstr "" "att-göra tillbaka till en vanlig anteckning." #: packages/app-desktop/gui/UpdateNotification/UpdateNotification.tsx:62 -#, fuzzy msgid "A new update (%s) is available" -msgstr "Uppdatering tillgänglig" +msgstr "En ny uppdatering (%s) är tillgänglig" #: packages/lib/models/settings/builtInMetadata.ts:1253 msgid "A3" @@ -373,7 +374,7 @@ msgstr "Lägg till mottagare:" #: packages/app-mobile/components/screens/NoteTagsDialog.tsx:94 msgid "Add tag %s to note" -msgstr "" +msgstr "Lägg till taggen %s till anteckningen" #: packages/app-mobile/components/screens/Note/Note.tsx:1574 msgid "Add title" @@ -384,9 +385,8 @@ msgid "Add to dictionary" msgstr "Lägg till i ordlistan" #: packages/app-mobile/components/CameraView/ScannedBarcodes.tsx:98 -#, fuzzy msgid "Add to note" -msgstr "Lägg till titel" +msgstr "Lägg till i anteckning" #: packages/server/src/services/MustacheService.ts:162 #: packages/server/src/services/MustacheService.ts:286 @@ -410,9 +410,8 @@ msgid "Advanced tools" msgstr "Avancerade verktyg" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:18 -#, fuzzy msgid "all" -msgstr "Installera" +msgstr "alla" #: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:109 msgid "" @@ -522,13 +521,12 @@ msgid "Apply" msgstr "Tillämpa" #: packages/app-mobile/components/EditorToolbar/ToolbarEditorDialog.tsx:146 -#, fuzzy msgid "" "Are you sure that you want to restore the default toolbar layout?\n" "This cannot be undone." msgstr "" -"Är du säker på att du vill återgå till standardlayouten? Den nuvarande " -"layoutkonfigurationen kommer att gå förlorad." +"Är du säker på att du vill återställa standardlayouten för verktygsfältet?\n" +"Detta kan inte ångras." #: packages/app-desktop/gui/ClipperConfigScreen.tsx:38 msgid "Are you sure you want to renew the authorisation token?" @@ -555,6 +553,8 @@ msgid "" "At present, Joplin Web can only be open in one tab at a time. Please close " "the other instance of Joplin." msgstr "" +"För närvarande kan Joplin Web endast vara öppen på en flik åt gången. Stäng " +"den andra instansen av Joplin." #: packages/app-mobile/components/NoteEditor/ImageEditor/promptRestoreAutosave.ts:25 msgid "Attach" @@ -640,7 +640,7 @@ msgstr "Para automatiskt hakparenteser, paranteser, situationstecken, etc." #: packages/lib/models/settings/builtInMetadata.ts:656 msgid "Autocomplete Markdown and HTML" -msgstr "" +msgstr "Slutför automatiskt Markdown och HTML" #: packages/lib/models/settings/builtInMetadata.ts:1198 msgid "Automatically check for updates" @@ -702,7 +702,7 @@ msgstr "av %s" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:20 msgid "by word" -msgstr "" +msgstr "med ord" #: packages/server/src/routes/admin/users.ts:160 msgid "Can Share" @@ -878,13 +878,12 @@ msgid "Change language" msgstr "Ändra språk" #: packages/app-mobile/components/CameraView/ActionButtons.tsx:124 -#, fuzzy msgid "Change ratio" -msgstr "Konfiguration" +msgstr "Ändra förhållande" #: packages/app-desktop/gui/KeymapConfig/KeymapConfigScreen.tsx:98 msgid "Change shortcut for \"%s\"" -msgstr "" +msgstr "Ändra genväg för \"%s\"" #: packages/app-desktop/gui/NoteContentPropertiesDialog.tsx:106 msgid "Characters" @@ -896,7 +895,7 @@ msgstr "Tecken exklusive mellanslag" #: packages/app-mobile/components/EditorToolbar/ToolbarEditorDialog.tsx:168 msgid "Check elements to display in the toolbar" -msgstr "" +msgstr "Markera element som ska visas i verktygsfältet" #: packages/app-desktop/gui/MenuBar.tsx:634 #: packages/app-desktop/gui/MenuBar.tsx:929 @@ -962,9 +961,8 @@ msgid "Client ID: %s" msgstr "Klient-ID: %s" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:23 -#, fuzzy msgid "close" -msgstr "Stäng" +msgstr "stäng" #: packages/app-desktop/gui/MenuBar.tsx:359 #: packages/app-desktop/gui/NoteContentPropertiesDialog.tsx:175 @@ -984,13 +982,12 @@ msgid "Close dropdown" msgstr "Stäng rullgardinsmenyn" #: packages/app-mobile/components/accessibility/AccessibleModalMenu.tsx:46 -#, fuzzy msgid "Close menu" -msgstr "Stäng" +msgstr "Stäng menyn" #: packages/app-mobile/components/SideMenu.tsx:300 msgid "Close side menu" -msgstr "" +msgstr "Stäng sidomenyn" #: packages/lib/models/settings/settingValidations.ts:33 msgid "" @@ -1038,7 +1035,7 @@ msgstr "Samarbeta på anteckningsböcker tillsammans med andra" #: packages/app-desktop/gui/Sidebar/listItemComponents/ExpandIcon.tsx:28 msgid "Collapsed, press space to expand." -msgstr "" +msgstr "Komprimerad, tryck på blanksteg för att expandera." #: packages/lib/services/ReportService.ts:351 msgid "Coming alarms" @@ -1047,9 +1044,9 @@ msgstr "Kommande larm" #: packages/lib/models/settings/builtInMetadata.ts:1379 msgid "" "Comma-separated list of paths to directories to load the certificates from, " -"or path to individual cert files. For example: /my/cert_dir, /other/" -"custom.pem. Note that if you make changes to the TLS settings, you must save " -"your changes before clicking on \"Check synchronisation configuration\"." +"or path to individual cert files. For example: /my/cert_dir, /other/custom." +"pem. Note that if you make changes to the TLS settings, you must save your " +"changes before clicking on \"Check synchronisation configuration\"." msgstr "" "Kommaseparerad lista över sökvägar till kataloger för att läsa certifikaten " "från eller sökvägen till enskilda cert-filer. Till exempel: /my/cert_dir,/" @@ -1078,14 +1075,12 @@ msgid "Compact" msgstr "Kompakt" #: packages/app-desktop/gui/NoteList/utils/useOnKeyDown.ts:153 -#, fuzzy msgid "Complete" -msgstr "Slutförd" +msgstr "Slutför" #: packages/app-desktop/gui/NoteListItem/utils/prepareViewProps.ts:40 -#, fuzzy msgid "Complete to-do" -msgstr "Slutförd" +msgstr "Slutför att-göra" #: packages/app-desktop/gui/NoteListHeader/utils/getColumnTitle.ts:12 #: packages/app-desktop/gui/NotePropertiesDialog.tsx:70 @@ -1158,11 +1153,10 @@ msgid "Consolidated billing" msgstr "Konsoliderad fakturering" #: packages/app-desktop/gui/Sidebar/listItemComponents/NoteCount.tsx:11 -#, fuzzy msgid "Contains %d note" msgid_plural "Contains %d notes" -msgstr[0] "Konvertera till anteckning" -msgstr[1] "Konvertera till anteckning" +msgstr[0] "Innehåller %d anteckning" +msgstr[1] "Innehåller %d anteckningar" #: packages/app-desktop/gui/ConfigScreen/controls/plugins/SearchPlugins.tsx:106 msgid "Content provided by %s" @@ -1177,9 +1171,8 @@ msgid "Continue" msgstr "Fortsätt" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:6 -#, fuzzy msgid "Control character" -msgstr "Tecken" +msgstr "Kontrollera tecken" #: packages/app-mobile/components/screens/Note/Note.tsx:1221 msgid "Convert to note" @@ -1416,14 +1409,12 @@ msgid "Ctrl-click to open: %s" msgstr "Ctrl-klicka för att öppna: %s" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:24 -#, fuzzy msgid "current match" -msgstr "Nästa träff" +msgstr "aktuell matchning" #: packages/app-desktop/gui/MasterPasswordDialog/Dialog.tsx:153 -#, fuzzy msgid "Current password" -msgstr "Ange lösenord" +msgstr "Aktuellt lösenord" #: packages/app-desktop/checkForUpdates.ts:90 msgid "Current version is up-to-date." @@ -1545,6 +1536,8 @@ msgid "" "Delete model and re-download?\n" "This cannot be undone." msgstr "" +"Ta bort modell och hämta igen?\n" +"Detta kan inte ångras." #: packages/lib/commands/deleteNote.ts:7 msgid "Delete note" @@ -1625,14 +1618,12 @@ msgid "Deletes the notes without asking for confirmation." msgstr "Tar bort anteckningarna utan att be om bekräftelse." #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:551 -#, fuzzy msgid "Deletion log" -msgstr "Ta bort rad" +msgstr "Borttagningslogg" #: packages/app-mobile/components/NoteItem.tsx:144 -#, fuzzy msgid "Deselect" -msgstr "Välj" +msgstr "Avmarkera" #: packages/app-cli/app/command-export.ts:24 msgid "Destination format: %s" @@ -1644,9 +1635,8 @@ msgid "Detailed" msgstr "Detaljerad" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/PluginChips.tsx:99 -#, fuzzy msgid "Dev" -msgstr "Förfaller" +msgstr "Dev" #: packages/lib/services/interop/Module.ts:62 msgid "Directory" @@ -1683,9 +1673,8 @@ msgid "Disabled" msgstr "Inaktiverad" #: packages/app-mobile/components/screens/encryption-config.tsx:323 -#, fuzzy msgid "Disabled keys" -msgstr "Dölj inaktiverade nycklar" +msgstr "Inaktiverade nycklar" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:200 #: packages/app-mobile/components/screens/encryption-config.tsx:251 @@ -1727,9 +1716,9 @@ msgid "" "to-dos, while `-tnt` would display notes and to-dos." msgstr "" "Visar endast objekt av den specifika typen/typerna. Kan vara `n` för " -"anteckningar, `t` för att-göra eller `nt` för anteckningar och att-göra " -"(t.ex. `-tt` skulle bara visa att-göra, medan `-tnt` skulle visa " -"anteckningar och att-göra." +"anteckningar, `t` för att-göra eller `nt` för anteckningar och att-göra (t." +"ex. `-tt` skulle bara visa att-göra, medan `-tnt` skulle visa anteckningar " +"och att-göra." #: packages/app-cli/app/command-status.js:13 msgid "Displays summary about the notes and notebooks." @@ -1797,9 +1786,8 @@ msgid "Download and install the relevant extension for your browser:" msgstr "Hämta och installera det relevanta tillägget för din webbläsare:" #: packages/app-mobile/components/voiceTyping/VoiceTypingDialog.tsx:206 -#, fuzzy msgid "Download updated model" -msgstr "Hämtad" +msgstr "Hämta uppdaterad modell" #: packages/lib/models/Resource.ts:409 msgid "Downloaded" @@ -1897,12 +1885,11 @@ msgstr "Redigera i extern redigerare" #: packages/app-desktop/commands/openNoteInNewWindow.ts:10 msgid "Edit in new window" -msgstr "" +msgstr "Redigera i nytt fönster" #: packages/app-desktop/gui/utils/NoteListUtils.ts:70 -#, fuzzy msgid "Edit in..." -msgstr "Redigera länk" +msgstr "Redigera i..." #: packages/app-mobile/components/NoteEditor/EditLinkDialog.tsx:143 msgid "Edit link" @@ -1933,9 +1920,8 @@ msgid "Editor" msgstr "Redigerare" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/Toolbar.tsx:38 -#, fuzzy msgid "Editor actions" -msgstr "Redigerarens teckensnitt" +msgstr "Redigeraråtgärder" #: packages/lib/models/settings/builtInMetadata.ts:1074 msgid "Editor font" @@ -2051,7 +2037,7 @@ msgstr "Aktivera kryptering" #: packages/lib/models/settings/builtInMetadata.ts:994 msgid "Enable file:// URLs for images and videos" -msgstr "" +msgstr "Aktivera file:// URL:er för bilder och videor" #: packages/lib/models/settings/builtInMetadata.ts:975 msgid "Enable footnotes" @@ -2107,9 +2093,8 @@ msgid "Enable soft breaks" msgstr "Aktivera mjuk radbrytning" #: packages/lib/models/settings/builtInMetadata.ts:1303 -#, fuzzy msgid "Enable spell checking in Markdown editor" -msgstr "Aktivera stavningskontroll i textredigeraren" +msgstr "Aktivera stavningskontroll i Markdown-redigeraren" #: packages/lib/models/settings/builtInMetadata.ts:789 msgid "Enable spellcheck in the text editor" @@ -2148,6 +2133,8 @@ msgid "" "Enables Markdown list continuation, auto-closing HTML tags, and other markup " "autocompletions." msgstr "" +"Aktiverar fortsättning av Markdown-lista, automatisk stängning av HTML-" +"taggar och andra automatiska slutföranden av uppmärkning." #: packages/lib/components/EncryptionConfigScreen/utils.ts:50 msgid "" @@ -2193,9 +2180,8 @@ msgid "End-to-end encryption" msgstr "Ände-till-ände-kryptering" #: packages/app-mobile/components/voiceTyping/VoiceTypingDialog.tsx:244 -#, fuzzy msgid "Ends voice typing" -msgstr "Röstskrivning..." +msgstr "Avslutar röstinmatning" #: packages/app-mobile/components/screens/dropbox-login.tsx:70 msgid "Enter code here" @@ -2215,9 +2201,8 @@ msgid "Enter password" msgstr "Ange lösenord" #: packages/app-mobile/components/NoteItem.tsx:120 -#, fuzzy msgid "Entering selection mode" -msgstr "Öppnar avsnitt %s" +msgstr "Går in i urvalsläge" #: packages/app-cli/app/help-utils.js:56 msgid "Enum" @@ -2284,7 +2269,7 @@ msgstr "Fäll ut %s" #: packages/app-desktop/gui/Sidebar/listItemComponents/ExpandIcon.tsx:26 msgid "Expanded, press space to collapse." -msgstr "" +msgstr "Expanderad, tryck på blanksteg för att komprimera." #: packages/app-desktop/gui/KeymapConfig/KeymapConfigScreen.tsx:182 #: packages/app-desktop/gui/Sidebar/hooks/useOnRenderItem.tsx:213 @@ -2310,9 +2295,8 @@ msgid "Export Debug Report" msgstr "Exportera felsökningsrapport" #: packages/app-desktop/commands/exportDeletionLog.ts:11 -#, fuzzy msgid "Export deletion log" -msgstr "Exportera alla" +msgstr "Exportera borttagningslogg" #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/ExportProfileButton.tsx:16 msgid "Export profile" @@ -2399,9 +2383,8 @@ msgid "Filter tags" msgstr "Filtrera taggar" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:14 -#, fuzzy msgid "Find" -msgstr "Hitta: " +msgstr "Hitta" #: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:253 msgid "Find: " @@ -2439,7 +2422,7 @@ msgstr "Fokus på titel" #: packages/app-mobile/components/CameraView/ScannedBarcodes.tsx:97 msgid "Follow link" -msgstr "" +msgstr "Följ länken" #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/ExportProfileButton.tsx:38 msgid "For debugging purpose only: export your profile to an external SD card." @@ -2534,11 +2517,11 @@ msgstr "" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:13 msgid "go" -msgstr "" +msgstr "gå" #: packages/app-mobile/components/CameraView/CameraView.tsx:165 msgid "Go back" -msgstr "" +msgstr "Gå tillbaka" #: packages/app-desktop/gui/JoplinCloudConfigScreen.tsx:44 #: packages/app-mobile/components/screens/ConfigScreen/JoplinCloudConfig.tsx:59 @@ -2547,7 +2530,7 @@ msgstr "Gå till Joplin Cloud-profil" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:12 msgid "Go to line" -msgstr "" +msgstr "Gå till rad" #: packages/app-mobile/components/screens/Note/Note.tsx:1051 msgid "Go to source URL" @@ -2614,9 +2597,8 @@ msgid "Hide keyboard" msgstr "Dölj tangentbord" #: packages/app-desktop/gui/PasswordInput/PasswordInput.tsx:21 -#, fuzzy msgid "Hide password" -msgstr "Ogiltigt lösenord" +msgstr "Dölj lösenord" #: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/setupToolbarButtons.ts:14 msgid "Highlight" @@ -2835,14 +2817,12 @@ msgid "Incompatible" msgstr "Inkompatibel" #: packages/app-desktop/gui/NoteList/utils/useOnKeyDown.ts:153 -#, fuzzy msgid "Incomplete" -msgstr "Slutförd" +msgstr "Ofullständig" #: packages/app-desktop/gui/NoteListItem/utils/prepareViewProps.ts:40 -#, fuzzy msgid "Incomplete to-do" -msgstr "Visa slutförda att-göra" +msgstr "Ofullständig att-göra" #: packages/app-mobile/components/NoteEditor/commandDeclarations.ts:97 msgid "Increase indent level" @@ -2858,7 +2838,7 @@ msgstr "Mer indrag" #: packages/app-mobile/components/DialogManager/hooks/useDialogControl.ts:21 msgid "Info" -msgstr "" +msgstr "Info" #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:223 msgid "Information" @@ -2960,9 +2940,8 @@ msgid "Items that cannot be synchronised" msgstr "Objekt som inte kan synkroniseras" #: packages/app-desktop/gui/MenuBar.tsx:923 -#, fuzzy msgid "Join us on %s" -msgstr "Följ oss på Twitter" +msgstr "Följ oss ​​på %s" #: packages/app-desktop/gui/SyncWizard/Dialog.tsx:267 msgid "" @@ -3018,9 +2997,8 @@ msgid "Joplin Forum" msgstr "Joplin-forum" #: packages/app-mobile/utils/lockToSingleInstance.ts:16 -#, fuzzy msgid "Joplin is already running." -msgstr "Servern körs redan på port %d" +msgstr "Joplin körs redan." #: packages/lib/services/plugins/PluginService.ts:523 msgid "Joplin Mobile" @@ -3270,9 +3248,8 @@ msgid "Manage shared notebooks" msgstr "Hantera delade anteckningsböcker" #: packages/app-mobile/components/EditorToolbar/ToolbarEditorDialog.tsx:165 -#, fuzzy msgid "Manage toolbar options" -msgstr "Hantera dina insticksmoduler" +msgstr "Hantera verktygsfältsalternativ" #: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.tsx:331 msgid "Manage your plugins" @@ -3284,8 +3261,8 @@ msgid "" "Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, " "`status`, `decrypt-file`, and `target-status`." msgstr "" -"Hanterar E2EE-konfigurationen. Kommandona är `enable`,` disable`, " -"`decrypt`,` status`, `decrypt-file` och `target-status`." +"Hanterar E2EE-konfigurationen. Kommandona är `enable`,` disable`, `decrypt`," +"` status`, `decrypt-file` och `target-status`." #: packages/lib/models/settings/builtInMetadata.ts:397 msgid "Manual" @@ -3305,9 +3282,8 @@ msgstr "Markdown + Front Matter" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/CodeMirror.tsx:375 #: packages/app-mobile/components/NoteEditor/NoteEditor.tsx:352 -#, fuzzy msgid "Markdown editor" -msgstr "Markdown" +msgstr "Markdown-redigerare" #: packages/app-cli/app/command-done.ts:15 msgid "Marks a to-do as done." @@ -3338,11 +3314,11 @@ msgstr "Huvudlösenord:" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:19 msgid "match case" -msgstr "" +msgstr "matcha skiftläge" #: packages/app-mobile/components/NoteEditor/commandDeclarations.ts:72 msgid "Math" -msgstr "" +msgstr "Matematik" #: packages/lib/models/settings/builtInMetadata.ts:421 msgid "Max concurrent connections" @@ -3369,9 +3345,8 @@ msgid "Minimise" msgstr "Minimera" #: packages/app-mobile/components/CameraView/CameraView.tsx:163 -#, fuzzy msgid "Missing camera permission" -msgstr "Saknade huvudnycklar" +msgstr "Kameratillstånd saknas" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:320 msgid "Missing keys" @@ -3460,14 +3435,12 @@ msgid "Never resize" msgstr "Ändra aldrig storlek" #: packages/app-mobile/setupQuickActions.ts:33 -#, fuzzy msgid "New attachment" -msgstr "Anteckningsbilagor" +msgstr "Ny bilaga" #: packages/app-mobile/setupQuickActions.ts:34 -#, fuzzy msgid "New drawing" -msgstr "Teckning" +msgstr "Ny ritning" #: packages/app-mobile/components/screens/ShareManager/index.tsx:120 msgid "New invitations" @@ -3498,9 +3471,8 @@ msgstr "" "importeras till den" #: packages/app-mobile/setupQuickActions.ts:32 -#, fuzzy msgid "New photo" -msgstr "Ta ett foto" +msgstr "Nytt foto" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/newSubFolder.ts:6 msgid "New sub-notebook" @@ -3524,7 +3496,7 @@ msgstr "Ny version: %s" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:16 msgid "next" -msgstr "" +msgstr "nästa" #: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:271 msgid "Next match" @@ -3608,14 +3580,12 @@ msgstr "" "path>`" #: packages/app-desktop/gui/UpdateNotification/UpdateNotification.tsx:93 -#, fuzzy msgid "No updates available" -msgstr "Uppdatering tillgänglig" +msgstr "Inga uppdateringar tillgängliga" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/moveToFolder.ts:44 -#, fuzzy msgid "None" -msgstr "(Ingen)" +msgstr "Ingen" #: packages/lib/models/settings/builtInMetadata.ts:47 msgid "Nord" @@ -3775,12 +3745,11 @@ msgstr "Numrerad lista" #: packages/lib/models/settings/builtInMetadata.ts:531 msgid "OCR: Clear cache and re-download language data files" -msgstr "" +msgstr "OCR: Rensa cacheminnet och hämta språkdatafiler igen" #: packages/lib/models/settings/builtInMetadata.ts:512 -#, fuzzy msgid "OCR: Language data URL or path" -msgstr "Språk, datumformat" +msgstr "OCR: Språkdata-URL eller -sökväg" #: packages/app-desktop/bridge.ts:360 packages/app-desktop/bridge.ts:373 #: packages/app-desktop/bridge.ts:387 packages/app-desktop/bridge.ts:403 @@ -3816,7 +3785,7 @@ msgstr "På %s: %s" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:27 msgid "on line" -msgstr "" +msgstr "på rad" #: packages/app-desktop/gui/MainScreen.tsx:525 msgid "One of your master keys use an obsolete encryption method." @@ -3847,9 +3816,8 @@ msgid "OneDrive Login" msgstr "OneDrive-inloggning" #: packages/lib/services/interop/InteropService.ts:144 -#, fuzzy msgid "OneNote Notebook" -msgstr "Ny anteckningsbok" +msgstr "OneNote-anteckningsbok" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/print.ts:18 msgid "Only one note can be printed at a time." @@ -3876,9 +3844,8 @@ msgid "Open profile directory" msgstr "Öppna profilmapp" #: packages/app-mobile/components/CameraView/CameraView.tsx:164 -#, fuzzy msgid "Open settings" -msgstr "Öppnar avsnitt %s" +msgstr "Öppna inställningar" #: packages/app-mobile/components/screens/ConfigScreen/plugins/EnablePluginSupportPage.tsx:115 msgid "Open Source" @@ -3897,19 +3864,16 @@ msgid "Opening section %s" msgstr "Öppnar avsnitt %s" #: packages/app-mobile/components/Dropdown.tsx:215 -#, fuzzy msgid "Opens dropdown" -msgstr "Stäng rullgardinsmenyn" +msgstr "Öppnar rullgardinsmenyn" #: packages/app-mobile/components/NoteItem.tsx:162 -#, fuzzy msgid "Opens note" -msgstr "Öppna den" +msgstr "Öppnar anteckning" #: packages/app-mobile/components/side-menu-content.tsx:273 -#, fuzzy msgid "Opens notebook" -msgstr "Ny anteckningsbok" +msgstr "Öppnar anteckningsboken" #: packages/app-cli/app/command-e2ee.ts:41 #: packages/app-cli/app/command-e2ee.ts:87 @@ -4175,11 +4139,11 @@ msgstr "Föredraget ljust tema" #: packages/lib/models/settings/builtInMetadata.ts:1704 msgid "Preferred voice typing provider" -msgstr "" +msgstr "Föredragen leverantör av röstinmatning" #: packages/lib/models/settings/builtInMetadata.ts:667 msgid "Preserve colours when pasting text in Rich Text Editor" -msgstr "" +msgstr "Bevara färger när du klistrar in text i Rich Text Editor" #: packages/app-cli/app/app-gui.js:758 msgid "Press Ctrl+D or type \"exit\" to exit the application" @@ -4202,9 +4166,8 @@ msgid "Press to set the decryption password." msgstr "Tryck för att ställa in dekrypteringslösenordet." #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:17 -#, fuzzy msgid "previous" -msgstr "Föregående träff" +msgstr "föregående" #: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:281 msgid "Previous match" @@ -4247,9 +4210,8 @@ msgid "Processing" msgstr "Bearbetning" #: packages/app-mobile/components/CameraView/ActionButtons.tsx:111 -#, fuzzy msgid "Processing photo..." -msgstr "Bearbetning" +msgstr "Bearbetar foto..." #: packages/server/src/routes/admin/users.ts:254 msgid "Profile" @@ -4305,9 +4267,8 @@ msgid "Publish notes to the internet" msgstr "Publicera anteckningar till internet" #: packages/app-mobile/components/CameraView/ScannedBarcodes.tsx:78 -#, fuzzy msgid "QR Code" -msgstr "Kod" +msgstr "QR-kod" #: packages/app-desktop/app.ts:219 #: packages/app-desktop/ElectronAppWrapper.ts:123 @@ -4318,7 +4279,7 @@ msgstr "Avsluta" #: packages/app-mobile/components/voiceTyping/VoiceTypingDialog.tsx:206 msgid "Re-download model" -msgstr "" +msgstr "Hämta modellen igen" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:342 msgid "Re-encrypt data" @@ -4329,9 +4290,8 @@ msgid "Re-encryption" msgstr "Omkryptering" #: packages/app-desktop/gui/MasterPasswordDialog/Dialog.tsx:181 -#, fuzzy msgid "Re-enter password" -msgstr "Ange lösenord" +msgstr "Ange lösenordet igen" #: packages/lib/models/settings/builtInMetadata.ts:1180 msgid "Re-upload local data to sync target" @@ -4397,9 +4357,8 @@ msgid "Remove" msgstr "Ta bort" #: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:330 -#, fuzzy msgid "Remove %s from share" -msgstr "Ta bort taggen \"%s\" från alla anteckningar?" +msgstr "Ta bort %s från delningen" #: packages/app-desktop/gui/Sidebar/hooks/useOnRenderItem.tsx:111 msgid "Remove tag \"%s\" from all notes?" @@ -4433,9 +4392,8 @@ msgid "Renew token" msgstr "Förnya token" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:21 -#, fuzzy msgid "replace" -msgstr "Ersätt" +msgstr "ersätt" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:15 #: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:291 @@ -4443,9 +4401,8 @@ msgid "Replace" msgstr "Ersätt" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:22 -#, fuzzy msgid "replace all" -msgstr "Ersätt alla" +msgstr "ersätt alla" #: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:301 msgid "Replace all" @@ -4461,11 +4418,11 @@ msgstr "Ersätt: " #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:25 msgid "replaced $ matches" -msgstr "" +msgstr "ersatte $-matchningar" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:26 msgid "replaced match on line $" -msgstr "" +msgstr "ersatte matchning på rad $" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginInfoModal.tsx:162 msgid "Report an issue" @@ -4528,9 +4485,8 @@ msgid "Restore" msgstr "Återställ" #: packages/app-mobile/components/EditorToolbar/ToolbarEditorDialog.tsx:156 -#, fuzzy msgid "Restore defaults" -msgstr "Återställda objekt" +msgstr "Återställ standardinställningar" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/restoreNote.ts:10 msgid "Restore note" @@ -4588,11 +4544,12 @@ msgstr "Revision: %s (%s)" #: packages/app-desktop/gui/ToggleEditorsButton/ToggleEditorsButton.tsx:28 msgid "Rich Text" -msgstr "" +msgstr "Rich Text" #: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx:686 msgid "Rich Text editor. Press Escape then Tab to escape focus." msgstr "" +"Rich Text redigerare. Tryck på Escape och sedan på Tab för att undvika fokus." #: packages/app-cli/app/command-batch.js:10 msgid "" @@ -4672,7 +4629,7 @@ msgstr "Spara geolokalisering med anteckningar" #: packages/app-mobile/components/CameraView/ScannedBarcodes.tsx:89 msgid "Scanned code" -msgstr "" +msgstr "Skannad kod" #: packages/app-desktop/gui/lib/SearchInput/SearchInput.tsx:62 #: packages/app-mobile/components/NoteEditor/commandDeclarations.ts:102 @@ -4705,9 +4662,8 @@ msgid "Search in current note" msgstr "Sök i aktuell anteckning" #: packages/app-desktop/plugins/GotoAnything.tsx:665 -#, fuzzy msgid "Search results" -msgstr "Inga resultat" +msgstr "Sökresultat" #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:170 msgid "Search shown" @@ -4730,9 +4686,8 @@ msgid "Searches for the given in all the notes." msgstr "Söker efter det givna i alla anteckningarna." #: packages/app-desktop/gui/UpdateNotification/UpdateNotification.tsx:63 -#, fuzzy msgid "See changelog" -msgstr "Fullständig ändringslogg" +msgstr "Se ändringslogg" #: packages/lib/models/settings/builtInMetadata.ts:1199 msgid "See the pre-release page for more details: %s" @@ -4761,14 +4716,12 @@ msgid "Select parent notebook" msgstr "Välj överordnad anteckningsbok" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:9 -#, fuzzy msgid "Selection deleted" -msgstr "färdigställande datum" +msgstr "Urvalet har tagits bort" #: packages/app-mobile/components/FolderPicker.tsx:68 -#, fuzzy msgid "Selects a notebook" -msgstr "Välj överordnad anteckningsbok" +msgstr "Väljer en anteckningsbok" #: packages/app-desktop/gui/MenuBar.tsx:359 msgid "Send bug report" @@ -4824,7 +4777,7 @@ msgstr "" #: packages/app-mobile/components/EditorToolbar/EditorToolbar.tsx:47 msgid "Settings" -msgstr "" +msgstr "Inställningar" #: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:281 #: packages/app-mobile/components/NoteBodyViewer/hooks/useOnResourceLongPress.ts:44 @@ -4863,9 +4816,8 @@ msgid "Share permissions" msgstr "Dela behörigheter" #: packages/app-desktop/gui/Sidebar/listItemComponents/FolderItem.tsx:56 -#, fuzzy msgid "Shared" -msgstr "Dela" +msgstr "Delad" #: packages/app-mobile/components/screens/ShareManager/index.tsx:107 msgid "Shares" @@ -4912,14 +4864,12 @@ msgid "Show note counts" msgstr "Visa anteckningsantal" #: packages/app-mobile/components/side-menu-content.tsx:258 -#, fuzzy msgid "Show notebook options" -msgstr "Visa anteckningsantal" +msgstr "Visa alternativ för anteckningsboken" #: packages/app-desktop/gui/PasswordInput/PasswordInput.tsx:21 -#, fuzzy msgid "Show password" -msgstr "Ställ in lösenord" +msgstr "Visa lösenord" #: packages/lib/models/settings/builtInMetadata.ts:698 msgid "Show sort order buttons" @@ -4934,9 +4884,8 @@ msgid "Show/hide the sidebar" msgstr "Visa/dölj sidofältet" #: packages/app-mobile/components/screens/tags.tsx:76 -#, fuzzy msgid "Shows notes for tag" -msgstr "Visa anteckningsantal" +msgstr "Visar anteckningar för tagg" #: packages/lib/models/settings/builtInMetadata.ts:863 msgid "Shrink large images before adding them to notes." @@ -5018,11 +4967,11 @@ msgstr "" #: packages/app-desktop/gui/ResourceScreen.tsx:92 msgid "Sort \"%s\" in ascending order" -msgstr "" +msgstr "Sortera \"%s\" i stigande ordning" #: packages/app-desktop/gui/ResourceScreen.tsx:92 msgid "Sort \"%s\" in descending order" -msgstr "" +msgstr "Sortera \"%s\" i fallande ordning" #: packages/lib/models/settings/builtInMetadata.ts:754 msgid "Sort notebooks by" @@ -5207,12 +5156,11 @@ msgstr "Byt profil" #: packages/app-mobile/components/CameraView/ActionButtons.tsx:101 msgid "Switch to back-facing camera" -msgstr "" +msgstr "Byt till bakåtvänd kamera" #: packages/app-mobile/components/CameraView/ActionButtons.tsx:101 -#, fuzzy msgid "Switch to front-facing camera" -msgstr "Byt till profil %d" +msgstr "Växla till kameran på framsidan" #: packages/app-desktop/gui/utils/NoteListUtils.ts:93 msgid "Switch to note type" @@ -5225,14 +5173,12 @@ msgid "Switch to profile %d" msgstr "Byt till profil %d" #: packages/app-desktop/gui/ToggleEditorsButton/ToggleEditorsButton.tsx:28 -#, fuzzy msgid "Switch to the %s Editor" -msgstr "Byt till anteckningstyp" +msgstr "Växla till %s-redigeraren" #: packages/app-desktop/gui/NoteEditor/WarningBanner/WarningBanner.tsx:78 -#, fuzzy msgid "Switch to the legacy editor" -msgstr "Byt till anteckningstyp" +msgstr "Byt till den äldre redigeraren" #: packages/app-desktop/gui/utils/NoteListUtils.ts:102 msgid "Switch to to-do type" @@ -5509,6 +5455,7 @@ msgstr "" #: packages/app-desktop/gui/NoteEditor/WarningBanner/WarningBanner.tsx:83 msgid "The following plugins may not support the current markdown editor:" msgstr "" +"Följande plugins kanske inte stöder den nuvarande markdown-redigeraren:" #: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.tsx:257 #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/RecommendedBadge.tsx:49 @@ -5637,6 +5584,11 @@ msgid "" "\n" "Error: \"%s\"" msgstr "" +"Webbklienten stöder inte accepterande av krypterade delade " +"anteckningsböcker. Byt till skrivbords- eller mobilappen innan du accepterar " +"delningen.\n" +"\n" +"Fel: \"%s\"" #: packages/app-desktop/gui/Root.tsx:150 msgid "The Web Clipper needs your authorisation to access your data." @@ -5993,9 +5945,8 @@ msgid "Toggle editor layout" msgstr "Växla redigeringslayout" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleEditorPlugin.ts:11 -#, fuzzy msgid "Toggle editor plugin" -msgstr "Växla redigeringslayout" +msgstr "Växla redigeringsinsticksmodul" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleEditors.ts:8 msgid "Toggle editors" @@ -6124,9 +6075,8 @@ msgstr "" #: packages/app-mobile/utils/getVersionInfoText.ts:13 #: packages/app-mobile/utils/getVersionInfoText.ts:14 -#, fuzzy msgid "Unknown" -msgstr "Okänd flagga: %s" +msgstr "Okänd" #: packages/app-desktop/bridge.ts:446 msgid "Unknown file type" @@ -6142,9 +6092,8 @@ msgid "" msgstr "Okänd objekttyp hämtad - uppgradera Joplin till den senaste versionen" #: packages/app-mobile/utils/getVersionInfoText.ts:28 -#, fuzzy msgid "Unknown platform" -msgstr "Okänd flagga: %s" +msgstr "Okänd plattform" #: packages/app-mobile/components/NoteEditor/commandDeclarations.ts:82 msgid "Unordered list" @@ -6176,11 +6125,12 @@ msgid "Unsupported link or message: %s" msgstr "Länk eller meddelande stöds inte: %s" #: packages/app-mobile/commands/openItem.ts:60 -#, fuzzy msgid "" "Unsupported link or message: %s.\n" "Error: %s" -msgstr "Länk eller meddelande stöds inte: %s" +msgstr "" +"Länk eller meddelande som inte stöds: %s.\n" +"Fel: %s" #: packages/app-desktop/gui/ResourceScreen.tsx:123 #: packages/lib/models/BaseItem.ts:921 packages/lib/path-utils.ts:27 @@ -6198,9 +6148,8 @@ msgid "Update available" msgstr "Uppdatering tillgänglig" #: packages/app-desktop/gui/UpdateNotification/UpdateNotification.tsx:65 -#, fuzzy msgid "Update later" -msgstr "uppdaterat datum" +msgstr "Uppdatera senare" #: packages/server/src/routes/admin/users.ts:257 #: packages/server/src/routes/index/users.ts:91 @@ -6300,9 +6249,8 @@ msgstr "" "avsluta." #: packages/lib/models/settings/builtInMetadata.ts:1347 -#, fuzzy msgid "Use the legacy Markdown editor" -msgstr "Aktivera Markdown-verktygsfältet" +msgstr "Använd den äldre Markdown-redigeraren" #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:552 msgid "" @@ -6397,7 +6345,7 @@ msgstr "Röstskrivning..." #: packages/lib/models/settings/builtInMetadata.ts:1712 msgid "Vosk" -msgstr "" +msgstr "Vosk" #: packages/lib/services/joplinCloudUtils.ts:27 msgid "Waiting for authorisation..." @@ -6504,7 +6452,7 @@ msgstr "" #: packages/lib/models/settings/builtInMetadata.ts:1713 msgid "Whisper" -msgstr "" +msgstr "Whisper" #: packages/app-desktop/ElectronAppWrapper.ts:222 msgid "Window unresponsive." From 18ebd164287a60373a3341e4c33a805d2bc8901e Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Sat, 29 Mar 2025 05:46:37 -0700 Subject: [PATCH 094/158] iOS: Fixes #11711: Fix Markdown toolbar partially covered by keyboard on some iOS devices (#12027) --- .eslintignore | 3 +- .gitignore | 3 +- .../components/ToggleSpaceButton.tsx | 97 ------------ packages/app-mobile/components/app-nav.tsx | 146 ++++++------------ .../components/screens/Note/Note.tsx | 17 +- .../utils/hooks/useKeyboardState.ts | 35 +++++ .../utils/hooks/useKeyboardVisible.ts | 27 ---- .../lib/models/settings/builtInMetadata.ts | 16 -- 8 files changed, 86 insertions(+), 258 deletions(-) delete mode 100644 packages/app-mobile/components/ToggleSpaceButton.tsx create mode 100644 packages/app-mobile/utils/hooks/useKeyboardState.ts delete mode 100644 packages/app-mobile/utils/hooks/useKeyboardVisible.ts diff --git a/.eslintignore b/.eslintignore index 0d741e902d..7dd8cad832 100644 --- a/.eslintignore +++ b/.eslintignore @@ -686,7 +686,6 @@ packages/app-mobile/components/SelectDateTimeDialog.js packages/app-mobile/components/SideMenu.js packages/app-mobile/components/SideMenuContentNote.js packages/app-mobile/components/TextInput.js -packages/app-mobile/components/ToggleSpaceButton.js packages/app-mobile/components/accessibility/AccessibleModalMenu.js packages/app-mobile/components/accessibility/AccessibleView.test.js packages/app-mobile/components/accessibility/AccessibleView.js @@ -859,7 +858,7 @@ packages/app-mobile/utils/fs-driver/testUtil/createFilesFromPathRecord.js packages/app-mobile/utils/fs-driver/testUtil/verifyDirectoryMatches.js packages/app-mobile/utils/getPackageInfo.js packages/app-mobile/utils/getVersionInfoText.js -packages/app-mobile/utils/hooks/useKeyboardVisible.js +packages/app-mobile/utils/hooks/useKeyboardState.js packages/app-mobile/utils/hooks/useOnLongPressProps.js packages/app-mobile/utils/hooks/useReduceMotionEnabled.js packages/app-mobile/utils/image/fileToImage.web.js diff --git a/.gitignore b/.gitignore index e67719f994..c12a756f06 100644 --- a/.gitignore +++ b/.gitignore @@ -661,7 +661,6 @@ packages/app-mobile/components/SelectDateTimeDialog.js packages/app-mobile/components/SideMenu.js packages/app-mobile/components/SideMenuContentNote.js packages/app-mobile/components/TextInput.js -packages/app-mobile/components/ToggleSpaceButton.js packages/app-mobile/components/accessibility/AccessibleModalMenu.js packages/app-mobile/components/accessibility/AccessibleView.test.js packages/app-mobile/components/accessibility/AccessibleView.js @@ -834,7 +833,7 @@ packages/app-mobile/utils/fs-driver/testUtil/createFilesFromPathRecord.js packages/app-mobile/utils/fs-driver/testUtil/verifyDirectoryMatches.js packages/app-mobile/utils/getPackageInfo.js packages/app-mobile/utils/getVersionInfoText.js -packages/app-mobile/utils/hooks/useKeyboardVisible.js +packages/app-mobile/utils/hooks/useKeyboardState.js packages/app-mobile/utils/hooks/useOnLongPressProps.js packages/app-mobile/utils/hooks/useReduceMotionEnabled.js packages/app-mobile/utils/image/fileToImage.web.js diff --git a/packages/app-mobile/components/ToggleSpaceButton.tsx b/packages/app-mobile/components/ToggleSpaceButton.tsx deleted file mode 100644 index 7ec8a66698..0000000000 --- a/packages/app-mobile/components/ToggleSpaceButton.tsx +++ /dev/null @@ -1,97 +0,0 @@ - -// On some devices, the SafeAreaView conflicts with the KeyboardAvoidingView, creating -// additional (or a lack of additional) space at the bottom of the screen. Because this -// is different on different devices, this button allows toggling additional space a the bottom -// of the screen to compensate. - -// Works around https://github.com/facebook/react-native/issues/13393 by adding additional -// space below the given component when the keyboard is visible unless a button is pressed. - -import Setting from '@joplin/lib/models/Setting'; -import { themeStyle } from '@joplin/lib/theme'; - -import * as React from 'react'; -import { ReactNode, useCallback, useState, useEffect } from 'react'; -import { Platform, useWindowDimensions, View, ViewStyle } from 'react-native'; -import IconButton from './IconButton'; -import useKeyboardVisible from '../utils/hooks/useKeyboardVisible'; - -interface Props { - children: ReactNode; - themeId: number; - style?: ViewStyle; -} - -const ToggleSpaceButton = (props: Props) => { - const [additionalSpace, setAdditionalSpace] = useState(0); - const [decreaseSpaceBtnVisible, setDecreaseSpaceBtnVisible] = useState(true); - - // Some devices need space added, others need space removed. - const additionalPositiveSpace = 14; - const additionalNegativeSpace = -14; - - // Switch from adding +14px to -14px. - const onDecreaseSpace = useCallback(() => { - setAdditionalSpace(additionalNegativeSpace); - setDecreaseSpaceBtnVisible(false); - Setting.setValue('editor.mobile.removeSpaceBelowToolbar', true); - }, [setAdditionalSpace, setDecreaseSpaceBtnVisible, additionalNegativeSpace]); - - useEffect(() => { - if (Setting.value('editor.mobile.removeSpaceBelowToolbar')) { - onDecreaseSpace(); - } - }, [onDecreaseSpace]); - - const theme = themeStyle(props.themeId); - - const decreaseSpaceButton = ( - <> - - - - ); - - const { keyboardVisible } = useKeyboardVisible(); - const windowSize = useWindowDimensions(); - const isPortrait = windowSize.height > windowSize.width; - const spaceApplicable = keyboardVisible && Platform.OS === 'ios' && isPortrait; - - const style: ViewStyle = { - marginBottom: spaceApplicable ? additionalSpace : 0, - ...props.style, - }; - - return ( - - {props.children} - { decreaseSpaceBtnVisible && spaceApplicable ? decreaseSpaceButton : null } - - ); -}; - -export default ToggleSpaceButton; diff --git a/packages/app-mobile/components/app-nav.tsx b/packages/app-mobile/components/app-nav.tsx index 9248fb7140..1a44d1eb6f 100644 --- a/packages/app-mobile/components/app-nav.tsx +++ b/packages/app-mobile/components/app-nav.tsx @@ -2,15 +2,12 @@ import * as React from 'react'; import { connect } from 'react-redux'; import NotesScreen from './screens/Notes'; import SearchScreen from './screens/SearchScreen'; -import { Component } from 'react'; -import { KeyboardAvoidingView, Keyboard, Platform, View, KeyboardEvent, Dimensions, EmitterSubscription } from 'react-native'; +import { KeyboardAvoidingView, Platform, View } from 'react-native'; import { AppState } from '../utils/types'; import { themeStyle } from './global-style'; - -interface State { - autoCompletionBarExtraHeight: number; - floatingKeyboardEnabled: boolean; -} +import { useSafeAreaInsets } from 'react-native-safe-area-context'; +import useKeyboardState from '../utils/hooks/useKeyboardState'; +import usePrevious from '@joplin/lib/hooks/usePrevious'; interface Props { // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied @@ -22,107 +19,58 @@ interface Props { themeId: number; } -class AppNavComponent extends Component { - private previousRouteName_: string|null = null; - private keyboardDidShowListener: EmitterSubscription|null = null; - private keyboardDidHideListener: EmitterSubscription|null = null; - private keyboardWillChangeFrameListener: EmitterSubscription|null = null; +const AppNavComponent: React.FC = (props) => { + const keyboardState = useKeyboardState(); + const safeAreaPadding = useSafeAreaInsets(); - public constructor(props: Props) { - super(props); + if (!props.route) throw new Error('Route must not be null'); - this.previousRouteName_ = null; - this.state = { - autoCompletionBarExtraHeight: 0, // Extra padding for the auto completion bar at the top of the keyboard - floatingKeyboardEnabled: false, - }; + // Note: certain screens are kept into memory, in particular Notes and Search + // so that the scroll position is not lost when the user navigate away from them. + + const route = props.route; + let Screen = null; + let notesScreenVisible = false; + let searchScreenVisible = false; + + if (route.routeName === 'Notes') { + notesScreenVisible = true; + } else if (route.routeName === 'Search') { + searchScreenVisible = true; + } else { + Screen = props.screens[route.routeName].screen; } - public UNSAFE_componentWillMount() { - if (Platform.OS === 'ios') { - this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this.keyboardDidShow.bind(this)); - this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this.keyboardDidHide.bind(this)); - this.keyboardWillChangeFrameListener = Keyboard.addListener('keyboardWillChangeFrame', this.keyboardWillChangeFrame); - } - } + const previousRouteName = usePrevious(route.routeName, ''); - public componentWillUnmount() { - this.keyboardDidShowListener?.remove(); - this.keyboardDidHideListener?.remove(); - this.keyboardWillChangeFrameListener?.remove(); + // Keep the search screen loaded if the user is viewing a note from that search screen + // so that if the back button is pressed, the screen is still loaded. However, unload + // it if navigating away. + const searchScreenLoaded = searchScreenVisible || (previousRouteName === 'Search' && route.routeName === 'Note'); - this.keyboardDidShowListener = null; - this.keyboardDidHideListener = null; - this.keyboardWillChangeFrameListener = null; - } + const theme = themeStyle(props.themeId); - public keyboardDidShow() { - this.setState({ autoCompletionBarExtraHeight: 30 }); - } + const style = { flex: 1, backgroundColor: theme.backgroundColor }; - public keyboardDidHide() { - this.setState({ autoCompletionBarExtraHeight: 0 }); - } + // When the floating keyboard is enabled, the KeyboardAvoidingView can have a very small + // height. Don't use the KeyboardAvoidingView when the floating keyboard is enabled. + // See https://github.com/facebook/react-native/issues/29473 + const keyboardAvoidingViewEnabled = !keyboardState.isFloatingKeyboard; + const autocompletionBarPadding = Platform.OS === 'ios' && keyboardState.keyboardVisible ? safeAreaPadding.top : 0; - private keyboardWillChangeFrame = (evt: KeyboardEvent) => { - const windowWidth = Dimensions.get('window').width; - - // If the keyboard isn't as wide as the window, the floating keyboard is disabled. - // See https://github.com/facebook/react-native/issues/29473#issuecomment-696658937 - this.setState({ - floatingKeyboardEnabled: evt.endCoordinates.width < windowWidth, - }); - }; - - public render() { - if (!this.props.route) throw new Error('Route must not be null'); - - // Note: certain screens are kept into memory, in particular Notes and Search - // so that the scroll position is not lost when the user navigate away from them. - - const route = this.props.route; - let Screen = null; - let notesScreenVisible = false; - let searchScreenVisible = false; - - if (route.routeName === 'Notes') { - notesScreenVisible = true; - } else if (route.routeName === 'Search') { - searchScreenVisible = true; - } else { - Screen = this.props.screens[route.routeName].screen; - } - - // Keep the search screen loaded if the user is viewing a note from that search screen - // so that if the back button is pressed, the screen is still loaded. However, unload - // it if navigating away. - const searchScreenLoaded = searchScreenVisible || (this.previousRouteName_ === 'Search' && route.routeName === 'Note'); - - this.previousRouteName_ = route.routeName; - - const theme = themeStyle(this.props.themeId); - - const style = { flex: 1, backgroundColor: theme.backgroundColor }; - - // When the floating keyboard is enabled, the KeyboardAvoidingView can have a very small - // height. Don't use the KeyboardAvoidingView when the floating keyboard is enabled. - // See https://github.com/facebook/react-native/issues/29473 - const keyboardAvoidingViewEnabled = !this.state.floatingKeyboardEnabled; - - return ( - - - {searchScreenLoaded && } - {!notesScreenVisible && !searchScreenVisible && } - - - ); - } -} + return ( + + + {searchScreenLoaded && } + {!notesScreenVisible && !searchScreenVisible && } + + + ); +}; const AppNav = connect((state: AppState) => { return { diff --git a/packages/app-mobile/components/screens/Note/Note.tsx b/packages/app-mobile/components/screens/Note/Note.tsx index b80906b353..89f0040d86 100644 --- a/packages/app-mobile/components/screens/Note/Note.tsx +++ b/packages/app-mobile/components/screens/Note/Note.tsx @@ -61,7 +61,6 @@ import { DialogContext, DialogControl } from '../../DialogManager'; import { CommandRuntimeProps, EditorMode, PickerResponse } from './types'; import commands from './commands'; import { AttachFileAction, AttachFileOptions } from './commands/attachFile'; -import ToggleSpaceButton from '../../ToggleSpaceButton'; import PluginService from '@joplin/lib/services/plugins/PluginService'; import PluginUserWebView from '../../plugins/dialogs/PluginUserWebView'; import getShownPluginEditorView from '@joplin/lib/services/plugins/utils/getShownPluginEditorView'; @@ -1675,19 +1674,6 @@ class NoteScreenComponent extends BaseScreenComponent imp return result; }; - const renderWrappedContent = () => { - const content = <> - {bodyComponent} - {renderVoiceTypingDialogs()} - ; - - return this.state.mode === 'edit' ? ( - - {content} - - ) : content; - }; - const { editorPlugin: activeEditorPlugin } = getActivePluginEditorView(this.props.plugins); return ( @@ -1709,7 +1695,8 @@ class NoteScreenComponent extends BaseScreenComponent imp title={getDisplayParentTitle(this.state.note, this.state.folder)} /> {titleComp} - {renderWrappedContent()} + {bodyComponent} + {renderVoiceTypingDialogs()} {renderActionButton()} diff --git a/packages/app-mobile/utils/hooks/useKeyboardState.ts b/packages/app-mobile/utils/hooks/useKeyboardState.ts new file mode 100644 index 0000000000..a731eb0d63 --- /dev/null +++ b/packages/app-mobile/utils/hooks/useKeyboardState.ts @@ -0,0 +1,35 @@ +import { useEffect, useMemo, useState } from 'react'; +import { Dimensions, Keyboard } from 'react-native'; + +const useKeyboardState = () => { + const [keyboardVisible, setKeyboardVisible] = useState(false); + const [hasSoftwareKeyboard, setHasSoftwareKeyboard] = useState(false); + const [isFloatingKeyboard, setIsFloatingKeyboard] = useState(false); + useEffect(() => { + const showListener = Keyboard.addListener('keyboardDidShow', () => { + setKeyboardVisible(true); + setHasSoftwareKeyboard(true); + }); + const hideListener = Keyboard.addListener('keyboardDidHide', () => { + setKeyboardVisible(false); + }); + const floatingListener = Keyboard.addListener('keyboardWillChangeFrame', (evt) => { + const windowWidth = Dimensions.get('window').width; + // If the keyboard isn't as wide as the window, the floating keyboard is disabled. + // See https://github.com/facebook/react-native/issues/29473#issuecomment-696658937 + setIsFloatingKeyboard(evt.endCoordinates.width < windowWidth); + }); + + return (() => { + showListener.remove(); + hideListener.remove(); + floatingListener.remove(); + }); + }); + + return useMemo(() => { + return { keyboardVisible, hasSoftwareKeyboard, isFloatingKeyboard }; + }, [keyboardVisible, hasSoftwareKeyboard, isFloatingKeyboard]); +}; + +export default useKeyboardState; diff --git a/packages/app-mobile/utils/hooks/useKeyboardVisible.ts b/packages/app-mobile/utils/hooks/useKeyboardVisible.ts deleted file mode 100644 index a6aa8499cb..0000000000 --- a/packages/app-mobile/utils/hooks/useKeyboardVisible.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { useEffect, useMemo, useState } from 'react'; -import { Keyboard } from 'react-native'; - -const useKeyboardVisible = () => { - const [keyboardVisible, setKeyboardVisible] = useState(false); - const [hasSoftwareKeyboard, setHasSoftwareKeyboard] = useState(false); - useEffect(() => { - const showListener = Keyboard.addListener('keyboardDidShow', () => { - setKeyboardVisible(true); - setHasSoftwareKeyboard(true); - }); - const hideListener = Keyboard.addListener('keyboardDidHide', () => { - setKeyboardVisible(false); - }); - - return (() => { - showListener.remove(); - hideListener.remove(); - }); - }); - - return useMemo(() => { - return { keyboardVisible, hasSoftwareKeyboard }; - }, [keyboardVisible, hasSoftwareKeyboard]); -}; - -export default useKeyboardVisible; diff --git a/packages/lib/models/settings/builtInMetadata.ts b/packages/lib/models/settings/builtInMetadata.ts index f8ad72c665..eb42dd5155 100644 --- a/packages/lib/models/settings/builtInMetadata.ts +++ b/packages/lib/models/settings/builtInMetadata.ts @@ -839,22 +839,6 @@ const builtInMetadata = (Setting: typeof SettingType) => { isGlobal: true, }, - // Works around a bug in which additional space is visible beneath the toolbar on some devices. - // See https://github.com/laurent22/joplin/pull/6823 - 'editor.mobile.removeSpaceBelowToolbar': { - value: false, - type: SettingItemType.Bool, - section: 'note', - public: true, - appTypes: [AppType.Mobile], - // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied - show: (settings: any) => settings['editor.mobile.removeSpaceBelowToolbar'], - label: () => 'Remove extra space below the markdown toolbar', - description: () => 'Works around bug on some devices where the markdown toolbar does not touch the bottom of the screen.', - storage: SettingStorage.File, - isGlobal: true, - }, - newTodoFocus: { value: 'title', type: SettingItemType.String, From 0acb14d0bff06582c0dcbe761b1e54d513776643 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 30 Mar 2025 10:31:16 +0200 Subject: [PATCH 095/158] Server: Trying to build Joplin Server Docker image for ARM64 (#12030) --- .github/scripts/run_ci.sh | 23 ++++++++++++++++++++++- .github/workflows/github-actions-main.yml | 14 +++++++++++--- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/.github/scripts/run_ci.sh b/.github/scripts/run_ci.sh index e644c3bda3..adfa01424e 100755 --- a/.github/scripts/run_ci.sh +++ b/.github/scripts/run_ci.sh @@ -43,10 +43,31 @@ if [ "$IS_SERVER_RELEASE" = 0 ] && [ "$IS_DESKTOP_RELEASE" = 0 ]; then RUN_TESTS=1 fi +if [ "$RUNNER_ARCH" == "ARM64" ] && [ "$IS_SERVER_RELEASE" == "0" ]; then + # We exit now because nothing works properly with the ARM64 architecture. + # We only proceed if building the server image. + echo "Running on ARM64 and not trying to build server image - early exit" + exit 0 +fi + +if [ "$RUNNER_ARCH" == "ARM64" ]; then + # Canvas is only needed for tests and it doesn't build in ARM64 so remove it + RUN_TESTS=0 + cd "$ROOT_DIR/packages/lib" + yarn remove canvas + cd "$ROOT_DIR" + + # Delete certain directories because `yarn install` will fail on ARM64. + rm -rf app-desktop + rm -rf app-mobile +fi + # ============================================================================= # Print environment # ============================================================================= +echo "RUNNER_OS=$RUNNER_OS" +echo "RUNNER_ARCH=$RUNNER_ARCH" echo "GITHUB_WORKFLOW=$GITHUB_WORKFLOW" echo "GITHUB_EVENT_NAME=$GITHUB_EVENT_NAME" echo "GITHUB_REF=$GITHUB_REF" @@ -276,7 +297,7 @@ if [ "$IS_DESKTOP_RELEASE" == "1" ]; then fi elif [[ $IS_LINUX = 1 ]] && [ "$IS_SERVER_RELEASE" == "1" ]; then echo "Step: Building Docker Image..." - cd "$ROOT_DIR" + cd "$ROOT_DIR" yarn buildServerDocker --tag-name $GIT_TAG_NAME --push-images --repository $SERVER_REPOSITORY else echo "Step: Building but *not* publishing desktop application..." diff --git a/.github/workflows/github-actions-main.yml b/.github/workflows/github-actions-main.yml index b122839144..f450df9845 100644 --- a/.github/workflows/github-actions-main.yml +++ b/.github/workflows/github-actions-main.yml @@ -9,7 +9,7 @@ jobs: matrix: # Do not use unbuntu-latest because it causes `The operation was canceled` failures: # https://github.com/actions/runner-images/issues/6709 - os: [macos-13, ubuntu-22.04, windows-2019] + os: [macos-13, ubuntu-22.04, windows-2019, ubuntu-22.04-arm] steps: - uses: actions/checkout@v4 @@ -91,7 +91,7 @@ jobs: matrix: # Do not use unbuntu-latest because it causes `The operation was canceled` failures: # https://github.com/actions/runner-images/issues/6709 - os: [ubuntu-22.04] + os: [ubuntu-22.04, ubuntu-22.04-arm] steps: - name: Install Docker Engine @@ -124,11 +124,19 @@ jobs: env: BUILD_SEQUENCIAL: 1 run: | + echo "RUNNER_OS=$RUNNER_OS" + echo "RUNNER_ARCH=$RUNNER_ARCH" + + # Canvas is only needed for tests and it doesn't build in ARM64 so remove it + cd packages/lib + yarn remove canvas + cd ../.. + yarn install yarn buildServerDocker --tag-name server-v0.0.0 --repository joplin/server # Basic test to ensure that the created build is valid. It should exit with - # code 0 if it works. + # code 0 if it works. docker run joplin/server:0.0.0-beta node dist/app.js migrate list - name: Check HTTP request From f0121e77990d318335ae47087ff3a209481f1efd Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 30 Mar 2025 10:32:01 +0200 Subject: [PATCH 096/158] Server v3.3.5 --- .../components/ToggleSpaceButton.js | 60 +++++++++++++++++++ .../utils/hooks/useKeyboardVisible.js | 26 ++++++++ packages/server/package.json | 2 +- readme/about/changelog/server.md | 6 ++ 4 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 packages/app-mobile/components/ToggleSpaceButton.js create mode 100644 packages/app-mobile/utils/hooks/useKeyboardVisible.js diff --git a/packages/app-mobile/components/ToggleSpaceButton.js b/packages/app-mobile/components/ToggleSpaceButton.js new file mode 100644 index 0000000000..c793024643 --- /dev/null +++ b/packages/app-mobile/components/ToggleSpaceButton.js @@ -0,0 +1,60 @@ +'use strict'; +// On some devices, the SafeAreaView conflicts with the KeyboardAvoidingView, creating +// additional (or a lack of additional) space at the bottom of the screen. Because this +// is different on different devices, this button allows toggling additional space a the bottom +// of the screen to compensate. +Object.defineProperty(exports, '__esModule', { value: true }); +// Works around https://github.com/facebook/react-native/issues/13393 by adding additional +// space below the given component when the keyboard is visible unless a button is pressed. +const Setting_1 = require('@joplin/lib/models/Setting'); +const theme_1 = require('@joplin/lib/theme'); +const React = require('react'); +const react_1 = require('react'); +const react_native_1 = require('react-native'); +const IconButton_1 = require('./IconButton'); +const useKeyboardVisible_1 = require('../utils/hooks/useKeyboardVisible'); +const ToggleSpaceButton = (props) => { + const [additionalSpace, setAdditionalSpace] = (0, react_1.useState)(0); + const [decreaseSpaceBtnVisible, setDecreaseSpaceBtnVisible] = (0, react_1.useState)(true); + // Some devices need space added, others need space removed. + const additionalPositiveSpace = 14; + const additionalNegativeSpace = -14; + // Switch from adding +14px to -14px. + const onDecreaseSpace = (0, react_1.useCallback)(() => { + setAdditionalSpace(additionalNegativeSpace); + setDecreaseSpaceBtnVisible(false); + Setting_1.default.setValue('editor.mobile.removeSpaceBelowToolbar', true); + }, [setAdditionalSpace, setDecreaseSpaceBtnVisible, additionalNegativeSpace]); + (0, react_1.useEffect)(() => { + if (Setting_1.default.value('editor.mobile.removeSpaceBelowToolbar')) { + onDecreaseSpace(); + } + }, [onDecreaseSpace]); + const theme = (0, theme_1.themeStyle)(props.themeId); + const decreaseSpaceButton = (React.createElement(React.Fragment, null, + React.createElement(react_native_1.View, { style: { + height: additionalPositiveSpace, + zIndex: -2, + } }), + React.createElement(IconButton_1.default, { themeId: props.themeId, description: 'Move toolbar to bottom of screen', containerStyle: { + height: additionalPositiveSpace, + width: '100%', + // Ensure that the icon is near the bottom of the screen, + // and thus invisible on devices where it isn't necessary. + position: 'absolute', + bottom: 0, + // Don't show the button on top of views with content. + zIndex: -1, + alignItems: 'center', + }, onPress: onDecreaseSpace, iconName: 'material chevron-down', iconStyle: { color: theme.color } }))); + const { keyboardVisible } = (0, useKeyboardVisible_1.default)(); + const windowSize = (0, react_native_1.useWindowDimensions)(); + const isPortrait = windowSize.height > windowSize.width; + const spaceApplicable = keyboardVisible && react_native_1.Platform.OS === 'ios' && isPortrait; + const style = { marginBottom: spaceApplicable ? additionalSpace : 0, ...props.style }; + return (React.createElement(react_native_1.View, { style: style }, + props.children, + decreaseSpaceBtnVisible && spaceApplicable ? decreaseSpaceButton : null)); +}; +exports.default = ToggleSpaceButton; +// # sourceMappingURL=ToggleSpaceButton.js.map diff --git a/packages/app-mobile/utils/hooks/useKeyboardVisible.js b/packages/app-mobile/utils/hooks/useKeyboardVisible.js new file mode 100644 index 0000000000..f43417263b --- /dev/null +++ b/packages/app-mobile/utils/hooks/useKeyboardVisible.js @@ -0,0 +1,26 @@ +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const react_1 = require('react'); +const react_native_1 = require('react-native'); +const useKeyboardVisible = () => { + const [keyboardVisible, setKeyboardVisible] = (0, react_1.useState)(false); + const [hasSoftwareKeyboard, setHasSoftwareKeyboard] = (0, react_1.useState)(false); + (0, react_1.useEffect)(() => { + const showListener = react_native_1.Keyboard.addListener('keyboardDidShow', () => { + setKeyboardVisible(true); + setHasSoftwareKeyboard(true); + }); + const hideListener = react_native_1.Keyboard.addListener('keyboardDidHide', () => { + setKeyboardVisible(false); + }); + return (() => { + showListener.remove(); + hideListener.remove(); + }); + }); + return (0, react_1.useMemo)(() => { + return { keyboardVisible, hasSoftwareKeyboard }; + }, [keyboardVisible, hasSoftwareKeyboard]); +}; +exports.default = useKeyboardVisible; +// # sourceMappingURL=useKeyboardVisible.js.map diff --git a/packages/server/package.json b/packages/server/package.json index 364807e286..67375f31c5 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@joplin/server", - "version": "3.3.4", + "version": "3.3.5", "private": true, "scripts": { "start-dev": "yarn build && JOPLIN_IS_TESTING=1 nodemon --config nodemon.json --ext ts,js,mustache,css,tsx dist/app.js --env dev", diff --git a/readme/about/changelog/server.md b/readme/about/changelog/server.md index 608ceef370..763c44515e 100644 --- a/readme/about/changelog/server.md +++ b/readme/about/changelog/server.md @@ -1,5 +1,11 @@ # Joplin Server Changelog +## [server-v3.3.5](https://github.com/laurent22/joplin/releases/tag/server-v3.3.5) - 2025-03-30T08:31:41Z + +- New: Added links to social networks (04fc634) +- Improved: Joplin Server Docker image for ARM64 (#12030) +- Fixed: Disable faulty dark theme to prevent published notes from being unreadable (#11910) + ## [server-v3.3.4](https://github.com/laurent22/joplin/releases/tag/server-v3.3.4) - 2025-03-03T22:29:29Z - Security: Improve request validation in default route (#11916 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) From 47f6b1ce33f32573c3ca8841dd495caf7215dd5d Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 30 Mar 2025 10:32:42 +0200 Subject: [PATCH 097/158] Chore: Remove JS files --- .../components/ToggleSpaceButton.js | 60 ------------------- .../utils/hooks/useKeyboardVisible.js | 26 -------- 2 files changed, 86 deletions(-) delete mode 100644 packages/app-mobile/components/ToggleSpaceButton.js delete mode 100644 packages/app-mobile/utils/hooks/useKeyboardVisible.js diff --git a/packages/app-mobile/components/ToggleSpaceButton.js b/packages/app-mobile/components/ToggleSpaceButton.js deleted file mode 100644 index c793024643..0000000000 --- a/packages/app-mobile/components/ToggleSpaceButton.js +++ /dev/null @@ -1,60 +0,0 @@ -'use strict'; -// On some devices, the SafeAreaView conflicts with the KeyboardAvoidingView, creating -// additional (or a lack of additional) space at the bottom of the screen. Because this -// is different on different devices, this button allows toggling additional space a the bottom -// of the screen to compensate. -Object.defineProperty(exports, '__esModule', { value: true }); -// Works around https://github.com/facebook/react-native/issues/13393 by adding additional -// space below the given component when the keyboard is visible unless a button is pressed. -const Setting_1 = require('@joplin/lib/models/Setting'); -const theme_1 = require('@joplin/lib/theme'); -const React = require('react'); -const react_1 = require('react'); -const react_native_1 = require('react-native'); -const IconButton_1 = require('./IconButton'); -const useKeyboardVisible_1 = require('../utils/hooks/useKeyboardVisible'); -const ToggleSpaceButton = (props) => { - const [additionalSpace, setAdditionalSpace] = (0, react_1.useState)(0); - const [decreaseSpaceBtnVisible, setDecreaseSpaceBtnVisible] = (0, react_1.useState)(true); - // Some devices need space added, others need space removed. - const additionalPositiveSpace = 14; - const additionalNegativeSpace = -14; - // Switch from adding +14px to -14px. - const onDecreaseSpace = (0, react_1.useCallback)(() => { - setAdditionalSpace(additionalNegativeSpace); - setDecreaseSpaceBtnVisible(false); - Setting_1.default.setValue('editor.mobile.removeSpaceBelowToolbar', true); - }, [setAdditionalSpace, setDecreaseSpaceBtnVisible, additionalNegativeSpace]); - (0, react_1.useEffect)(() => { - if (Setting_1.default.value('editor.mobile.removeSpaceBelowToolbar')) { - onDecreaseSpace(); - } - }, [onDecreaseSpace]); - const theme = (0, theme_1.themeStyle)(props.themeId); - const decreaseSpaceButton = (React.createElement(React.Fragment, null, - React.createElement(react_native_1.View, { style: { - height: additionalPositiveSpace, - zIndex: -2, - } }), - React.createElement(IconButton_1.default, { themeId: props.themeId, description: 'Move toolbar to bottom of screen', containerStyle: { - height: additionalPositiveSpace, - width: '100%', - // Ensure that the icon is near the bottom of the screen, - // and thus invisible on devices where it isn't necessary. - position: 'absolute', - bottom: 0, - // Don't show the button on top of views with content. - zIndex: -1, - alignItems: 'center', - }, onPress: onDecreaseSpace, iconName: 'material chevron-down', iconStyle: { color: theme.color } }))); - const { keyboardVisible } = (0, useKeyboardVisible_1.default)(); - const windowSize = (0, react_native_1.useWindowDimensions)(); - const isPortrait = windowSize.height > windowSize.width; - const spaceApplicable = keyboardVisible && react_native_1.Platform.OS === 'ios' && isPortrait; - const style = { marginBottom: spaceApplicable ? additionalSpace : 0, ...props.style }; - return (React.createElement(react_native_1.View, { style: style }, - props.children, - decreaseSpaceBtnVisible && spaceApplicable ? decreaseSpaceButton : null)); -}; -exports.default = ToggleSpaceButton; -// # sourceMappingURL=ToggleSpaceButton.js.map diff --git a/packages/app-mobile/utils/hooks/useKeyboardVisible.js b/packages/app-mobile/utils/hooks/useKeyboardVisible.js deleted file mode 100644 index f43417263b..0000000000 --- a/packages/app-mobile/utils/hooks/useKeyboardVisible.js +++ /dev/null @@ -1,26 +0,0 @@ -'use strict'; -Object.defineProperty(exports, '__esModule', { value: true }); -const react_1 = require('react'); -const react_native_1 = require('react-native'); -const useKeyboardVisible = () => { - const [keyboardVisible, setKeyboardVisible] = (0, react_1.useState)(false); - const [hasSoftwareKeyboard, setHasSoftwareKeyboard] = (0, react_1.useState)(false); - (0, react_1.useEffect)(() => { - const showListener = react_native_1.Keyboard.addListener('keyboardDidShow', () => { - setKeyboardVisible(true); - setHasSoftwareKeyboard(true); - }); - const hideListener = react_native_1.Keyboard.addListener('keyboardDidHide', () => { - setKeyboardVisible(false); - }); - return (() => { - showListener.remove(); - hideListener.remove(); - }); - }); - return (0, react_1.useMemo)(() => { - return { keyboardVisible, hasSoftwareKeyboard }; - }, [keyboardVisible, hasSoftwareKeyboard]); -}; -exports.default = useKeyboardVisible; -// # sourceMappingURL=useKeyboardVisible.js.map From e8144f9ee22c99a703f98886608eb29572838a43 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 30 Mar 2025 11:15:19 +0200 Subject: [PATCH 098/158] Doc: Update sponsors --- .../images/sponsors/TiktokRise.jpg | Bin 0 -> 72257 bytes packages/tools/sponsors.json | 19 ++++++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 Assets/WebsiteAssets/images/sponsors/TiktokRise.jpg diff --git a/Assets/WebsiteAssets/images/sponsors/TiktokRise.jpg b/Assets/WebsiteAssets/images/sponsors/TiktokRise.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1bffc23fc817d563f76380a96795178e59c1c1b5 GIT binary patch literal 72257 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 literal 0 HcmV?d00001 diff --git a/packages/tools/sponsors.json b/packages/tools/sponsors.json index cacc6cdbc1..c70a43c3b5 100644 --- a/packages/tools/sponsors.json +++ b/packages/tools/sponsors.json @@ -100,12 +100,6 @@ "title": "Casino Reviews", "imageName": "CasinoReviews.png" }, - { - "url": "https://ca.edubirdie.com/", - "title": "Achieve academic success with Edubirdie — your trusted partner for expert writing assistance and resources!", - "imageName": "Edubirdie.png", - "alt": "EduBirdie" - }, { "url": "https://topagency.webflow.io", "title": "WebDesignAgency", @@ -129,6 +123,13 @@ "title": "casino without making any upfront cost", "imageName": "Slotozilla.png", "alt": "casino without making any upfront cost" + }, + { + "url": "https://www.reddit.com/r/tiktokRise/", + "title": "Tiktok Rise", + "imageName": "TiktokRise.jpg", + "alt": "Tiktok Rise", + "githubUser": "knickman" } ], "orgsOld": [ @@ -164,6 +165,12 @@ "title": "BYTV", "imageName": "BYTV.png", "githubUser": "bytv1" + }, + { + "url": "https://ca.edubirdie.com/", + "title": "Achieve academic success with Edubirdie — your trusted partner for expert writing assistance and resources!", + "imageName": "Edubirdie.png", + "alt": "EduBirdie" } ] } From 76a3250707c89789aaef91f4a6641bd1a66b42bc Mon Sep 17 00:00:00 2001 From: Maxim Medvedev Date: Sun, 30 Mar 2025 12:01:39 +0200 Subject: [PATCH 099/158] Server: buildx support for Docker images (#11582) Co-authored-by: Laurent Cozic --- .github/workflows/github-actions-main.yml | 4 +- Dockerfile.server | 14 ++- packages/tools/buildServerDocker.test.ts | 11 +- packages/tools/buildServerDocker.ts | 121 ++++++++++++++++++---- packages/tools/cspell/dictionary4.txt | 1 + 5 files changed, 121 insertions(+), 30 deletions(-) diff --git a/.github/workflows/github-actions-main.yml b/.github/workflows/github-actions-main.yml index f450df9845..7763585b0f 100644 --- a/.github/workflows/github-actions-main.yml +++ b/.github/workflows/github-actions-main.yml @@ -30,7 +30,7 @@ jobs: "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt-get update || true - sudo apt-get install -y docker-ce docker-ce-cli containerd.io + sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin # Login to Docker only if we're on a server release tag. If we run this on # a pull request it will fail because the PR doesn't have access to @@ -106,7 +106,7 @@ jobs: "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt-get update || true - sudo apt-get install -y docker-ce docker-ce-cli containerd.io + sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin - uses: actions/checkout@v4 diff --git a/Dockerfile.server b/Dockerfile.server index 076da5859a..2ab61b9404 100644 --- a/Dockerfile.server +++ b/Dockerfile.server @@ -7,6 +7,9 @@ FROM node:18 AS builder RUN apt-get update \ && apt-get install -y \ python3 tini \ + # needed for node-canvas for ARM32 platform. + # See also https://github.com/Automattic/node-canvas/wiki/Installation:-Ubuntu-and-other-Debian-based-systems + libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev \ && rm -rf /var/lib/apt/lists/* # Enables Yarn @@ -47,9 +50,9 @@ RUN sed --in-place '/onenote-converter/d' ./packages/lib/package.json # Note that `yarn install` ignores `NODE_ENV=production` and will install dev # dependencies too, but this is fine because we need them to build the app. -RUN BUILD_SEQUENCIAL=1 yarn install --inline-builds \ - && yarn cache clean \ - && rm -rf .yarn/berry +RUN --mount=type=cache,target=/build/.yarn/cache --mount=type=cache,target=/build/.yarn/berry/cache\ + BUILD_SEQUENCIAL=1 yarn config set cacheFolder /build/.yarn/cache \ + && yarn install --inline-builds # ============================================================================= # Final stage - we copy only the relevant files from the build stage and start @@ -81,10 +84,11 @@ CMD ["yarn", "start-prod"] ARG BUILD_DATE ARG REVISION ARG VERSION +ARG SOURCE LABEL org.opencontainers.image.created="$BUILD_DATE" \ org.opencontainers.image.title="Joplin Server" \ org.opencontainers.image.description="Docker image for Joplin Server" \ org.opencontainers.image.url="https://joplinapp.org/" \ org.opencontainers.image.revision="$REVISION" \ - org.opencontainers.image.source="https://github.com/laurent22/joplin.git" \ - org.opencontainers.image.version="${VERSION}" + org.opencontainers.image.source="$SOURCE" \ + org.opencontainers.image.version="$VERSION" diff --git a/packages/tools/buildServerDocker.test.ts b/packages/tools/buildServerDocker.test.ts index 332d23423b..de01b6b833 100644 --- a/packages/tools/buildServerDocker.test.ts +++ b/packages/tools/buildServerDocker.test.ts @@ -6,8 +6,15 @@ describe('buildServerDocker', () => { type TestCase = [string, boolean, string]; const testCases: TestCase[] = [ - ['server-v1.1.2-beta', true, '1.1.2-beta'], - ['server-v1.1.2', false, '1.1.2'], + ['server-v1.2.3-beta', true, '1.2.3-beta'], + ['server-v1.2.3-beta', false, '1.2.3'], + ['server-v1.2.3', false, '1.2.3'], + ['server-v1.2.3-zxc', true, '1.2.3-beta.zxc'], + ['server-v1.2.3-zxc', false, '1.2.3'], + ['server-v1.2.3-4-zxc', true, '1.2.3-beta.4.zxc'], + ['server-v1.2.3-4-zxc', false, '1.2.3'], + ['server-1.2.3-4-zxc', true, '1.2.3-beta.4.zxc'], + ['server-1.2.3-4-zxc', false, '1.2.3'], ]; for (const testCase of testCases) { diff --git a/packages/tools/buildServerDocker.ts b/packages/tools/buildServerDocker.ts index 479bb49b26..0e35bc4750 100644 --- a/packages/tools/buildServerDocker.ts +++ b/packages/tools/buildServerDocker.ts @@ -7,12 +7,66 @@ interface Argv { pushImages?: boolean; repository?: string; tagName?: string; + platform?: string; + source?: string; + addLatestTag?: boolean; +} + +function parseArgv(): Argv { + return require('yargs') + .scriptName('yarn buildServerDocker') + .usage('$0 --repository OWNER/IMAGE [args]') + .option('r', { + alias: 'repository', + describe: 'Target image repository. Usually in format `OWNER/NAME`', + demandOption: true, + type: 'string', + }) + .option('t', { + alias: 'tagName', + describe: 'Base image tag. Usually should be in format `server-v1.2.3` or `server-v1.2.3-beta`. The latest `server-v*` git tag will be used by default.', + type: 'string', + }) + .option('l', { + alias: 'addLatestTag', + describe: 'Add `latest` tag even for pre-release images.', + type: 'boolean', + default: false, + }) + .option('platform', { + describe: 'Comma separated list of target image platforms. E.g. `linux/amd64` or `linux/amd64,linux/arm64`', + type: 'string', + default: 'linux/amd64', + }) + .option('source', { + describe: 'Source Git repository for the images.', + type: 'string', + default: 'https://github.com/laurent22/joplin.git', + }) + .option('p', { + alias: 'pushImages', + describe: 'Publish images to target repository.', + type: 'boolean', + default: false, + }) + .option('dryRun', { + alias: 'dryRun', + describe: 'Do not call docker, just show command instead.', + type: 'boolean', + default: false, + }) + .help() + .argv as Argv; } export function getVersionFromTag(tagName: string, isPreRelease: boolean): string { const s = tagName.split('-'); - const suffix = isPreRelease ? '-beta' : ''; - return s[1].substr(1) + suffix; + const mainVersion = s[1].replace(/^(v)/, ''); + const metaComponents = s.slice(2).filter(item => item !== 'beta'); + + // Append `git describe` components for pre release images. Mostly for case without `tagName` arg + const suffix = isPreRelease ? `-beta${metaComponents.length > 0 ? `.${metaComponents.join('.')}` : ''}` : ''; + return mainVersion + suffix; } export function getIsPreRelease(_tagName: string): boolean { @@ -23,14 +77,17 @@ export function getIsPreRelease(_tagName: string): boolean { } async function main() { - const argv = require('yargs').argv as Argv; - if (!argv.tagName) throw new Error('--tag-name not provided'); - if (!argv.repository) throw new Error('--repository not provided'); + const argv = parseArgv(); + if (!argv.tagName) console.info('No `--tag-name` was specified. A latest git tag will be used instead.'); - const dryRun = !!argv.dryRun; - const pushImages = !!argv.pushImages; + const dryRun = argv.dryRun; + const addLatestTag = argv.addLatestTag; + const pushImages = argv.pushImages; const repository = argv.repository; - const tagName = argv.tagName; + const tagName = argv.tagName || `server-${await execCommand('git describe --tags --match v*', { showStdout: false })}`; + const platform = argv.platform; + const source = argv.source; + const isPreRelease = getIsPreRelease(tagName); const imageVersion = getVersionFromTag(tagName, isPreRelease); const buildDate = moment(new Date().getTime()).format('YYYY-MM-DDTHH:mm:ssZ'); @@ -40,35 +97,57 @@ async function main() { } catch (error) { console.info('Could not get git commit: metadata revision field will be empty'); } - const buildArgs = `--build-arg BUILD_DATE="${buildDate}" --build-arg REVISION="${revision}" --build-arg VERSION="${imageVersion}"`; + + const buildArgs = []; + buildArgs.push(`BUILD_DATE="${buildDate}"`); + buildArgs.push(`REVISION="${revision}"`); + buildArgs.push(`VERSION="${imageVersion}"`); + buildArgs.push(`SOURCE="${source}"`); + const dockerTags: string[] = []; - const versionPart = imageVersion.split('.'); - dockerTags.push(isPreRelease ? 'beta' : 'latest'); - dockerTags.push(versionPart[0] + (isPreRelease ? '-beta' : '')); - dockerTags.push(`${versionPart[0]}.${versionPart[1]}${isPreRelease ? '-beta' : ''}`); - dockerTags.push(imageVersion); + const versionParts = imageVersion.split('.'); + const patchVersionPart = versionParts[2].split('-')[0]; + dockerTags.push(isPreRelease ? 'latest-beta' : 'latest'); + dockerTags.push(versionParts[0] + (isPreRelease ? '-beta' : '')); + dockerTags.push(`${versionParts[0]}.${versionParts[1]}${isPreRelease ? '-beta' : ''}`); + dockerTags.push(`${versionParts[0]}.${versionParts[1]}.${patchVersionPart}${isPreRelease ? '-beta' : ''}`); + if (dockerTags.indexOf(imageVersion) < 0) { + dockerTags.push(imageVersion); + } + if (addLatestTag && dockerTags.indexOf('latest') < 0) { + dockerTags.push('latest'); + } + process.chdir(rootDir); console.info(`Running from: ${process.cwd()}`); + console.info('repository:', repository); console.info('tagName:', tagName); + console.info('platform:', platform); console.info('pushImages:', pushImages); console.info('imageVersion:', imageVersion); console.info('isPreRelease:', isPreRelease); console.info('Docker tags:', dockerTags.join(', ')); - const dockerCommand = `docker build --progress=plain -t "${repository}:${imageVersion}" ${buildArgs} -f Dockerfile.server .`; + const cliArgs = ['--progress=plain']; + cliArgs.push(`--platform ${platform}`); + cliArgs.push(...dockerTags.map(tag => `--tag "${repository}:${tag}"`)); + cliArgs.push(...buildArgs.map(arg => `--build-arg ${arg}`)); + if (pushImages) { + cliArgs.push('--push'); + } + cliArgs.push('-f Dockerfile.server'); + cliArgs.push('.'); + + const dockerCommand = `docker buildx build ${cliArgs.join(' ')}`; + + console.info('exec:', dockerCommand); if (dryRun) { - console.info(dockerCommand); return; } await execCommand(dockerCommand); - - for (const tag of dockerTags) { - await execCommand(`docker tag "${repository}:${imageVersion}" "${repository}:${tag}"`); - if (pushImages) await execCommand(`docker push ${repository}:${tag}`); - } } if (require.main === module) { diff --git a/packages/tools/cspell/dictionary4.txt b/packages/tools/cspell/dictionary4.txt index 96040b232c..8befd0996f 100644 --- a/packages/tools/cspell/dictionary4.txt +++ b/packages/tools/cspell/dictionary4.txt @@ -161,6 +161,7 @@ unwatcher pedr Slotozilla keyshortcuts +buildx atag HMAC Siri From ee2b1867525663502ce664b8aed1cb40c62f526a Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 30 Mar 2025 12:05:22 +0200 Subject: [PATCH 100/158] Server: Trying to build ARM64 Docker image --- .github/scripts/run_ci.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/scripts/run_ci.sh b/.github/scripts/run_ci.sh index adfa01424e..6a1d39bead 100755 --- a/.github/scripts/run_ci.sh +++ b/.github/scripts/run_ci.sh @@ -35,6 +35,8 @@ else IS_MACOS=1 fi +DOCKER_IMAGE_PLATFORM="linux/amd64" + # Tests can randomly fail in some cases, so only run them when not publishing # a release RUN_TESTS=0 @@ -57,6 +59,8 @@ if [ "$RUNNER_ARCH" == "ARM64" ]; then yarn remove canvas cd "$ROOT_DIR" + DOCKER_IMAGE_PLATFORM="linux/arm64" + # Delete certain directories because `yarn install` will fail on ARM64. rm -rf app-desktop rm -rf app-mobile @@ -297,8 +301,8 @@ if [ "$IS_DESKTOP_RELEASE" == "1" ]; then fi elif [[ $IS_LINUX = 1 ]] && [ "$IS_SERVER_RELEASE" == "1" ]; then echo "Step: Building Docker Image..." - cd "$ROOT_DIR" - yarn buildServerDocker --tag-name $GIT_TAG_NAME --push-images --repository $SERVER_REPOSITORY + cd "$ROOT_DIR" + yarn buildServerDocker --platform $DOCKER_IMAGE_PLATFORM --tag-name $GIT_TAG_NAME --push-images --repository $SERVER_REPOSITORY else echo "Step: Building but *not* publishing desktop application..." From c524f5a6b55a813b0f04104b415798ec5e4e0d9f Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 30 Mar 2025 12:06:08 +0200 Subject: [PATCH 101/158] Server v3.3.6 --- packages/server/package.json | 2 +- readme/about/changelog/server.md | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index 67375f31c5..1992a0a933 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@joplin/server", - "version": "3.3.5", + "version": "3.3.6", "private": true, "scripts": { "start-dev": "yarn build && JOPLIN_IS_TESTING=1 nodemon --config nodemon.json --ext ts,js,mustache,css,tsx dist/app.js --env dev", diff --git a/readme/about/changelog/server.md b/readme/about/changelog/server.md index 763c44515e..c1f89150d8 100644 --- a/readme/about/changelog/server.md +++ b/readme/about/changelog/server.md @@ -1,7 +1,8 @@ # Joplin Server Changelog -## [server-v3.3.5](https://github.com/laurent22/joplin/releases/tag/server-v3.3.5) - 2025-03-30T08:31:41Z +## [server-v3.3.6](https://github.com/laurent22/joplin/releases/tag/server-v3.3.6) - 2025-03-30T10:05:42Z +- Improved: Buildx support for Docker images (#11582 by [@redrathnure](https://github.com/redrathnure)) - New: Added links to social networks (04fc634) - Improved: Joplin Server Docker image for ARM64 (#12030) - Fixed: Disable faulty dark theme to prevent published notes from being unreadable (#11910) From b0c9c4c8cea43cdc78d2610b1ab2e815d0c43f05 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 30 Mar 2025 12:56:05 +0200 Subject: [PATCH 102/158] Server: Trying to build ARM64 Docker image --- .github/workflows/github-actions-main.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/github-actions-main.yml b/.github/workflows/github-actions-main.yml index 7763585b0f..3eb20fa34c 100644 --- a/.github/workflows/github-actions-main.yml +++ b/.github/workflows/github-actions-main.yml @@ -20,6 +20,7 @@ jobs: # if: runner.os == 'Linux' && startsWith(github.ref, 'refs/tags/server-v') if: runner.os == 'Linux' run: | + ARCH_LOWERCASE="${RUNNER_ARCH}" | tr '[:upper:]' '[:lower:]' sudo apt-get install -y apt-transport-https sudo apt-get install -y ca-certificates sudo apt-get install -y curl @@ -27,7 +28,7 @@ jobs: sudo apt-get install -y lsb-release curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg echo \ - "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ + "deb [arch=$ARCH_LOWERCASE signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt-get update || true sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin @@ -96,6 +97,7 @@ jobs: - name: Install Docker Engine run: | + ARCH_LOWERCASE="${RUNNER_ARCH}" | tr '[:upper:]' '[:lower:]' sudo apt-get install -y apt-transport-https sudo apt-get install -y ca-certificates sudo apt-get install -y curl @@ -103,7 +105,7 @@ jobs: sudo apt-get install -y lsb-release curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg echo \ - "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ + "deb [arch=$ARCH_LOWERCASE signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt-get update || true sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin From 611e8df81ad58ee475becc294fb67f915d52ebe7 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 30 Mar 2025 12:56:47 +0200 Subject: [PATCH 103/158] Server v3.3.7 --- node | 0 packages/server/package.json | 2 +- readme/about/changelog/server.md | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 node diff --git a/node b/node new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/server/package.json b/packages/server/package.json index 1992a0a933..a4a33e4a68 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@joplin/server", - "version": "3.3.6", + "version": "3.3.7", "private": true, "scripts": { "start-dev": "yarn build && JOPLIN_IS_TESTING=1 nodemon --config nodemon.json --ext ts,js,mustache,css,tsx dist/app.js --env dev", diff --git a/readme/about/changelog/server.md b/readme/about/changelog/server.md index c1f89150d8..6bbe8be213 100644 --- a/readme/about/changelog/server.md +++ b/readme/about/changelog/server.md @@ -1,6 +1,6 @@ # Joplin Server Changelog -## [server-v3.3.6](https://github.com/laurent22/joplin/releases/tag/server-v3.3.6) - 2025-03-30T10:05:42Z +## [server-v3.3.7](https://github.com/laurent22/joplin/releases/tag/server-v3.3.7) - 2025-03-30T10:56:24Z - Improved: Buildx support for Docker images (#11582 by [@redrathnure](https://github.com/redrathnure)) - New: Added links to social networks (04fc634) From 9d73e583b9017446589bc6c06427a67905e96d4d Mon Sep 17 00:00:00 2001 From: Joplin Bot Date: Sun, 30 Mar 2025 12:56:53 +0000 Subject: [PATCH 104/158] Doc: Auto-update documentation Auto-updated using release-website.sh --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4543da127e..727035bd83 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Please see the [donation page](https://github.com/laurent22/joplin/blob/dev/read # Sponsors - EduBirdie web design agency RealGambling.ca write an essay online with EssayPro casino without making any upfront cost + web design agency RealGambling.ca write an essay online with EssayPro casino without making any upfront cost Tiktok Rise * * * From f5f7b1eb60398ce3723ff93c788c7ee1f3ce2349 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 30 Mar 2025 16:31:45 +0200 Subject: [PATCH 105/158] Server: Trying to build ARM64 Docker image (#12033) --- .github/scripts/run_ci.sh | 1 + .github/workflows/github-actions-main.yml | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/scripts/run_ci.sh b/.github/scripts/run_ci.sh index 6a1d39bead..5fddbe12c2 100755 --- a/.github/scripts/run_ci.sh +++ b/.github/scripts/run_ci.sh @@ -80,6 +80,7 @@ echo "GIT_TAG_NAME=$GIT_TAG_NAME" echo "BUILD_SEQUENCIAL=$BUILD_SEQUENCIAL" echo "SERVER_REPOSITORY=$SERVER_REPOSITORY" echo "SERVER_TAG_PREFIX=$SERVER_TAG_PREFIX" +echo "DOCKER_IMAGE_PLATFORM=$DOCKER_IMAGE_PLATFORM" echo "IS_CONTINUOUS_INTEGRATION=$IS_CONTINUOUS_INTEGRATION" echo "IS_PULL_REQUEST=$IS_PULL_REQUEST" diff --git a/.github/workflows/github-actions-main.yml b/.github/workflows/github-actions-main.yml index 3eb20fa34c..937fd2e85a 100644 --- a/.github/workflows/github-actions-main.yml +++ b/.github/workflows/github-actions-main.yml @@ -20,7 +20,6 @@ jobs: # if: runner.os == 'Linux' && startsWith(github.ref, 'refs/tags/server-v') if: runner.os == 'Linux' run: | - ARCH_LOWERCASE="${RUNNER_ARCH}" | tr '[:upper:]' '[:lower:]' sudo apt-get install -y apt-transport-https sudo apt-get install -y ca-certificates sudo apt-get install -y curl @@ -28,7 +27,7 @@ jobs: sudo apt-get install -y lsb-release curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg echo \ - "deb [arch=$ARCH_LOWERCASE signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ + "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt-get update || true sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin @@ -97,7 +96,6 @@ jobs: - name: Install Docker Engine run: | - ARCH_LOWERCASE="${RUNNER_ARCH}" | tr '[:upper:]' '[:lower:]' sudo apt-get install -y apt-transport-https sudo apt-get install -y ca-certificates sudo apt-get install -y curl @@ -105,7 +103,7 @@ jobs: sudo apt-get install -y lsb-release curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg echo \ - "deb [arch=$ARCH_LOWERCASE signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ + "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt-get update || true sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin @@ -126,16 +124,21 @@ jobs: env: BUILD_SEQUENCIAL: 1 run: | + if [ "$RUNNER_ARCH" == "ARM64" ]; then + DOCKER_IMAGE_PLATFORM="linux/arm64" + fi + echo "RUNNER_OS=$RUNNER_OS" echo "RUNNER_ARCH=$RUNNER_ARCH" + echo "DOCKER_IMAGE_PLATFORM=$DOCKER_IMAGE_PLATFORM" # Canvas is only needed for tests and it doesn't build in ARM64 so remove it cd packages/lib yarn remove canvas cd ../.. - + yarn install - yarn buildServerDocker --tag-name server-v0.0.0 --repository joplin/server + yarn buildServerDocker --platform $DOCKER_IMAGE_PLATFORM --tag-name server-v0.0.0 --repository joplin/server # Basic test to ensure that the created build is valid. It should exit with # code 0 if it works. From 0f08688ce8813864044f249d5a4ff16e928e0e34 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 30 Mar 2025 16:32:47 +0200 Subject: [PATCH 106/158] Server v3.3.8 --- packages/server/package.json | 2 +- readme/about/changelog/server.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index a4a33e4a68..d7b00e5513 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@joplin/server", - "version": "3.3.7", + "version": "3.3.8", "private": true, "scripts": { "start-dev": "yarn build && JOPLIN_IS_TESTING=1 nodemon --config nodemon.json --ext ts,js,mustache,css,tsx dist/app.js --env dev", diff --git a/readme/about/changelog/server.md b/readme/about/changelog/server.md index 6bbe8be213..8a02abc5de 100644 --- a/readme/about/changelog/server.md +++ b/readme/about/changelog/server.md @@ -1,6 +1,6 @@ # Joplin Server Changelog -## [server-v3.3.7](https://github.com/laurent22/joplin/releases/tag/server-v3.3.7) - 2025-03-30T10:56:24Z +## [server-v3.3.8](https://github.com/laurent22/joplin/releases/tag/server-v3.3.8) - 2025-03-30T14:32:32Z - Improved: Buildx support for Docker images (#11582 by [@redrathnure](https://github.com/redrathnure)) - New: Added links to social networks (04fc634) From c8a2802181da7152eb4e3d5d3db1917de9224174 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 30 Mar 2025 17:14:51 +0200 Subject: [PATCH 107/158] Chore: Fixed dictionary --- packages/tools/cspell/dictionary4.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/tools/cspell/dictionary4.txt b/packages/tools/cspell/dictionary4.txt index 8befd0996f..a68c6d77a3 100644 --- a/packages/tools/cspell/dictionary4.txt +++ b/packages/tools/cspell/dictionary4.txt @@ -176,3 +176,4 @@ collapseall newfolder unfocusable unlocker +Tiktok From c921976e9da149ace086b8f7da4567b528f4cddf Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 30 Mar 2025 17:15:13 +0200 Subject: [PATCH 108/158] Server v3.3.9 --- packages/server/package.json | 2 +- readme/about/changelog/server.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index d7b00e5513..42998269dd 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@joplin/server", - "version": "3.3.8", + "version": "3.3.9", "private": true, "scripts": { "start-dev": "yarn build && JOPLIN_IS_TESTING=1 nodemon --config nodemon.json --ext ts,js,mustache,css,tsx dist/app.js --env dev", diff --git a/readme/about/changelog/server.md b/readme/about/changelog/server.md index 8a02abc5de..448a23ad1f 100644 --- a/readme/about/changelog/server.md +++ b/readme/about/changelog/server.md @@ -1,6 +1,6 @@ # Joplin Server Changelog -## [server-v3.3.8](https://github.com/laurent22/joplin/releases/tag/server-v3.3.8) - 2025-03-30T14:32:32Z +## [server-v3.3.9](https://github.com/laurent22/joplin/releases/tag/server-v3.3.9) - 2025-03-30T15:15:02Z - Improved: Buildx support for Docker images (#11582 by [@redrathnure](https://github.com/redrathnure)) - New: Added links to social networks (04fc634) From e74d5e7c2315fe3f7114e137d809ca353611b940 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 30 Mar 2025 18:50:57 +0200 Subject: [PATCH 109/158] Server: Trying to build ARM64 Docker image --- .github/scripts/publish_docker_manifest.sh | 19 +++++++++++++++++++ .github/workflows/github-actions-main.yml | 8 ++++++++ packages/tools/buildServerDocker.ts | 3 ++- 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 .github/scripts/publish_docker_manifest.sh diff --git a/.github/scripts/publish_docker_manifest.sh b/.github/scripts/publish_docker_manifest.sh new file mode 100644 index 0000000000..f4803fb25b --- /dev/null +++ b/.github/scripts/publish_docker_manifest.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +echo "GIT_TAG_NAME=$GIT_TAG_NAME" +echo "SERVER_TAG_PREFIX=$SERVER_TAG_PREFIX" +echo "SERVER_REPOSITORY=$SERVER_REPOSITORY" + +# Check if it's a server release, otherwise exit +if [[ $GIT_TAG_NAME != $SERVER_TAG_PREFIX-* ]]; then + exit 0 +fi + +docker manifest create $SERVER_REPOSITORY:$GIT_TAG_NAME \ + $SERVER_REPOSITORY:arm64-$GIT_TAG_NAME \ + $SERVER_REPOSITORY:amd64-$GIT_TAG_NAME + +docker manifest annotate $SERVER_REPOSITORY:$GIT_TAG_NAME $SERVER_REPOSITORY:arm64-$GIT_TAG_NAME --arch arm64 +docker manifest annotate $SERVER_REPOSITORY:$GIT_TAG_NAME $SERVER_REPOSITORY:amd64-$GIT_TAG_NAME --arch amd64 + +docker manifest push $SERVER_REPOSITORY:$GIT_TAG_NAME diff --git a/.github/workflows/github-actions-main.yml b/.github/workflows/github-actions-main.yml index 937fd2e85a..60d9bc217c 100644 --- a/.github/workflows/github-actions-main.yml +++ b/.github/workflows/github-actions-main.yml @@ -84,6 +84,14 @@ jobs: run: | yarn install && cd packages/app-desktop && yarn dist --publish=never + - name: Publish Docker manifest + if: runner.os == 'Linux' + env: + SERVER_REPOSITORY: joplin/server + SERVER_TAG_PREFIX: server + run: | + "${GITHUB_WORKSPACE}/.github/scripts/publish_docker_manifest.sh" + ServerDockerImage: if: github.repository == 'laurent22/joplin' runs-on: ${{ matrix.os }} diff --git a/packages/tools/buildServerDocker.ts b/packages/tools/buildServerDocker.ts index 0e35bc4750..ce92341ed2 100644 --- a/packages/tools/buildServerDocker.ts +++ b/packages/tools/buildServerDocker.ts @@ -87,6 +87,7 @@ async function main() { const tagName = argv.tagName || `server-${await execCommand('git describe --tags --match v*', { showStdout: false })}`; const platform = argv.platform; const source = argv.source; + const architecture = argv.platform.split('/')[1]; const isPreRelease = getIsPreRelease(tagName); const imageVersion = getVersionFromTag(tagName, isPreRelease); @@ -132,7 +133,7 @@ async function main() { const cliArgs = ['--progress=plain']; cliArgs.push(`--platform ${platform}`); - cliArgs.push(...dockerTags.map(tag => `--tag "${repository}:${tag}"`)); + cliArgs.push(...dockerTags.map(tag => `--tag "${repository}:${architecture}-${tag}"`)); cliArgs.push(...buildArgs.map(arg => `--build-arg ${arg}`)); if (pushImages) { cliArgs.push('--push'); From 3438c58ec4176ec012d471a7340bed8f05b180df Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 30 Mar 2025 18:51:28 +0200 Subject: [PATCH 110/158] Server v3.3.10 --- packages/server/package.json | 2 +- readme/about/changelog/server.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index 42998269dd..38c20d8fcd 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@joplin/server", - "version": "3.3.9", + "version": "3.3.10", "private": true, "scripts": { "start-dev": "yarn build && JOPLIN_IS_TESTING=1 nodemon --config nodemon.json --ext ts,js,mustache,css,tsx dist/app.js --env dev", diff --git a/readme/about/changelog/server.md b/readme/about/changelog/server.md index 448a23ad1f..b1e6f25337 100644 --- a/readme/about/changelog/server.md +++ b/readme/about/changelog/server.md @@ -1,6 +1,6 @@ # Joplin Server Changelog -## [server-v3.3.9](https://github.com/laurent22/joplin/releases/tag/server-v3.3.9) - 2025-03-30T15:15:02Z +## [server-v3.3.10](https://github.com/laurent22/joplin/releases/tag/server-v3.3.10) - 2025-03-30T16:51:18Z - Improved: Buildx support for Docker images (#11582 by [@redrathnure](https://github.com/redrathnure)) - New: Added links to social networks (04fc634) From 77048caeeb849017e13b48a912a2b3bcc161a89a Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 30 Mar 2025 19:14:32 +0200 Subject: [PATCH 111/158] Server: Trying to build ARM64 Docker image --- .github/workflows/github-actions-main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/github-actions-main.yml b/.github/workflows/github-actions-main.yml index 60d9bc217c..86d749ac2b 100644 --- a/.github/workflows/github-actions-main.yml +++ b/.github/workflows/github-actions-main.yml @@ -90,6 +90,7 @@ jobs: SERVER_REPOSITORY: joplin/server SERVER_TAG_PREFIX: server run: | + chmod 700 "${GITHUB_WORKSPACE}/.github/scripts/publish_docker_manifest.sh" "${GITHUB_WORKSPACE}/.github/scripts/publish_docker_manifest.sh" ServerDockerImage: From 8dcfc81ceeec6b52887c0ad5cd9233192f6cbdda Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 30 Mar 2025 19:14:52 +0200 Subject: [PATCH 112/158] Server v3.3.11 --- packages/server/package.json | 2 +- readme/about/changelog/server.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index 38c20d8fcd..33ce9f3fba 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@joplin/server", - "version": "3.3.10", + "version": "3.3.11", "private": true, "scripts": { "start-dev": "yarn build && JOPLIN_IS_TESTING=1 nodemon --config nodemon.json --ext ts,js,mustache,css,tsx dist/app.js --env dev", diff --git a/readme/about/changelog/server.md b/readme/about/changelog/server.md index b1e6f25337..6aaca5dd2d 100644 --- a/readme/about/changelog/server.md +++ b/readme/about/changelog/server.md @@ -1,6 +1,6 @@ # Joplin Server Changelog -## [server-v3.3.10](https://github.com/laurent22/joplin/releases/tag/server-v3.3.10) - 2025-03-30T16:51:18Z +## [server-v3.3.11](https://github.com/laurent22/joplin/releases/tag/server-v3.3.11) - 2025-03-30T17:14:43Z - Improved: Buildx support for Docker images (#11582 by [@redrathnure](https://github.com/redrathnure)) - New: Added links to social networks (04fc634) From 020cd914af6b929a582a108ffd849894970dcefe Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 30 Mar 2025 19:38:18 +0200 Subject: [PATCH 113/158] Server: Trying to build ARM64 Docker image --- .github/scripts/publish_docker_manifest.sh | 15 +++++++++------ packages/tools/buildServerDocker.ts | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/scripts/publish_docker_manifest.sh b/.github/scripts/publish_docker_manifest.sh index f4803fb25b..1dcb3f1230 100644 --- a/.github/scripts/publish_docker_manifest.sh +++ b/.github/scripts/publish_docker_manifest.sh @@ -1,6 +1,9 @@ #!/bin/bash +VERSION=$(echo "$GIT_TAG_NAME" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+') + echo "GIT_TAG_NAME=$GIT_TAG_NAME" +echo "VERSION=$VERSION" echo "SERVER_TAG_PREFIX=$SERVER_TAG_PREFIX" echo "SERVER_REPOSITORY=$SERVER_REPOSITORY" @@ -9,11 +12,11 @@ if [[ $GIT_TAG_NAME != $SERVER_TAG_PREFIX-* ]]; then exit 0 fi -docker manifest create $SERVER_REPOSITORY:$GIT_TAG_NAME \ - $SERVER_REPOSITORY:arm64-$GIT_TAG_NAME \ - $SERVER_REPOSITORY:amd64-$GIT_TAG_NAME +docker manifest create $SERVER_REPOSITORY:$VERSION \ + $SERVER_REPOSITORY:arm64-$VERSION \ + $SERVER_REPOSITORY:amd64-$VERSION -docker manifest annotate $SERVER_REPOSITORY:$GIT_TAG_NAME $SERVER_REPOSITORY:arm64-$GIT_TAG_NAME --arch arm64 -docker manifest annotate $SERVER_REPOSITORY:$GIT_TAG_NAME $SERVER_REPOSITORY:amd64-$GIT_TAG_NAME --arch amd64 +docker manifest annotate $SERVER_REPOSITORY:$VERSION $SERVER_REPOSITORY:arm64-$VERSION --arch arm64 +docker manifest annotate $SERVER_REPOSITORY:$VERSION $SERVER_REPOSITORY:amd64-$VERSION --arch amd64 -docker manifest push $SERVER_REPOSITORY:$GIT_TAG_NAME +docker manifest push $SERVER_REPOSITORY:$VERSION diff --git a/packages/tools/buildServerDocker.ts b/packages/tools/buildServerDocker.ts index ce92341ed2..2cabc5db55 100644 --- a/packages/tools/buildServerDocker.ts +++ b/packages/tools/buildServerDocker.ts @@ -72,7 +72,7 @@ export function getVersionFromTag(tagName: string, isPreRelease: boolean): strin export function getIsPreRelease(_tagName: string): boolean { // For now we only create pre-releases from CI. It's after, once the release // has been proven stable, that it is tagged as "latest". - return true; + return false; // return tagName.indexOf('-beta') > 0; } From ff4d18dec3256034caee63a7cb10a06bedea7eef Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 30 Mar 2025 19:38:58 +0200 Subject: [PATCH 114/158] Server v3.3.12 --- packages/server/package.json | 2 +- readme/about/changelog/server.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index 33ce9f3fba..cb467688e3 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@joplin/server", - "version": "3.3.11", + "version": "3.3.12", "private": true, "scripts": { "start-dev": "yarn build && JOPLIN_IS_TESTING=1 nodemon --config nodemon.json --ext ts,js,mustache,css,tsx dist/app.js --env dev", diff --git a/readme/about/changelog/server.md b/readme/about/changelog/server.md index 6aaca5dd2d..49f6b68a71 100644 --- a/readme/about/changelog/server.md +++ b/readme/about/changelog/server.md @@ -1,6 +1,6 @@ # Joplin Server Changelog -## [server-v3.3.11](https://github.com/laurent22/joplin/releases/tag/server-v3.3.11) - 2025-03-30T17:14:43Z +## [server-v3.3.12](https://github.com/laurent22/joplin/releases/tag/server-v3.3.12) - 2025-03-30T17:38:46Z - Improved: Buildx support for Docker images (#11582 by [@redrathnure](https://github.com/redrathnure)) - New: Added links to social networks (04fc634) From f10fd4b2da4f13e267db38fa10a4a0e1ed83721a Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 30 Mar 2025 20:28:29 +0200 Subject: [PATCH 115/158] Server: Trying to build ARM64 Docker image --- .github/scripts/publish_docker_manifest.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/scripts/publish_docker_manifest.sh b/.github/scripts/publish_docker_manifest.sh index 1dcb3f1230..3a02135484 100644 --- a/.github/scripts/publish_docker_manifest.sh +++ b/.github/scripts/publish_docker_manifest.sh @@ -12,6 +12,18 @@ if [[ $GIT_TAG_NAME != $SERVER_TAG_PREFIX-* ]]; then exit 0 fi +docker manifest inspect $SERVER_REPOSITORY:arm64-$VERSION > /dev/null 2>&1 +if [ $? -ne 0 ]; then + echo "Image $SERVER_REPOSITORY:arm64-$VERSION does not exist on the remote registry." + exit 0 +fi + +docker manifest inspect $SERVER_REPOSITORY:amd64-$VERSION > /dev/null 2>&1 +if [ $? -ne 0 ]; then + echo "Image $SERVER_REPOSITORY:amd64-$VERSION does not exist on the remote registry." + exit 0 +fi + docker manifest create $SERVER_REPOSITORY:$VERSION \ $SERVER_REPOSITORY:arm64-$VERSION \ $SERVER_REPOSITORY:amd64-$VERSION From 716e5252c1d925367b79fc2454fa896413eadf29 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 30 Mar 2025 20:29:09 +0200 Subject: [PATCH 116/158] Server v3.3.13 --- packages/server/package.json | 2 +- readme/about/changelog/server.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index cb467688e3..b1cb378e1f 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@joplin/server", - "version": "3.3.12", + "version": "3.3.13", "private": true, "scripts": { "start-dev": "yarn build && JOPLIN_IS_TESTING=1 nodemon --config nodemon.json --ext ts,js,mustache,css,tsx dist/app.js --env dev", diff --git a/readme/about/changelog/server.md b/readme/about/changelog/server.md index 49f6b68a71..73c3a9d4e6 100644 --- a/readme/about/changelog/server.md +++ b/readme/about/changelog/server.md @@ -1,6 +1,6 @@ # Joplin Server Changelog -## [server-v3.3.12](https://github.com/laurent22/joplin/releases/tag/server-v3.3.12) - 2025-03-30T17:38:46Z +## [server-v3.3.13](https://github.com/laurent22/joplin/releases/tag/server-v3.3.13) - 2025-03-30T18:28:47Z - Improved: Buildx support for Docker images (#11582 by [@redrathnure](https://github.com/redrathnure)) - New: Added links to social networks (04fc634) From 1e5c41dc4808612719c5bf296d60e98f303f31dc Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 30 Mar 2025 23:29:17 +0200 Subject: [PATCH 117/158] Chore: Fixed CI --- .github/workflows/github-actions-main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/github-actions-main.yml b/.github/workflows/github-actions-main.yml index 86d749ac2b..0ce1bef0a0 100644 --- a/.github/workflows/github-actions-main.yml +++ b/.github/workflows/github-actions-main.yml @@ -151,12 +151,12 @@ jobs: # Basic test to ensure that the created build is valid. It should exit with # code 0 if it works. - docker run joplin/server:0.0.0-beta node dist/app.js migrate list + docker run joplin/server:0.0.0 node dist/app.js migrate list - name: Check HTTP request run: | # Need to pass environment variables: - docker run -p 22300:22300 joplin/server:0.0.0-beta node dist/app.js --env dev & + docker run -p 22300:22300 joplin/server:0.0.0 node dist/app.js --env dev & # Wait for server to start sleep 30 From 471f5a72febbac03ccf5fa7bf0c701b4703598e8 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 30 Mar 2025 23:41:49 +0200 Subject: [PATCH 118/158] Chore: Fixing CI --- .github/workflows/github-actions-main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/github-actions-main.yml b/.github/workflows/github-actions-main.yml index 0ce1bef0a0..9785e70111 100644 --- a/.github/workflows/github-actions-main.yml +++ b/.github/workflows/github-actions-main.yml @@ -151,12 +151,12 @@ jobs: # Basic test to ensure that the created build is valid. It should exit with # code 0 if it works. - docker run joplin/server:0.0.0 node dist/app.js migrate list + docker run joplin/server:amd64-0.0.0 node dist/app.js migrate list - name: Check HTTP request run: | # Need to pass environment variables: - docker run -p 22300:22300 joplin/server:0.0.0 node dist/app.js --env dev & + docker run -p 22300:22300 joplin/server:amd64-0.0.0 node dist/app.js --env dev & # Wait for server to start sleep 30 From 287e0da4b4779c74f3f05fa7086baf5235d7f45e Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Mon, 31 Mar 2025 09:22:00 +0200 Subject: [PATCH 119/158] Chore: Fixing CI --- .github/workflows/github-actions-main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/github-actions-main.yml b/.github/workflows/github-actions-main.yml index 9785e70111..6c918bc53c 100644 --- a/.github/workflows/github-actions-main.yml +++ b/.github/workflows/github-actions-main.yml @@ -151,12 +151,12 @@ jobs: # Basic test to ensure that the created build is valid. It should exit with # code 0 if it works. - docker run joplin/server:amd64-0.0.0 node dist/app.js migrate list + docker run joplin/server:$(dpkg --print-architecture)-0.0.0 node dist/app.js migrate list - name: Check HTTP request run: | # Need to pass environment variables: - docker run -p 22300:22300 joplin/server:amd64-0.0.0 node dist/app.js --env dev & + docker run -p 22300:22300 joplin/server:$(dpkg --print-architecture)-0.0.0 node dist/app.js --env dev & # Wait for server to start sleep 30 From e17ef72111452cde8a365bb9d71703c87497f96d Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Mon, 31 Mar 2025 10:43:12 +0200 Subject: [PATCH 120/158] Chore: Trying to fix CI (#12036) --- packages/tools/buildServerDocker.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/tools/buildServerDocker.test.ts b/packages/tools/buildServerDocker.test.ts index de01b6b833..01b84b3811 100644 --- a/packages/tools/buildServerDocker.test.ts +++ b/packages/tools/buildServerDocker.test.ts @@ -28,8 +28,8 @@ describe('buildServerDocker', () => { type TestCase = [string, boolean]; const testCases: TestCase[] = [ - ['server-v1.1.2-beta', true], - ['server-v1.1.2', true], // For now, always returns true + ['server-v1.1.2-beta', false], // For now, always returns false + ['server-v1.1.2', false], ]; for (const testCase of testCases) { From b8c88af82d2a36fa1824639986274563f31da266 Mon Sep 17 00:00:00 2001 From: Joplin Bot Date: Tue, 1 Apr 2025 02:19:22 +0000 Subject: [PATCH 121/158] Doc: Auto-update documentation Auto-updated using release-website.sh --- readme/about/stats.md | 469 +++++++++++++++++++++--------------------- 1 file changed, 235 insertions(+), 234 deletions(-) diff --git a/readme/about/stats.md b/readme/about/stats.md index 6dee2a876d..fa5068d10a 100644 --- a/readme/about/stats.md +++ b/readme/about/stats.md @@ -1,14 +1,14 @@ --- -updated: 2025-03-01T02:07:09Z +updated: 2025-04-01T02:18:08Z --- # Joplin statistics | Name | Value | | ----- | ----- | -| Total Windows downloads | 6,120,235 | -| Total macOs downloads | 1,924,690 | -| Total Linux downloads | 1,443,432 | +| Total Windows downloads | 6,268,462 | +| Total macOs downloads | 1,946,509 | +| Total Linux downloads | 1,468,822 | | Windows % | 65% | | macOS % | 20% | | Linux % | 15% | @@ -17,214 +17,215 @@ updated: 2025-03-01T02:07:09Z | Version | Date | Windows | macOS | Linux | Total | | ----- | ----- | ----- | ----- | ----- | ----- | -| [v3.2.13](https://github.com/laurent22/joplin/releases/tag/v3.2.13) | 2025-02-28T14:38:21Z | 7,380 | 2,161 | 381 | 9,922 | -| [v3.3.2](https://github.com/laurent22/joplin/releases/tag/v3.3.2) (p) | 2025-02-19T17:34:26Z | 1,575 | 315 | 372 | 2,262 | -| [v3.3.1](https://github.com/laurent22/joplin/releases/tag/v3.3.1) (p) | 2025-02-16T17:06:26Z | 797 | 156 | 152 | 1,105 | -| [v3.2.12](https://github.com/laurent22/joplin/releases/tag/v3.2.12) | 2025-01-23T23:52:04Z | 150,526 | 25,007 | 27,451 | 202,984 | -| [v3.2.11](https://github.com/laurent22/joplin/releases/tag/v3.2.11) | 2025-01-13T17:48:21Z | 65,131 | 14,766 | 6,823 | 86,720 | -| [v3.2.10](https://github.com/laurent22/joplin/releases/tag/v3.2.10) (p) | 2025-01-10T10:17:28Z | 1,039 | 160 | 184 | 1,383 | -| [v3.2.9](https://github.com/laurent22/joplin/releases/tag/v3.2.9) (p) | 2025-01-09T22:58:42Z | 349 | 83 | 49 | 481 | -| [v3.2.7](https://github.com/laurent22/joplin/releases/tag/v3.2.7) (p) | 2025-01-06T16:35:41Z | 856 | 147 | 689 | 1,692 | -| [v3.2.6](https://github.com/laurent22/joplin/releases/tag/v3.2.6) (p) | 2024-12-23T21:54:40Z | 1,707 | 329 | 471 | 2,507 | +| [v3.3.3](https://github.com/laurent22/joplin/releases/tag/v3.3.3) (p) | 2025-03-16T11:52:33Z | 1,991 | 568 | 576 | 3,135 | +| [v3.2.13](https://github.com/laurent22/joplin/releases/tag/v3.2.13) | 2025-02-28T14:38:21Z | 142,008 | 22,730 | 24,132 | 188,870 | +| [v3.3.2](https://github.com/laurent22/joplin/releases/tag/v3.3.2) (p) | 2025-02-19T17:34:26Z | 2,320 | 550 | 618 | 3,488 | +| [v3.3.1](https://github.com/laurent22/joplin/releases/tag/v3.3.1) (p) | 2025-02-16T17:06:26Z | 821 | 157 | 157 | 1,135 | +| [v3.2.12](https://github.com/laurent22/joplin/releases/tag/v3.2.12) | 2025-01-23T23:52:04Z | 151,244 | 25,115 | 27,847 | 204,206 | +| [v3.2.11](https://github.com/laurent22/joplin/releases/tag/v3.2.11) | 2025-01-13T17:48:21Z | 65,392 | 14,799 | 6,846 | 87,037 | +| [v3.2.10](https://github.com/laurent22/joplin/releases/tag/v3.2.10) (p) | 2025-01-10T10:17:28Z | 1,091 | 160 | 184 | 1,435 | +| [v3.2.9](https://github.com/laurent22/joplin/releases/tag/v3.2.9) (p) | 2025-01-09T22:58:42Z | 353 | 83 | 50 | 486 | +| [v3.2.7](https://github.com/laurent22/joplin/releases/tag/v3.2.7) (p) | 2025-01-06T16:35:41Z | 856 | 148 | 736 | 1,740 | +| [v3.2.6](https://github.com/laurent22/joplin/releases/tag/v3.2.6) (p) | 2024-12-23T21:54:40Z | 1,716 | 329 | 471 | 2,516 | | [v3.2.5](https://github.com/laurent22/joplin/releases/tag/v3.2.5) (p) | 2024-12-18T10:41:13Z | 985 | 193 | 217 | 1,395 | -| [v3.2.4](https://github.com/laurent22/joplin/releases/tag/v3.2.4) (p) | 2024-12-12T17:59:52Z | 999 | 145 | 226 | 1,370 | -| [v3.2.3](https://github.com/laurent22/joplin/releases/tag/v3.2.3) (p) | 2024-11-18T00:09:05Z | 2,688 | 547 | 870 | 4,105 | -| [v3.2.1](https://github.com/laurent22/joplin/releases/tag/v3.2.1) (p) | 2024-11-10T16:16:27Z | 1,223 | 224 | 343 | 1,790 | -| [v3.1.24](https://github.com/laurent22/joplin/releases/tag/v3.1.24) | 2024-11-09T15:08:29Z | 207,018 | 33,436 | 43,732 | 284,186 | -| [v3.1.23](https://github.com/laurent22/joplin/releases/tag/v3.1.23) | 2024-11-07T10:56:45Z | 26,752 | 6,728 | 1,517 | 34,997 | -| [v3.1.22](https://github.com/laurent22/joplin/releases/tag/v3.1.22) | 2024-11-05T08:59:32Z | 28,549 | 8,694 | 1,221 | 38,464 | -| [v3.1.20](https://github.com/laurent22/joplin/releases/tag/v3.1.20) | 2024-10-22T12:21:32Z | 94,034 | 19,117 | 13,893 | 127,044 | -| [v3.1.18](https://github.com/laurent22/joplin/releases/tag/v3.1.18) (p) | 2024-10-11T23:27:10Z | 1,502 | 278 | 586 | 2,366 | +| [v3.2.4](https://github.com/laurent22/joplin/releases/tag/v3.2.4) (p) | 2024-12-12T17:59:52Z | 1,000 | 145 | 227 | 1,372 | +| [v3.2.3](https://github.com/laurent22/joplin/releases/tag/v3.2.3) (p) | 2024-11-18T00:09:05Z | 2,688 | 547 | 874 | 4,109 | +| [v3.2.1](https://github.com/laurent22/joplin/releases/tag/v3.2.1) (p) | 2024-11-10T16:16:27Z | 1,229 | 224 | 343 | 1,796 | +| [v3.1.24](https://github.com/laurent22/joplin/releases/tag/v3.1.24) | 2024-11-09T15:08:29Z | 207,460 | 33,448 | 43,757 | 284,665 | +| [v3.1.23](https://github.com/laurent22/joplin/releases/tag/v3.1.23) | 2024-11-07T10:56:45Z | 26,893 | 6,728 | 1,517 | 35,138 | +| [v3.1.22](https://github.com/laurent22/joplin/releases/tag/v3.1.22) | 2024-11-05T08:59:32Z | 28,682 | 8,694 | 1,222 | 38,598 | +| [v3.1.20](https://github.com/laurent22/joplin/releases/tag/v3.1.20) | 2024-10-22T12:21:32Z | 94,267 | 19,143 | 13,901 | 127,311 | +| [v3.1.18](https://github.com/laurent22/joplin/releases/tag/v3.1.18) (p) | 2024-10-11T23:27:10Z | 1,502 | 278 | 587 | 2,367 | | [v3.1.17](https://github.com/laurent22/joplin/releases/tag/v3.1.17) (p) | 2024-09-26T11:57:54Z | 1,696 | 348 | 529 | 2,573 | -| [v3.1.15](https://github.com/laurent22/joplin/releases/tag/v3.1.15) (p) | 2024-09-17T09:15:10Z | 1,177 | 222 | 491 | 1,890 | +| [v3.1.15](https://github.com/laurent22/joplin/releases/tag/v3.1.15) (p) | 2024-09-17T09:15:10Z | 1,177 | 222 | 492 | 1,891 | | [v3.1.8](https://github.com/laurent22/joplin/releases/tag/v3.1.8) (p) | 2024-09-08T20:32:44Z | 1,216 | 252 | 332 | 1,800 | -| [v3.1.6](https://github.com/laurent22/joplin/releases/tag/v3.1.6) (p) | 2024-09-02T13:19:40Z | 959 | 225 | 423 | 1,607 | +| [v3.1.6](https://github.com/laurent22/joplin/releases/tag/v3.1.6) (p) | 2024-09-02T13:19:40Z | 959 | 225 | 424 | 1,608 | | [v3.1.4](https://github.com/laurent22/joplin/releases/tag/v3.1.4) (p) | 2024-08-27T17:46:38Z | 940 | 173 | 245 | 1,358 | -| [v3.0.15](https://github.com/laurent22/joplin/releases/tag/v3.0.15) | 2024-08-21T09:19:58Z | 202,506 | 37,787 | 45,049 | 285,342 | -| [v3.1.3](https://github.com/laurent22/joplin/releases/tag/v3.1.3) (p) | 2024-08-17T13:08:21Z | 1,222 | 269 | 475 | 1,966 | +| [v3.0.15](https://github.com/laurent22/joplin/releases/tag/v3.0.15) | 2024-08-21T09:19:58Z | 202,698 | 37,792 | 45,095 | 285,585 | +| [v3.1.3](https://github.com/laurent22/joplin/releases/tag/v3.1.3) (p) | 2024-08-17T13:08:21Z | 1,222 | 269 | 476 | 1,967 | | [v3.1.2](https://github.com/laurent22/joplin/releases/tag/v3.1.2) (p) | 2024-08-16T09:00:59Z | 432 | 98 | 79 | 609 | -| [v3.1.1](https://github.com/laurent22/joplin/releases/tag/v3.1.1) (p) | 2024-08-10T11:36:02Z | 1,074 | 197 | 259 | 1,530 | -| [v2.14.23](https://github.com/laurent22/joplin/releases/tag/v2.14.23) | 2024-08-07T11:15:25Z | 10,652 | 2,585 | 602 | 13,839 | -| [v3.0.14](https://github.com/laurent22/joplin/releases/tag/v3.0.14) | 2024-07-28T13:55:50Z | 88,695 | 18,564 | 18,797 | 126,056 | -| [v3.0.12](https://github.com/laurent22/joplin/releases/tag/v3.0.12) | 2024-07-02T17:11:14Z | 43,364 | 12,806 | 7,263 | 63,433 | -| [v3.0.11](https://github.com/laurent22/joplin/releases/tag/v3.0.11) (p) | 2024-06-29T10:20:02Z | 839 | 161 | 264 | 1,264 | +| [v3.1.1](https://github.com/laurent22/joplin/releases/tag/v3.1.1) (p) | 2024-08-10T11:36:02Z | 1,075 | 198 | 259 | 1,532 | +| [v2.14.23](https://github.com/laurent22/joplin/releases/tag/v2.14.23) | 2024-08-07T11:15:25Z | 10,692 | 2,606 | 611 | 13,909 | +| [v3.0.14](https://github.com/laurent22/joplin/releases/tag/v3.0.14) | 2024-07-28T13:55:50Z | 88,869 | 18,565 | 18,805 | 126,239 | +| [v3.0.12](https://github.com/laurent22/joplin/releases/tag/v3.0.12) | 2024-07-02T17:11:14Z | 43,662 | 12,823 | 7,316 | 63,801 | +| [v3.0.11](https://github.com/laurent22/joplin/releases/tag/v3.0.11) (p) | 2024-06-29T10:20:02Z | 839 | 162 | 264 | 1,265 | | [v3.0.10](https://github.com/laurent22/joplin/releases/tag/v3.0.10) (p) | 2024-06-19T15:24:07Z | 1,613 | 287 | 558 | 2,458 | | [v3.0.9](https://github.com/laurent22/joplin/releases/tag/v3.0.9) (p) | 2024-06-12T19:07:50Z | 1,258 | 253 | 377 | 1,888 | -| [v3.0.8](https://github.com/laurent22/joplin/releases/tag/v3.0.8) (p) | 2024-05-22T14:20:45Z | 2,655 | 0 | 910 | 3,565 | -| [v2.14.22](https://github.com/laurent22/joplin/releases/tag/v2.14.22) | 2024-05-22T19:19:02Z | 142,333 | 30,681 | 25,447 | 198,461 | -| [v3.0.6](https://github.com/laurent22/joplin/releases/tag/v3.0.6) (p) | 2024-04-27T13:16:04Z | 3,000 | 680 | 860 | 4,540 | -| [v3.0.3](https://github.com/laurent22/joplin/releases/tag/v3.0.3) (p) | 2024-04-18T15:41:38Z | 1,475 | 306 | 328 | 2,109 | -| [v3.0.2](https://github.com/laurent22/joplin/releases/tag/v3.0.2) (p) | 2024-03-21T18:18:49Z | 2,855 | 701 | 1,096 | 4,652 | -| [v2.14.20](https://github.com/laurent22/joplin/releases/tag/v2.14.20) | 2024-03-18T17:05:17Z | 192,056 | 39,482 | 38,187 | 269,725 | -| [v2.14.19](https://github.com/laurent22/joplin/releases/tag/v2.14.19) | 2024-03-08T10:45:16Z | 64,444 | 18,466 | 8,543 | 91,453 | -| [v2.14.17](https://github.com/laurent22/joplin/releases/tag/v2.14.17) | 2024-03-01T18:10:26Z | 63,162 | 18,628 | 7,611 | 89,401 | -| [v2.14.16](https://github.com/laurent22/joplin/releases/tag/v2.14.16) (p) | 2024-02-22T22:49:10Z | 1,346 | 282 | 377 | 2,005 | +| [v3.0.8](https://github.com/laurent22/joplin/releases/tag/v3.0.8) (p) | 2024-05-22T14:20:45Z | 2,657 | 0 | 910 | 3,567 | +| [v2.14.22](https://github.com/laurent22/joplin/releases/tag/v2.14.22) | 2024-05-22T19:19:02Z | 142,488 | 30,703 | 25,451 | 198,642 | +| [v3.0.6](https://github.com/laurent22/joplin/releases/tag/v3.0.6) (p) | 2024-04-27T13:16:04Z | 3,001 | 686 | 860 | 4,547 | +| [v3.0.3](https://github.com/laurent22/joplin/releases/tag/v3.0.3) (p) | 2024-04-18T15:41:38Z | 1,475 | 311 | 328 | 2,114 | +| [v3.0.2](https://github.com/laurent22/joplin/releases/tag/v3.0.2) (p) | 2024-03-21T18:18:49Z | 2,858 | 714 | 1,096 | 4,668 | +| [v2.14.20](https://github.com/laurent22/joplin/releases/tag/v2.14.20) | 2024-03-18T17:05:17Z | 192,310 | 39,500 | 38,191 | 270,001 | +| [v2.14.19](https://github.com/laurent22/joplin/releases/tag/v2.14.19) | 2024-03-08T10:45:16Z | 64,548 | 18,468 | 8,545 | 91,561 | +| [v2.14.17](https://github.com/laurent22/joplin/releases/tag/v2.14.17) | 2024-03-01T18:10:26Z | 63,277 | 18,631 | 7,611 | 89,519 | +| [v2.14.16](https://github.com/laurent22/joplin/releases/tag/v2.14.16) (p) | 2024-02-22T22:49:10Z | 1,346 | 283 | 377 | 2,006 | | [v2.14.15](https://github.com/laurent22/joplin/releases/tag/v2.14.15) (p) | 2024-02-19T11:24:57Z | 851 | 178 | 189 | 1,218 | | [v2.14.14](https://github.com/laurent22/joplin/releases/tag/v2.14.14) (p) | 2024-02-10T16:03:08Z | 1,269 | 242 | 378 | 1,889 | | [v2.14.13](https://github.com/laurent22/joplin/releases/tag/v2.14.13) (p) | 2024-02-09T16:31:54Z | 409 | 80 | 79 | 568 | -| [v2.14.12](https://github.com/laurent22/joplin/releases/tag/v2.14.12) (p) | 2024-02-03T12:11:47Z | 976 | 216 | 244 | 1,436 | -| [v2.14.11](https://github.com/laurent22/joplin/releases/tag/v2.14.11) (p) | 2024-01-26T11:53:05Z | 1,263 | 258 | 456 | 1,977 | -| [v2.14.10](https://github.com/laurent22/joplin/releases/tag/v2.14.10) (p) | 2024-01-18T22:45:04Z | 2,084 | 267 | 370 | 2,721 | -| [v2.13.15](https://github.com/laurent22/joplin/releases/tag/v2.13.15) | 2024-01-15T13:01:19Z | 149,325 | 34,128 | 29,246 | 212,699 | -| [v2.13.14](https://github.com/laurent22/joplin/releases/tag/v2.13.14) | 2024-01-13T19:11:04Z | 19,554 | 7,823 | 2,359 | 29,736 | +| [v2.14.12](https://github.com/laurent22/joplin/releases/tag/v2.14.12) (p) | 2024-02-03T12:11:47Z | 977 | 217 | 244 | 1,438 | +| [v2.14.11](https://github.com/laurent22/joplin/releases/tag/v2.14.11) (p) | 2024-01-26T11:53:05Z | 1,263 | 258 | 457 | 1,978 | +| [v2.14.10](https://github.com/laurent22/joplin/releases/tag/v2.14.10) (p) | 2024-01-18T22:45:04Z | 2,085 | 267 | 370 | 2,722 | +| [v2.13.15](https://github.com/laurent22/joplin/releases/tag/v2.13.15) | 2024-01-15T13:01:19Z | 149,484 | 34,144 | 29,255 | 212,883 | +| [v2.13.14](https://github.com/laurent22/joplin/releases/tag/v2.13.14) | 2024-01-13T19:11:04Z | 19,657 | 7,823 | 2,359 | 29,839 | | [v2.14.9](https://github.com/laurent22/joplin/releases/tag/v2.14.9) (p) | 2024-01-11T22:17:59Z | 1,055 | 0 | 239 | 1,294 | | [v2.14.8](https://github.com/laurent22/joplin/releases/tag/v2.14.8) (p) | 2024-01-09T22:57:07Z | 752 | 235 | 173 | 1,160 | | [v2.14.7](https://github.com/laurent22/joplin/releases/tag/v2.14.7) (p) | 2024-01-08T11:51:49Z | 620 | 127 | 173 | 920 | | [v2.14.6](https://github.com/laurent22/joplin/releases/tag/v2.14.6) (p) | 2024-01-06T16:38:32Z | 726 | 149 | 149 | 1,024 | -| [v2.13.13](https://github.com/laurent22/joplin/releases/tag/v2.13.13) | 2024-01-06T13:33:11Z | 53,547 | 15,929 | 6,345 | 75,821 | -| [v2.13.12](https://github.com/laurent22/joplin/releases/tag/v2.13.12) | 2023-12-31T16:08:02Z | 44,874 | 14,295 | 5,083 | 64,252 | -| [v2.13.11](https://github.com/laurent22/joplin/releases/tag/v2.13.11) | 2023-12-24T12:58:53Z | 45,797 | 13,260 | 5,970 | 65,027 | -| [v2.13.10](https://github.com/laurent22/joplin/releases/tag/v2.13.10) | 2023-12-22T10:11:08Z | 19,601 | 8,691 | 1,457 | 29,749 | -| [v2.13.9](https://github.com/laurent22/joplin/releases/tag/v2.13.9) | 2023-12-09T17:18:58Z | 67,598 | 21,923 | 8,603 | 98,124 | -| [v2.13.8](https://github.com/laurent22/joplin/releases/tag/v2.13.8) | 2023-12-03T12:07:08Z | 50,352 | 17,900 | 5,211 | 73,463 | +| [v2.13.13](https://github.com/laurent22/joplin/releases/tag/v2.13.13) | 2024-01-06T13:33:11Z | 53,674 | 15,929 | 6,345 | 75,948 | +| [v2.13.12](https://github.com/laurent22/joplin/releases/tag/v2.13.12) | 2023-12-31T16:08:02Z | 44,990 | 14,295 | 5,083 | 64,368 | +| [v2.13.11](https://github.com/laurent22/joplin/releases/tag/v2.13.11) | 2023-12-24T12:58:53Z | 45,891 | 13,262 | 5,972 | 65,125 | +| [v2.13.10](https://github.com/laurent22/joplin/releases/tag/v2.13.10) | 2023-12-22T10:11:08Z | 19,656 | 8,692 | 1,459 | 29,807 | +| [v2.13.9](https://github.com/laurent22/joplin/releases/tag/v2.13.9) | 2023-12-09T17:18:58Z | 67,709 | 21,923 | 8,605 | 98,237 | +| [v2.13.8](https://github.com/laurent22/joplin/releases/tag/v2.13.8) | 2023-12-03T12:07:08Z | 50,461 | 17,902 | 5,211 | 73,574 | | [v2.13.6](https://github.com/laurent22/joplin/releases/tag/v2.13.6) (p) | 2023-11-17T19:24:03Z | 2,155 | 443 | 573 | 3,171 | -| [v2.13.5](https://github.com/laurent22/joplin/releases/tag/v2.13.5) (p) | 2023-11-09T20:24:09Z | 1,467 | 338 | 437 | 2,242 | -| [v2.13.4](https://github.com/laurent22/joplin/releases/tag/v2.13.4) (p) | 2023-10-31T00:01:00Z | 1,539 | 372 | 482 | 2,393 | +| [v2.13.5](https://github.com/laurent22/joplin/releases/tag/v2.13.5) (p) | 2023-11-09T20:24:09Z | 1,467 | 339 | 438 | 2,244 | +| [v2.13.4](https://github.com/laurent22/joplin/releases/tag/v2.13.4) (p) | 2023-10-31T00:01:00Z | 1,539 | 372 | 483 | 2,394 | | [v2.13.3](https://github.com/laurent22/joplin/releases/tag/v2.13.3) (p) | 2023-10-24T09:25:33Z | 1,302 | 281 | 301 | 1,884 | -| [v2.12.19](https://github.com/laurent22/joplin/releases/tag/v2.12.19) | 2023-10-21T09:39:18Z | 166,234 | 43,649 | 27,833 | 237,716 | +| [v2.12.19](https://github.com/laurent22/joplin/releases/tag/v2.12.19) | 2023-10-21T09:39:18Z | 166,401 | 43,652 | 27,848 | 237,901 | | [v2.13.2](https://github.com/laurent22/joplin/releases/tag/v2.13.2) (p) | 2023-10-06T17:00:07Z | 2,032 | 503 | 703 | 3,238 | -| [v2.12.18](https://github.com/laurent22/joplin/releases/tag/v2.12.18) | 2023-09-22T14:37:24Z | 108,531 | 36,513 | 18,693 | 163,737 | -| [v2.12.17](https://github.com/laurent22/joplin/releases/tag/v2.12.17) | 2023-09-14T21:54:52Z | 47,173 | 21,030 | 6,626 | 74,829 | +| [v2.12.18](https://github.com/laurent22/joplin/releases/tag/v2.12.18) | 2023-09-22T14:37:24Z | 108,666 | 36,514 | 18,697 | 163,877 | +| [v2.12.17](https://github.com/laurent22/joplin/releases/tag/v2.12.17) | 2023-09-14T21:54:52Z | 47,258 | 21,031 | 6,630 | 74,919 | | [v2.13.1](https://github.com/laurent22/joplin/releases/tag/v2.13.1) (p) | 2023-09-13T09:31:50Z | 1,390 | 427 | 661 | 2,478 | -| [v2.12.16](https://github.com/laurent22/joplin/releases/tag/v2.12.16) | 2023-09-11T22:33:37Z | 28,266 | 14,665 | 2,446 | 45,377 | -| [v2.12.15](https://github.com/laurent22/joplin/releases/tag/v2.12.15) | 2023-08-27T11:35:39Z | 64,101 | 28,054 | 8,359 | 100,514 | -| [v2.12.12](https://github.com/laurent22/joplin/releases/tag/v2.12.12) (p) | 2023-08-19T22:44:56Z | 2,671 | 387 | 428 | 3,486 | -| [v2.12.10](https://github.com/laurent22/joplin/releases/tag/v2.12.10) (p) | 2023-07-30T18:25:58Z | 7,312 | 3,815 | 913 | 12,040 | -| [v2.12.9](https://github.com/laurent22/joplin/releases/tag/v2.12.9) (p) | 2023-07-25T16:06:08Z | 2,130 | 369 | 321 | 2,820 | -| [v2.12.7](https://github.com/laurent22/joplin/releases/tag/v2.12.7) (p) | 2023-07-13T12:55:31Z | 2,145 | 662 | 590 | 3,397 | -| [v2.12.5](https://github.com/laurent22/joplin/releases/tag/v2.12.5) (p) | 2023-07-12T15:03:46Z | 1,796 | 163 | 148 | 2,107 | -| [v2.12.4](https://github.com/laurent22/joplin/releases/tag/v2.12.4) (p) | 2023-07-07T22:36:53Z | 1,047 | 430 | 215 | 1,692 | -| [v2.12.3](https://github.com/laurent22/joplin/releases/tag/v2.12.3) (p) | 2023-07-07T10:16:55Z | 383 | 184 | 93 | 660 | -| [v2.11.11](https://github.com/laurent22/joplin/releases/tag/v2.11.11) | 2023-06-23T15:16:37Z | 188,935 | 67,215 | 38,837 | 294,987 | -| [v2.11.9](https://github.com/laurent22/joplin/releases/tag/v2.11.9) (p) | 2023-06-06T16:23:27Z | 2,294 | 571 | 744 | 3,609 | -| [v2.11.6](https://github.com/laurent22/joplin/releases/tag/v2.11.6) (p) | 2023-05-31T20:13:08Z | 1,156 | 433 | 342 | 1,931 | -| [v2.11.5](https://github.com/laurent22/joplin/releases/tag/v2.11.5) (p) | 2023-05-28T00:41:40Z | 1,021 | 306 | 279 | 1,606 | -| [v2.10.19](https://github.com/laurent22/joplin/releases/tag/v2.10.19) | 2023-05-17T12:25:41Z | 124,237 | 48,328 | 22,466 | 195,031 | +| [v2.12.16](https://github.com/laurent22/joplin/releases/tag/v2.12.16) | 2023-09-11T22:33:37Z | 28,315 | 14,666 | 2,447 | 45,428 | +| [v2.12.15](https://github.com/laurent22/joplin/releases/tag/v2.12.15) | 2023-08-27T11:35:39Z | 64,258 | 28,067 | 8,372 | 100,697 | +| [v2.12.12](https://github.com/laurent22/joplin/releases/tag/v2.12.12) (p) | 2023-08-19T22:44:56Z | 2,718 | 387 | 428 | 3,533 | +| [v2.12.10](https://github.com/laurent22/joplin/releases/tag/v2.12.10) (p) | 2023-07-30T18:25:58Z | 7,356 | 3,815 | 914 | 12,085 | +| [v2.12.9](https://github.com/laurent22/joplin/releases/tag/v2.12.9) (p) | 2023-07-25T16:06:08Z | 2,173 | 369 | 321 | 2,863 | +| [v2.12.7](https://github.com/laurent22/joplin/releases/tag/v2.12.7) (p) | 2023-07-13T12:55:31Z | 2,147 | 663 | 591 | 3,401 | +| [v2.12.5](https://github.com/laurent22/joplin/releases/tag/v2.12.5) (p) | 2023-07-12T15:03:46Z | 1,835 | 163 | 149 | 2,147 | +| [v2.12.4](https://github.com/laurent22/joplin/releases/tag/v2.12.4) (p) | 2023-07-07T22:36:53Z | 1,049 | 430 | 215 | 1,694 | +| [v2.12.3](https://github.com/laurent22/joplin/releases/tag/v2.12.3) (p) | 2023-07-07T10:16:55Z | 388 | 184 | 93 | 665 | +| [v2.11.11](https://github.com/laurent22/joplin/releases/tag/v2.11.11) | 2023-06-23T15:16:37Z | 189,081 | 67,221 | 38,843 | 295,145 | +| [v2.11.9](https://github.com/laurent22/joplin/releases/tag/v2.11.9) (p) | 2023-06-06T16:23:27Z | 2,299 | 572 | 744 | 3,615 | +| [v2.11.6](https://github.com/laurent22/joplin/releases/tag/v2.11.6) (p) | 2023-05-31T20:13:08Z | 1,159 | 433 | 342 | 1,934 | +| [v2.11.5](https://github.com/laurent22/joplin/releases/tag/v2.11.5) (p) | 2023-05-28T00:41:40Z | 1,023 | 306 | 279 | 1,608 | +| [v2.10.19](https://github.com/laurent22/joplin/releases/tag/v2.10.19) | 2023-05-17T12:25:41Z | 124,340 | 48,329 | 22,470 | 195,139 | | [v2.11.4](https://github.com/laurent22/joplin/releases/tag/v2.11.4) (p) | 2023-05-16T10:02:21Z | 1,078 | 466 | 412 | 1,956 | -| [v2.11.3](https://github.com/laurent22/joplin/releases/tag/v2.11.3) (p) | 2023-05-16T09:09:57Z | 124 | 38 | 37 | 199 | -| [v2.10.18](https://github.com/laurent22/joplin/releases/tag/v2.10.18) | 2023-05-09T13:27:43Z | 56,146 | 24,252 | 6,774 | 87,172 | -| [v2.10.17](https://github.com/laurent22/joplin/releases/tag/v2.10.17) | 2023-05-08T17:27:28Z | 18,887 | 11,506 | 885 | 31,278 | -| [v2.10.16](https://github.com/laurent22/joplin/releases/tag/v2.10.16) | 2023-04-27T09:27:45Z | 9,130 | 4,255 | 779 | 14,164 | +| [v2.11.3](https://github.com/laurent22/joplin/releases/tag/v2.11.3) (p) | 2023-05-16T09:09:57Z | 132 | 38 | 38 | 208 | +| [v2.10.18](https://github.com/laurent22/joplin/releases/tag/v2.10.18) | 2023-05-09T13:27:43Z | 56,244 | 24,253 | 6,782 | 87,279 | +| [v2.10.17](https://github.com/laurent22/joplin/releases/tag/v2.10.17) | 2023-05-08T17:27:28Z | 18,962 | 11,506 | 885 | 31,353 | +| [v2.10.16](https://github.com/laurent22/joplin/releases/tag/v2.10.16) | 2023-04-27T09:27:45Z | 9,205 | 4,255 | 779 | 14,239 | | [v2.10.15](https://github.com/laurent22/joplin/releases/tag/v2.10.15) (p) | 2023-04-26T22:02:16Z | 370 | 139 | 56 | 565 | -| [v2.10.13](https://github.com/laurent22/joplin/releases/tag/v2.10.13) (p) | 2023-04-03T16:53:46Z | 4,438 | 829 | 1,078 | 6,345 | -| [v2.10.12](https://github.com/laurent22/joplin/releases/tag/v2.10.12) (p) | 2023-03-23T12:17:13Z | 3,412 | 518 | 604 | 4,534 | -| [v2.10.11](https://github.com/laurent22/joplin/releases/tag/v2.10.11) (p) | 2023-03-17T10:54:02Z | 2,776 | 383 | 392 | 3,551 | -| [v2.10.10](https://github.com/laurent22/joplin/releases/tag/v2.10.10) (p) | 2023-03-13T23:16:37Z | 2,286 | 283 | 255 | 2,824 | -| [v2.10.9](https://github.com/laurent22/joplin/releases/tag/v2.10.9) (p) | 2023-03-12T16:16:45Z | 1,818 | 214 | 297 | 2,329 | -| [v2.10.8](https://github.com/laurent22/joplin/releases/tag/v2.10.8) (p) | 2023-02-26T12:53:55Z | 4,296 | 573 | 872 | 5,741 | -| [v2.10.7](https://github.com/laurent22/joplin/releases/tag/v2.10.7) (p) | 2023-02-24T10:56:20Z | 1,963 | 191 | 279 | 2,433 | -| [v2.10.6](https://github.com/laurent22/joplin/releases/tag/v2.10.6) (p) | 2023-02-20T14:00:05Z | 2,762 | 342 | 290 | 3,394 | -| [v2.10.5](https://github.com/laurent22/joplin/releases/tag/v2.10.5) | 2023-01-16T15:00:53Z | 365 | 101 | 307 | 773 | -| [v2.10.4](https://github.com/laurent22/joplin/releases/tag/v2.10.4) (p) | 2023-01-05T13:09:20Z | 7,980 | 1,303 | 1,812 | 11,095 | -| [v2.10.3](https://github.com/laurent22/joplin/releases/tag/v2.10.3) (p) | 2022-12-31T15:53:23Z | 2,549 | 313 | 412 | 3,274 | -| [v2.10.2](https://github.com/laurent22/joplin/releases/tag/v2.10.2) (p) | 2022-12-18T18:05:08Z | 3,984 | 589 | 635 | 5,208 | -| [v2.9.17](https://github.com/laurent22/joplin/releases/tag/v2.9.17) | 2022-11-15T10:28:37Z | 335,188 | 108,776 | 83,340 | 527,304 | -| [v2.9.12](https://github.com/laurent22/joplin/releases/tag/v2.9.12) (p) | 2022-11-01T17:06:05Z | 11,163 | 612 | 541 | 12,316 | -| [v2.9.11](https://github.com/laurent22/joplin/releases/tag/v2.9.11) (p) | 2022-10-23T16:09:58Z | 3,313 | 530 | 756 | 4,599 | -| [v2.9.4](https://github.com/laurent22/joplin/releases/tag/v2.9.4) (p) | 2022-08-18T16:52:26Z | 8,356 | 1,868 | 2,194 | 12,418 | -| [v2.9.3](https://github.com/laurent22/joplin/releases/tag/v2.9.3) (p) | 2022-08-18T13:11:09Z | 363 | 92 | 270 | 725 | +| [v2.10.13](https://github.com/laurent22/joplin/releases/tag/v2.10.13) (p) | 2023-04-03T16:53:46Z | 4,483 | 829 | 1,078 | 6,390 | +| [v2.10.12](https://github.com/laurent22/joplin/releases/tag/v2.10.12) (p) | 2023-03-23T12:17:13Z | 3,455 | 518 | 604 | 4,577 | +| [v2.10.11](https://github.com/laurent22/joplin/releases/tag/v2.10.11) (p) | 2023-03-17T10:54:02Z | 2,821 | 383 | 392 | 3,596 | +| [v2.10.10](https://github.com/laurent22/joplin/releases/tag/v2.10.10) (p) | 2023-03-13T23:16:37Z | 2,332 | 283 | 255 | 2,870 | +| [v2.10.9](https://github.com/laurent22/joplin/releases/tag/v2.10.9) (p) | 2023-03-12T16:16:45Z | 1,861 | 214 | 297 | 2,372 | +| [v2.10.8](https://github.com/laurent22/joplin/releases/tag/v2.10.8) (p) | 2023-02-26T12:53:55Z | 4,342 | 573 | 872 | 5,787 | +| [v2.10.7](https://github.com/laurent22/joplin/releases/tag/v2.10.7) (p) | 2023-02-24T10:56:20Z | 2,008 | 191 | 279 | 2,478 | +| [v2.10.6](https://github.com/laurent22/joplin/releases/tag/v2.10.6) (p) | 2023-02-20T14:00:05Z | 2,811 | 342 | 290 | 3,443 | +| [v2.10.5](https://github.com/laurent22/joplin/releases/tag/v2.10.5) | 2023-01-16T15:00:53Z | 365 | 102 | 307 | 774 | +| [v2.10.4](https://github.com/laurent22/joplin/releases/tag/v2.10.4) (p) | 2023-01-05T13:09:20Z | 8,025 | 1,303 | 1,812 | 11,140 | +| [v2.10.3](https://github.com/laurent22/joplin/releases/tag/v2.10.3) (p) | 2022-12-31T15:53:23Z | 2,596 | 313 | 413 | 3,322 | +| [v2.10.2](https://github.com/laurent22/joplin/releases/tag/v2.10.2) (p) | 2022-12-18T18:05:08Z | 4,029 | 589 | 635 | 5,253 | +| [v2.9.17](https://github.com/laurent22/joplin/releases/tag/v2.9.17) | 2022-11-15T10:28:37Z | 335,331 | 108,783 | 83,349 | 527,463 | +| [v2.9.12](https://github.com/laurent22/joplin/releases/tag/v2.9.12) (p) | 2022-11-01T17:06:05Z | 11,212 | 612 | 541 | 12,365 | +| [v2.9.11](https://github.com/laurent22/joplin/releases/tag/v2.9.11) (p) | 2022-10-23T16:09:58Z | 3,357 | 530 | 757 | 4,644 | +| [v2.9.4](https://github.com/laurent22/joplin/releases/tag/v2.9.4) (p) | 2022-08-18T16:52:26Z | 8,400 | 1,868 | 2,195 | 12,463 | +| [v2.9.3](https://github.com/laurent22/joplin/releases/tag/v2.9.3) (p) | 2022-08-18T13:11:09Z | 363 | 92 | 272 | 727 | | [v2.9.2](https://github.com/laurent22/joplin/releases/tag/v2.9.2) (p) | 2022-08-12T18:12:12Z | 1,533 | 447 | 0 | 1,980 | -| [v2.9.1](https://github.com/laurent22/joplin/releases/tag/v2.9.1) (p) | 2022-07-11T09:59:32Z | 7,797 | 1,343 | 1,405 | 10,545 | -| [v2.8.8](https://github.com/laurent22/joplin/releases/tag/v2.8.8) | 2022-05-17T14:48:06Z | 351,304 | 114,355 | 113,564 | 579,223 | -| [v2.8.7](https://github.com/laurent22/joplin/releases/tag/v2.8.7) (p) | 2022-05-06T11:34:27Z | 4,301 | 366 | 423 | 5,090 | -| [v2.8.6](https://github.com/laurent22/joplin/releases/tag/v2.8.6) (p) | 2022-05-03T10:08:25Z | 3,929 | 403 | 329 | 4,661 | -| [v2.8.5](https://github.com/laurent22/joplin/releases/tag/v2.8.5) (p) | 2022-04-27T13:51:50Z | 4,018 | 370 | 352 | 4,740 | -| [v2.8.4](https://github.com/laurent22/joplin/releases/tag/v2.8.4) (p) | 2022-04-19T18:00:09Z | 4,507 | 590 | 328 | 5,425 | -| [v2.8.2](https://github.com/laurent22/joplin/releases/tag/v2.8.2) (p) | 2022-04-14T11:35:45Z | 3,907 | 280 | 267 | 4,454 | -| [v2.7.15](https://github.com/laurent22/joplin/releases/tag/v2.7.15) | 2022-03-17T13:03:23Z | 156,153 | 56,777 | 51,265 | 264,195 | -| [v2.7.14](https://github.com/laurent22/joplin/releases/tag/v2.7.14) | 2022-02-27T11:30:53Z | 34,476 | 16,783 | 4,803 | 56,062 | -| [v2.7.13](https://github.com/laurent22/joplin/releases/tag/v2.7.13) | 2022-02-24T17:42:12Z | 54,850 | 25,725 | 11,713 | 92,288 | -| [v2.7.12](https://github.com/laurent22/joplin/releases/tag/v2.7.12) (p) | 2022-02-14T15:06:14Z | 4,697 | 465 | 483 | 5,645 | -| [v2.7.11](https://github.com/laurent22/joplin/releases/tag/v2.7.11) (p) | 2022-02-12T13:00:02Z | 3,837 | 195 | 169 | 4,201 | -| [v2.7.10](https://github.com/laurent22/joplin/releases/tag/v2.7.10) (p) | 2022-02-11T18:19:09Z | 3,345 | 126 | 83 | 3,554 | -| [v2.7.8](https://github.com/laurent22/joplin/releases/tag/v2.7.8) (p) | 2022-01-19T09:35:27Z | 5,570 | 771 | 825 | 7,166 | -| [v2.7.7](https://github.com/laurent22/joplin/releases/tag/v2.7.7) (p) | 2022-01-18T14:05:07Z | 3,668 | 157 | 136 | 3,961 | -| [v2.7.6](https://github.com/laurent22/joplin/releases/tag/v2.7.6) (p) | 2022-01-17T17:08:28Z | 3,590 | 183 | 115 | 3,888 | -| [v2.6.10](https://github.com/laurent22/joplin/releases/tag/v2.6.10) | 2021-12-19T11:31:16Z | 136,105 | 51,199 | 49,311 | 236,615 | -| [v2.6.9](https://github.com/laurent22/joplin/releases/tag/v2.6.9) | 2021-12-17T11:57:32Z | 19,116 | 9,498 | 3,187 | 31,801 | -| [v2.6.7](https://github.com/laurent22/joplin/releases/tag/v2.6.7) (p) | 2021-12-16T10:47:23Z | 3,811 | 180 | 104 | 4,095 | -| [v2.6.6](https://github.com/laurent22/joplin/releases/tag/v2.6.6) (p) | 2021-12-13T12:31:43Z | 3,803 | 257 | 167 | 4,227 | -| [v2.6.5](https://github.com/laurent22/joplin/releases/tag/v2.6.5) (p) | 2021-12-13T10:07:04Z | 3,138 | 51 | 31 | 3,220 | -| [v2.6.4](https://github.com/laurent22/joplin/releases/tag/v2.6.4) (p) | 2021-12-09T19:53:43Z | 3,882 | 291 | 202 | 4,375 | -| [v2.6.2](https://github.com/laurent22/joplin/releases/tag/v2.6.2) (p) | 2021-11-18T12:19:12Z | 5,672 | 793 | 702 | 7,167 | -| [v2.5.12](https://github.com/laurent22/joplin/releases/tag/v2.5.12) | 2021-11-08T11:07:11Z | 82,848 | 32,504 | 25,233 | 140,585 | -| [v2.5.10](https://github.com/laurent22/joplin/releases/tag/v2.5.10) | 2021-11-01T08:22:42Z | 47,059 | 19,049 | 10,096 | 76,204 | -| [v2.5.8](https://github.com/laurent22/joplin/releases/tag/v2.5.8) | 2021-10-31T11:38:03Z | 15,791 | 6,579 | 2,325 | 24,695 | -| [v2.5.7](https://github.com/laurent22/joplin/releases/tag/v2.5.7) (p) | 2021-10-29T14:47:33Z | 3,409 | 203 | 164 | 3,776 | -| [v2.5.6](https://github.com/laurent22/joplin/releases/tag/v2.5.6) (p) | 2021-10-28T22:03:09Z | 3,463 | 177 | 107 | 3,747 | -| [v2.5.4](https://github.com/laurent22/joplin/releases/tag/v2.5.4) (p) | 2021-10-19T10:10:54Z | 4,960 | 568 | 580 | 6,108 | -| [v2.4.12](https://github.com/laurent22/joplin/releases/tag/v2.4.12) | 2021-10-13T17:24:34Z | 47,473 | 19,980 | 9,786 | 77,239 | -| [v2.5.1](https://github.com/laurent22/joplin/releases/tag/v2.5.1) (p) | 2021-10-02T09:51:58Z | 5,997 | 907 | 947 | 7,851 | -| [v2.4.9](https://github.com/laurent22/joplin/releases/tag/v2.4.9) | 2021-09-29T19:08:58Z | 59,195 | 23,260 | 15,913 | 98,368 | -| [v2.4.8](https://github.com/laurent22/joplin/releases/tag/v2.4.8) (p) | 2021-09-22T19:01:46Z | 9,810 | 1,774 | 535 | 12,119 | -| [v2.4.7](https://github.com/laurent22/joplin/releases/tag/v2.4.7) (p) | 2021-09-19T12:53:22Z | 3,930 | 259 | 210 | 4,399 | -| [v2.4.6](https://github.com/laurent22/joplin/releases/tag/v2.4.6) (p) | 2021-09-09T18:57:17Z | 4,696 | 460 | 520 | 5,676 | -| [v2.4.5](https://github.com/laurent22/joplin/releases/tag/v2.4.5) (p) | 2021-09-06T18:03:28Z | 3,938 | 275 | 225 | 4,438 | -| [v2.4.4](https://github.com/laurent22/joplin/releases/tag/v2.4.4) (p) | 2021-08-30T16:02:51Z | 4,146 | 380 | 371 | 4,897 | -| [v2.4.3](https://github.com/laurent22/joplin/releases/tag/v2.4.3) (p) | 2021-08-28T15:27:32Z | 3,644 | 207 | 180 | 4,031 | -| [v2.4.2](https://github.com/laurent22/joplin/releases/tag/v2.4.2) (p) | 2021-08-27T17:13:21Z | 3,409 | 151 | 91 | 3,651 | -| [v2.4.1](https://github.com/laurent22/joplin/releases/tag/v2.4.1) (p) | 2021-08-21T11:52:30Z | 4,255 | 372 | 337 | 4,964 | -| [v2.3.5](https://github.com/laurent22/joplin/releases/tag/v2.3.5) | 2021-08-17T06:43:30Z | 85,158 | 31,436 | 33,142 | 149,736 | -| [v2.3.3](https://github.com/laurent22/joplin/releases/tag/v2.3.3) | 2021-08-14T09:19:40Z | 18,370 | 6,885 | 4,062 | 29,317 | -| [v2.2.7](https://github.com/laurent22/joplin/releases/tag/v2.2.7) | 2021-08-11T11:03:26Z | 18,246 | 7,524 | 2,607 | 28,377 | -| [v2.2.6](https://github.com/laurent22/joplin/releases/tag/v2.2.6) (p) | 2021-08-09T19:29:20Z | 10,670 | 4,619 | 958 | 16,247 | -| [v2.2.5](https://github.com/laurent22/joplin/releases/tag/v2.2.5) (p) | 2021-08-07T10:35:24Z | 3,986 | 278 | 208 | 4,472 | -| [v2.2.4](https://github.com/laurent22/joplin/releases/tag/v2.2.4) (p) | 2021-08-05T16:42:48Z | 3,650 | 208 | 133 | 3,991 | -| [v2.2.2](https://github.com/laurent22/joplin/releases/tag/v2.2.2) (p) | 2021-07-19T10:28:35Z | 5,559 | 737 | 648 | 6,944 | -| [v2.1.9](https://github.com/laurent22/joplin/releases/tag/v2.1.9) | 2021-07-19T10:28:43Z | 49,857 | 18,959 | 16,816 | 85,632 | -| [v2.2.1](https://github.com/laurent22/joplin/releases/tag/v2.2.1) (p) | 2021-07-09T17:38:25Z | 5,188 | 417 | 394 | 5,999 | -| [v2.1.8](https://github.com/laurent22/joplin/releases/tag/v2.1.8) | 2021-07-03T08:25:16Z | 33,448 | 12,205 | 12,736 | 58,389 | -| [v2.1.7](https://github.com/laurent22/joplin/releases/tag/v2.1.7) | 2021-06-26T19:48:55Z | 16,754 | 6,410 | 3,636 | 26,800 | -| [v2.1.5](https://github.com/laurent22/joplin/releases/tag/v2.1.5) (p) | 2021-06-23T15:08:52Z | 4,086 | 254 | 202 | 4,542 | -| [v2.1.3](https://github.com/laurent22/joplin/releases/tag/v2.1.3) (p) | 2021-06-19T16:32:51Z | 4,154 | 312 | 217 | 4,683 | -| [v2.0.11](https://github.com/laurent22/joplin/releases/tag/v2.0.11) | 2021-06-16T17:55:49Z | 26,458 | 9,279 | 9,903 | 45,640 | -| [v2.0.10](https://github.com/laurent22/joplin/releases/tag/v2.0.10) | 2021-06-16T07:58:29Z | 5,682 | 945 | 399 | 7,026 | -| [v2.0.9](https://github.com/laurent22/joplin/releases/tag/v2.0.9) (p) | 2021-06-12T09:30:30Z | 4,080 | 306 | 899 | 5,285 | -| [v2.0.8](https://github.com/laurent22/joplin/releases/tag/v2.0.8) (p) | 2021-06-10T16:15:08Z | 3,578 | 246 | 598 | 4,422 | -| [v2.0.4](https://github.com/laurent22/joplin/releases/tag/v2.0.4) (p) | 2021-06-02T12:54:17Z | 1,642 | 404 | 392 | 2,438 | -| [v2.0.2](https://github.com/laurent22/joplin/releases/tag/v2.0.2) (p) | 2021-05-21T18:07:48Z | 5,667 | 503 | 1,681 | 7,851 | +| [v2.9.1](https://github.com/laurent22/joplin/releases/tag/v2.9.1) (p) | 2022-07-11T09:59:32Z | 7,842 | 1,343 | 1,406 | 10,591 | +| [v2.8.8](https://github.com/laurent22/joplin/releases/tag/v2.8.8) | 2022-05-17T14:48:06Z | 351,445 | 114,366 | 113,573 | 579,384 | +| [v2.8.7](https://github.com/laurent22/joplin/releases/tag/v2.8.7) (p) | 2022-05-06T11:34:27Z | 4,347 | 366 | 425 | 5,138 | +| [v2.8.6](https://github.com/laurent22/joplin/releases/tag/v2.8.6) (p) | 2022-05-03T10:08:25Z | 3,975 | 403 | 329 | 4,707 | +| [v2.8.5](https://github.com/laurent22/joplin/releases/tag/v2.8.5) (p) | 2022-04-27T13:51:50Z | 4,063 | 370 | 353 | 4,786 | +| [v2.8.4](https://github.com/laurent22/joplin/releases/tag/v2.8.4) (p) | 2022-04-19T18:00:09Z | 4,552 | 590 | 329 | 5,471 | +| [v2.8.2](https://github.com/laurent22/joplin/releases/tag/v2.8.2) (p) | 2022-04-14T11:35:45Z | 3,955 | 280 | 267 | 4,502 | +| [v2.7.15](https://github.com/laurent22/joplin/releases/tag/v2.7.15) | 2022-03-17T13:03:23Z | 156,218 | 56,778 | 51,273 | 264,269 | +| [v2.7.14](https://github.com/laurent22/joplin/releases/tag/v2.7.14) | 2022-02-27T11:30:53Z | 34,527 | 16,783 | 4,804 | 56,114 | +| [v2.7.13](https://github.com/laurent22/joplin/releases/tag/v2.7.13) | 2022-02-24T17:42:12Z | 54,908 | 25,726 | 11,714 | 92,348 | +| [v2.7.12](https://github.com/laurent22/joplin/releases/tag/v2.7.12) (p) | 2022-02-14T15:06:14Z | 4,742 | 465 | 485 | 5,692 | +| [v2.7.11](https://github.com/laurent22/joplin/releases/tag/v2.7.11) (p) | 2022-02-12T13:00:02Z | 3,882 | 195 | 170 | 4,247 | +| [v2.7.10](https://github.com/laurent22/joplin/releases/tag/v2.7.10) (p) | 2022-02-11T18:19:09Z | 3,389 | 126 | 84 | 3,599 | +| [v2.7.8](https://github.com/laurent22/joplin/releases/tag/v2.7.8) (p) | 2022-01-19T09:35:27Z | 5,616 | 771 | 826 | 7,213 | +| [v2.7.7](https://github.com/laurent22/joplin/releases/tag/v2.7.7) (p) | 2022-01-18T14:05:07Z | 3,714 | 157 | 137 | 4,008 | +| [v2.7.6](https://github.com/laurent22/joplin/releases/tag/v2.7.6) (p) | 2022-01-17T17:08:28Z | 3,635 | 183 | 116 | 3,934 | +| [v2.6.10](https://github.com/laurent22/joplin/releases/tag/v2.6.10) | 2021-12-19T11:31:16Z | 136,200 | 51,202 | 49,313 | 236,715 | +| [v2.6.9](https://github.com/laurent22/joplin/releases/tag/v2.6.9) | 2021-12-17T11:57:32Z | 19,192 | 9,498 | 3,188 | 31,878 | +| [v2.6.7](https://github.com/laurent22/joplin/releases/tag/v2.6.7) (p) | 2021-12-16T10:47:23Z | 3,856 | 180 | 105 | 4,141 | +| [v2.6.6](https://github.com/laurent22/joplin/releases/tag/v2.6.6) (p) | 2021-12-13T12:31:43Z | 3,849 | 257 | 168 | 4,274 | +| [v2.6.5](https://github.com/laurent22/joplin/releases/tag/v2.6.5) (p) | 2021-12-13T10:07:04Z | 3,182 | 51 | 32 | 3,265 | +| [v2.6.4](https://github.com/laurent22/joplin/releases/tag/v2.6.4) (p) | 2021-12-09T19:53:43Z | 3,928 | 291 | 203 | 4,422 | +| [v2.6.2](https://github.com/laurent22/joplin/releases/tag/v2.6.2) (p) | 2021-11-18T12:19:12Z | 5,720 | 793 | 702 | 7,215 | +| [v2.5.12](https://github.com/laurent22/joplin/releases/tag/v2.5.12) | 2021-11-08T11:07:11Z | 82,923 | 32,507 | 25,234 | 140,664 | +| [v2.5.10](https://github.com/laurent22/joplin/releases/tag/v2.5.10) | 2021-11-01T08:22:42Z | 47,120 | 19,049 | 10,097 | 76,266 | +| [v2.5.8](https://github.com/laurent22/joplin/releases/tag/v2.5.8) | 2021-10-31T11:38:03Z | 15,857 | 6,581 | 2,325 | 24,763 | +| [v2.5.7](https://github.com/laurent22/joplin/releases/tag/v2.5.7) (p) | 2021-10-29T14:47:33Z | 3,453 | 203 | 164 | 3,820 | +| [v2.5.6](https://github.com/laurent22/joplin/releases/tag/v2.5.6) (p) | 2021-10-28T22:03:09Z | 3,507 | 177 | 107 | 3,791 | +| [v2.5.4](https://github.com/laurent22/joplin/releases/tag/v2.5.4) (p) | 2021-10-19T10:10:54Z | 5,007 | 568 | 580 | 6,155 | +| [v2.4.12](https://github.com/laurent22/joplin/releases/tag/v2.4.12) | 2021-10-13T17:24:34Z | 47,543 | 19,982 | 9,788 | 77,313 | +| [v2.5.1](https://github.com/laurent22/joplin/releases/tag/v2.5.1) (p) | 2021-10-02T09:51:58Z | 6,044 | 907 | 947 | 7,898 | +| [v2.4.9](https://github.com/laurent22/joplin/releases/tag/v2.4.9) | 2021-09-29T19:08:58Z | 59,258 | 23,261 | 15,914 | 98,433 | +| [v2.4.8](https://github.com/laurent22/joplin/releases/tag/v2.4.8) (p) | 2021-09-22T19:01:46Z | 9,854 | 1,774 | 535 | 12,163 | +| [v2.4.7](https://github.com/laurent22/joplin/releases/tag/v2.4.7) (p) | 2021-09-19T12:53:22Z | 3,973 | 259 | 210 | 4,442 | +| [v2.4.6](https://github.com/laurent22/joplin/releases/tag/v2.4.6) (p) | 2021-09-09T18:57:17Z | 4,742 | 460 | 520 | 5,722 | +| [v2.4.5](https://github.com/laurent22/joplin/releases/tag/v2.4.5) (p) | 2021-09-06T18:03:28Z | 3,982 | 275 | 225 | 4,482 | +| [v2.4.4](https://github.com/laurent22/joplin/releases/tag/v2.4.4) (p) | 2021-08-30T16:02:51Z | 4,192 | 380 | 371 | 4,943 | +| [v2.4.3](https://github.com/laurent22/joplin/releases/tag/v2.4.3) (p) | 2021-08-28T15:27:32Z | 3,688 | 207 | 180 | 4,075 | +| [v2.4.2](https://github.com/laurent22/joplin/releases/tag/v2.4.2) (p) | 2021-08-27T17:13:21Z | 3,455 | 151 | 91 | 3,697 | +| [v2.4.1](https://github.com/laurent22/joplin/releases/tag/v2.4.1) (p) | 2021-08-21T11:52:30Z | 4,299 | 372 | 337 | 5,008 | +| [v2.3.5](https://github.com/laurent22/joplin/releases/tag/v2.3.5) | 2021-08-17T06:43:30Z | 85,238 | 31,437 | 33,142 | 149,817 | +| [v2.3.3](https://github.com/laurent22/joplin/releases/tag/v2.3.3) | 2021-08-14T09:19:40Z | 18,441 | 6,886 | 4,062 | 29,389 | +| [v2.2.7](https://github.com/laurent22/joplin/releases/tag/v2.2.7) | 2021-08-11T11:03:26Z | 18,318 | 7,524 | 2,607 | 28,449 | +| [v2.2.6](https://github.com/laurent22/joplin/releases/tag/v2.2.6) (p) | 2021-08-09T19:29:20Z | 10,716 | 4,619 | 958 | 16,293 | +| [v2.2.5](https://github.com/laurent22/joplin/releases/tag/v2.2.5) (p) | 2021-08-07T10:35:24Z | 4,031 | 278 | 208 | 4,517 | +| [v2.2.4](https://github.com/laurent22/joplin/releases/tag/v2.2.4) (p) | 2021-08-05T16:42:48Z | 3,696 | 208 | 133 | 4,037 | +| [v2.2.2](https://github.com/laurent22/joplin/releases/tag/v2.2.2) (p) | 2021-07-19T10:28:35Z | 5,605 | 737 | 648 | 6,990 | +| [v2.1.9](https://github.com/laurent22/joplin/releases/tag/v2.1.9) | 2021-07-19T10:28:43Z | 49,937 | 18,959 | 16,817 | 85,713 | +| [v2.2.1](https://github.com/laurent22/joplin/releases/tag/v2.2.1) (p) | 2021-07-09T17:38:25Z | 5,237 | 417 | 394 | 6,048 | +| [v2.1.8](https://github.com/laurent22/joplin/releases/tag/v2.1.8) | 2021-07-03T08:25:16Z | 33,498 | 12,205 | 12,736 | 58,439 | +| [v2.1.7](https://github.com/laurent22/joplin/releases/tag/v2.1.7) | 2021-06-26T19:48:55Z | 16,801 | 6,410 | 3,636 | 26,847 | +| [v2.1.5](https://github.com/laurent22/joplin/releases/tag/v2.1.5) (p) | 2021-06-23T15:08:52Z | 4,131 | 254 | 202 | 4,587 | +| [v2.1.3](https://github.com/laurent22/joplin/releases/tag/v2.1.3) (p) | 2021-06-19T16:32:51Z | 4,199 | 312 | 217 | 4,728 | +| [v2.0.11](https://github.com/laurent22/joplin/releases/tag/v2.0.11) | 2021-06-16T17:55:49Z | 26,520 | 9,280 | 9,904 | 45,704 | +| [v2.0.10](https://github.com/laurent22/joplin/releases/tag/v2.0.10) | 2021-06-16T07:58:29Z | 5,732 | 946 | 399 | 7,077 | +| [v2.0.9](https://github.com/laurent22/joplin/releases/tag/v2.0.9) (p) | 2021-06-12T09:30:30Z | 4,140 | 306 | 899 | 5,345 | +| [v2.0.8](https://github.com/laurent22/joplin/releases/tag/v2.0.8) (p) | 2021-06-10T16:15:08Z | 3,624 | 246 | 598 | 4,468 | +| [v2.0.4](https://github.com/laurent22/joplin/releases/tag/v2.0.4) (p) | 2021-06-02T12:54:17Z | 1,642 | 404 | 393 | 2,439 | +| [v2.0.2](https://github.com/laurent22/joplin/releases/tag/v2.0.2) (p) | 2021-05-21T18:07:48Z | 5,717 | 503 | 1,681 | 7,901 | | [v2.0.1](https://github.com/laurent22/joplin/releases/tag/v2.0.1) (p) | 2021-05-15T13:22:58Z | 948 | 287 | 1,039 | 2,274 | -| [v1.8.5](https://github.com/laurent22/joplin/releases/tag/v1.8.5) | 2021-05-10T11:58:14Z | 41,530 | 16,302 | 19,436 | 77,268 | -| [v1.8.4](https://github.com/laurent22/joplin/releases/tag/v1.8.4) (p) | 2021-05-09T18:05:05Z | 3,514 | 152 | 473 | 4,139 | -| [v1.8.3](https://github.com/laurent22/joplin/releases/tag/v1.8.3) (p) | 2021-05-04T10:38:16Z | 4,547 | 320 | 951 | 5,818 | -| [v1.8.2](https://github.com/laurent22/joplin/releases/tag/v1.8.2) (p) | 2021-04-25T10:50:51Z | 4,828 | 451 | 1,300 | 6,579 | -| [v1.8.1](https://github.com/laurent22/joplin/releases/tag/v1.8.1) (p) | 2021-03-29T10:46:41Z | 5,839 | 840 | 2,466 | 9,145 | -| [v1.7.11](https://github.com/laurent22/joplin/releases/tag/v1.7.11) | 2021-02-03T12:50:01Z | 120,782 | 42,980 | 64,450 | 228,212 | -| [v1.7.10](https://github.com/laurent22/joplin/releases/tag/v1.7.10) | 2021-01-30T13:25:29Z | 14,587 | 4,883 | 4,528 | 23,998 | +| [v1.8.5](https://github.com/laurent22/joplin/releases/tag/v1.8.5) | 2021-05-10T11:58:14Z | 41,607 | 16,303 | 19,436 | 77,346 | +| [v1.8.4](https://github.com/laurent22/joplin/releases/tag/v1.8.4) (p) | 2021-05-09T18:05:05Z | 3,560 | 152 | 473 | 4,185 | +| [v1.8.3](https://github.com/laurent22/joplin/releases/tag/v1.8.3) (p) | 2021-05-04T10:38:16Z | 4,593 | 320 | 951 | 5,864 | +| [v1.8.2](https://github.com/laurent22/joplin/releases/tag/v1.8.2) (p) | 2021-04-25T10:50:51Z | 4,874 | 451 | 1,300 | 6,625 | +| [v1.8.1](https://github.com/laurent22/joplin/releases/tag/v1.8.1) (p) | 2021-03-29T10:46:41Z | 5,885 | 840 | 2,466 | 9,191 | +| [v1.7.11](https://github.com/laurent22/joplin/releases/tag/v1.7.11) | 2021-02-03T12:50:01Z | 120,853 | 42,986 | 64,451 | 228,290 | +| [v1.7.10](https://github.com/laurent22/joplin/releases/tag/v1.7.10) | 2021-01-30T13:25:29Z | 14,598 | 4,883 | 4,528 | 24,009 | | [v1.7.9](https://github.com/laurent22/joplin/releases/tag/v1.7.9) (p) | 2021-01-28T09:50:21Z | 531 | 148 | 514 | 1,193 | | [v1.7.6](https://github.com/laurent22/joplin/releases/tag/v1.7.6) (p) | 2021-01-27T10:36:05Z | 346 | 108 | 304 | 758 | | [v1.7.5](https://github.com/laurent22/joplin/releases/tag/v1.7.5) (p) | 2021-01-26T09:53:05Z | 439 | 219 | 468 | 1,126 | | [v1.7.4](https://github.com/laurent22/joplin/releases/tag/v1.7.4) (p) | 2021-01-22T17:58:38Z | 729 | 219 | 641 | 1,589 | -| [v1.6.8](https://github.com/laurent22/joplin/releases/tag/v1.6.8) | 2021-01-20T18:11:34Z | 23,104 | 7,731 | 7,635 | 38,470 | +| [v1.6.8](https://github.com/laurent22/joplin/releases/tag/v1.6.8) | 2021-01-20T18:11:34Z | 23,198 | 7,731 | 7,635 | 38,564 | | [v1.7.3](https://github.com/laurent22/joplin/releases/tag/v1.7.3) (p) | 2021-01-20T11:23:50Z | 383 | 95 | 459 | 937 | -| [v1.6.7](https://github.com/laurent22/joplin/releases/tag/v1.6.7) | 2021-01-11T23:20:33Z | 14,705 | 4,663 | 4,572 | 23,940 | -| [v1.6.6](https://github.com/laurent22/joplin/releases/tag/v1.6.6) | 2021-01-09T16:15:31Z | 12,861 | 3,440 | 4,818 | 21,119 | -| [v1.6.5](https://github.com/laurent22/joplin/releases/tag/v1.6.5) (p) | 2021-01-09T01:24:32Z | 3,791 | 91 | 324 | 4,206 | +| [v1.6.7](https://github.com/laurent22/joplin/releases/tag/v1.6.7) | 2021-01-11T23:20:33Z | 14,774 | 4,669 | 4,572 | 24,015 | +| [v1.6.6](https://github.com/laurent22/joplin/releases/tag/v1.6.6) | 2021-01-09T16:15:31Z | 12,863 | 3,440 | 4,818 | 21,121 | +| [v1.6.5](https://github.com/laurent22/joplin/releases/tag/v1.6.5) (p) | 2021-01-09T01:24:32Z | 3,837 | 91 | 324 | 4,252 | | [v1.6.4](https://github.com/laurent22/joplin/releases/tag/v1.6.4) (p) | 2021-01-07T19:11:32Z | 422 | 93 | 220 | 735 | | [v1.6.2](https://github.com/laurent22/joplin/releases/tag/v1.6.2) (p) | 2021-01-04T22:34:55Z | 704 | 242 | 606 | 1,552 | -| [v1.5.14](https://github.com/laurent22/joplin/releases/tag/v1.5.14) | 2020-12-30T01:48:46Z | 15,208 | 5,233 | 5,551 | 25,992 | +| [v1.5.14](https://github.com/laurent22/joplin/releases/tag/v1.5.14) | 2020-12-30T01:48:46Z | 15,273 | 5,233 | 5,551 | 26,057 | | [v1.6.1](https://github.com/laurent22/joplin/releases/tag/v1.6.1) (p) | 2020-12-29T19:37:45Z | 202 | 53 | 184 | 439 | -| [v1.5.13](https://github.com/laurent22/joplin/releases/tag/v1.5.13) | 2020-12-29T18:29:15Z | 782 | 242 | 228 | 1,252 | -| [v1.5.12](https://github.com/laurent22/joplin/releases/tag/v1.5.12) | 2020-12-28T15:14:08Z | 2,563 | 1,796 | 943 | 5,302 | -| [v1.5.11](https://github.com/laurent22/joplin/releases/tag/v1.5.11) | 2020-12-27T19:54:07Z | 14,357 | 4,660 | 4,308 | 23,325 | +| [v1.5.13](https://github.com/laurent22/joplin/releases/tag/v1.5.13) | 2020-12-29T18:29:15Z | 784 | 242 | 228 | 1,254 | +| [v1.5.12](https://github.com/laurent22/joplin/releases/tag/v1.5.12) | 2020-12-28T15:14:08Z | 2,565 | 1,796 | 943 | 5,304 | +| [v1.5.11](https://github.com/laurent22/joplin/releases/tag/v1.5.11) | 2020-12-27T19:54:07Z | 14,415 | 4,662 | 4,308 | 23,385 | | [v1.5.10](https://github.com/laurent22/joplin/releases/tag/v1.5.10) (p) | 2020-12-26T12:35:36Z | 324 | 124 | 286 | 734 | | [v1.5.9](https://github.com/laurent22/joplin/releases/tag/v1.5.9) (p) | 2020-12-23T18:01:08Z | 358 | 386 | 427 | 1,171 | | [v1.5.8](https://github.com/laurent22/joplin/releases/tag/v1.5.8) (p) | 2020-12-20T09:45:19Z | 594 | 179 | 660 | 1,433 | | [v1.5.7](https://github.com/laurent22/joplin/releases/tag/v1.5.7) (p) | 2020-12-10T12:58:33Z | 920 | 269 | 1,010 | 2,199 | | [v1.5.4](https://github.com/laurent22/joplin/releases/tag/v1.5.4) (p) | 2020-12-05T12:07:49Z | 732 | 182 | 652 | 1,566 | -| [v1.4.19](https://github.com/laurent22/joplin/releases/tag/v1.4.19) | 2020-12-01T11:11:16Z | 29,577 | 13,619 | 11,714 | 54,910 | -| [v1.4.18](https://github.com/laurent22/joplin/releases/tag/v1.4.18) | 2020-11-28T12:21:41Z | 11,750 | 3,910 | 3,162 | 18,822 | -| [v1.4.16](https://github.com/laurent22/joplin/releases/tag/v1.4.16) | 2020-11-27T19:40:16Z | 1,642 | 861 | 621 | 3,124 | -| [v1.4.15](https://github.com/laurent22/joplin/releases/tag/v1.4.15) | 2020-11-27T13:25:43Z | 1,032 | 513 | 296 | 1,841 | -| [v1.4.12](https://github.com/laurent22/joplin/releases/tag/v1.4.12) | 2020-11-23T18:58:07Z | 3,215 | 1,376 | 1,328 | 5,919 | -| [v1.4.11](https://github.com/laurent22/joplin/releases/tag/v1.4.11) (p) | 2020-11-19T23:06:51Z | 4,579 | 191 | 611 | 5,381 | -| [v1.4.10](https://github.com/laurent22/joplin/releases/tag/v1.4.10) (p) | 2020-11-14T09:53:15Z | 693 | 232 | 703 | 1,628 | +| [v1.4.19](https://github.com/laurent22/joplin/releases/tag/v1.4.19) | 2020-12-01T11:11:16Z | 29,637 | 13,623 | 11,714 | 54,974 | +| [v1.4.18](https://github.com/laurent22/joplin/releases/tag/v1.4.18) | 2020-11-28T12:21:41Z | 11,753 | 3,910 | 3,162 | 18,825 | +| [v1.4.16](https://github.com/laurent22/joplin/releases/tag/v1.4.16) | 2020-11-27T19:40:16Z | 1,644 | 861 | 621 | 3,126 | +| [v1.4.15](https://github.com/laurent22/joplin/releases/tag/v1.4.15) | 2020-11-27T13:25:43Z | 1,034 | 513 | 296 | 1,843 | +| [v1.4.12](https://github.com/laurent22/joplin/releases/tag/v1.4.12) | 2020-11-23T18:58:07Z | 3,217 | 1,376 | 1,328 | 5,921 | +| [v1.4.11](https://github.com/laurent22/joplin/releases/tag/v1.4.11) (p) | 2020-11-19T23:06:51Z | 4,626 | 191 | 611 | 5,428 | +| [v1.4.10](https://github.com/laurent22/joplin/releases/tag/v1.4.10) (p) | 2020-11-14T09:53:15Z | 694 | 232 | 703 | 1,629 | | [v1.4.9](https://github.com/laurent22/joplin/releases/tag/v1.4.9) (p) | 2020-11-11T14:23:17Z | 873 | 177 | 420 | 1,470 | | [v1.4.7](https://github.com/laurent22/joplin/releases/tag/v1.4.7) (p) | 2020-11-07T18:23:29Z | 559 | 208 | 534 | 1,301 | -| [v1.3.18](https://github.com/laurent22/joplin/releases/tag/v1.3.18) | 2020-11-06T12:07:02Z | 35,147 | 11,387 | 10,548 | 57,082 | +| [v1.3.18](https://github.com/laurent22/joplin/releases/tag/v1.3.18) | 2020-11-06T12:07:02Z | 35,217 | 11,388 | 10,548 | 57,153 | | [v1.3.17](https://github.com/laurent22/joplin/releases/tag/v1.3.17) (p) | 2020-11-06T11:35:15Z | 86 | 64 | 43 | 193 | | [v1.4.6](https://github.com/laurent22/joplin/releases/tag/v1.4.6) (p) | 2020-11-05T22:44:12Z | 750 | 128 | 70 | 948 | -| [v1.3.15](https://github.com/laurent22/joplin/releases/tag/v1.3.15) | 2020-11-04T12:22:50Z | 2,784 | 1,343 | 871 | 4,998 | +| [v1.3.15](https://github.com/laurent22/joplin/releases/tag/v1.3.15) | 2020-11-04T12:22:50Z | 2,786 | 1,343 | 871 | 5,000 | | [v1.3.11](https://github.com/laurent22/joplin/releases/tag/v1.3.11) (p) | 2020-10-31T13:22:20Z | 740 | 220 | 499 | 1,459 | | [v1.3.10](https://github.com/laurent22/joplin/releases/tag/v1.3.10) (p) | 2020-10-29T13:27:14Z | 413 | 151 | 334 | 898 | | [v1.3.9](https://github.com/laurent22/joplin/releases/tag/v1.3.9) (p) | 2020-10-23T16:04:26Z | 894 | 278 | 652 | 1,824 | @@ -234,113 +235,113 @@ updated: 2025-03-01T02:07:09Z | [v1.3.3](https://github.com/laurent22/joplin/releases/tag/v1.3.3) (p) | 2020-10-17T10:56:57Z | 156 | 81 | 52 | 289 | | [v1.3.2](https://github.com/laurent22/joplin/releases/tag/v1.3.2) (p) | 2020-10-11T20:39:49Z | 709 | 217 | 587 | 1,513 | | [v1.3.1](https://github.com/laurent22/joplin/releases/tag/v1.3.1) (p) | 2020-10-11T15:10:18Z | 121 | 87 | 63 | 271 | -| [v1.2.6](https://github.com/laurent22/joplin/releases/tag/v1.2.6) | 2020-10-09T13:56:59Z | 49,114 | 17,792 | 14,090 | 80,996 | +| [v1.2.6](https://github.com/laurent22/joplin/releases/tag/v1.2.6) | 2020-10-09T13:56:59Z | 49,182 | 17,792 | 14,090 | 81,064 | | [v1.2.4](https://github.com/laurent22/joplin/releases/tag/v1.2.4) (p) | 2020-09-30T07:34:29Z | 860 | 288 | 821 | 1,969 | | [v1.2.3](https://github.com/laurent22/joplin/releases/tag/v1.2.3) (p) | 2020-09-29T15:13:02Z | 258 | 100 | 102 | 460 | | [v1.2.2](https://github.com/laurent22/joplin/releases/tag/v1.2.2) (p) | 2020-09-22T20:31:55Z | 1,155 | 242 | 658 | 2,055 | -| [v1.1.4](https://github.com/laurent22/joplin/releases/tag/v1.1.4) | 2020-09-21T11:20:09Z | 28,226 | 13,552 | 7,784 | 49,562 | +| [v1.1.4](https://github.com/laurent22/joplin/releases/tag/v1.1.4) | 2020-09-21T11:20:09Z | 28,229 | 13,554 | 7,785 | 49,568 | | [v1.1.3](https://github.com/laurent22/joplin/releases/tag/v1.1.3) (p) | 2020-09-17T10:30:37Z | 626 | 189 | 484 | 1,299 | | [v1.1.2](https://github.com/laurent22/joplin/releases/tag/v1.1.2) (p) | 2020-09-15T12:58:38Z | 420 | 152 | 271 | 843 | | [v1.1.1](https://github.com/laurent22/joplin/releases/tag/v1.1.1) (p) | 2020-09-11T23:32:47Z | 597 | 232 | 371 | 1,200 | -| [v1.0.245](https://github.com/laurent22/joplin/releases/tag/v1.0.245) | 2020-09-09T12:56:10Z | 22,942 | 10,064 | 5,676 | 38,682 | -| [v1.0.242](https://github.com/laurent22/joplin/releases/tag/v1.0.242) | 2020-09-04T22:00:34Z | 12,904 | 6,463 | 3,046 | 22,413 | -| [v1.0.241](https://github.com/laurent22/joplin/releases/tag/v1.0.241) | 2020-09-04T18:06:00Z | 26,650 | 5,987 | 5,147 | 37,784 | +| [v1.0.245](https://github.com/laurent22/joplin/releases/tag/v1.0.245) | 2020-09-09T12:56:10Z | 22,949 | 10,065 | 5,676 | 38,690 | +| [v1.0.242](https://github.com/laurent22/joplin/releases/tag/v1.0.242) | 2020-09-04T22:00:34Z | 12,906 | 6,463 | 3,046 | 22,415 | +| [v1.0.241](https://github.com/laurent22/joplin/releases/tag/v1.0.241) | 2020-09-04T18:06:00Z | 26,653 | 5,987 | 5,147 | 37,787 | | [v1.0.239](https://github.com/laurent22/joplin/releases/tag/v1.0.239) (p) | 2020-09-01T21:56:36Z | 988 | 268 | 425 | 1,681 | | [v1.0.237](https://github.com/laurent22/joplin/releases/tag/v1.0.237) (p) | 2020-08-29T15:38:04Z | 637 | 963 | 360 | 1,960 | | [v1.0.236](https://github.com/laurent22/joplin/releases/tag/v1.0.236) (p) | 2020-08-28T09:16:54Z | 360 | 150 | 126 | 636 | | [v1.0.235](https://github.com/laurent22/joplin/releases/tag/v1.0.235) (p) | 2020-08-18T22:08:01Z | 2,063 | 528 | 944 | 3,535 | | [v1.0.234](https://github.com/laurent22/joplin/releases/tag/v1.0.234) (p) | 2020-08-17T23:13:02Z | 696 | 164 | 123 | 983 | -| [v1.0.233](https://github.com/laurent22/joplin/releases/tag/v1.0.233) | 2020-08-01T14:51:15Z | 47,724 | 18,246 | 12,387 | 78,357 | +| [v1.0.233](https://github.com/laurent22/joplin/releases/tag/v1.0.233) | 2020-08-01T14:51:15Z | 47,789 | 18,246 | 12,387 | 78,422 | | [v1.0.232](https://github.com/laurent22/joplin/releases/tag/v1.0.232) (p) | 2020-07-28T22:34:40Z | 703 | 262 | 201 | 1,166 | -| [v1.0.227](https://github.com/laurent22/joplin/releases/tag/v1.0.227) | 2020-07-07T20:44:54Z | 41,753 | 15,324 | 9,672 | 66,749 | -| [v1.0.226](https://github.com/laurent22/joplin/releases/tag/v1.0.226) (p) | 2020-07-04T10:21:26Z | 4,970 | 2,293 | 710 | 7,973 | -| [v1.0.224](https://github.com/laurent22/joplin/releases/tag/v1.0.224) | 2020-06-20T22:26:08Z | 25,289 | 11,049 | 6,031 | 42,369 | +| [v1.0.227](https://github.com/laurent22/joplin/releases/tag/v1.0.227) | 2020-07-07T20:44:54Z | 41,969 | 15,324 | 9,673 | 66,966 | +| [v1.0.226](https://github.com/laurent22/joplin/releases/tag/v1.0.226) (p) | 2020-07-04T10:21:26Z | 4,972 | 2,293 | 710 | 7,975 | +| [v1.0.224](https://github.com/laurent22/joplin/releases/tag/v1.0.224) | 2020-06-20T22:26:08Z | 25,294 | 11,049 | 6,031 | 42,374 | | [v1.0.223](https://github.com/laurent22/joplin/releases/tag/v1.0.223) (p) | 2020-06-20T11:51:27Z | 231 | 152 | 101 | 484 | -| [v1.0.221](https://github.com/laurent22/joplin/releases/tag/v1.0.221) (p) | 2020-06-20T01:44:20Z | 898 | 247 | 235 | 1,380 | -| [v1.0.220](https://github.com/laurent22/joplin/releases/tag/v1.0.220) | 2020-06-13T18:26:22Z | 32,821 | 9,970 | 6,445 | 49,236 | -| [v1.0.218](https://github.com/laurent22/joplin/releases/tag/v1.0.218) | 2020-06-07T10:43:34Z | 14,638 | 7,018 | 3,154 | 24,810 | +| [v1.0.221](https://github.com/laurent22/joplin/releases/tag/v1.0.221) (p) | 2020-06-20T01:44:20Z | 901 | 247 | 235 | 1,383 | +| [v1.0.220](https://github.com/laurent22/joplin/releases/tag/v1.0.220) | 2020-06-13T18:26:22Z | 32,823 | 9,970 | 6,445 | 49,238 | +| [v1.0.218](https://github.com/laurent22/joplin/releases/tag/v1.0.218) | 2020-06-07T10:43:34Z | 14,640 | 7,018 | 3,154 | 24,812 | | [v1.0.217](https://github.com/laurent22/joplin/releases/tag/v1.0.217) (p) | 2020-06-06T15:17:27Z | 280 | 138 | 85 | 503 | -| [v1.0.216](https://github.com/laurent22/joplin/releases/tag/v1.0.216) | 2020-05-24T14:21:01Z | 41,491 | 14,355 | 10,218 | 66,064 | -| [v1.0.214](https://github.com/laurent22/joplin/releases/tag/v1.0.214) (p) | 2020-05-21T17:15:15Z | 7,103 | 3,513 | 789 | 11,405 | +| [v1.0.216](https://github.com/laurent22/joplin/releases/tag/v1.0.216) | 2020-05-24T14:21:01Z | 41,560 | 14,355 | 10,220 | 66,135 | +| [v1.0.214](https://github.com/laurent22/joplin/releases/tag/v1.0.214) (p) | 2020-05-21T17:15:15Z | 7,104 | 3,513 | 789 | 11,406 | | [v1.0.212](https://github.com/laurent22/joplin/releases/tag/v1.0.212) (p) | 2020-05-21T07:48:39Z | 255 | 112 | 72 | 439 | | [v1.0.211](https://github.com/laurent22/joplin/releases/tag/v1.0.211) (p) | 2020-05-20T08:59:16Z | 354 | 174 | 113 | 641 | | [v1.0.209](https://github.com/laurent22/joplin/releases/tag/v1.0.209) (p) | 2020-05-17T18:32:51Z | 1,449 | 894 | 173 | 2,516 | | [v1.0.207](https://github.com/laurent22/joplin/releases/tag/v1.0.207) (p) | 2020-05-10T16:37:35Z | 1,252 | 305 | 1,044 | 2,601 | -| [v1.0.201](https://github.com/laurent22/joplin/releases/tag/v1.0.201) | 2020-04-15T22:55:13Z | 54,404 | 20,100 | 18,214 | 92,718 | -| [v1.0.200](https://github.com/laurent22/joplin/releases/tag/v1.0.200) | 2020-04-12T12:17:46Z | 9,634 | 4,935 | 1,931 | 16,500 | -| [v1.0.199](https://github.com/laurent22/joplin/releases/tag/v1.0.199) | 2020-04-10T18:41:58Z | 19,860 | 5,931 | 3,827 | 29,618 | -| [v1.0.197](https://github.com/laurent22/joplin/releases/tag/v1.0.197) | 2020-03-30T17:21:22Z | 23,478 | 9,870 | 6,599 | 39,947 | -| [v1.0.195](https://github.com/laurent22/joplin/releases/tag/v1.0.195) | 2020-03-22T19:56:12Z | 19,172 | 7,993 | 4,535 | 31,700 | -| [v1.0.194](https://github.com/laurent22/joplin/releases/tag/v1.0.194) (p) | 2020-03-14T00:00:32Z | 1,339 | 1,430 | 543 | 3,312 | -| [v1.0.193](https://github.com/laurent22/joplin/releases/tag/v1.0.193) | 2020-03-08T08:58:53Z | 28,842 | 10,968 | 7,445 | 47,255 | -| [v1.0.192](https://github.com/laurent22/joplin/releases/tag/v1.0.192) (p) | 2020-03-06T23:27:52Z | 559 | 164 | 113 | 836 | +| [v1.0.201](https://github.com/laurent22/joplin/releases/tag/v1.0.201) | 2020-04-15T22:55:13Z | 54,405 | 20,101 | 18,216 | 92,722 | +| [v1.0.200](https://github.com/laurent22/joplin/releases/tag/v1.0.200) | 2020-04-12T12:17:46Z | 9,635 | 4,935 | 1,931 | 16,501 | +| [v1.0.199](https://github.com/laurent22/joplin/releases/tag/v1.0.199) | 2020-04-10T18:41:58Z | 19,864 | 5,931 | 3,827 | 29,622 | +| [v1.0.197](https://github.com/laurent22/joplin/releases/tag/v1.0.197) | 2020-03-30T17:21:22Z | 23,482 | 9,870 | 6,609 | 39,961 | +| [v1.0.195](https://github.com/laurent22/joplin/releases/tag/v1.0.195) | 2020-03-22T19:56:12Z | 19,174 | 7,995 | 4,535 | 31,704 | +| [v1.0.194](https://github.com/laurent22/joplin/releases/tag/v1.0.194) (p) | 2020-03-14T00:00:32Z | 1,339 | 1,431 | 543 | 3,313 | +| [v1.0.193](https://github.com/laurent22/joplin/releases/tag/v1.0.193) | 2020-03-08T08:58:53Z | 28,843 | 10,968 | 7,445 | 47,256 | +| [v1.0.192](https://github.com/laurent22/joplin/releases/tag/v1.0.192) (p) | 2020-03-06T23:27:52Z | 560 | 164 | 113 | 837 | | [v1.0.190](https://github.com/laurent22/joplin/releases/tag/v1.0.190) (p) | 2020-03-06T01:22:22Z | 439 | 133 | 110 | 682 | -| [v1.0.189](https://github.com/laurent22/joplin/releases/tag/v1.0.189) (p) | 2020-03-04T17:27:15Z | 427 | 136 | 121 | 684 | +| [v1.0.189](https://github.com/laurent22/joplin/releases/tag/v1.0.189) (p) | 2020-03-04T17:27:15Z | 428 | 136 | 122 | 686 | | [v1.0.187](https://github.com/laurent22/joplin/releases/tag/v1.0.187) (p) | 2020-03-01T12:31:06Z | 983 | 277 | 298 | 1,558 | -| [v1.0.179](https://github.com/laurent22/joplin/releases/tag/v1.0.179) | 2020-01-24T22:42:41Z | 71,741 | 29,106 | 22,596 | 123,443 | +| [v1.0.179](https://github.com/laurent22/joplin/releases/tag/v1.0.179) | 2020-01-24T22:42:41Z | 71,750 | 29,118 | 22,596 | 123,464 | | [v1.0.178](https://github.com/laurent22/joplin/releases/tag/v1.0.178) | 2020-01-20T19:06:45Z | 17,677 | 6,006 | 2,620 | 26,303 | -| [v1.0.177](https://github.com/laurent22/joplin/releases/tag/v1.0.177) (p) | 2019-12-30T14:40:40Z | 2,011 | 478 | 748 | 3,237 | +| [v1.0.177](https://github.com/laurent22/joplin/releases/tag/v1.0.177) (p) | 2019-12-30T14:40:40Z | 2,013 | 478 | 749 | 3,240 | | [v1.0.176](https://github.com/laurent22/joplin/releases/tag/v1.0.176) (p) | 2019-12-14T10:36:44Z | 3,176 | 2,579 | 496 | 6,251 | -| [v1.0.175](https://github.com/laurent22/joplin/releases/tag/v1.0.175) | 2019-12-08T11:48:47Z | 73,782 | 17,022 | 16,625 | 107,429 | -| [v1.0.174](https://github.com/laurent22/joplin/releases/tag/v1.0.174) | 2019-11-12T18:20:58Z | 30,744 | 11,803 | 8,253 | 50,800 | -| [v1.0.173](https://github.com/laurent22/joplin/releases/tag/v1.0.173) | 2019-11-11T08:33:35Z | 5,152 | 2,122 | 772 | 8,046 | -| [v1.0.170](https://github.com/laurent22/joplin/releases/tag/v1.0.170) | 2019-10-13T22:13:04Z | 27,859 | 8,821 | 7,715 | 44,395 | -| [v1.0.169](https://github.com/laurent22/joplin/releases/tag/v1.0.169) | 2019-09-27T18:35:13Z | 17,279 | 5,971 | 3,784 | 27,034 | +| [v1.0.175](https://github.com/laurent22/joplin/releases/tag/v1.0.175) | 2019-12-08T11:48:47Z | 73,789 | 17,022 | 16,625 | 107,436 | +| [v1.0.174](https://github.com/laurent22/joplin/releases/tag/v1.0.174) | 2019-11-12T18:20:58Z | 30,749 | 11,803 | 8,253 | 50,805 | +| [v1.0.173](https://github.com/laurent22/joplin/releases/tag/v1.0.173) | 2019-11-11T08:33:35Z | 5,154 | 2,123 | 773 | 8,050 | +| [v1.0.170](https://github.com/laurent22/joplin/releases/tag/v1.0.170) | 2019-10-13T22:13:04Z | 27,868 | 8,821 | 7,715 | 44,404 | +| [v1.0.169](https://github.com/laurent22/joplin/releases/tag/v1.0.169) | 2019-09-27T18:35:13Z | 17,282 | 5,971 | 3,784 | 27,037 | | [v1.0.168](https://github.com/laurent22/joplin/releases/tag/v1.0.168) | 2019-09-25T21:21:38Z | 5,394 | 2,316 | 745 | 8,455 | -| [v1.0.167](https://github.com/laurent22/joplin/releases/tag/v1.0.167) | 2019-09-10T08:48:37Z | 17,005 | 5,747 | 3,740 | 26,492 | +| [v1.0.167](https://github.com/laurent22/joplin/releases/tag/v1.0.167) | 2019-09-10T08:48:37Z | 17,011 | 5,747 | 3,740 | 26,498 | | [v1.0.166](https://github.com/laurent22/joplin/releases/tag/v1.0.166) | 2019-09-09T17:35:54Z | 2,006 | 601 | 261 | 2,868 | | [v1.0.165](https://github.com/laurent22/joplin/releases/tag/v1.0.165) | 2019-08-14T21:46:29Z | 19,120 | 7,022 | 5,491 | 31,633 | -| [v1.0.161](https://github.com/laurent22/joplin/releases/tag/v1.0.161) | 2019-07-13T18:30:00Z | 19,446 | 6,391 | 4,161 | 29,998 | -| [v1.0.160](https://github.com/laurent22/joplin/releases/tag/v1.0.160) | 2019-06-15T00:21:40Z | 30,853 | 7,795 | 8,132 | 46,780 | -| [v1.0.159](https://github.com/laurent22/joplin/releases/tag/v1.0.159) | 2019-06-08T00:00:19Z | 5,272 | 2,220 | 1,293 | 8,785 | -| [v1.0.158](https://github.com/laurent22/joplin/releases/tag/v1.0.158) | 2019-05-27T19:01:18Z | 9,890 | 3,588 | 1,961 | 15,439 | +| [v1.0.161](https://github.com/laurent22/joplin/releases/tag/v1.0.161) | 2019-07-13T18:30:00Z | 19,449 | 6,391 | 4,161 | 30,001 | +| [v1.0.160](https://github.com/laurent22/joplin/releases/tag/v1.0.160) | 2019-06-15T00:21:40Z | 30,866 | 7,796 | 8,133 | 46,795 | +| [v1.0.159](https://github.com/laurent22/joplin/releases/tag/v1.0.159) | 2019-06-08T00:00:19Z | 5,272 | 2,220 | 1,297 | 8,789 | +| [v1.0.158](https://github.com/laurent22/joplin/releases/tag/v1.0.158) | 2019-05-27T19:01:18Z | 9,891 | 3,590 | 1,962 | 15,443 | | [v1.0.157](https://github.com/laurent22/joplin/releases/tag/v1.0.157) | 2019-05-26T17:55:53Z | 2,248 | 881 | 314 | 3,443 | | [v1.0.153](https://github.com/laurent22/joplin/releases/tag/v1.0.153) (p) | 2019-05-15T06:27:29Z | 916 | 143 | 131 | 1,190 | -| [v1.0.152](https://github.com/laurent22/joplin/releases/tag/v1.0.152) | 2019-05-13T09:08:07Z | 13,947 | 4,475 | 4,091 | 22,513 | -| [v1.0.151](https://github.com/laurent22/joplin/releases/tag/v1.0.151) | 2019-05-12T15:14:32Z | 2,002 | 574 | 984 | 3,560 | +| [v1.0.152](https://github.com/laurent22/joplin/releases/tag/v1.0.152) | 2019-05-13T09:08:07Z | 13,948 | 4,475 | 4,091 | 22,514 | +| [v1.0.151](https://github.com/laurent22/joplin/releases/tag/v1.0.151) | 2019-05-12T15:14:32Z | 2,002 | 575 | 984 | 3,561 | | [v1.0.150](https://github.com/laurent22/joplin/releases/tag/v1.0.150) | 2019-05-12T11:27:48Z | 496 | 175 | 94 | 765 | | [v1.0.148](https://github.com/laurent22/joplin/releases/tag/v1.0.148) (p) | 2019-05-08T19:12:24Z | 186 | 93 | 120 | 399 | | [v1.0.145](https://github.com/laurent22/joplin/releases/tag/v1.0.145) | 2019-05-03T09:16:53Z | 7,083 | 2,901 | 1,465 | 11,449 | -| [v1.0.143](https://github.com/laurent22/joplin/releases/tag/v1.0.143) | 2019-04-22T10:51:38Z | 11,993 | 3,593 | 2,808 | 18,394 | +| [v1.0.143](https://github.com/laurent22/joplin/releases/tag/v1.0.143) | 2019-04-22T10:51:38Z | 11,994 | 3,593 | 2,808 | 18,395 | | [v1.0.142](https://github.com/laurent22/joplin/releases/tag/v1.0.142) | 2019-04-02T16:44:51Z | 14,863 | 4,607 | 4,757 | 24,227 | -| [v1.0.140](https://github.com/laurent22/joplin/releases/tag/v1.0.140) | 2019-03-10T20:59:58Z | 13,723 | 4,217 | 3,406 | 21,346 | +| [v1.0.140](https://github.com/laurent22/joplin/releases/tag/v1.0.140) | 2019-03-10T20:59:58Z | 13,725 | 4,217 | 3,407 | 21,349 | | [v1.0.139](https://github.com/laurent22/joplin/releases/tag/v1.0.139) (p) | 2019-03-09T10:06:48Z | 186 | 104 | 69 | 359 | -| [v1.0.138](https://github.com/laurent22/joplin/releases/tag/v1.0.138) (p) | 2019-03-03T17:23:00Z | 225 | 128 | 107 | 460 | +| [v1.0.138](https://github.com/laurent22/joplin/releases/tag/v1.0.138) (p) | 2019-03-03T17:23:00Z | 226 | 128 | 107 | 461 | | [v1.0.137](https://github.com/laurent22/joplin/releases/tag/v1.0.137) (p) | 2019-03-03T01:12:51Z | 650 | 95 | 107 | 852 | | [v1.0.135](https://github.com/laurent22/joplin/releases/tag/v1.0.135) | 2019-02-27T23:36:57Z | 12,704 | 3,996 | 4,106 | 20,806 | | [v1.0.134](https://github.com/laurent22/joplin/releases/tag/v1.0.134) | 2019-02-27T10:21:44Z | 1,512 | 610 | 244 | 2,366 | | [v1.0.132](https://github.com/laurent22/joplin/releases/tag/v1.0.132) | 2019-02-26T23:02:05Z | 1,150 | 491 | 119 | 1,760 | -| [v1.0.127](https://github.com/laurent22/joplin/releases/tag/v1.0.127) | 2019-02-14T23:12:48Z | 10,023 | 3,212 | 2,957 | 16,192 | +| [v1.0.127](https://github.com/laurent22/joplin/releases/tag/v1.0.127) | 2019-02-14T23:12:48Z | 10,026 | 3,212 | 2,958 | 16,196 | | [v1.0.126](https://github.com/laurent22/joplin/releases/tag/v1.0.126) (p) | 2019-02-09T19:46:16Z | 1,001 | 115 | 138 | 1,254 | -| [v1.0.125](https://github.com/laurent22/joplin/releases/tag/v1.0.125) | 2019-01-26T18:14:33Z | 10,397 | 3,596 | 1,726 | 15,719 | -| [v1.0.120](https://github.com/laurent22/joplin/releases/tag/v1.0.120) | 2019-01-10T21:42:53Z | 15,705 | 5,251 | 6,544 | 27,500 | -| [v1.0.119](https://github.com/laurent22/joplin/releases/tag/v1.0.119) | 2018-12-18T12:40:22Z | 9,006 | 3,301 | 2,040 | 14,347 | +| [v1.0.125](https://github.com/laurent22/joplin/releases/tag/v1.0.125) | 2019-01-26T18:14:33Z | 10,403 | 3,597 | 1,726 | 15,726 | +| [v1.0.120](https://github.com/laurent22/joplin/releases/tag/v1.0.120) | 2019-01-10T21:42:53Z | 15,706 | 5,252 | 6,546 | 27,504 | +| [v1.0.119](https://github.com/laurent22/joplin/releases/tag/v1.0.119) | 2018-12-18T12:40:22Z | 9,007 | 3,302 | 2,041 | 14,350 | | [v1.0.118](https://github.com/laurent22/joplin/releases/tag/v1.0.118) | 2019-01-11T08:34:13Z | 763 | 288 | 115 | 1,166 | -| [v1.0.117](https://github.com/laurent22/joplin/releases/tag/v1.0.117) | 2018-11-24T12:05:24Z | 16,347 | 4,940 | 6,409 | 27,696 | -| [v1.0.116](https://github.com/laurent22/joplin/releases/tag/v1.0.116) | 2018-11-20T19:09:24Z | 4,069 | 1,165 | 740 | 5,974 | +| [v1.0.117](https://github.com/laurent22/joplin/releases/tag/v1.0.117) | 2018-11-24T12:05:24Z | 16,348 | 4,940 | 6,409 | 27,697 | +| [v1.0.116](https://github.com/laurent22/joplin/releases/tag/v1.0.116) | 2018-11-20T19:09:24Z | 4,069 | 1,167 | 740 | 5,976 | | [v1.0.115](https://github.com/laurent22/joplin/releases/tag/v1.0.115) | 2018-11-16T16:52:02Z | 3,723 | 1,341 | 827 | 5,891 | | [v1.0.114](https://github.com/laurent22/joplin/releases/tag/v1.0.114) | 2018-10-24T20:14:10Z | 11,470 | 3,540 | 3,855 | 18,865 | -| [v1.0.111](https://github.com/laurent22/joplin/releases/tag/v1.0.111) | 2018-09-30T20:15:09Z | 12,504 | 3,531 | 3,707 | 19,742 | +| [v1.0.111](https://github.com/laurent22/joplin/releases/tag/v1.0.111) | 2018-09-30T20:15:09Z | 12,513 | 3,536 | 3,707 | 19,756 | | [v1.0.110](https://github.com/laurent22/joplin/releases/tag/v1.0.110) | 2018-09-29T12:29:21Z | 1,010 | 449 | 142 | 1,601 | | [v1.0.109](https://github.com/laurent22/joplin/releases/tag/v1.0.109) | 2018-09-27T18:01:41Z | 2,146 | 743 | 356 | 3,245 | | [v1.0.108](https://github.com/laurent22/joplin/releases/tag/v1.0.108) (p) | 2018-09-29T18:49:29Z | 66 | 60 | 38 | 164 | | [v1.0.107](https://github.com/laurent22/joplin/releases/tag/v1.0.107) | 2018-09-16T19:51:07Z | 7,209 | 2,175 | 1,734 | 11,118 | | [v1.0.106](https://github.com/laurent22/joplin/releases/tag/v1.0.106) | 2018-09-08T15:23:40Z | 4,601 | 1,495 | 341 | 6,437 | -| [v1.0.105](https://github.com/laurent22/joplin/releases/tag/v1.0.105) | 2018-09-05T11:29:36Z | 4,701 | 1,632 | 1,484 | 7,817 | -| [v1.0.104](https://github.com/laurent22/joplin/releases/tag/v1.0.104) | 2018-06-28T20:25:36Z | 15,186 | 4,739 | 7,409 | 27,334 | +| [v1.0.105](https://github.com/laurent22/joplin/releases/tag/v1.0.105) | 2018-09-05T11:29:36Z | 4,702 | 1,632 | 1,485 | 7,819 | +| [v1.0.104](https://github.com/laurent22/joplin/releases/tag/v1.0.104) | 2018-06-28T20:25:36Z | 15,187 | 4,740 | 7,410 | 27,337 | | [v1.0.103](https://github.com/laurent22/joplin/releases/tag/v1.0.103) | 2018-06-21T19:38:13Z | 2,128 | 926 | 703 | 3,757 | | [v1.0.101](https://github.com/laurent22/joplin/releases/tag/v1.0.101) | 2018-06-17T18:35:11Z | 1,374 | 648 | 434 | 2,456 | | [v1.0.100](https://github.com/laurent22/joplin/releases/tag/v1.0.100) | 2018-06-14T17:41:43Z | 959 | 477 | 272 | 1,708 | -| [v1.0.99](https://github.com/laurent22/joplin/releases/tag/v1.0.99) | 2018-06-10T13:18:23Z | 1,325 | 638 | 408 | 2,371 | +| [v1.0.99](https://github.com/laurent22/joplin/releases/tag/v1.0.99) | 2018-06-10T13:18:23Z | 1,329 | 642 | 408 | 2,379 | | [v1.0.97](https://github.com/laurent22/joplin/releases/tag/v1.0.97) | 2018-06-09T19:23:34Z | 357 | 193 | 86 | 636 | -| [v1.0.96](https://github.com/laurent22/joplin/releases/tag/v1.0.96) | 2018-05-26T16:36:39Z | 2,800 | 1,267 | 1,748 | 5,815 | +| [v1.0.96](https://github.com/laurent22/joplin/releases/tag/v1.0.96) | 2018-05-26T16:36:39Z | 2,800 | 1,267 | 1,749 | 5,816 | | [v1.0.95](https://github.com/laurent22/joplin/releases/tag/v1.0.95) | 2018-05-25T13:04:30Z | 466 | 258 | 163 | 887 | | [v1.0.94](https://github.com/laurent22/joplin/releases/tag/v1.0.94) | 2018-05-21T20:52:59Z | 1,214 | 629 | 444 | 2,287 | -| [v1.0.93](https://github.com/laurent22/joplin/releases/tag/v1.0.93) | 2018-05-14T11:36:01Z | 1,878 | 1,356 | 802 | 4,036 | -| [v1.0.91](https://github.com/laurent22/joplin/releases/tag/v1.0.91) | 2018-05-10T14:48:04Z | 872 | 593 | 364 | 1,829 | -| [v1.0.89](https://github.com/laurent22/joplin/releases/tag/v1.0.89) | 2018-05-09T13:05:05Z | 546 | 284 | 157 | 987 | +| [v1.0.93](https://github.com/laurent22/joplin/releases/tag/v1.0.93) | 2018-05-14T11:36:01Z | 1,878 | 1,357 | 802 | 4,037 | +| [v1.0.91](https://github.com/laurent22/joplin/releases/tag/v1.0.91) | 2018-05-10T14:48:04Z | 872 | 594 | 364 | 1,830 | +| [v1.0.89](https://github.com/laurent22/joplin/releases/tag/v1.0.89) | 2018-05-09T13:05:05Z | 546 | 285 | 157 | 988 | | [v1.0.85](https://github.com/laurent22/joplin/releases/tag/v1.0.85) | 2018-05-01T21:08:24Z | 1,696 | 992 | 677 | 3,365 | -| [v1.0.83](https://github.com/laurent22/joplin/releases/tag/v1.0.83) | 2018-04-04T19:43:58Z | 5,627 | 2,577 | 2,703 | 10,907 | +| [v1.0.83](https://github.com/laurent22/joplin/releases/tag/v1.0.83) | 2018-04-04T19:43:58Z | 5,629 | 2,577 | 2,703 | 10,909 | | [v1.0.82](https://github.com/laurent22/joplin/releases/tag/v1.0.82) | 2018-03-31T19:16:31Z | 751 | 450 | 167 | 1,368 | | [v1.0.81](https://github.com/laurent22/joplin/releases/tag/v1.0.81) | 2018-03-28T08:13:58Z | 1,039 | 637 | 826 | 2,502 | | [v1.0.79](https://github.com/laurent22/joplin/releases/tag/v1.0.79) | 2018-03-23T18:00:11Z | 971 | 580 | 428 | 1,979 | @@ -348,20 +349,20 @@ updated: 2025-03-01T02:07:09Z | [v1.0.77](https://github.com/laurent22/joplin/releases/tag/v1.0.77) | 2018-03-16T15:12:35Z | 202 | 144 | 88 | 434 | | [v1.0.72](https://github.com/laurent22/joplin/releases/tag/v1.0.72) | 2018-03-14T09:44:35Z | 451 | 296 | 98 | 845 | | [v1.0.70](https://github.com/laurent22/joplin/releases/tag/v1.0.70) | 2018-02-28T20:04:30Z | 2,004 | 1,093 | 1,296 | 4,393 | -| [v1.0.67](https://github.com/laurent22/joplin/releases/tag/v1.0.67) | 2018-02-19T22:51:08Z | 1,946 | 645 | 0 | 2,591 | +| [v1.0.67](https://github.com/laurent22/joplin/releases/tag/v1.0.67) | 2018-02-19T22:51:08Z | 1,947 | 645 | 0 | 2,592 | | [v1.0.66](https://github.com/laurent22/joplin/releases/tag/v1.0.66) | 2018-02-18T23:09:09Z | 450 | 174 | 108 | 732 | | [v1.0.65](https://github.com/laurent22/joplin/releases/tag/v1.0.65) | 2018-02-17T20:02:25Z | 349 | 171 | 156 | 676 | | [v1.0.64](https://github.com/laurent22/joplin/releases/tag/v1.0.64) | 2018-02-16T00:58:20Z | 1,195 | 583 | 1,147 | 2,925 | | [v1.0.63](https://github.com/laurent22/joplin/releases/tag/v1.0.63) | 2018-02-14T19:40:36Z | 413 | 200 | 115 | 728 | | [v1.0.62](https://github.com/laurent22/joplin/releases/tag/v1.0.62) | 2018-02-12T20:19:58Z | 714 | 345 | 400 | 1,459 | | [v0.10.61](https://github.com/laurent22/joplin/releases/tag/v0.10.61) | 2018-02-08T18:27:39Z | 1,123 | 678 | 987 | 2,788 | -| [v0.10.60](https://github.com/laurent22/joplin/releases/tag/v0.10.60) | 2018-02-06T13:09:56Z | 770 | 565 | 577 | 1,912 | +| [v0.10.60](https://github.com/laurent22/joplin/releases/tag/v0.10.60) | 2018-02-06T13:09:56Z | 771 | 565 | 577 | 1,913 | | [v0.10.54](https://github.com/laurent22/joplin/releases/tag/v0.10.54) | 2018-01-31T20:21:30Z | 1,959 | 1,503 | 347 | 3,809 | | [v0.10.52](https://github.com/laurent22/joplin/releases/tag/v0.10.52) | 2018-01-31T19:25:18Z | 164 | 677 | 41 | 882 | | [v0.10.51](https://github.com/laurent22/joplin/releases/tag/v0.10.51) | 2018-01-28T18:47:02Z | 1,430 | 1,643 | 352 | 3,425 | | [v0.10.48](https://github.com/laurent22/joplin/releases/tag/v0.10.48) | 2018-01-23T11:19:51Z | 2,112 | 1,795 | 56 | 3,963 | | [v0.10.47](https://github.com/laurent22/joplin/releases/tag/v0.10.47) | 2018-01-16T17:27:17Z | 1,334 | 1,317 | 91 | 2,742 | -| [v0.10.43](https://github.com/laurent22/joplin/releases/tag/v0.10.43) | 2018-01-08T10:12:10Z | 3,486 | 2,401 | 1,237 | 7,124 | +| [v0.10.43](https://github.com/laurent22/joplin/releases/tag/v0.10.43) | 2018-01-08T10:12:10Z | 3,486 | 2,401 | 1,239 | 7,126 | | [v0.10.41](https://github.com/laurent22/joplin/releases/tag/v0.10.41) | 2018-01-05T20:38:12Z | 1,245 | 1,597 | 266 | 3,108 | | [v0.10.40](https://github.com/laurent22/joplin/releases/tag/v0.10.40) | 2018-01-02T23:16:57Z | 1,638 | 1,832 | 362 | 3,832 | | [v0.10.39](https://github.com/laurent22/joplin/releases/tag/v0.10.39) | 2017-12-11T21:19:44Z | 5,995 | 4,443 | 3,324 | 13,762 | @@ -371,13 +372,13 @@ updated: 2025-03-01T02:07:09Z | [v0.10.35](https://github.com/laurent22/joplin/releases/tag/v0.10.35) | 2017-12-02T15:56:08Z | 1,611 | 1,593 | 769 | 3,973 | | [v0.10.34](https://github.com/laurent22/joplin/releases/tag/v0.10.34) | 2017-12-02T14:50:28Z | 117 | 717 | 85 | 919 | | [v0.10.33](https://github.com/laurent22/joplin/releases/tag/v0.10.33) | 2017-12-02T13:20:39Z | 95 | 711 | 51 | 857 | -| [v0.10.31](https://github.com/laurent22/joplin/releases/tag/v0.10.31) | 2017-12-01T09:56:44Z | 918 | 1,499 | 435 | 2,852 | +| [v0.10.31](https://github.com/laurent22/joplin/releases/tag/v0.10.31) | 2017-12-01T09:56:44Z | 918 | 1,499 | 436 | 2,853 | | [v0.10.30](https://github.com/laurent22/joplin/releases/tag/v0.10.30) | 2017-11-30T20:28:16Z | 842 | 1,428 | 452 | 2,722 | | [v0.10.28](https://github.com/laurent22/joplin/releases/tag/v0.10.28) | 2017-11-30T01:07:46Z | 1,491 | 1,761 | 906 | 4,158 | | [v0.10.26](https://github.com/laurent22/joplin/releases/tag/v0.10.26) | 2017-11-29T16:02:17Z | 307 | 756 | 291 | 1,354 | -| [v0.10.25](https://github.com/laurent22/joplin/releases/tag/v0.10.25) | 2017-11-24T14:27:49Z | 259 | 752 | 6,769 | 7,780 | +| [v0.10.25](https://github.com/laurent22/joplin/releases/tag/v0.10.25) | 2017-11-24T14:27:49Z | 259 | 752 | 6,771 | 7,782 | | [v0.10.23](https://github.com/laurent22/joplin/releases/tag/v0.10.23) | 2017-11-21T19:38:41Z | 247 | 714 | 65 | 1,026 | | [v0.10.22](https://github.com/laurent22/joplin/releases/tag/v0.10.22) | 2017-11-20T21:45:57Z | 192 | 700 | 49 | 941 | | [v0.10.21](https://github.com/laurent22/joplin/releases/tag/v0.10.21) | 2017-11-18T00:53:15Z | 170 | 693 | 44 | 907 | | [v0.10.20](https://github.com/laurent22/joplin/releases/tag/v0.10.20) | 2017-11-17T17:18:25Z | 161 | 706 | 56 | 923 | -| [v0.10.19](https://github.com/laurent22/joplin/releases/tag/v0.10.19) | 2017-11-20T18:59:48Z | 180 | 707 | 55 | 942 | \ No newline at end of file +| [v0.10.19](https://github.com/laurent22/joplin/releases/tag/v0.10.19) | 2017-11-20T18:59:48Z | 181 | 707 | 55 | 943 | \ No newline at end of file From 8d6d7ca6d21b32c50f263082ba5d66f3b670352d Mon Sep 17 00:00:00 2001 From: Henrique Santos Date: Wed, 2 Apr 2025 10:22:33 +0100 Subject: [PATCH 122/158] Desktop: Fixes #9291: A note scrolls to top if reached by following a link to a section (#12038) --- packages/app-desktop/gui/note-viewer/index.html | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/app-desktop/gui/note-viewer/index.html b/packages/app-desktop/gui/note-viewer/index.html index 8ef3db3f6a..635fd5083d 100644 --- a/packages/app-desktop/gui/note-viewer/index.html +++ b/packages/app-desktop/gui/note-viewer/index.html @@ -139,11 +139,8 @@ const viewerPercent = scrollmap.translateL2V(percent); const newScrollTop = viewerPercent * maxScrollTop(); - // Even if the scroll position hasn't changed (percent is the same), - // we still ignore the next scroll event, so that it doesn't create - // undesired side effects. - // https://github.com/laurent22/joplin/issues/7617 - ignoreNextScrollEvent(); + // The next scroll event cannot be skipped in order to correctly + // scroll to the target section in a different note when follwing a link if (Math.floor(contentElement.scrollTop) !== Math.floor(newScrollTop)) { percentScroll_ = percent; From 050871bc65c5b33394348dec1aee41b161146213 Mon Sep 17 00:00:00 2001 From: pedr Date: Thu, 3 Apr 2025 05:08:25 -0300 Subject: [PATCH 123/158] Desktop: Resolves #11608: Increase the likelihood of text generation from image recognition (#12028) Co-authored-by: Laurent Cozic --- .../ocr_samples/low_confidence_testing.png | Bin 0 -> 393734 bytes packages/lib/services/ocr/OcrService.test.ts | 24 ++++++++++++++++++ .../ocr/drivers/OcrDriverTesseract.ts | 13 +++++++--- 3 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 packages/app-cli/tests/ocr_samples/low_confidence_testing.png diff --git a/packages/app-cli/tests/ocr_samples/low_confidence_testing.png b/packages/app-cli/tests/ocr_samples/low_confidence_testing.png new file mode 100644 index 0000000000000000000000000000000000000000..97eff62e775288434976b68a6e3dc894de3a13d5 GIT binary patch literal 393734 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

(GU(G4w^bE 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 { // await service.dispose(); // }); + it('should generate text even on cases of lower confidence', async () => { + const { resource } = await createNoteAndResource({ path: `${ocrSampleDir}/low_confidence_testing.png` }); + + const service = newOcrService(); + await service.processResources(); + + const processedResource: ResourceEntity = await Resource.load(resource.id); + expect(processedResource.ocr_text.includes('1.')).toBe(true); + // cSpell:disable + expect(processedResource.ocr_text.includes('eback Mountain (2005)')).toBe(true); + // cSpell:enable + + expect(processedResource.ocr_text.includes('2.')).toBe(true); + expect(processedResource.ocr_text.includes('Havoc (2005)')).toBe(true); + + expect(processedResource.ocr_text.includes('3.')).toBe(true); + expect(processedResource.ocr_text.includes('Love & Other Drugs (2010)')).toBe(true); + + expect(processedResource.ocr_text.includes('4.')).toBe(true); + expect(processedResource.ocr_text.includes('The Last Thing He Wanted (2020)')).toBe(true); + + await service.dispose(); + }); + }); diff --git a/packages/lib/services/ocr/drivers/OcrDriverTesseract.ts b/packages/lib/services/ocr/drivers/OcrDriverTesseract.ts index d5534ea2c1..e2792ee3fd 100644 --- a/packages/lib/services/ocr/drivers/OcrDriverTesseract.ts +++ b/packages/lib/services/ocr/drivers/OcrDriverTesseract.ts @@ -23,10 +23,15 @@ const formatTesseractBoundingBox = (boundingBox: Tesseract.Bbox): RecognizeResul return [boundingBox.x0, boundingBox.x1, boundingBox.y0, boundingBox.y1]; }; -// Empirically, it seems anything below 70 is not usable. Between 70 and 75 it's -// hit and miss, but often it's good enough that we should keep the result. -// Above this is usually reliable. -const minConfidence = 70; +// 2023-12-13: Empirically, it seems anything below 70 is not usable. Between 70 +// and 75 it's hit and miss, but often it's good enough that we should keep the result. +// Above this is usually reliable. Using 70 for now. +// +// 2025-04-03: Changed to 55 to detect text in images that are supported in +// other tools but were not in Joplin. +// +// https://github.com/laurent22/joplin/issues/11608 +const minConfidence = 55; interface Options { workerPath: string; From 9be533a19e54cf30b313333e00714ac31e67a025 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Thu, 3 Apr 2025 14:10:30 +0200 Subject: [PATCH 124/158] Doc: Update sponsors --- packages/tools/cspell/dictionary4.txt | 1 + packages/tools/sponsors.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/tools/cspell/dictionary4.txt b/packages/tools/cspell/dictionary4.txt index a68c6d77a3..c4e267f028 100644 --- a/packages/tools/cspell/dictionary4.txt +++ b/packages/tools/cspell/dictionary4.txt @@ -177,3 +177,4 @@ newfolder unfocusable unlocker Tiktok +topagency \ No newline at end of file diff --git a/packages/tools/sponsors.json b/packages/tools/sponsors.json index c70a43c3b5..658bdd87f3 100644 --- a/packages/tools/sponsors.json +++ b/packages/tools/sponsors.json @@ -104,7 +104,7 @@ "url": "https://topagency.webflow.io", "title": "WebDesignAgency", "imageName": "WebDesignAgency.png", - "alt": "web design agency" + "alt": "topagency" }, { "url": "https://realgambling.ca/", From da0a7faf1251f36a1eb004d0dfe9db1de5440f78 Mon Sep 17 00:00:00 2001 From: Joplin Bot Date: Thu, 3 Apr 2025 13:02:25 +0000 Subject: [PATCH 125/158] Doc: Auto-update documentation Auto-updated using release-website.sh --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 727035bd83..9a9ab7545d 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Please see the [donation page](https://github.com/laurent22/joplin/blob/dev/read # Sponsors - web design agency RealGambling.ca write an essay online with EssayPro casino without making any upfront cost Tiktok Rise + topagency RealGambling.ca write an essay online with EssayPro casino without making any upfront cost Tiktok Rise * * * From 911689a4ace1834acdaf0320edb1bee7919133e4 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Mon, 7 Apr 2025 18:29:25 +0100 Subject: [PATCH 126/158] Chore: Add exported type to fix plugin type generation --- packages/utils/ipc.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils/ipc.ts b/packages/utils/ipc.ts index 344d669681..6fde385ca5 100644 --- a/packages/utils/ipc.ts +++ b/packages/utils/ipc.ts @@ -158,7 +158,7 @@ export const stopServer = async (server: IpcServer) => { }); }; -interface SendMessageOutput { +export interface SendMessageOutput { port: number; response: Response; } From 8ac19d80ea3fb709a2d9e96b463e295afde60c20 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Mon, 7 Apr 2025 18:30:20 +0100 Subject: [PATCH 127/158] Chore: Update plugin types --- .../generators/app/templates/api/Joplin.d.ts | 4 ++++ .../generators/app/templates/api/JoplinSettings.d.ts | 8 ++++++-- .../app/templates/api/JoplinViewsDialogs.d.ts | 3 +++ .../app/templates/api/JoplinViewsEditor.d.ts | 10 +++++----- .../generators/app/templates/api/types.ts | 7 ++++++- 5 files changed, 24 insertions(+), 8 deletions(-) diff --git a/packages/generator-joplin/generators/app/templates/api/Joplin.d.ts b/packages/generator-joplin/generators/app/templates/api/Joplin.d.ts index 4dae70d4a1..15c672c043 100644 --- a/packages/generator-joplin/generators/app/templates/api/Joplin.d.ts +++ b/packages/generator-joplin/generators/app/templates/api/Joplin.d.ts @@ -73,4 +73,8 @@ export default class Joplin { */ require(_path: string): any; versionInfo(): Promise; + /** + * Tells whether the current theme is a dark one or not. + */ + shouldUseDarkColors(): Promise; } diff --git a/packages/generator-joplin/generators/app/templates/api/JoplinSettings.d.ts b/packages/generator-joplin/generators/app/templates/api/JoplinSettings.d.ts index 9a4638bd85..ab9663dc1a 100644 --- a/packages/generator-joplin/generators/app/templates/api/JoplinSettings.d.ts +++ b/packages/generator-joplin/generators/app/templates/api/JoplinSettings.d.ts @@ -52,11 +52,15 @@ export default class JoplinSettings { */ setValue(key: string, value: any): Promise; /** - * Gets a global setting value, including app-specific settings and those set by other plugins. + * Gets global setting values, including app-specific settings and those set by other plugins. * * The list of available settings is not documented yet, but can be found by looking at the source code: * - * https://github.com/laurent22/joplin/blob/dev/packages/lib/models/Setting.ts#L142 + * https://github.com/laurent22/joplin/blob/dev/packages/lib/models/settings/builtInMetadata.ts + */ + globalValues(keys: string[]): Promise; + /** + * @deprecated Use joplin.settings.globalValues() */ globalValue(key: string): Promise; /** diff --git a/packages/generator-joplin/generators/app/templates/api/JoplinViewsDialogs.d.ts b/packages/generator-joplin/generators/app/templates/api/JoplinViewsDialogs.d.ts index e1831a3e4d..55db51851e 100644 --- a/packages/generator-joplin/generators/app/templates/api/JoplinViewsDialogs.d.ts +++ b/packages/generator-joplin/generators/app/templates/api/JoplinViewsDialogs.d.ts @@ -43,6 +43,9 @@ export default class JoplinViewsDialogs { * Displays a message box with OK/Cancel buttons. Returns the button index that was clicked - "0" for OK and "1" for "Cancel" */ showMessageBox(message: string): Promise; + /** + * Displays a Toast notification in the corner of the application screen. + */ showToast(toast: Toast): Promise; /** * Displays a dialog to select a file or a directory. Same options and diff --git a/packages/generator-joplin/generators/app/templates/api/JoplinViewsEditor.d.ts b/packages/generator-joplin/generators/app/templates/api/JoplinViewsEditor.d.ts index cab36bba95..bd4dd1631e 100644 --- a/packages/generator-joplin/generators/app/templates/api/JoplinViewsEditor.d.ts +++ b/packages/generator-joplin/generators/app/templates/api/JoplinViewsEditor.d.ts @@ -60,14 +60,14 @@ export default class JoplinViewsEditors { */ onMessage(handle: ViewHandle, callback: Function): Promise; /** - * Emitted when the editor can potentially be activated - this for example when the current note - * is changed, or when the application is opened. At that point should can check the current - * note and decide whether your editor should be activated or not. If it should return `true`, - * otherwise return `false`. + * Emitted when the editor can potentially be activated - this is for example when the current + * note is changed, or when the application is opened. At that point you should check the + * current note and decide whether your editor should be activated or not. If it should, return + * `true`, otherwise return `false`. */ onActivationCheck(handle: ViewHandle, callback: ActivationCheckCallback): Promise; /** - * Emitted when the editor content should be updated. This for example when the currently + * Emitted when your editor content should be updated. This is for example when the currently * selected note changes, or when the user makes the editor visible. */ onUpdate(handle: ViewHandle, callback: UpdateCallback): Promise; diff --git a/packages/generator-joplin/generators/app/templates/api/types.ts b/packages/generator-joplin/generators/app/templates/api/types.ts index 4dfa8b66cd..3cd7b0f0ae 100644 --- a/packages/generator-joplin/generators/app/templates/api/types.ts +++ b/packages/generator-joplin/generators/app/templates/api/types.ts @@ -626,7 +626,7 @@ export interface CodeMirrorControl { /** * A CodeMirror [facet](https://codemirror.net/docs/ref/#state.EditorState.facet) that contains * the ID of the note currently open in the editor. - * + * * Access the value of this facet using * ```ts * const noteIdFacet = editorControl.joplinExtensions.noteIdFacet; @@ -636,6 +636,11 @@ export interface CodeMirrorControl { */ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- No better type available noteIdFacet: any; + /** + * A CodeMirror [StateEffect](https://codemirror.net/docs/ref/#state.StateEffect) that is + * included in a [Transaction](https://codemirror.net/docs/ref/#state.Transaction) when the + * note ID changes. + */ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- No better type available setNoteIdEffect: any; }; From 2e73ea2d9fab7eb633ede58684eaa0d6e4a631d0 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Mon, 7 Apr 2025 18:30:50 +0100 Subject: [PATCH 128/158] Plugin Generator release v3.3.1 --- packages/generator-joplin/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/generator-joplin/package.json b/packages/generator-joplin/package.json index cacfbb3548..4a230ef809 100644 --- a/packages/generator-joplin/package.json +++ b/packages/generator-joplin/package.json @@ -1,6 +1,6 @@ { "name": "generator-joplin", - "version": "3.3.0", + "version": "3.3.1", "description": "Scaffolds out a new Joplin plugin", "homepage": "https://github.com/laurent22/joplin/tree/dev/packages/generator-joplin", "author": { @@ -38,4 +38,4 @@ "repository": "https://github.com/laurent22/generator-joplin", "license": "AGPL-3.0-or-later", "private": true -} +} \ No newline at end of file From f185480cebb6badd361b57af14fff2511b670c44 Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Mon, 7 Apr 2025 11:59:35 -0700 Subject: [PATCH 129/158] Desktop: Update Electron to v35.1.4 (#12068) --- packages/app-desktop/package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/app-desktop/package.json b/packages/app-desktop/package.json index 44bdb9e1f6..5d8347a199 100644 --- a/packages/app-desktop/package.json +++ b/packages/app-desktop/package.json @@ -144,7 +144,7 @@ "@types/styled-components": "5.1.32", "@types/tesseract.js": "2.0.0", "axios": "^1.7.7", - "electron": "35.0.1", + "electron": "35.1.4", "electron-builder": "24.13.3", "glob": "10.4.5", "gulp": "4.0.2", diff --git a/yarn.lock b/yarn.lock index 4aeaee1933..a2e7b6c617 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8297,7 +8297,7 @@ __metadata: compare-versions: 6.1.1 countable: 3.0.1 debounce: 1.2.1 - electron: 35.0.1 + electron: 35.1.4 electron-builder: 24.13.3 electron-updater: 6.2.1 electron-window-state: 5.0.3 @@ -22971,16 +22971,16 @@ __metadata: languageName: node linkType: hard -"electron@npm:35.0.1": - version: 35.0.1 - resolution: "electron@npm:35.0.1" +"electron@npm:35.1.4": + version: 35.1.4 + resolution: "electron@npm:35.1.4" dependencies: "@electron/get": ^2.0.0 "@types/node": ^22.7.7 extract-zip: ^2.0.1 bin: electron: cli.js - checksum: 633bc35206e86f5166a4cefffc20bc2e7866eebdab50f78f1225ebbdd4219f50ce4a62f35d82982b26ab68a2c92e991437cf30379fc8147a59f33072b3ef873a + checksum: 78ac69d76823d9f2096726684f57b9d9e1bbf90a2207aaa003d69ed96eb2c7d93b0b8a6cee25a99382332606f09ea3b6b9f0868a5a6eca53429b5ff087fa1c10 languageName: node linkType: hard From d4fafd74d261773fba6c499eeb1d32bd91474015 Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Mon, 7 Apr 2025 11:59:44 -0700 Subject: [PATCH 130/158] Mobile: Update react-native-quick-crypto (#12067) --- packages/app-mobile/ios/Podfile.lock | 4 ++-- packages/app-mobile/package.json | 2 +- yarn.lock | 13 +++++-------- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/packages/app-mobile/ios/Podfile.lock b/packages/app-mobile/ios/Podfile.lock index 722fa23c56..fe0fbf63c6 100644 --- a/packages/app-mobile/ios/Podfile.lock +++ b/packages/app-mobile/ios/Podfile.lock @@ -1034,7 +1034,7 @@ PODS: - React-Core - react-native-netinfo (11.3.3): - React-Core - - react-native-quick-crypto (0.7.5): + - react-native-quick-crypto (0.7.12): - DoubleConversion - glog - hermes-engine @@ -1709,7 +1709,7 @@ SPEC CHECKSUMS: react-native-image-picker: 10f58d521d8da62b9747cd107045bce399cf5a1e react-native-image-resizer: 24c5d06fae2176dc0caed4b6396e02befb44064a react-native-netinfo: 28c2462c85067fe653615f6f595673bdca93a287 - react-native-quick-crypto: 08ecf18a70a8a49dbd0b5d983afbd56bdd809f86 + react-native-quick-crypto: 38fde7e5ddfb667b54536c25e6a6ac6d404633d3 react-native-rsa-native: a7931cdda1f73a8576a46d7f431378c5550f0c38 react-native-saf-x: 318d0cdb38f4618bd7ef5840d4f5c12e097dfbe7 react-native-safe-area-context: b72c4611af2e86d80a59ac76279043d8f75f454c diff --git a/packages/app-mobile/package.json b/packages/app-mobile/package.json index e426d35723..28194d2991 100644 --- a/packages/app-mobile/package.json +++ b/packages/app-mobile/package.json @@ -64,7 +64,7 @@ "react-native-paper": "5.13.1", "react-native-popup-menu": "0.16.1", "react-native-quick-actions": "0.3.13", - "react-native-quick-crypto": "0.7.5", + "react-native-quick-crypto": "0.7.12", "react-native-rsa-native": "2.0.5", "react-native-safe-area-context": "4.10.8", "react-native-securerandom": "1.0.1", diff --git a/yarn.lock b/yarn.lock index a2e7b6c617..33f3114210 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8428,7 +8428,7 @@ __metadata: react-native-paper: 5.13.1 react-native-popup-menu: 0.16.1 react-native-quick-actions: 0.3.13 - react-native-quick-crypto: 0.7.5 + react-native-quick-crypto: 0.7.12 react-native-rsa-native: 2.0.5 react-native-safe-area-context: 4.10.8 react-native-securerandom: 1.0.1 @@ -40026,19 +40026,16 @@ __metadata: languageName: node linkType: hard -"react-native-quick-crypto@npm:0.7.5": - version: 0.7.5 - resolution: "react-native-quick-crypto@npm:0.7.5" +"react-native-quick-crypto@npm:0.7.12": + version: 0.7.12 + resolution: "react-native-quick-crypto@npm:0.7.12" dependencies: "@craftzdog/react-native-buffer": ^6.0.5 events: ^3.3.0 readable-stream: ^4.5.2 string_decoder: ^1.3.0 util: ^0.12.5 - peerDependencies: - react: "*" - react-native: "*" - checksum: 07f5abc4ddf7fbc8d5bfa9b459f04a7e1fbc3afe9b1add8e07d0918401abb2a8a987da00741b2baa4e94d2125cec10b3a77c4136250a20f6f3376cefba048135 + checksum: f640cfc8dd3643d2530ef830c788033648311530c211385b2eaaa55bfc353b0af2400bd9a0df09338ee7ff4db2c72b99e06f06e7d6adf10a240db5ae82570896 languageName: node linkType: hard From 04196e448549731d887f91dc7de82cbc4ddb3011 Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Mon, 7 Apr 2025 12:02:06 -0700 Subject: [PATCH 131/158] Mobile: Add "swap line up" and "swap line down" to toolbar extended options (#12053) --- .../utils/allToolbarCommandNamesFromState.ts | 2 ++ .../utils/selectedCommandNamesFromState.ts | 3 +++ .../components/NoteEditor/commandDeclarations.ts | 10 ++++++++++ 3 files changed, 15 insertions(+) diff --git a/packages/app-mobile/components/EditorToolbar/utils/allToolbarCommandNamesFromState.ts b/packages/app-mobile/components/EditorToolbar/utils/allToolbarCommandNamesFromState.ts index e6b0d8806f..e0a78c80c3 100644 --- a/packages/app-mobile/components/EditorToolbar/utils/allToolbarCommandNamesFromState.ts +++ b/packages/app-mobile/components/EditorToolbar/utils/allToolbarCommandNamesFromState.ts @@ -22,6 +22,8 @@ const builtInCommandNames = [ '-', EditorCommandType.IndentLess, EditorCommandType.IndentMore, + `editor.${EditorCommandType.SwapLineDown}`, + `editor.${EditorCommandType.SwapLineUp}`, '-', 'insertDateTime', '-', diff --git a/packages/app-mobile/components/EditorToolbar/utils/selectedCommandNamesFromState.ts b/packages/app-mobile/components/EditorToolbar/utils/selectedCommandNamesFromState.ts index c4a3ec67e1..f955f0c345 100644 --- a/packages/app-mobile/components/EditorToolbar/utils/selectedCommandNamesFromState.ts +++ b/packages/app-mobile/components/EditorToolbar/utils/selectedCommandNamesFromState.ts @@ -1,3 +1,4 @@ +import { EditorCommandType } from '@joplin/editor/types'; import { AppState } from '../../../utils/types'; import allToolbarCommandNamesFromState from './allToolbarCommandNamesFromState'; import { Platform } from 'react-native'; @@ -7,6 +8,8 @@ const omitFromDefault: string[] = [ 'editor.textHeading3', 'editor.textHeading4', 'editor.textHeading5', + `editor.${EditorCommandType.SwapLineDown}`, + `editor.${EditorCommandType.SwapLineUp}`, ]; // The "hide keyboard" button is only needed on iOS, so only show it there by default. diff --git a/packages/app-mobile/components/NoteEditor/commandDeclarations.ts b/packages/app-mobile/components/NoteEditor/commandDeclarations.ts index 5ea3b46d38..470ce195e4 100644 --- a/packages/app-mobile/components/NoteEditor/commandDeclarations.ts +++ b/packages/app-mobile/components/NoteEditor/commandDeclarations.ts @@ -97,6 +97,16 @@ const declarations: CommandDeclaration[] = [ label: () => _('Increase indent level'), iconName: 'ant indent-right', }, + { + name: `editor.${EditorCommandType.SwapLineDown}`, + label: () => _('Swap line down'), + iconName: 'material chevron-double-down', + }, + { + name: `editor.${EditorCommandType.SwapLineUp}`, + label: () => _('Swap line up'), + iconName: 'material chevron-double-up', + }, { name: EditorCommandType.ToggleSearch, label: () => _('Search'), From 59447f4c45aab266620b05d6454a4d910dca0617 Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Mon, 7 Apr 2025 12:02:19 -0700 Subject: [PATCH 132/158] Desktop: Rich Text Editor: Fix "Remove color" button doesn't work (#12052) --- .../app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx index 84ba3d2ccb..8d51ddc8ae 100644 --- a/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx +++ b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx @@ -736,7 +736,9 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => { joplinSub: { inline: 'sub', remove: 'all' }, joplinSup: { inline: 'sup', remove: 'all' }, code: { inline: 'code', remove: 'all', attributes: { spellcheck: 'false' } }, - forecolor: { inline: 'span', styles: { color: '%value' } }, + // Foreground color: The remove_similar: true is necessary here for the "remove formatting" + // button to work. See https://github.com/tinymce/tinymce/issues/5026. + forecolor: { inline: 'span', styles: { color: '%value' }, remove_similar: true }, }, text_patterns: props.enableTextPatterns ? [ // See https://www.tiny.cloud/docs/tinymce/latest/content-behavior-options/#text_patterns From 338dabf5da78b45ff3282650ca8a1a492485c1b5 Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Mon, 7 Apr 2025 12:03:55 -0700 Subject: [PATCH 133/158] Mobile,Desktop: Resolves #11872: Explain why items could not be decrypted (#12048) --- .../app-mobile/components/screens/status.tsx | 260 +++++++++++------- packages/lib/services/DecryptionWorker.ts | 41 ++- packages/lib/services/KvStore.ts | 9 +- packages/lib/services/ReportService.test.ts | 156 ++++++++++- packages/lib/services/ReportService.ts | 42 ++- .../synchronizer/Synchronizer.e2ee.test.ts | 2 +- packages/lib/testing/test-utils.ts | 3 +- 7 files changed, 399 insertions(+), 114 deletions(-) diff --git a/packages/app-mobile/components/screens/status.tsx b/packages/app-mobile/components/screens/status.tsx index a164ce1697..fcde858ed6 100644 --- a/packages/app-mobile/components/screens/status.tsx +++ b/packages/app-mobile/components/screens/status.tsx @@ -1,16 +1,17 @@ import * as React from 'react'; -import { View, Text, Button, FlatList, TextStyle, StyleSheet } from 'react-native'; +import { View, Text, Button, FlatList, TextStyle, StyleSheet, Role } from 'react-native'; import Setting from '@joplin/lib/models/Setting'; import { connect } from 'react-redux'; import { ScreenHeader } from '../ScreenHeader'; -import ReportService, { ReportSection } from '@joplin/lib/services/ReportService'; +import ReportService, { ReportItemType, ReportSection } from '@joplin/lib/services/ReportService'; import { _ } from '@joplin/lib/locale'; import { BaseScreenComponent } from '../base-screen'; import { themeStyle } from '../global-style'; import { AppState } from '../../utils/types'; import checkDisabledSyncItemsNotification from '@joplin/lib/services/synchronizer/utils/checkDisabledSyncItemsNotification'; import { Dispatch } from 'redux'; +import Icon from '../Icon'; interface Props { themeId: number; @@ -21,6 +22,86 @@ interface State { report: ReportSection[]; } +interface ProcessedLine { + key: string; + text?: string; + isSection?: boolean; + isDivider?: boolean; + retryAllHandler?: ()=> void; + retryHandler?: ()=> void; + ignoreHandler?: ()=> void; + listItems?: ProcessedLine[]; +} + +type OnRefreshScreen = ()=> Promise; + +const processReport = (report: ReportSection[], refreshScreen: OnRefreshScreen, dispatch: Dispatch, baseStyle: TextStyle) => { + const lines: ProcessedLine[] = []; + let currentList: ProcessedLine[]|null = null; + + for (let i = 0; i < report.length; i++) { + const section = report[i]; + + let style: TextStyle = { ...baseStyle }; + style.fontWeight = 'bold'; + if (i > 0) style.paddingTop = 20; + lines.push({ key: `section_${i}`, isSection: true, text: section.title }); + if (section.canRetryAll) { + lines.push({ key: `retry_all_${i}`, text: '', retryAllHandler: section.retryAllHandler }); + } + + for (const n in section.body) { + if (!section.body.hasOwnProperty(n)) continue; + style = { ...baseStyle }; + const item = section.body[n]; + + let text = ''; + + let retryHandler = null; + let ignoreHandler = null; + if (typeof item === 'object') { + if (item.canRetry) { + retryHandler = async () => { + await item.retryHandler(); + await refreshScreen(); + }; + } + if (item.canIgnore) { + ignoreHandler = async () => { + await item.ignoreHandler(); + await refreshScreen(); + await checkDisabledSyncItemsNotification((action) => dispatch(action)); + }; + } + if (item.type === ReportItemType.OpenList) { + currentList = []; + } else if (item.type === ReportItemType.CloseList) { + lines.push({ key: `list_${i}_${n}`, listItems: currentList }); + currentList = null; + } + text = item.text; + } else { + text = item; + } + + const line = { key: `item_${i}_${n}`, text: text, retryHandler, ignoreHandler }; + if (currentList) { + // The OpenList item, for example, might be empty and should be skipped: + const hasContent = line.text || retryHandler || ignoreHandler; + if (hasContent) { + currentList.push(line); + } + } else { + lines.push(line); + } + } + + lines.push({ key: `divider2_${i}`, isDivider: true }); + } + + return lines; +}; + class StatusScreenComponent extends BaseScreenComponent { public constructor(props: Props) { super(props); @@ -52,15 +133,11 @@ class StatusScreenComponent extends BaseScreenComponent { marginLeft: 2, marginRight: 2, }, - }); - } - - public override render() { - const theme = themeStyle(this.props.themeId); - const styles = this.styles(); - - const renderBody = (report: ReportSection[]) => { - const baseStyle = { + retryAllButton: { + flexGrow: 0, + alignSelf: 'flex-start', + }, + baseStyle: { paddingLeft: 6, paddingRight: 6, paddingTop: 2, @@ -68,98 +145,95 @@ class StatusScreenComponent extends BaseScreenComponent { flex: 0, color: theme.color, fontSize: theme.fontSize, - }; + alignSelf: 'center', + }, + listWrapper: { + paddingBottom: 5, + }, + listBullet: { + fontSize: theme.fontSize / 3, + color: theme.color, + alignSelf: 'center', + justifyContent: 'center', + flexGrow: 0, + marginStart: 12, + marginEnd: 2, + }, + divider: { + borderBottomWidth: 1, + borderBottomColor: theme.dividerColor, + marginTop: 20, + marginBottom: 20, + }, + }); + } - const lines = []; + public override render() { + const styles = this.styles(); - for (let i = 0; i < report.length; i++) { - const section = report[i]; + const renderItem = (item: ProcessedLine, inList: boolean) => { + const style: TextStyle = { ...styles.baseStyle }; - let style: TextStyle = { ...baseStyle }; + let textRole: Role|null = undefined; + const text = item.text; + if (item.isSection === true) { style.fontWeight = 'bold'; - if (i > 0) style.paddingTop = 20; - lines.push({ key: `section_${i}`, isSection: true, text: section.title }); - if (section.canRetryAll) { - lines.push({ key: `retry_all_${i}`, text: '', retryAllHandler: section.retryAllHandler }); - } - - for (const n in section.body) { - if (!section.body.hasOwnProperty(n)) continue; - style = { ...baseStyle }; - const item = section.body[n]; - - let text = ''; - - let retryHandler = null; - let ignoreHandler = null; - if (typeof item === 'object') { - if (item.canRetry) { - retryHandler = async () => { - await item.retryHandler(); - await this.refreshScreen(); - }; - } - if (item.canIgnore) { - ignoreHandler = async () => { - await item.ignoreHandler(); - await this.refreshScreen(); - await checkDisabledSyncItemsNotification((action) => this.props.dispatch(action)); - }; - } - text = item.text; - } else { - text = item; - } - - lines.push({ key: `item_${i}_${n}`, text: text, retryHandler, ignoreHandler }); - } - - lines.push({ key: `divider2_${i}`, isDivider: true }); + style.marginBottom = 5; + textRole = 'heading'; + } else if (inList) { + textRole = 'listitem'; } + style.flex = 1; + + const retryAllButton = item.retryAllHandler ? ( + + + ; +}; + +export default TrashNotificationMessage; diff --git a/packages/app-desktop/gui/TrashNotification/style.scss b/packages/app-desktop/gui/TrashNotification/style.scss deleted file mode 100644 index d6add8b988..0000000000 --- a/packages/app-desktop/gui/TrashNotification/style.scss +++ /dev/null @@ -1,27 +0,0 @@ -body .notyf { - color: var(--joplin-color5); -} - -.notyf__toast { - - > .notyf__wrapper { - - > .notyf__message { - - > .cancel { - color: var(--joplin-color5); - text-decoration: underline; - } - - } - - > .notyf__icon { - - > .notyf__icon--success { - background-color: var(--joplin-color5); - } - - } - - } -} diff --git a/packages/app-desktop/gui/UpdateNotification/UpdateNotification.tsx b/packages/app-desktop/gui/UpdateNotification/UpdateNotification.tsx index 05ea6e5025..63d3a662c9 100644 --- a/packages/app-desktop/gui/UpdateNotification/UpdateNotification.tsx +++ b/packages/app-desktop/gui/UpdateNotification/UpdateNotification.tsx @@ -1,17 +1,15 @@ import * as React from 'react'; -import { useCallback, useContext, useEffect, useMemo, useRef } from 'react'; -import { themeStyle } from '@joplin/lib/theme'; -import NotyfContext from '../NotyfContext'; +import { useCallback, useContext, useEffect } from 'react'; import { UpdateInfo } from 'electron-updater'; import { ipcRenderer, IpcRendererEvent } from 'electron'; import { AutoUpdaterEvents } from '../../services/autoUpdater/AutoUpdaterService'; -import { NotyfEvent, NotyfNotification } from 'notyf'; import { _ } from '@joplin/lib/locale'; -import { htmlentities } from '@joplin/utils/html'; import shim from '@joplin/lib/shim'; +import { PopupNotificationContext } from '../PopupNotification/PopupNotificationProvider'; +import Button, { ButtonLevel } from '../Button/Button'; +import { NotificationType } from '../PopupNotification/types'; -interface UpdateNotificationProps { - themeId: number; +interface Props { } export enum UpdateNotificationEvents { @@ -22,111 +20,61 @@ export enum UpdateNotificationEvents { const changelogLink = 'https://github.com/laurent22/joplin/releases'; -window.openChangelogLink = () => { +const openChangelogLink = () => { shim.openUrl(changelogLink); }; -const UpdateNotification = ({ themeId }: UpdateNotificationProps) => { - const notyfContext = useContext(NotyfContext); - const notificationRef = useRef(null); // Use ref to hold the current notification - - const theme = useMemo(() => themeStyle(themeId), [themeId]); - - const notyf = useMemo(() => { - const output = notyfContext; - output.options.types = notyfContext.options.types.map(type => { - if (type.type === 'success') { - type.background = theme.backgroundColor5; - // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied - (type.icon as any).color = theme.backgroundColor5; - } - return type; - }); - return output; - }, [notyfContext, theme]); - - const handleDismissNotification = useCallback(() => { - notyf.dismiss(notificationRef.current); - notificationRef.current = null; - }, [notyf]); - - const handleApplyUpdate = useCallback(() => { - ipcRenderer.send('apply-update-now'); - handleDismissNotification(); - }, [handleDismissNotification]); +const handleApplyUpdate = () => { + ipcRenderer.send('apply-update-now'); +}; +const UpdateNotification: React.FC = () => { + const popupManager = useContext(PopupNotificationContext); const handleUpdateDownloaded = useCallback((_event: IpcRendererEvent, info: UpdateInfo) => { - if (notificationRef.current) return; - - const updateAvailableHtml = htmlentities(_('A new update (%s) is available', info.version)); - const seeChangelogHtml = htmlentities(_('See changelog')); - const restartNowHtml = htmlentities(_('Restart now')); - const updateLaterHtml = htmlentities(_('Update later')); - - const messageHtml = ` -

- ${updateAvailableHtml} ${seeChangelogHtml} -
- - + const notification = popupManager.createPopup(() => ( +
+ {_('A new update (%s) is available', info.version)} + +
+
-
- `; - - const notification: NotyfNotification = notyf.open({ - type: 'success', - message: messageHtml, - position: { - x: 'right', - y: 'bottom', - }, - duration: 0, - }); - - notificationRef.current = notification; - }, [notyf, theme]); + )); + }, [popupManager]); const handleUpdateNotAvailable = useCallback(() => { - if (notificationRef.current) return; - - const noUpdateMessageHtml = htmlentities(_('No updates available')); - - const messageHtml = ` -
- ${noUpdateMessageHtml} + const notification = popupManager.createPopup(() => ( +
+ {_('No updates available')}
- `; - - const notification: NotyfNotification = notyf.open({ - type: 'success', - message: messageHtml, - position: { - x: 'right', - y: 'bottom', - }, - duration: 5000, - }); - - notification.on(NotyfEvent.Dismiss, () => { - notificationRef.current = null; - }); - - notificationRef.current = notification; - }, [notyf, theme]); + ), { type: NotificationType.Info }); + notification.scheduleDismiss(); + }, [popupManager]); useEffect(() => { ipcRenderer.on(AutoUpdaterEvents.UpdateDownloaded, handleUpdateDownloaded); ipcRenderer.on(AutoUpdaterEvents.UpdateNotAvailable, handleUpdateNotAvailable); - document.addEventListener(UpdateNotificationEvents.ApplyUpdate, handleApplyUpdate); - document.addEventListener(UpdateNotificationEvents.Dismiss, handleDismissNotification); return () => { ipcRenderer.removeListener(AutoUpdaterEvents.UpdateDownloaded, handleUpdateDownloaded); ipcRenderer.removeListener(AutoUpdaterEvents.UpdateNotAvailable, handleUpdateNotAvailable); - document.removeEventListener(UpdateNotificationEvents.ApplyUpdate, handleApplyUpdate); }; - }, [handleApplyUpdate, handleDismissNotification, handleUpdateDownloaded, handleUpdateNotAvailable]); + }, [handleUpdateDownloaded, handleUpdateNotAvailable]); return ( diff --git a/packages/app-desktop/gui/UpdateNotification/style.scss b/packages/app-desktop/gui/UpdateNotification/style.scss index 65fbb36d03..553a67b081 100644 --- a/packages/app-desktop/gui/UpdateNotification/style.scss +++ b/packages/app-desktop/gui/UpdateNotification/style.scss @@ -1,27 +1,11 @@ .update-notification { - display: flex; - flex-direction: column; - align-items: flex-start; + display: flex; + flex-direction: column; + align-items: flex-start; - .button-container { - display: flex; - gap: 10px; - margin-top: 8px; - } - - .notyf__button { - padding: 5px 10px; - border: 1px solid; - border-radius: 4px; - background-color: transparent; - cursor: pointer; - - &:hover { - background-color: rgba(255, 255, 255, 0.2); - } - } - - a { - text-decoration: underline; - } + > .buttons { + display: flex; + gap: 10px; + margin-top: 8px; + } } \ No newline at end of file diff --git a/packages/app-desktop/gui/WindowCommandsAndDialogs/WindowCommandsAndDialogs.tsx b/packages/app-desktop/gui/WindowCommandsAndDialogs/WindowCommandsAndDialogs.tsx index f8984dfcee..870c6aa007 100644 --- a/packages/app-desktop/gui/WindowCommandsAndDialogs/WindowCommandsAndDialogs.tsx +++ b/packages/app-desktop/gui/WindowCommandsAndDialogs/WindowCommandsAndDialogs.tsx @@ -18,6 +18,7 @@ import useWindowCommands from './utils/useWindowCommands'; import PluginDialogs from './PluginDialogs'; import useSyncDialogState from './utils/useSyncDialogState'; import AppDialogs from './AppDialogs'; +import PopupNotificationList from '../PopupNotification/PopupNotificationList'; const PluginManager = require('@joplin/lib/services/PluginManager'); @@ -113,7 +114,9 @@ const WindowCommandsAndDialogs: React.FC = props => { const dialogInfo = PluginManager.instance().pluginDialogToShow(props.pluginsLegacy); const pluginDialog = !dialogInfo ? null : ; - const { noteContentPropertiesDialogOptions, notePropertiesDialogOptions, shareNoteDialogOptions, shareFolderDialogOptions, promptOptions } = dialogState; + const { + noteContentPropertiesDialogOptions, notePropertiesDialogOptions, shareNoteDialogOptions, shareFolderDialogOptions, promptOptions, + } = dialogState; return <> @@ -173,6 +176,8 @@ const WindowCommandsAndDialogs: React.FC = props => { buttons={promptOptions && 'buttons' in promptOptions ? promptOptions.buttons : null} inputType={promptOptions && 'inputType' in promptOptions ? promptOptions.inputType : null} /> + + ; }; diff --git a/packages/app-desktop/gui/styles/index.scss b/packages/app-desktop/gui/styles/index.scss index b87f736e29..1c061eff6e 100644 --- a/packages/app-desktop/gui/styles/index.scss +++ b/packages/app-desktop/gui/styles/index.scss @@ -3,6 +3,7 @@ @use './user-webview-dialog.scss'; @use './prompt-dialog.scss'; @use './flat-button.scss'; +@use './link-button.scss'; @use './help-text.scss'; @use './toolbar-button.scss'; @use './toolbar-icon.scss'; @@ -14,3 +15,5 @@ @use './combobox-wrapper.scss'; @use './combobox-suggestion-option.scss'; @use './change-app-layout-dialog.scss'; +@use './popup-notification-list.scss'; +@use './popup-notification-item.scss'; diff --git a/packages/app-desktop/gui/styles/link-button.scss b/packages/app-desktop/gui/styles/link-button.scss new file mode 100644 index 0000000000..e10d040dc3 --- /dev/null +++ b/packages/app-desktop/gui/styles/link-button.scss @@ -0,0 +1,13 @@ + +.link-button { + background: transparent; + border: none; + font-size: inherit; + font-weight: inherit; + color: inherit; + padding: 0; + margin: 0; + + text-decoration: underline; + cursor: pointer; +} diff --git a/packages/app-desktop/gui/styles/popup-notification-item.scss b/packages/app-desktop/gui/styles/popup-notification-item.scss new file mode 100644 index 0000000000..8a985e368f --- /dev/null +++ b/packages/app-desktop/gui/styles/popup-notification-item.scss @@ -0,0 +1,126 @@ +@keyframes slide-in { + from { + opacity: 0; + transform: translateY(25%); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slide-out { + from { + opacity: 1; + transform: translateY(0); + } + to { + opacity: 0; + transform: translateY(25%); + } +} + +@keyframes grow { + from { + transform: scale(0); + } + to { + transform: scale(1); + } +} + +.popup-notification-item { + margin: 12px; + padding: 13px 15px; + border-radius: 4px; + + overflow: clip; + position: relative; + display: flex; + align-items: center; + + box-shadow: 0 3px 7px 0px rgba(0, 0, 0, 0.25); + + --text-color: var(--joplin-color5); + --ripple-color: var(--joplin-background-color5); + background-color: color-mix(in srgb, var(--ripple-color) 20%, transparent 70%); + color: var(--text-color); + + animation: slide-in 0.3s ease-in both; + + > .icon { + font-size: 14px; + text-align: center; + + width: 24px; + height: 24px; + // Make the line hight slightly larger than the icon size + // to vertically center the text + line-height: 26px; + + margin-inline-end: 13px; + border-radius: 50%; + + color: var(--ripple-color); + background-color: var(--text-color); + } + + > .content { + padding: 10px 0; + max-width: min(280px, 70vw); + font-size: 1.1em; + font-weight: 500; + } + + > .ripple { + --ripple-size: 500px; + + position: absolute; + transform-origin: bottom right; + top: calc(var(--ripple-size) / -2); + right: -40px; + z-index: -1; + + background-color: var(--ripple-color); + width: var(--ripple-size); + height: var(--ripple-size); + border-radius: calc(var(--ripple-size) / 2); + + transform: scale(0); + animation: grow 0.4s ease-out forwards; + } + + &.-dismissing { + // Animate the icon and content first + animation: slide-out 0.25s ease-out both; + animation-delay: 0.25s; + + & > .content, & > .icon { + animation: slide-out 0.3s ease-out both; + } + } + + &.-success { + --ripple-color: var(--joplin-color-correct); + } + + &.-error { + --ripple-color: var(--joplin-color-error); + } + + &.-info { + --text-color: var(--joplin-color5); + --ripple-color: var(--joplin-background-color5); + } + + @media (prefers-reduced-motion) { + &, & > .content, & > .icon { + transform: none !important; + } + + > .ripple { + transform: scale(1); + animation: none; + } + } +} diff --git a/packages/app-desktop/gui/styles/popup-notification-list.scss b/packages/app-desktop/gui/styles/popup-notification-list.scss new file mode 100644 index 0000000000..fbf5a2f648 --- /dev/null +++ b/packages/app-desktop/gui/styles/popup-notification-list.scss @@ -0,0 +1,22 @@ + +.popup-notification-list { + display: flex; + align-items: end; + flex-direction: column; + list-style-type: none; + padding-left: 0; + padding-right: 0; + + &.-overlay { + // Focus should jump to the bottom item first + flex-direction: column-reverse; + + position: absolute; + bottom: 0; + inset-inline-end: 0; // right: 0 in ltr, left: 0 in rtl + z-index: 10; + + max-height: 100vh; + overflow-y: auto; + } +} diff --git a/packages/app-desktop/index.html b/packages/app-desktop/index.html index d5c39a52ce..43e07a8c6a 100644 --- a/packages/app-desktop/index.html +++ b/packages/app-desktop/index.html @@ -10,7 +10,6 @@ Joplin - @@ -19,6 +18,5 @@
- diff --git a/packages/app-desktop/integration-tests/noteList.spec.ts b/packages/app-desktop/integration-tests/noteList.spec.ts index 2affee7e28..629182ba72 100644 --- a/packages/app-desktop/integration-tests/noteList.spec.ts +++ b/packages/app-desktop/integration-tests/noteList.spec.ts @@ -75,6 +75,32 @@ test.describe('noteList', () => { await expect(noteList.getNoteItemByTitle('test note 1')).toBeVisible(); }); + test('deleting a note to the trash should show a notification', async ({ electronApp, mainWindow }) => { + const mainScreen = await new MainScreen(mainWindow).setup(); + await mainScreen.createNewNote('test note 1'); + + const noteList = mainScreen.noteList; + await noteList.focusContent(electronApp); + const testNoteItem = noteList.getNoteItemByTitle('test note 1'); + await expect(testNoteItem).toBeVisible(); + + // Should be removed after deleting + await testNoteItem.press('Delete'); + await expect(testNoteItem).not.toBeVisible(); + + // Should show a deleted notification + const notification = mainWindow.locator('[role=alert]', { + hasText: /The note was successfully moved to the trash./i, + }); + await expect(notification).toBeVisible(); + + // Should be possible to un-delete + const undeleteButton = notification.getByRole('button', { name: 'Cancel' }); + await undeleteButton.click(); + + await expect(testNoteItem).toBeVisible(); + }); + test('arrow keys should navigate the note list', async ({ electronApp, mainWindow }) => { const mainScreen = await new MainScreen(mainWindow).setup(); const sidebar = mainScreen.sidebar; diff --git a/packages/app-desktop/main.scss b/packages/app-desktop/main.scss index 73ec9ee737..a1834aaec6 100644 --- a/packages/app-desktop/main.scss +++ b/packages/app-desktop/main.scss @@ -345,41 +345,3 @@ mark { height: 100%; width: 100%; } - -// ---------------------------------------------------------- -// Notyf style -// ---------------------------------------------------------- - -.notyf__toast--info { - color: var(--joplin-color5) !important; -} - -.notyf__toast--info .notyf__ripple { - background-color: var(--joplin-background-color5) !important; -} - -.notyf__toast--success { - color: var(--joplin-color5) !important; -} - -.notyf__toast--success .notyf__ripple { - background-color: var(--joplin-color-correct) !important; -} - -.notyf__icon--success { - color: var(--joplin-color) !important; - background-color: var(--joplin-color5) !important; -} - -.notyf__toast--error { - color: var(--joplin-color2) !important; -} - -.notyf__toast--error .notyf__ripple { - background-color: var(--joplin-color-error) !important; -} - -.notyf__icon--error { - color: var(--joplin-color) !important; - background-color: var(--joplin-color5) !important; -} \ No newline at end of file diff --git a/packages/app-desktop/package.json b/packages/app-desktop/package.json index 5d8347a199..dc75f71e78 100644 --- a/packages/app-desktop/package.json +++ b/packages/app-desktop/package.json @@ -188,7 +188,6 @@ "node-fetch": "2.6.7", "node-notifier": "10.0.1", "node-rsa": "1.1.1", - "notyf": "3.10.0", "pdfjs-dist": "3.11.174", "pretty-bytes": "5.6.0", "re-resizable": "6.9.17", diff --git a/packages/app-desktop/style.scss b/packages/app-desktop/style.scss index 6a0ddc6966..8638ec29b2 100644 --- a/packages/app-desktop/style.scss +++ b/packages/app-desktop/style.scss @@ -9,7 +9,6 @@ @use 'gui/JoplinCloudLoginScreen.scss' as joplin-cloud-login-screen; @use 'gui/NoteListHeader/style.scss' as note-list-header; @use 'gui/UpdateNotification/style.scss' as update-notification; -@use 'gui/TrashNotification/style.scss' as trash-notification; @use 'gui/Sidebar/style.scss' as sidebar-styles; @use 'gui/NoteEditor/style.scss' as note-editor-styles; @use 'gui/KeymapConfig/style.scss' as keymap-styles; diff --git a/packages/tools/cspell/dictionary4.txt b/packages/tools/cspell/dictionary4.txt index c4e267f028..a37891ce7e 100644 --- a/packages/tools/cspell/dictionary4.txt +++ b/packages/tools/cspell/dictionary4.txt @@ -90,8 +90,6 @@ signup activatable Prec titlewrapper -notyf -Notyf unresponded activeline Prec diff --git a/yarn.lock b/yarn.lock index 33f3114210..64fbc962bf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8319,7 +8319,6 @@ __metadata: node-fetch: 2.6.7 node-notifier: 10.0.1 node-rsa: 1.1.1 - notyf: 3.10.0 pdfjs-dist: 3.11.174 pretty-bytes: 5.6.0 re-resizable: 6.9.17 @@ -35814,13 +35813,6 @@ __metadata: languageName: node linkType: hard -"notyf@npm:3.10.0": - version: 3.10.0 - resolution: "notyf@npm:3.10.0" - checksum: 6cc533fccb0d74e544edf10e82d2942975adc4c993a68c966694bbb451dc06056d02e8dced4ecfce2c4586682223759cb1f9f3e3f609c83458e99c2bf5494b00 - languageName: node - linkType: hard - "now-and-later@npm:^2.0.0": version: 2.0.1 resolution: "now-and-later@npm:2.0.1" From 821558fe309155e50ff80fedc8e7276d9cc43c28 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Mon, 7 Apr 2025 20:13:30 +0100 Subject: [PATCH 137/158] Desktop release v3.3.4 --- packages/app-desktop/gui/NotyfContext.js | 19 ++ packages/app-desktop/package.json | 2 +- .../accessibility/AccessibleModalMenu.js | 34 +++ .../app-mobile/components/screens/Notes.js | 233 ++++++++++++++++++ 4 files changed, 287 insertions(+), 1 deletion(-) create mode 100644 packages/app-desktop/gui/NotyfContext.js create mode 100644 packages/app-mobile/components/accessibility/AccessibleModalMenu.js create mode 100644 packages/app-mobile/components/screens/Notes.js diff --git a/packages/app-desktop/gui/NotyfContext.js b/packages/app-desktop/gui/NotyfContext.js new file mode 100644 index 0000000000..08c3e740f3 --- /dev/null +++ b/packages/app-desktop/gui/NotyfContext.js @@ -0,0 +1,19 @@ +'use strict'; +// Based on https://github.com/caroso1222/notyf/blob/master/recipes/react.md +Object.defineProperty(exports, '__esModule', { value: true }); +const React = require('react'); +const notyf_1 = require('notyf'); +const types_1 = require('@joplin/lib/services/plugins/api/types'); +exports.default = React.createContext(new notyf_1.Notyf({ + // Set your global Notyf configuration here + duration: 6000, + types: [ + { + type: types_1.ToastType.Info, + icon: false, + className: 'notyf__toast--info', + background: 'blue', // Need to set a background, otherwise Notyf won't create the background element. But the color will be overriden in CSS. + }, + ], +})); +// # sourceMappingURL=NotyfContext.js.map diff --git a/packages/app-desktop/package.json b/packages/app-desktop/package.json index dc75f71e78..701113e990 100644 --- a/packages/app-desktop/package.json +++ b/packages/app-desktop/package.json @@ -1,6 +1,6 @@ { "name": "@joplin/app-desktop", - "version": "3.3.3", + "version": "3.3.4", "description": "Joplin for Desktop", "main": "main.js", "private": true, diff --git a/packages/app-mobile/components/accessibility/AccessibleModalMenu.js b/packages/app-mobile/components/accessibility/AccessibleModalMenu.js new file mode 100644 index 0000000000..bfbb3423fa --- /dev/null +++ b/packages/app-mobile/components/accessibility/AccessibleModalMenu.js @@ -0,0 +1,34 @@ +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const React = require('react'); +const react_native_1 = require('react-native'); +const Modal_1 = require('../Modal'); +const react_1 = require('react'); +const locale_1 = require('@joplin/lib/locale'); +const buttons_1 = require('../buttons'); +// react-native-paper's floating action button menu is inaccessible on web +// (can't be activated by a screen reader, and, in some cases, by the tab key). +// This component provides an alternative. +const AccessibleModalMenu = props => { + let _a; + const [open, setOpen] = (0, react_1.useState)(false); + const onClick = (0, react_1.useCallback)(() => { + if (props.onPress) { + props.onPress(); + } else { + setOpen(!open); + } + }, [open, props.onPress]); + const options = []; + for (const action of ((_a = props.actions) !== null && _a !== void 0 ? _a : [])) { + options.push(React.createElement(buttons_1.PrimaryButton, { key: action.label, onPress: action.onPress }, action.label)); + } + const modal = (React.createElement(Modal_1.default, { visible: open }, + options, + React.createElement(buttons_1.SecondaryButton, { onPress: onClick }, (0, locale_1._)('Close menu')))); + return React.createElement(react_native_1.View, { style: { height: 0, overflow: 'visible' } }, + modal, + React.createElement(buttons_1.SecondaryButton, { onPress: onClick }, props.label)); +}; +exports.default = AccessibleModalMenu; +// # sourceMappingURL=AccessibleModalMenu.js.map diff --git a/packages/app-mobile/components/screens/Notes.js b/packages/app-mobile/components/screens/Notes.js new file mode 100644 index 0000000000..b7ef7e7cfc --- /dev/null +++ b/packages/app-mobile/components/screens/Notes.js @@ -0,0 +1,233 @@ +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const React = require('react'); +const react_native_1 = require('react-native'); +const reducer_1 = require('@joplin/lib/reducer'); +const react_redux_1 = require('react-redux'); +const NoteList_1 = require('../NoteList'); +const Folder_1 = require('@joplin/lib/models/Folder'); +const Tag_1 = require('@joplin/lib/models/Tag'); +const Note_1 = require('@joplin/lib/models/Note'); +const Setting_1 = require('@joplin/lib/models/Setting'); +const global_style_1 = require('../global-style'); +const ScreenHeader_1 = require('../ScreenHeader'); +const locale_1 = require('@joplin/lib/locale'); +const FloatingActionButton_1 = require('../buttons/FloatingActionButton'); +const base_screen_1 = require('../base-screen'); +const trash_1 = require('@joplin/lib/services/trash'); +const AccessibleView_1 = require('../accessibility/AccessibleView'); +const DialogManager_1 = require('../DialogManager'); +const react_1 = require('react'); +class NotesScreenComponent extends base_screen_1.BaseScreenComponent { + constructor(props) { + super(props); + this.onAppStateChangeSub_ = null; + this.styles_ = {}; + this.onAppStateChange_ = async () => { + // Force an update to the notes list when app state changes + const newProps = { ...this.props }; + newProps.notesSource = ''; + await this.refreshNotes(newProps); + }; + this.sortButton_press = async () => { + const buttons = []; + const sortNoteOptions = Setting_1.default.enumOptions('notes.sortOrder.field'); + for (const field in sortNoteOptions) { + if (!sortNoteOptions.hasOwnProperty(field)) { continue; } + buttons.push({ + text: sortNoteOptions[field], + iconChecked: 'fas fa-circle', + checked: Setting_1.default.value('notes.sortOrder.field') === field, + id: { name: 'notes.sortOrder.field', value: field }, + }); + } + buttons.push({ + text: `[ ${Setting_1.default.settingMetadata('notes.sortOrder.reverse').label()} ]`, + checked: Setting_1.default.value('notes.sortOrder.reverse'), + id: { name: 'notes.sortOrder.reverse', value: !Setting_1.default.value('notes.sortOrder.reverse') }, + }); + buttons.push({ + text: `[ ${Setting_1.default.settingMetadata('uncompletedTodosOnTop').label()} ]`, + checked: Setting_1.default.value('uncompletedTodosOnTop'), + id: { name: 'uncompletedTodosOnTop', value: !Setting_1.default.value('uncompletedTodosOnTop') }, + }); + buttons.push({ + text: `[ ${Setting_1.default.settingMetadata('showCompletedTodos').label()} ]`, + checked: Setting_1.default.value('showCompletedTodos'), + id: { name: 'showCompletedTodos', value: !Setting_1.default.value('showCompletedTodos') }, + }); + const r = await this.props.dialogManager.showMenu(Setting_1.default.settingMetadata('notes.sortOrder.field').label(), buttons); + if (!r) { return; } + Setting_1.default.setValue(r.name, r.value); + }; + this.newNoteNavigate = async (folderId, isTodo) => { + try { + const newNote = await Note_1.default.save({ + parent_id: folderId, + is_todo: isTodo ? 1 : 0, + }, { provisional: true }); + this.props.dispatch({ + type: 'NAV_GO', + routeName: 'Note', + noteId: newNote.id, + }); + } catch (error) { + alert((0, locale_1._)('Cannot create a new note: %s', error.message)); + } + }; + } + styles() { + if (!this.styles_) { this.styles_ = {}; } + const themeId = this.props.themeId; + const cacheKey = themeId; + if (this.styles_[cacheKey]) { return this.styles_[cacheKey]; } + this.styles_ = {}; + const styles = { + noteList: { + flex: 1, + }, + }; + this.styles_[cacheKey] = react_native_1.StyleSheet.create(styles); + return this.styles_[cacheKey]; + } + async componentDidMount() { + await this.refreshNotes(); + this.onAppStateChangeSub_ = react_native_1.AppState.addEventListener('change', this.onAppStateChange_); + } + async componentWillUnmount() { + if (this.onAppStateChangeSub_) { this.onAppStateChangeSub_.remove(); } + } + async componentDidUpdate(prevProps) { + if (prevProps.notesOrder !== this.props.notesOrder || prevProps.selectedFolderId !== this.props.selectedFolderId || prevProps.selectedTagId !== this.props.selectedTagId || prevProps.selectedSmartFilterId !== this.props.selectedSmartFilterId || prevProps.notesParentType !== this.props.notesParentType || prevProps.uncompletedTodosOnTop !== this.props.uncompletedTodosOnTop || prevProps.showCompletedTodos !== this.props.showCompletedTodos) { + await this.refreshNotes(this.props); + } + } + async refreshNotes(props = null) { + if (props === null) { props = this.props; } + const options = { + order: props.notesOrder, + uncompletedTodosOnTop: props.uncompletedTodosOnTop, + showCompletedTodos: props.showCompletedTodos, + caseInsensitive: true, + }; + const parent = this.parentItem(props); + if (!parent) { return; } + const source = JSON.stringify({ + options: options, + parentId: parent.id, + }); + if (source === props.notesSource) { return; } + // For now, search refresh is handled by the search screen. + if (props.notesParentType === 'Search') { return; } + let notes = []; + if (props.notesParentType === 'Folder') { + notes = await Note_1.default.previews(props.selectedFolderId, options); + } else if (props.notesParentType === 'Tag') { + notes = await Tag_1.default.notes(props.selectedTagId, options); + } else if (props.notesParentType === 'SmartFilter') { + notes = await Note_1.default.previews(null, options); + } + this.props.dispatch({ + type: 'NOTE_UPDATE_ALL', + notes: notes, + notesSource: source, + }); + } + parentItem(props = null) { + if (!props) { props = this.props; } + let output = null; + if (props.notesParentType === 'Folder') { + output = Folder_1.default.byId(props.folders, props.selectedFolderId); + } else if (props.notesParentType === 'Tag') { + output = Tag_1.default.byId(props.tags, props.selectedTagId); + } else if (props.notesParentType === 'SmartFilter') { + output = { id: this.props.selectedSmartFilterId, title: (0, locale_1._)('All notes') }; + } else { + return null; + // throw new Error('Invalid parent type: ' + props.notesParentType); + } + return output; + } + folderPickerOptions() { + const options = { + visible: this.props.noteSelectionEnabled, + mustSelect: true, + }; + if (this.folderPickerOptions_ && options.visible === this.folderPickerOptions_.visible) { return this.folderPickerOptions_; } + this.folderPickerOptions_ = options; + return this.folderPickerOptions_; + } + render() { + const parent = this.parentItem(); + const theme = (0, global_style_1.themeStyle)(this.props.themeId); + const rootStyle = this.props.visible ? theme.rootStyle : theme.hiddenRootStyle; + const title = parent ? parent.title : null; + if (!parent) { + return (React.createElement(react_native_1.View, { style: rootStyle }, + React.createElement(ScreenHeader_1.ScreenHeader, { title: title, showSideMenuButton: true, showBackButton: false }))); + } + const icon = Folder_1.default.unserializeIcon(parent.icon); + const iconString = icon ? `${icon.emoji} ` : ''; + let buttonFolderId = this.props.selectedFolderId !== Folder_1.default.conflictFolderId() ? this.props.selectedFolderId : null; + if (!buttonFolderId) { buttonFolderId = this.props.activeFolderId; } + const addFolderNoteButtons = !!buttonFolderId; + const makeActionButtonComp = () => { + if ((this.props.notesParentType === 'Folder' && (0, trash_1.itemIsInTrash)(parent)) || !Folder_1.default.atLeastOneRealFolderExists(this.props.folders)) { return null; } + if (addFolderNoteButtons && this.props.folders.length > 0) { + const buttons = []; + buttons.push({ + label: (0, locale_1._)('New to-do'), + onPress: async () => { + const isTodo = true; + void this.newNoteNavigate(buttonFolderId, isTodo); + }, + color: '#9b59b6', + icon: 'checkbox-outline', + }); + buttons.push({ + label: (0, locale_1._)('New note'), + onPress: async () => { + const isTodo = false; + void this.newNoteNavigate(buttonFolderId, isTodo); + }, + color: '#9b59b6', + icon: 'document', + }); + return React.createElement(FloatingActionButton_1.default, { buttons: buttons, dispatch: this.props.dispatch }); + } + return null; + }; + const actionButtonComp = this.props.noteSelectionEnabled || !this.props.visible ? null : makeActionButtonComp(); + // Ensure that screen readers can't focus the notes list when it isn't visible. + const accessibilityHidden = !this.props.visible; + return (React.createElement(AccessibleView_1.default, { style: rootStyle, inert: accessibilityHidden }, + React.createElement(ScreenHeader_1.ScreenHeader, { title: iconString + title, showBackButton: false, sortButton_press: this.sortButton_press, folderPickerOptions: this.folderPickerOptions(), showSearchButton: true, showSideMenuButton: true }), + React.createElement(NoteList_1.default, null), + actionButtonComp)); + } +} +const NotesScreenWrapper = props => { + const dialogManager = (0, react_1.useContext)(DialogManager_1.DialogContext); + return React.createElement(NotesScreenComponent, { ...props, dialogManager: dialogManager }); +}; +const NotesScreen = (0, react_redux_1.connect)((state) => { + return { + folders: state.folders, + tags: state.tags, + activeFolderId: state.settings.activeFolderId, + selectedFolderId: state.selectedFolderId, + selectedNoteIds: state.selectedNoteIds, + selectedTagId: state.selectedTagId, + selectedSmartFilterId: state.selectedSmartFilterId, + notesParentType: state.notesParentType, + notes: state.notes, + notesSource: state.notesSource, + uncompletedTodosOnTop: state.settings.uncompletedTodosOnTop, + showCompletedTodos: state.settings.showCompletedTodos, + themeId: state.settings.theme, + noteSelectionEnabled: state.noteSelectionEnabled, + notesOrder: reducer_1.stateUtils.notesOrder(state.settings), + }; +})(NotesScreenWrapper); +exports.default = NotesScreen; +// # sourceMappingURL=Notes.js.map From b7a652fb71702894085e4832fd9ebe8bf327bde9 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Mon, 7 Apr 2025 20:20:21 +0100 Subject: [PATCH 138/158] iOS 13.3.3 --- .../ios/Joplin.xcodeproj/project.pbxproj | 16 ++++++++-------- readme/about/changelog/ios.md | 13 +++++++++++++ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/packages/app-mobile/ios/Joplin.xcodeproj/project.pbxproj b/packages/app-mobile/ios/Joplin.xcodeproj/project.pbxproj index 1c687598fc..d5148f3dad 100644 --- a/packages/app-mobile/ios/Joplin.xcodeproj/project.pbxproj +++ b/packages/app-mobile/ios/Joplin.xcodeproj/project.pbxproj @@ -535,13 +535,13 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Joplin/Joplin.entitlements; - CURRENT_PROJECT_VERSION = 135; + CURRENT_PROJECT_VERSION = 136; DEVELOPMENT_TEAM = A9BXAFS6CT; ENABLE_BITCODE = NO; INFOPLIST_FILE = Joplin/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.4; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MARKETING_VERSION = 13.3.2; + MARKETING_VERSION = 13.3.3; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", @@ -567,12 +567,12 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Joplin/Joplin.entitlements; - CURRENT_PROJECT_VERSION = 135; + CURRENT_PROJECT_VERSION = 136; DEVELOPMENT_TEAM = A9BXAFS6CT; INFOPLIST_FILE = Joplin/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.4; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MARKETING_VERSION = 13.3.2; + MARKETING_VERSION = 13.3.3; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", @@ -758,14 +758,14 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 135; + CURRENT_PROJECT_VERSION = 136; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = A9BXAFS6CT; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = ShareExtension/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.4; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 13.3.2; + MARKETING_VERSION = 13.3.3; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; OTHER_LDFLAGS = ( @@ -797,14 +797,14 @@ CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 135; + CURRENT_PROJECT_VERSION = 136; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = A9BXAFS6CT; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = ShareExtension/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.4; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 13.3.2; + MARKETING_VERSION = 13.3.3; MTL_FAST_MATH = YES; OTHER_LDFLAGS = ( "$(inherited)", diff --git a/readme/about/changelog/ios.md b/readme/about/changelog/ios.md index e433bc8bb4..f21c7d3735 100644 --- a/readme/about/changelog/ios.md +++ b/readme/about/changelog/ios.md @@ -1,5 +1,18 @@ # Joplin iOS Changelog +## [ios-v13.3.3](https://github.com/laurent22/joplin/releases/tag/ios-v13.3.3) - 2025-04-07T19:20:10Z + +- New: Add "swap line up" and "swap line down" to toolbar extended options (#12053 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- New: Plugins: Add command to hide the plugin panel viewer (#12018 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Improved: Explain why items could not be decrypted (#12048) (#11872 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Improved: Implement new note menu redesign (#11780 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Improved: Remove slider component module and replace integer settings with new validated component (#11822) (#10883 by [@mrjo118](https://github.com/mrjo118)) +- Improved: Update react-native-quick-crypto (#12067 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Fixed: Changing the type of one list changes it for all the lists (#11986) (#11971 by [@Paramesh-T-S](https://github.com/Paramesh-T-S)) +- Fixed: Fix Markdown toolbar partially covered by keyboard on some iOS devices (#12027) (#11711 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Fixed: Fix cursor moves to incorrect position when revising TextInput value (#11821) (#11820 by [@mrjo118](https://github.com/mrjo118)) +- Fixed: Restoring a note which was in a deleted notebook (#12016) (#11934) + ## [ios-v13.3.2](https://github.com/laurent22/joplin/releases/tag/ios-v13.3.2) - 2025-03-16T11:47:05Z - New: Add setting migration for ocr.enabled (ab86b95) From 7a6a4e118a49c2997ab3a57f605811eec7c8a72c Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Mon, 7 Apr 2025 20:34:36 +0100 Subject: [PATCH 139/158] Android 3.3.5 --- packages/app-mobile/android/app/build.gradle | 4 ++-- packages/generator-joplin/package.json | 2 +- readme/about/changelog/android.md | 17 +++++++++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/packages/app-mobile/android/app/build.gradle b/packages/app-mobile/android/app/build.gradle index 38d41b4968..42690899f8 100644 --- a/packages/app-mobile/android/app/build.gradle +++ b/packages/app-mobile/android/app/build.gradle @@ -86,8 +86,8 @@ android { applicationId "net.cozic.joplin" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 2097767 - versionName "3.3.4" + versionCode 2097768 + versionName "3.3.5" ndk { abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64" } diff --git a/packages/generator-joplin/package.json b/packages/generator-joplin/package.json index 4a230ef809..a7fe299382 100644 --- a/packages/generator-joplin/package.json +++ b/packages/generator-joplin/package.json @@ -38,4 +38,4 @@ "repository": "https://github.com/laurent22/generator-joplin", "license": "AGPL-3.0-or-later", "private": true -} \ No newline at end of file +} diff --git a/readme/about/changelog/android.md b/readme/about/changelog/android.md index 383d067be6..679c08d3c2 100644 --- a/readme/about/changelog/android.md +++ b/readme/about/changelog/android.md @@ -1,5 +1,22 @@ # Joplin Android Changelog +## [android-v3.3.5](https://github.com/laurent22/joplin/releases/tag/android-v3.3.5) (Pre-release) - 2025-04-07T19:31:26Z + +- New: Add "swap line up" and "swap line down" to toolbar extended options (#12053 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- New: Plugins: Add command to hide the plugin panel viewer (#12018 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Improved: Explain why items could not be decrypted (#12048) (#11872 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Improved: Implement new note menu redesign (#11780 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Improved: Remove slider component module and replace integer settings with new validated component (#11822) (#10883 by [@mrjo118](https://github.com/mrjo118)) +- Improved: Update react-native-quick-crypto (#12067 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Improved: Voice typing: Default to a larger model (#12009 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Improved: Voice typing: Disable "Download update" button while downloading an updated model (#12015 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Improved: Voice typing: Improve transcription at the end of paragraphs (#12013 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Improved: Voice typing: Performance: Disable preview generation logic (#12008 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Fixed: Changing the type of one list changes it for all the lists (#11986) (#11971 by [@Paramesh-T-S](https://github.com/Paramesh-T-S)) +- Fixed: Fix cursor moves to incorrect position when revising TextInput value (#11821) (#11820 by [@mrjo118](https://github.com/mrjo118)) +- Fixed: Restoring a note which was in a deleted notebook (#12016) (#11934) +- Fixed: Voice typing: Fix incorrectly-calculated audio length (#12012 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) + ## [android-v3.3.4](https://github.com/laurent22/joplin/releases/tag/android-v3.3.4) (Pre-release) - 2025-03-21T18:07:00Z - Improved: Voice typing: Improve processing with larger models (#11983 by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) From bb50ad7c28e0c6d433475a431f599ac1336ec619 Mon Sep 17 00:00:00 2001 From: Joplin Bot Date: Tue, 8 Apr 2025 02:08:13 +0000 Subject: [PATCH 140/158] Doc: Auto-update documentation Auto-updated using release-website.sh --- packages/tools/postPreReleasesToForum.json | 5 ++++- readme/about/changelog/desktop.md | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/tools/postPreReleasesToForum.json b/packages/tools/postPreReleasesToForum.json index a8f5cca92a..f35a75b7ee 100644 --- a/packages/tools/postPreReleasesToForum.json +++ b/packages/tools/postPreReleasesToForum.json @@ -139,6 +139,9 @@ "v3.3.3": true, "android-v3.3.3": true, "ios-v13.3.2": true, - "android-v3.3.4": true + "android-v3.3.4": true, + "v3.3.4": true, + "android-v3.3.5": true, + "ios-v13.3.3": true } } \ No newline at end of file diff --git a/readme/about/changelog/desktop.md b/readme/about/changelog/desktop.md index 0320fa6bb4..4965bccfd7 100644 --- a/readme/about/changelog/desktop.md +++ b/readme/about/changelog/desktop.md @@ -1,5 +1,24 @@ # Joplin Desktop Changelog +## [v3.3.4](https://github.com/laurent22/joplin/releases/tag/v3.3.4) (Pre-release) - 2025-04-07T20:23:35Z + +- New: Plugins: Add `setting.globalValues` and deprecate `setting.globalValue` ([ef51386](https://github.com/laurent22/joplin/commit/ef51386)) +- New: Rich Text Editor: Add setting to allow disabling auto-format ([#12022](https://github.com/laurent22/joplin/issues/12022) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Improved: Accessibility: Add screen reader announcements when toggling the note list and/or sidebar ([#11776](https://github.com/laurent22/joplin/issues/11776)) ([#11741](https://github.com/laurent22/joplin/issues/11741) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Improved: Accessibility: Remove redundant accessibility information from sidebar notebooks ([#12020](https://github.com/laurent22/joplin/issues/12020)) ([#11903](https://github.com/laurent22/joplin/issues/11903) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Improved: Explain why items could not be decrypted ([#12048](https://github.com/laurent22/joplin/issues/12048)) ([#11872](https://github.com/laurent22/joplin/issues/11872) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Improved: Improve notification accessibility ([#11752](https://github.com/laurent22/joplin/issues/11752) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Improved: Increase the likelihood of text generation from image recognition ([#12028](https://github.com/laurent22/joplin/issues/12028)) ([#11608](https://github.com/laurent22/joplin/issues/11608) by [@pedr](https://github.com/pedr)) +- Improved: Multiple instances: Secure local server ([#11999](https://github.com/laurent22/joplin/issues/11999)) ([#11992](https://github.com/laurent22/joplin/issues/11992)) +- Improved: Update Electron to v35.1.4 ([#12068](https://github.com/laurent22/joplin/issues/12068) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) +- Fixed: A note scrolls to top if reached by following a link to a section ([#12038](https://github.com/laurent22/joplin/issues/12038)) ([#9291](https://github.com/laurent22/joplin/issues/9291) by [@Schmeilen](https://github.com/Schmeilen)) +- Fixed: App without a profile directory cannot start ([#12021](https://github.com/laurent22/joplin/issues/12021)) +- Fixed: Changing the type of one list changes it for all the lists ([#11986](https://github.com/laurent22/joplin/issues/11986)) ([#11971](https://github.com/laurent22/joplin/issues/11971) by [@Paramesh-T-S](https://github.com/Paramesh-T-S)) +- Fixed: Joplin became unusably slow on MacOS due to incorrect detection of architecture ([#11989](https://github.com/laurent22/joplin/issues/11989)) +- Fixed: Regression: Restarting app is broken ([#11975](https://github.com/laurent22/joplin/issues/11975)) +- Fixed: Restoring a note which was in a deleted notebook ([#12016](https://github.com/laurent22/joplin/issues/12016)) ([#11934](https://github.com/laurent22/joplin/issues/11934)) +- Fixed: Rich Text Editor: Fix "Remove color" button doesn't work ([#12052](https://github.com/laurent22/joplin/issues/12052) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) + ## [v3.3.3](https://github.com/laurent22/joplin/releases/tag/v3.3.3) (Pre-release) - 2025-03-16T11:52:33Z - New: Accessibility: Add a menu item that moves focus to the note viewer ([#11967](https://github.com/laurent22/joplin/issues/11967) by [@personalizedrefrigerator](https://github.com/personalizedrefrigerator)) From 5fb9d216fc3e654bdd5707f9a26cb8d4aeb152f6 Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Tue, 8 Apr 2025 12:36:30 -0700 Subject: [PATCH 141/158] Desktop: Update Freehand Drawing to v2.16.1 (#12073) --- packages/default-plugins/pluginRepositories.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/default-plugins/pluginRepositories.json b/packages/default-plugins/pluginRepositories.json index 22e8454b7c..c9217353b9 100644 --- a/packages/default-plugins/pluginRepositories.json +++ b/packages/default-plugins/pluginRepositories.json @@ -7,6 +7,6 @@ "io.github.personalizedrefrigerator.js-draw": { "cloneUrl": "https://github.com/personalizedrefrigerator/joplin-plugin-freehand-drawing.git", "branch": "main", - "commit": "94a78496fac0b3bc7b0f6a896a982480adad3994" + "commit": "3153fb0fc8dab23426accdcd4319b0654d364d2b" } } From 587db433a82bdd96a6e78a9286f4bb5e473b9233 Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Tue, 8 Apr 2025 13:12:36 -0700 Subject: [PATCH 142/158] Desktop: Fixes #12042: Fix toggling lists in the Rich Text Editor (#12071) --- Assets/TinyMCE/JoplinLists/src/main/ts/actions/ToggleList.ts | 2 +- .../gui/NoteEditor/NoteBody/TinyMCE/plugins/lists.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Assets/TinyMCE/JoplinLists/src/main/ts/actions/ToggleList.ts b/Assets/TinyMCE/JoplinLists/src/main/ts/actions/ToggleList.ts index d97845a413..60d97fbff4 100644 --- a/Assets/TinyMCE/JoplinLists/src/main/ts/actions/ToggleList.ts +++ b/Assets/TinyMCE/JoplinLists/src/main/ts/actions/ToggleList.ts @@ -48,7 +48,7 @@ const updateListWithDetails = function (dom, el, detail) { }; const removeStyles = (dom, element: HTMLElement, styles: string[]) => { - Tools.each(styles, (style) => dom.setStyle(element, { [style]: '' })); + Tools.each(styles, (style) => dom.setStyle(element, style, '')); }; const getEndPointNode = function (editor, rng, start, root) { diff --git a/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/plugins/lists.js b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/plugins/lists.js index 2d3a4c98e2..396639100f 100644 --- a/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/plugins/lists.js +++ b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/plugins/lists.js @@ -1576,7 +1576,7 @@ var removeStyles = function (dom, element, styles) { Tools.each(styles, function (style) { var _a; - return dom.setStyle(element, (_a = {}, _a[style] = '', _a)); + return dom.setStyle(element, style, ''); }); }; var getEndPointNode = function (editor, rng, start, root) { From 52ffd46a6abc2c233cb49d968baa469ab262d570 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Wed, 9 Apr 2025 08:14:17 +0100 Subject: [PATCH 143/158] Desktop: Resolves #12006: Add a new menu item to launch the primary instance from the secondary one --- .eslintignore | 3 ++- .gitignore | 3 ++- packages/app-desktop/ElectronAppWrapper.ts | 2 +- packages/app-desktop/bridge.ts | 8 +++++++- packages/app-desktop/commands/index.ts | 6 ++++-- .../commands/openPrimaryAppInstance.ts | 19 +++++++++++++++++++ ...nstance.ts => openSecondaryAppInstance.ts} | 6 +++--- packages/app-desktop/gui/MenuBar.tsx | 6 ++++-- packages/app-desktop/gui/menuCommandNames.ts | 3 ++- packages/utils/execCommand.ts | 12 ++++++++---- readme/apps/multiple_instances.md | 18 +++++++++++++++--- 11 files changed, 67 insertions(+), 19 deletions(-) create mode 100644 packages/app-desktop/commands/openPrimaryAppInstance.ts rename packages/app-desktop/commands/{newAppInstance.ts => openSecondaryAppInstance.ts} (75%) diff --git a/.eslintignore b/.eslintignore index 351518d5bb..24a0bd1a93 100644 --- a/.eslintignore +++ b/.eslintignore @@ -158,9 +158,10 @@ packages/app-desktop/commands/exportFolders.js packages/app-desktop/commands/exportNotes.js packages/app-desktop/commands/focusElement.js packages/app-desktop/commands/index.js -packages/app-desktop/commands/newAppInstance.js packages/app-desktop/commands/openNoteInNewWindow.js +packages/app-desktop/commands/openPrimaryAppInstance.js packages/app-desktop/commands/openProfileDirectory.js +packages/app-desktop/commands/openSecondaryAppInstance.js packages/app-desktop/commands/replaceMisspelling.js packages/app-desktop/commands/restoreNoteRevision.js packages/app-desktop/commands/startExternalEditing.js diff --git a/.gitignore b/.gitignore index 6a4604fb7b..ab0fe5484a 100644 --- a/.gitignore +++ b/.gitignore @@ -133,9 +133,10 @@ packages/app-desktop/commands/exportFolders.js packages/app-desktop/commands/exportNotes.js packages/app-desktop/commands/focusElement.js packages/app-desktop/commands/index.js -packages/app-desktop/commands/newAppInstance.js packages/app-desktop/commands/openNoteInNewWindow.js +packages/app-desktop/commands/openPrimaryAppInstance.js packages/app-desktop/commands/openProfileDirectory.js +packages/app-desktop/commands/openSecondaryAppInstance.js packages/app-desktop/commands/replaceMisspelling.js packages/app-desktop/commands/restoreNoteRevision.js packages/app-desktop/commands/startExternalEditing.js diff --git a/packages/app-desktop/ElectronAppWrapper.ts b/packages/app-desktop/ElectronAppWrapper.ts index 53c6aa7bf6..078ed82d29 100644 --- a/packages/app-desktop/ElectronAppWrapper.ts +++ b/packages/app-desktop/ElectronAppWrapper.ts @@ -655,7 +655,7 @@ export default class ElectronAppWrapper { // might still be there for a short while. await msleep(1000); this.ipcLogger_.warn('restartAltInstance: App is gone - restarting it'); - void bridge().launchNewAppInstance(this.env()); + void bridge().launchAltAppInstance(this.env()); } else { this.ipcLogger_.warn('restartAltInstance: Could not restart calling app because it was still open'); } diff --git a/packages/app-desktop/bridge.ts b/packages/app-desktop/bridge.ts index 9d4302673e..ade7e0785c 100644 --- a/packages/app-desktop/bridge.ts +++ b/packages/app-desktop/bridge.ts @@ -523,12 +523,18 @@ export class Bridge { } } - public async launchNewAppInstance(env: string) { + public async launchAltAppInstance(env: string) { const cmd = this.appLaunchCommand(env, 'alt1'); await execCommand([cmd.execPath].concat(cmd.args), { detached: true }); } + public async launchMainAppInstance(env: string) { + const cmd = this.appLaunchCommand(env, ''); + + await execCommand([cmd.execPath].concat(cmd.args), { detached: true }); + } + public async restart() { // Note that in this case we are not sending the "appClose" event // to notify services and component that the app is about to close diff --git a/packages/app-desktop/commands/index.ts b/packages/app-desktop/commands/index.ts index eadafe80eb..3161eceedd 100644 --- a/packages/app-desktop/commands/index.ts +++ b/packages/app-desktop/commands/index.ts @@ -6,7 +6,8 @@ import * as exportDeletionLog from './exportDeletionLog'; import * as exportFolders from './exportFolders'; import * as exportNotes from './exportNotes'; import * as focusElement from './focusElement'; -import * as newAppInstance from './newAppInstance'; +import * as openSecondaryAppInstance from './openSecondaryAppInstance'; +import * as openPrimaryAppInstance from './openPrimaryAppInstance'; import * as openNoteInNewWindow from './openNoteInNewWindow'; import * as openProfileDirectory from './openProfileDirectory'; import * as replaceMisspelling from './replaceMisspelling'; @@ -29,7 +30,8 @@ const index: any[] = [ exportFolders, exportNotes, focusElement, - newAppInstance, + openSecondaryAppInstance, + openPrimaryAppInstance, openNoteInNewWindow, openProfileDirectory, replaceMisspelling, diff --git a/packages/app-desktop/commands/openPrimaryAppInstance.ts b/packages/app-desktop/commands/openPrimaryAppInstance.ts new file mode 100644 index 0000000000..2baf8bd761 --- /dev/null +++ b/packages/app-desktop/commands/openPrimaryAppInstance.ts @@ -0,0 +1,19 @@ +import { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/services/CommandService'; +import { _ } from '@joplin/lib/locale'; +import bridge from '../services/bridge'; +import Setting from '@joplin/lib/models/Setting'; + +export const declaration: CommandDeclaration = { + name: 'openPrimaryAppInstance', + label: () => _('Open primary app instance...'), +}; + +export const runtime = (): CommandRuntime => { + return { + execute: async (_context: CommandContext) => { + await bridge().launchMainAppInstance(Setting.value('env')); + }, + + enabledCondition: 'isAltInstance', + }; +}; diff --git a/packages/app-desktop/commands/newAppInstance.ts b/packages/app-desktop/commands/openSecondaryAppInstance.ts similarity index 75% rename from packages/app-desktop/commands/newAppInstance.ts rename to packages/app-desktop/commands/openSecondaryAppInstance.ts index 5443a64c8e..b77a0078d8 100644 --- a/packages/app-desktop/commands/newAppInstance.ts +++ b/packages/app-desktop/commands/openSecondaryAppInstance.ts @@ -4,14 +4,14 @@ import bridge from '../services/bridge'; import Setting from '@joplin/lib/models/Setting'; export const declaration: CommandDeclaration = { - name: 'newAppInstance', - label: () => _('New application instance...'), + name: 'openSecondaryAppInstance', + label: () => _('Open secondary app instance...'), }; export const runtime = (): CommandRuntime => { return { execute: async (_context: CommandContext) => { - await bridge().launchNewAppInstance(Setting.value('env')); + await bridge().launchAltAppInstance(Setting.value('env')); }, enabledCondition: '!isAltInstance', diff --git a/packages/app-desktop/gui/MenuBar.tsx b/packages/app-desktop/gui/MenuBar.tsx index 977a0a2c23..34d60c6a40 100644 --- a/packages/app-desktop/gui/MenuBar.tsx +++ b/packages/app-desktop/gui/MenuBar.tsx @@ -555,7 +555,8 @@ function useMenu(props: Props) { const newFolderItem = menuItemDic.newFolder; const newSubFolderItem = menuItemDic.newSubFolder; const printItem = menuItemDic.print; - const newAppInstance = menuItemDic.newAppInstance; + const openSecondaryAppInstance = menuItemDic.openSecondaryAppInstance; + const openPrimaryAppInstance = menuItemDic.openPrimaryAppInstance; const switchProfileItem = { label: _('Switch profile'), submenu: switchProfileMenuItems, @@ -723,7 +724,8 @@ function useMenu(props: Props) { type: 'separator', }, switchProfileItem, - newAppInstance, + openSecondaryAppInstance, + openPrimaryAppInstance, ], }; diff --git a/packages/app-desktop/gui/menuCommandNames.ts b/packages/app-desktop/gui/menuCommandNames.ts index e04b001ed0..8602ba8e22 100644 --- a/packages/app-desktop/gui/menuCommandNames.ts +++ b/packages/app-desktop/gui/menuCommandNames.ts @@ -48,7 +48,8 @@ export default function() { 'toggleTabMovesFocus', 'editor.deleteLine', 'editor.duplicateLine', - 'newAppInstance', + 'openSecondaryAppInstance', + 'openPrimaryAppInstance', // We cannot put the undo/redo commands in the menu because they are // editor-specific commands. If we put them there it will break the // undo/redo in regular text fields. diff --git a/packages/utils/execCommand.ts b/packages/utils/execCommand.ts index 458e5d7234..694f8aa3e9 100644 --- a/packages/utils/execCommand.ts +++ b/packages/utils/execCommand.ts @@ -14,13 +14,17 @@ interface ExecCommandOptions { } export default async (command: string | string[], options: ExecCommandOptions | null = null): Promise => { + const detached = options ? options.detached : false; + + // When launching a detached executable it's better not to pipe the stdout and stderr, as this + // will most likely cause an EPIPE error. + options = { - showInput: true, - showStdout: true, - showStderr: true, + showInput: !detached, + showStdout: !detached, + showStderr: !detached, quiet: false, env: {}, - detached: false, ...options, }; diff --git a/readme/apps/multiple_instances.md b/readme/apps/multiple_instances.md index e687a9a2fb..5c046e526e 100644 --- a/readme/apps/multiple_instances.md +++ b/readme/apps/multiple_instances.md @@ -17,9 +17,9 @@ Each instance is completely isolated, operating as a standalone version of Jopli Currently, Joplin supports up to **two running instances**: -1. **Main Instance**: The primary application instance, with full access to all Joplin features. +1. **Primary Instance**: The primary application instance, with full access to all Joplin features. -2. **Alternative Instance**: A secondary application instance that functions independently. However, it does not support the **Web Clipper service**, which can only run in the main instance. +2. **Secondary Instance**: A secondary application instance that functions independently. However, it does not support the **Web Clipper service**, which can only run in the main instance. ## How to Launch a Second Instance @@ -29,8 +29,20 @@ To start a second instance of Joplin: 2. Navigate to the menu and select: -**File** => **New application instance...** +**File** => **Open secondary app instance...** 3. A new instance of Joplin will open with its own profile. This second instance operates independently, allowing you to customise it as needed. + +## Caveats + +### Launching the primary instance when the secondary instance is active + +Technically, the secondary instance is still initiated from the same executable file, which might confuse the operating system. Most operating systems reasonably assume that if you attempt to launch a GUI application that is already running, your intention is to bring that application into focus. + +In practical terms, this means the following: + +If you close the primary instance while the secondary instance remains open, and then attempt to reopen the primary instance—for instance, by clicking on its icon—the operating system will most likely refocus on the secondary instance instead of launching the primary one. To address this issue, the secondary instance includes a menu item labelled **Open primary app instance...**. Clicking on this option will explicitly launch the primary instance. + +In the same way, the secondary instance should generally be launched only from the first one, using the **Open secondary app instance...** menu item. From a3be7b52222778d95792f17c6624acd9e2f8318c Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Wed, 9 Apr 2025 06:39:39 -0700 Subject: [PATCH 144/158] Desktop: Resolves #12058: Fix pasting images in the Rich Text Editor (#12079) --- .../NoteBody/TinyMCE/utils/useContextMenu.ts | 2 +- .../gui/NoteEditor/utils/contextMenu.ts | 19 +++++-------------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.ts b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.ts index 1cb626cf2a..f772cbdf38 100644 --- a/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.ts +++ b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.ts @@ -60,7 +60,7 @@ export default function(editor: Editor, plugins: PluginStates, dispatch: Dispatc useEffect(() => { if (!editor) return () => {}; - const contextMenuItems = menuItems(dispatch, htmlToMd, mdToHtml); + const contextMenuItems = menuItems(dispatch); const targetWindow = bridge().activeWindow(); const makeMainMenuItems = (element: Element) => { diff --git a/packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts b/packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts index 04e342cd5d..195f5bddfe 100644 --- a/packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts +++ b/packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts @@ -8,13 +8,11 @@ const MenuItem = bridge().MenuItem; import Resource, { resourceOcrStatusToString } from '@joplin/lib/models/Resource'; import BaseItem from '@joplin/lib/models/BaseItem'; import BaseModel, { ModelType } from '@joplin/lib/BaseModel'; -import { processPastedHtml } from './resourceHandling'; import { NoteEntity, ResourceEntity, ResourceOcrStatus } from '@joplin/lib/services/database/types'; import { TinyMceEditorEvents } from '../NoteBody/TinyMCE/utils/types'; import { itemIsReadOnlySync, ItemSlice } from '@joplin/lib/models/utils/readOnly'; import Setting from '@joplin/lib/models/Setting'; import ItemChange from '@joplin/lib/models/ItemChange'; -import { HtmlToMarkdownHandler, MarkupToHtmlHandler } from './types'; import shim from '@joplin/lib/shim'; import { openFileWithExternalEditor } from '@joplin/lib/services/ExternalEditWatcher/utils'; const fs = require('fs-extra'); @@ -81,7 +79,7 @@ export async function openItemById(itemId: string, dispatch: Function, hash = '' } // eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied -export function menuItems(dispatch: Function, htmlToMd: HtmlToMarkdownHandler, mdToHtml: MarkupToHtmlHandler): ContextMenuItems { +export function menuItems(dispatch: Function): ContextMenuItems { return { open: { label: _('Open...'), @@ -195,17 +193,10 @@ export function menuItems(dispatch: Function, htmlToMd: HtmlToMarkdownHandler, m }, paste: { label: _('Paste'), - onAction: async (options: ContextMenuOptions) => { - const pastedHtml = clipboard.readHTML(); - let content = pastedHtml ? pastedHtml : clipboard.readText(); - - if (pastedHtml) { - content = await processPastedHtml(pastedHtml, htmlToMd, mdToHtml); - } - - options.insertContent(content); + onAction: async (_options: ContextMenuOptions) => { + bridge().activeWindow().webContents.paste(); }, - isActive: (_itemType: ContextMenuItemType, options: ContextMenuOptions) => !options.isReadOnly && (!!clipboard.readText() || !!clipboard.readHTML()), + isActive: (_itemType: ContextMenuItemType, options: ContextMenuOptions) => !options.isReadOnly && clipboard.availableFormats().length > 0, }, pasteAsText: { label: _('Paste as text'), @@ -228,7 +219,7 @@ export function menuItems(dispatch: Function, htmlToMd: HtmlToMarkdownHandler, m export default async function contextMenu(options: ContextMenuOptions, dispatch: Function) { const menu = new Menu(); - const items = menuItems(dispatch, options.htmlToMd, options.mdToHtml); + const items = menuItems(dispatch); if (!('readyOnly' in options)) options.isReadOnly = true; for (const itemKey in items) { From 600000a59a8cdeff4fab460e4abb76e73249411e Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Wed, 9 Apr 2025 06:40:11 -0700 Subject: [PATCH 145/158] Desktop: Fixes #9588: Rich Text Editor: Fix keyboard and plugin-opened context menus sometimes not displayed or have incorrect content (#12076) --- .../NoteBody/TinyMCE/utils/useContextMenu.ts | 82 ++++++++++--------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.ts b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.ts index f772cbdf38..ea100e25aa 100644 --- a/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.ts +++ b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.ts @@ -7,8 +7,7 @@ import { ContextMenuOptions, ContextMenuItemType } from '../../../utils/contextM import { menuItems } from '../../../utils/contextMenu'; import MenuUtils from '@joplin/lib/services/commands/MenuUtils'; import CommandService from '@joplin/lib/services/CommandService'; -import Setting from '@joplin/lib/models/Setting'; -import type { Event as ElectronEvent, MenuItemConstructorOptions } from 'electron'; +import type { ContextMenuParams, Event as ElectronEvent, MenuItemConstructorOptions } from 'electron'; import Resource from '@joplin/lib/models/Resource'; import { TinyMceEditorEvents } from './types'; @@ -23,33 +22,6 @@ const Menu = bridge().Menu; const MenuItem = bridge().MenuItem; const menuUtils = new MenuUtils(CommandService.instance()); -// x and y are the absolute coordinates, as returned by the context-menu event -// handler on the webContent. This function will return null if the point is -// not within the TinyMCE editor. -function contextMenuElement(editor: Editor, x: number, y: number) { - if (!editor || !editor.getDoc()) return null; - - const containerDoc = editor.getContainer().ownerDocument; - const iframes = containerDoc.getElementsByClassName('tox-edit-area__iframe'); - if (!iframes.length) return null; - - const zoom = Setting.value('windowContentZoomFactor') / 100; - const xScreen = x / zoom; - const yScreen = y / zoom; - - // We use .elementFromPoint to handle the case where a dialog is covering - // part of the editor. - const targetElement = containerDoc.elementFromPoint(xScreen, yScreen); - if (targetElement !== iframes[0]) { - return null; - } - - const iframeRect = iframes[0].getBoundingClientRect(); - const relativeX = xScreen - iframeRect.left; - const relativeY = yScreen - iframeRect.top; - return editor.getDoc().elementFromPoint(relativeX, relativeY); -} - interface ContextMenuActionOptions { current: ContextMenuOptions; } @@ -130,13 +102,7 @@ export default function(editor: Editor, plugins: PluginStates, dispatch: Dispatc return []; }; - // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied - function onContextMenu(event: ElectronEvent, params: any) { - const element = contextMenuElement(editor, params.x, params.y); - if (!element) return; - - event.preventDefault(); - + const showContextMenu = (element: HTMLElement, misspelledWord: string|null, dictionarySuggestions: string[]) => { const menu = new Menu(); const menuItems: MenuItemType[] = []; const toMenuItems = (specs: MenuItemConstructorOptions[]) => { @@ -145,7 +111,7 @@ export default function(editor: Editor, plugins: PluginStates, dispatch: Dispatc menuItems.push(...makeEditableMenuItems(element)); menuItems.push(...makeMainMenuItems(element)); - const spellCheckerMenuItems = SpellCheckerService.instance().contextMenuItems(params.misspelledWord, params.dictionarySuggestions); + const spellCheckerMenuItems = SpellCheckerService.instance().contextMenuItems(misspelledWord, dictionarySuggestions); menuItems.push( ...toMenuItems(spellCheckerMenuItems), ); @@ -157,13 +123,49 @@ export default function(editor: Editor, plugins: PluginStates, dispatch: Dispatc menu.append(item); } menu.popup({ window: targetWindow }); - } + }; - targetWindow.webContents.prependListener('context-menu', onContextMenu); + let lastTarget: EventTarget|null = null; + const onElectronContextMenu = (event: ElectronEvent, params: ContextMenuParams) => { + if (!lastTarget) return; + const element = lastTarget as HTMLElement; + lastTarget = null; + + event.preventDefault(); + showContextMenu(element, params.misspelledWord, params.dictionarySuggestions); + }; + + const onBrowserContextMenu = (event: PointerEvent) => { + const isKeyboard = event.buttons === 0; + if (isKeyboard) { + // Context menu events from the keyboard seem to always use as the + // event target. Since which context menu is displayed depends on what the + // target is, using event.target for keyboard-triggered contextmenu events + // would prevent keyboard-only users from accessing certain functionality. + // To fix this, use the selection instead. + lastTarget = editor.selection.getNode(); + } else { + lastTarget = event.target; + } + + // Plugins in the Rich Text Editor (e.g. the mermaid renderer) can sometimes + // create custom right-click events. These don't trigger the Electron 'context-menu' + // event. As such, the context menu must be shown manually. + const isFromPlugin = !event.isTrusted; + if (isFromPlugin) { + event.preventDefault(); + showContextMenu(lastTarget as HTMLElement, null, []); + lastTarget = null; + } + }; + + targetWindow.webContents.prependListener('context-menu', onElectronContextMenu); + editor.on('contextmenu', onBrowserContextMenu); return () => { + editor.off('contextmenu', onBrowserContextMenu); if (!targetWindow.isDestroyed() && targetWindow?.webContents?.off) { - targetWindow.webContents.off('context-menu', onContextMenu); + targetWindow.webContents.off('context-menu', onElectronContextMenu); } }; }, [editor, plugins, dispatch, htmlToMd, mdToHtml, editDialog]); From 418a2c17a5bc4d7bf67541b868239190821f0637 Mon Sep 17 00:00:00 2001 From: Miet Date: Wed, 9 Apr 2025 20:51:17 -0400 Subject: [PATCH 146/158] All: Translation: Update nl_BE.po (#12080) --- packages/tools/locales/nl_BE.po | 2252 ++++++++++++++----------------- 1 file changed, 1020 insertions(+), 1232 deletions(-) diff --git a/packages/tools/locales/nl_BE.po b/packages/tools/locales/nl_BE.po index 2619127492..3b7bcf221e 100644 --- a/packages/tools/locales/nl_BE.po +++ b/packages/tools/locales/nl_BE.po @@ -7,37 +7,39 @@ msgid "" msgstr "" "Project-Id-Version: Joplin-CLI 1.0.0\n" "Report-Msgid-Bugs-To: \n" -"Last-Translator: \n" -"Language-Team: \n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: MietVdh\n" +"Language-Team: Dutch (Belgium) / Nederlands (België)\n" "Language: nl_BE\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 2.4.2\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.6\n" #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:593 msgid "- Camera: to allow taking a picture and attaching it to a note." msgstr "" -"- Camera: om toe te laten een foto te maken en deze als bijlage te voegen " -"bij een notitie." +"- Camera: zodat je een foto kan maken en deze als bijlage kan toevoegen bij " +"een notitie." #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:596 msgid "- Location: to allow attaching geo-location information to a note." -msgstr "- Locatie: om toe te laten geo-locatie toe te voegen aan een notitie." +msgstr "- Locatie: zodat je geo-locatie-informatie kan toevoegen aan een notitie." #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:590 msgid "" "- Storage: to allow attaching files to notes and to enable filesystem " "synchronisation." msgstr "" -"- Opslag: om toe te laten bestanden als bijlage te voegen bij notities en om " -"filesystem-synchronisatie mogelijk te maken." +"- Opslag: zodat je bestanden als bijlage kan toevoegen bij notities en om " +"synchronisatie met het bestandsysteem mogelijk te maken." #: packages/lib/services/KeymapService.ts:321 #: packages/lib/services/KeymapService.ts:327 msgid "\"%s\" is missing the required \"%s\" property." -msgstr "\"%s\" ontbreekt de vereiste \"%s\" eigenschap." +msgstr "\"%s\" mist de vereiste \"%s\" eigenschap." #: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.tsx:267 msgid "(%s)" @@ -45,25 +47,25 @@ msgstr "(%s)" #: packages/lib/services/plugins/api/JoplinViewsDialogs.ts:76 msgid "(In plugin: %s)" -msgstr "" +msgstr "(In plugin: %s)" #: packages/app-mobile/components/side-menu-content.tsx:265 msgid "(level %d)" -msgstr "" +msgstr "(niveau %d)" #: packages/lib/SyncTargetNone.ts:16 msgid "(None)" -msgstr "(None)" +msgstr "(Geen)" #: packages/lib/models/settings/builtInMetadata.ts:29 #: packages/lib/models/settings/builtInMetadata.ts:30 msgid "(wysiwyg: %s)" -msgstr "(wysiwyg: %s)" +msgstr "(wuziwuk: %s)" #: packages/app-mobile/components/screens/Note/Note.tsx:712 #: packages/lib/shim-init-node.ts:264 msgid "(You may disable this prompt in the options)" -msgstr "" +msgstr "(Je kan deze prompt uitschakelen in de opties)" # remarkt that this is the second &B in the menu. #: packages/app-desktop/gui/MenuBar.tsx:1036 @@ -98,9 +100,8 @@ msgid "&View" msgstr "&Weergave" #: packages/app-desktop/gui/MenuBar.tsx:903 -#, fuzzy msgid "&Window" -msgstr "Venster sluiten" +msgstr "&Venster" #: packages/lib/models/settings/builtInMetadata.ts:1483 #: packages/lib/models/settings/builtInMetadata.ts:1735 @@ -111,13 +112,13 @@ msgstr "%d dagen" #: packages/lib/utils/joplinCloud/index.ts:149 #: packages/lib/utils/joplinCloud/index.ts:150 msgid "%d GB" -msgstr "" +msgstr "%d GB" #: packages/lib/utils/joplinCloud/index.ts:145 #: packages/lib/utils/joplinCloud/index.ts:146 #: packages/lib/utils/joplinCloud/index.ts:147 msgid "%d GB storage space" -msgstr "" +msgstr "%d GB opslagruimte" #: packages/lib/models/settings/builtInMetadata.ts:1227 msgid "%d hour" @@ -132,14 +133,13 @@ msgstr "%d uren" #: packages/lib/utils/joplinCloud/index.ts:137 #: packages/lib/utils/joplinCloud/index.ts:138 msgid "%d MB" -msgstr "" +msgstr "%d MB" #: packages/lib/utils/joplinCloud/index.ts:133 #: packages/lib/utils/joplinCloud/index.ts:134 #: packages/lib/utils/joplinCloud/index.ts:135 -#, fuzzy msgid "%d MB per note or attachment" -msgstr "Notitiebijlagen" +msgstr "%d MB per notitie of bijlage" #: packages/lib/models/settings/builtInMetadata.ts:1224 #: packages/lib/models/settings/builtInMetadata.ts:1225 @@ -149,18 +149,16 @@ msgstr "%d minuten" #: packages/app-cli/app/command-rmnote.ts:34 msgid "%d notes match this pattern. Delete them?" -msgstr "%d notities voldoen aan het patroon. Deze verwijderen?" +msgstr "%d notities komen overeen met het patroon. Deze verwijderen?" #: packages/app-cli/app/command-rmnote.ts:40 -#, fuzzy msgid "%d notes will be permanently deleted. Continue?" -msgstr "Deze notities verwijderen?" +msgstr "%d notities zullen permanent verwijderd worden. Doorgaan?" #: packages/app-desktop/gui/NoteListControls/NoteListControls.tsx:228 #: packages/app-desktop/gui/NoteListControls/NoteListControls.tsx:238 -#, fuzzy msgid "%s" -msgstr "(%s)" +msgstr "%s" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/duplicateNote.ts:18 msgid "%s - Copy" @@ -168,7 +166,7 @@ msgstr "%s - Kopieer" #: packages/lib/services/ReportService.ts:192 msgid "%s (%s) could not be uploaded: %s" -msgstr "%s (%s) kon niet opgeladen worden: %s" +msgstr "%s (%s) kon niet worden geüpload: %s" #: packages/app-desktop/gui/MainScreen.tsx:540 #: packages/app-mobile/components/ScreenHeader/WarningBanner.tsx:68 @@ -210,10 +208,12 @@ msgid "" "%s is not optimised for synchronising many small files so your initial " "synchronisation will be slow." msgstr "" +"%s is niet geoptimaliseerd om veel kleine bestanden te synchroniseren. " +"Daarom zal je initiële synchronisatie traag zijn." #: packages/app-mobile/components/plugins/dialogs/PluginPanelViewer.tsx:75 msgid "%s tab opened" -msgstr "" +msgstr "%s tab geopend" #: packages/lib/services/ReportService.ts:286 #: packages/lib/services/ReportService.ts:287 @@ -237,9 +237,8 @@ msgstr "%s: %s" #: packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx:224 #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:265 -#, fuzzy msgid "%s: Missing password." -msgstr "Geef hoofdpaswoord in:" +msgstr "%s: Wachtwoord ontbreekt." #: packages/app-cli/app/command-tag.js:14 msgid "" @@ -249,10 +248,10 @@ msgid "" "list all the tags (use -l for long option)." msgstr "" " kan \"add\", \"remove\", \"list\" of \"notetags\" zijn om een " -"[tag] toe te voegen aan of te verwijderen van een [note], om alle notities " -"geassocieerd met de [tag] op te lijsten of om alle tags van de [note] op te " -"lijsten. Het commando `tag list` kan gebruikt worden om alle tags op te " -"lijsten (gebruik -l voor lange optie)." +"label [tag] toe te voegen aan of te verwijderen van een notitie [note], om " +"alle notities geassocieerd met het label [tag] op te lijsten of om alle " +"labels van de notitie [note] op te lijsten. Het commando `tag list` kan " +"gebruikt worden om alle labels op te lijsten (gebruik -l voor lange optie)." #: packages/app-cli/app/command-todo.js:14 msgid "" @@ -267,9 +266,8 @@ msgstr "" "\"clear\" om terug te wisselen naar een standaard notitie." #: packages/app-desktop/gui/UpdateNotification/UpdateNotification.tsx:62 -#, fuzzy msgid "A new update (%s) is available" -msgstr "Exporteer profiel" +msgstr "Een nieuwe update (%s) is beschikbaar" #: packages/lib/models/settings/builtInMetadata.ts:1253 msgid "A3" @@ -286,7 +284,7 @@ msgstr "A5" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/index.tsx:75 #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginInfoModal.tsx:240 msgid "About" -msgstr "" +msgstr "Over" #: packages/app-desktop/gui/MenuBar.tsx:620 #: packages/app-desktop/gui/MenuBar.tsx:955 @@ -319,32 +317,30 @@ msgid "Accept" msgstr "Aanvaarden" #: packages/app-mobile/components/screens/ShareManager/index.tsx:98 -#, fuzzy msgid "Accepted invitations" -msgstr "Ontvanger heeft de uitnodiging aanvaard" +msgstr "Aanvaarde uitnodigingen" #: packages/lib/WebDavApi.js:451 msgid "Access denied: Please check your username and password" -msgstr "" +msgstr "Toegang geweigerd: Controleer je gebruikersnaam en wachtwoord" #: packages/lib/WebDavApi.js:449 msgid "Access denied: Please re-enter your password and/or username" -msgstr "" +msgstr "Toegang geweigerd: Geef je wachtwoord en/of gebruikersnaam opnieuw in" #: packages/server/src/routes/admin/users.ts:144 msgid "Account" -msgstr "" +msgstr "Account" #: packages/app-desktop/gui/JoplinCloudConfigScreen.tsx:31 #: packages/app-mobile/components/screens/ConfigScreen/JoplinCloudConfig.tsx:48 -#, fuzzy msgid "Account information" -msgstr "Meer informatie" +msgstr "Accountinformatie" #: packages/app-desktop/gui/JoplinCloudConfigScreen.tsx:35 #: packages/app-mobile/components/screens/ConfigScreen/JoplinCloudConfig.tsx:51 msgid "Account type" -msgstr "" +msgstr "Accounttype" #: packages/app-desktop/gui/ResourceScreen.tsx:113 msgid "Action" @@ -352,7 +348,6 @@ msgstr "Actie" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:172 #: packages/app-mobile/components/ScreenHeader/index.tsx:628 -#, fuzzy msgid "Actions" msgstr "Acties" @@ -363,21 +358,20 @@ msgstr "Actief" #: packages/app-desktop/gui/KeymapConfig/utils/getLabel.ts:18 #: packages/app-desktop/gui/MenuBar.tsx:828 msgid "Actual Size" -msgstr "Huidige grootte" +msgstr "Ware Grootte" # Context needed #: packages/app-mobile/components/screens/Note/Note.tsx:1501 msgid "Add body" -msgstr "Body toevoegen" +msgstr "Inhoud toevoegen" #: packages/app-mobile/components/buttons/FloatingActionButton.tsx:91 -#, fuzzy msgid "Add new" -msgstr "Titel toevoegen" +msgstr "Nieuw toevoegen" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/setTags.ts:43 msgid "Add or remove tags:" -msgstr "Tags toevoegen of verwijderen:" +msgstr "Labels toevoegen of verwijderen:" #: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:277 msgid "Add recipient:" @@ -385,7 +379,7 @@ msgstr "Ontvanger toevoegen:" #: packages/app-mobile/components/screens/NoteTagsDialog.tsx:94 msgid "Add tag %s to note" -msgstr "" +msgstr "Label %s toevoegen aan notitie" #: packages/app-mobile/components/screens/Note/Note.tsx:1574 msgid "Add title" @@ -396,46 +390,44 @@ msgid "Add to dictionary" msgstr "Toevoegen aan woordenboek" #: packages/app-mobile/components/CameraView/ScannedBarcodes.tsx:98 -#, fuzzy msgid "Add to note" -msgstr "Titel toevoegen" +msgstr "Toevoegen aan notitie" #: packages/server/src/services/MustacheService.ts:162 #: packages/server/src/services/MustacheService.ts:286 msgid "Admin" -msgstr "" +msgstr "Admin" #: packages/server/src/routes/admin/dashboard.ts:10 msgid "Admin dashboard" -msgstr "" +msgstr "Admin dashboard" #: packages/app-desktop/gui/ClipperConfigScreen.tsx:139 msgid "Advanced options" msgstr "Geavanceerde opties" #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:653 -#, fuzzy msgid "Advanced settings" -msgstr "Toon geavanceerde opties" +msgstr "Geavanceerde instellingen" #: packages/app-desktop/gui/StatusScreen/StatusScreen.tsx:196 -#, fuzzy msgid "Advanced tools" msgstr "Geavanceerde hulpmiddelen" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:18 -#, fuzzy msgid "all" -msgstr "Installeren" +msgstr "alle" #: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:109 msgid "" "All data, including notes, notebooks and tags will be permanently deleted." msgstr "" +"Alle data, inclusief notities, notitieboeken en labels zullen permanent " +"verwijderd worden." #: packages/lib/services/ReportService.ts:227 msgid "All item sync failures have been marked as \"ignored\"." -msgstr "" +msgstr "Alle gefaalde item-synchronisaties zijn gemarkeerd als \"genegeerd\"." #: packages/app-desktop/gui/Sidebar/listItemComponents/AllNotesItem.tsx:71 #: packages/app-mobile/components/screens/Notes.tsx:208 @@ -445,45 +437,44 @@ msgstr "Alle notities" #: packages/lib/onedrive-api-node-utils.js:46 msgid "All potential ports are in use - please report the issue at %s" -msgstr "" -"Alle potentiële poorten zijn in gebruik - gelieve dit te rapporteren aan %s" +msgstr "Alle potentiële poorten zijn in gebruik - meld het problem op %s" #: packages/lib/models/settings/builtInMetadata.ts:910 msgid "Allows debugging mobile plugins. See %s for details." -msgstr "" +msgstr "Laat toe mobiele plugins te debuggen. Zie %s voor details." #: packages/app-cli/app/command-config.ts:19 msgid "Also displays unset and hidden config variables." msgstr "Toont ook niet-ingestelde en verborgen configuratie-opties." #: packages/app-desktop/gui/ShareNoteDialog.tsx:205 -#, fuzzy msgid "Also publish linked notes" -msgstr "Delen" +msgstr "Publiceer ook gelinkte notities" #: packages/lib/models/settings/builtInMetadata.ts:396 msgid "Always" msgstr "Altijd" #: packages/lib/models/settings/builtInMetadata.ts:866 -#, fuzzy msgid "Always ask" -msgstr "Altijd" +msgstr "Altijd vragen" #: packages/app-desktop/bridge.ts:450 msgid "Always open %s files without asking." -msgstr "" +msgstr "%s bestanden altijd openen zonder te vragen." #: packages/lib/models/settings/builtInMetadata.ts:867 -#, fuzzy msgid "Always resize" -msgstr "Altijd" +msgstr "Formaat altijd aanpassen" #: packages/app-cli/app/command-mv.ts:37 msgid "" "Ambiguous notebook \"%s\". Please use notebook id instead - press \"ti\" to " "see the short notebook id or use $b for current selected notebook" msgstr "" +"Meerduidig notitieboek \"%s\". Gebruik het id van het notitieboek - druk " +"\"ti\" om het korte notitieboek-id te zien, of gebruik $b voor het huidige " +"notitieboek" #: packages/app-cli/app/command-mkbook.ts:33 #: packages/app-cli/app/command-mv.ts:30 @@ -491,22 +482,26 @@ msgid "" "Ambiguous notebook \"%s\". Please use short notebook id instead - press " "\"ti\" to see the short notebook id" msgstr "" +"Meerduidig notitieboek \"%s\". Gebruik het korte id van het notitieboek - " +"druk \"ti\" om het korte notitieboek-id te zien" #: packages/app-mobile/components/NoteEditor/ImageEditor/promptRestoreAutosave.ts:13 msgid "An autosaved drawing was found. Attach a copy of it to the note?" msgstr "" +"We hebben een automatisch opgeslagen tekening gevonden. Wil je een kopie " +"ervan toevoegen aan de notitie?" #: packages/app-desktop/ElectronAppWrapper.ts:133 msgid "An error occurred: %s" -msgstr "" +msgstr "Er ging iets fout: %s" #: packages/app-desktop/checkForUpdates.ts:107 msgid "An update is available, do you want to download it now?" -msgstr "Er is een update beschikbaar; wil je dit nu downloaden?" +msgstr "Er is een update beschikbaar; wil je die nu downloaden?" #: packages/app-mobile/utils/getVersionInfoText.ts:22 msgid "Android API level: %d" -msgstr "" +msgstr "Android API nummer: %d" #: packages/app-desktop/gui/JoplinCloudConfigScreen.tsx:48 #: packages/app-mobile/components/screens/ConfigScreen/JoplinCloudConfig.tsx:24 @@ -514,6 +509,9 @@ msgid "" "Any email sent to this address will be converted into a note and added to " "your collection. The note will be saved into the Inbox notebook" msgstr "" +"Elke email die naar dit adres verstuurd wordt, zal worden omgezet in een " +"notitie en toegevoegd worden aan je collectie . De notitie zal opgeslagen " +"worden in het Inbox notitieboek" #: packages/lib/models/Setting.ts:1174 msgid "Appearance" @@ -521,18 +519,19 @@ msgstr "Weergave" #: packages/lib/models/Setting.ts:1179 msgid "Application" -msgstr "Applicatie" +msgstr "Toepassing" #: packages/app-desktop/gui/ConfigScreen/ButtonBar.tsx:39 msgid "Apply" msgstr "Toepassen" #: packages/app-mobile/components/EditorToolbar/ToolbarEditorDialog.tsx:146 -#, fuzzy msgid "" "Are you sure that you want to restore the default toolbar layout?\n" "This cannot be undone." -msgstr "Ben je zeker dat je de authorisatietoken wil vernieuwen?" +msgstr "" +"Ben je zeker dat je de terug wil naar de standaardlayout voor de werkbalk?\n" +"Dit kan niet ongedaan worden." #: packages/app-desktop/gui/ClipperConfigScreen.tsx:38 msgid "Are you sure you want to renew the authorisation token?" @@ -543,6 +542,8 @@ msgid "" "Are you sure you want to return to the default layout? The current layout " "configuration will be lost." msgstr "" +"Ben je zeker dat je de terug wil naar de standaardlayout voor de werkbalk? " +"De huidige layout-configuratie zal verloren gaan." #: packages/app-desktop/gui/ConfigScreen/controls/SettingComponent.tsx:235 msgid "Arguments:" @@ -550,18 +551,19 @@ msgstr "Argumenten:" #: packages/lib/models/settings/builtInMetadata.ts:48 msgid "Aritim Dark" -msgstr "Aritim donker" +msgstr "Aritim Donker" #: packages/app-mobile/utils/lockToSingleInstance.ts:15 msgid "" "At present, Joplin Web can only be open in one tab at a time. Please close " "the other instance of Joplin." msgstr "" +"Momenteel kan Joplin Web slechts in één tab tegelijk open zijn. Gelieve de " +"andere instantie van Joplin te sluiten." #: packages/app-mobile/components/NoteEditor/ImageEditor/promptRestoreAutosave.ts:25 -#, fuzzy msgid "Attach" -msgstr "Bijvoegen ..." +msgstr "Toevoegen" #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:75 #: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx:729 @@ -576,17 +578,16 @@ msgstr "Voeg foto toe" #: packages/app-mobile/components/screens/Note/Note.tsx:1155 msgid "Attach..." -msgstr "Bijvoegen ..." +msgstr "Toevoegen..." #: packages/app-cli/app/command-attach.ts:13 msgid "Attaches the given file to the note." -msgstr "Voegt het bestand toe aan de notitie." +msgstr "Voegt het gegeven bestand toe aan de notitie." #: packages/server/src/models/UserModel.ts:247 #: packages/server/src/models/UserModel.ts:264 -#, fuzzy msgid "attachment" -msgstr "Bijlagen" +msgstr "bijlage" #: packages/lib/models/Resource.ts:509 msgid "Attachment conflict: \"%s\"" @@ -594,7 +595,7 @@ msgstr "Bijlageconflict: \"%s\"" #: packages/lib/models/settings/builtInMetadata.ts:392 msgid "Attachment download behaviour" -msgstr "Modus voor ophalen van bijlages" +msgstr "Downloadgedrag voor bijlagen" #: packages/lib/services/ReportService.ts:277 msgid "Attachments" @@ -602,7 +603,7 @@ msgstr "Bijlagen" #: packages/lib/services/ReportService.ts:301 msgid "Attachments that could not be downloaded" -msgstr "Bijlagen die niet opgehaald konden worden" +msgstr "Bijlagen die niet gedownload konden worden" #: packages/lib/models/settings/builtInMetadata.ts:33 msgid "" @@ -627,9 +628,8 @@ msgstr "Autorisatietoken:" #: packages/app-desktop/gui/JoplinCloudLoginScreen.tsx:88 #: packages/app-mobile/components/screens/JoplinCloudLoginScreen.tsx:162 -#, fuzzy msgid "Authorise" -msgstr "Autorisatietoken:" +msgstr "Autoriseer" #: packages/lib/models/settings/builtInMetadata.ts:398 msgid "Auto" @@ -637,25 +637,24 @@ msgstr "Auto" #: packages/server/src/services/TaskService.ts:30 msgid "Auto-add disabled accounts for deletion" -msgstr "" +msgstr "Uitgeschakelde accounts automatisch toevoegen voor verwijdering" # The "." at the end of the original text is not the period at the end of a sentence but merely the period to indicate that etc. is an abbreviation (of etcetera). #: packages/lib/models/settings/builtInMetadata.ts:645 msgid "Auto-pair braces, parentheses, quotations, etc." -msgstr "Haakjes, aanhalingstekens, etc. automatisch aanvullen" +msgstr "Haakjes, aanhalingstekens, etc. automatisch aanvullen." #: packages/lib/models/settings/builtInMetadata.ts:656 msgid "Autocomplete Markdown and HTML" -msgstr "" +msgstr "Markdown en HTML automatisch aanvullen" #: packages/lib/models/settings/builtInMetadata.ts:1198 -#, fuzzy msgid "Automatically check for updates" -msgstr "Controleren op updates ..." +msgstr "Automtisch controleren op updates" #: packages/lib/models/settings/builtInMetadata.ts:1722 msgid "Automatically delete notes in the trash after a number of days" -msgstr "" +msgstr "Notities in de prullenmand automatisch verwijderen na een aantal dagen" #: packages/lib/models/settings/builtInMetadata.ts:556 msgid "Automatically switch theme to match system theme" @@ -672,13 +671,13 @@ msgstr "Terug" #: packages/lib/utils/joplinCloud/index.ts:347 msgid "Basic" -msgstr "" +msgstr "Standaard" #: packages/app-mobile/components/BetaChip.tsx:37 #: packages/app-mobile/components/ScreenHeader/WebBetaButton.tsx:37 #: packages/app-mobile/components/ScreenHeader/WebBetaButton.tsx:45 msgid "Beta" -msgstr "" +msgstr "Beta" #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:55 #: packages/app-mobile/components/NoteEditor/commandDeclarations.ts:54 @@ -688,41 +687,41 @@ msgstr "Vet" #: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.tsx:222 #: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.tsx:319 msgid "Browse all plugins" -msgstr "Plugin doorbladeren" +msgstr "Alle plugins doorbladeren" #: packages/app-desktop/gui/ConfigScreen/controls/SettingComponent.tsx:275 msgid "Browse..." -msgstr "Bladeren ..." +msgstr "Bladeren..." #: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.tsx:223 #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/PluginChips.tsx:54 msgid "Built-in" -msgstr "" +msgstr "Ingebouwd" #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:85 msgid "Bulleted List" -msgstr "Opsommingstekens" +msgstr "Opsommingslijst" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginInfoModal.tsx:129 msgid "by %s" -msgstr "" +msgstr "volgens %s" +# Context unclear #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:20 msgid "by word" -msgstr "" +msgstr "per woord" #: packages/server/src/routes/admin/users.ts:160 -#, fuzzy msgid "Can Share" -msgstr "Delen" +msgstr "Kan Delen" #: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:120 msgid "Can view" -msgstr "" +msgstr "Kan bekijken" #: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:121 msgid "Can view and edit" -msgstr "" +msgstr "Kan bekijken en bewerken" #: packages/app-desktop/bridge.ts:373 packages/app-desktop/bridge.ts:389 #: packages/app-desktop/bridge.ts:452 @@ -762,11 +761,11 @@ msgstr "Achtergrond-synchronisatie wordt geannuleerd... Even geduld." #: packages/lib/Synchronizer.ts:206 msgid "Cancelling..." -msgstr "Annuleren..." +msgstr "Bezig met annuleren..." #: packages/app-cli/app/command-sync.ts:289 msgid "Cancelling... Please wait." -msgstr "Annuleren.. Even geduld." +msgstr "Bezig met annuleren.. Even geduld." #: packages/lib/shim-init-node.ts:325 msgid "Cannot access %s" @@ -781,9 +780,8 @@ msgid "Cannot copy note to \"%s\" notebook" msgstr "Kan notitie niet naar notitieboek \"%s\" kopiëren" #: packages/app-mobile/components/screens/Notes.tsx:195 -#, fuzzy msgid "Cannot create a new note: %s" -msgstr "Maakt een nieuwe notitie aan." +msgstr "Kan geen nieuwe notitie maken: %s" #: packages/app-cli/app/command-attach.ts:22 #: packages/app-cli/app/command-cat.ts:26 packages/app-cli/app/command-cp.ts:25 @@ -815,13 +813,12 @@ msgid "Cannot find \"%s\"." msgstr "Kan \"%s\" niet vinden." #: packages/app-cli/app/command-mkbook.ts:28 -#, fuzzy msgid "Cannot find: \"%s\"" msgstr "Kan \"%s\" niet vinden." #: packages/app-cli/app/command-sync.ts:202 msgid "Cannot initialise synchroniser." -msgstr "Kan de synchronisatie niet starten." +msgstr "Synchronisatie kan niet worden geïnitialiseerd." # Context needed #: packages/lib/services/interop/InteropService.ts:263 @@ -862,7 +859,7 @@ msgid "" "Cannot save %s \"%s\" because it would go over the total allowed size (%s) " "for this account" msgstr "" -"Kan %s \"%s\" niet opslaan omdat het groter is dan de maximum toegestane " +"Kan %s \"%s\" niet opslaan omdat het groter is dan de resterende toegestane " "bestandsgrootte voor dit account" #: packages/lib/services/share/ShareService.ts:337 @@ -871,30 +868,29 @@ msgid "" "enabled end-to-end encryption. They may do so from the screen Configuration " "> Encryption." msgstr "" -"Kan het versleutelde notitieblok niet delen met ontvanger %s omdat ze de end-" -"to-end versleuteling niet hebben ingesteld. Dit kan via Configuratie > " -"Encryptie." +"Kan het versleutelde notitieboek niet delen met ontvanger %s omdat ze de end-" +"to-end-versleuteling niet hebben ingesteld. Dit kunnen ze doen via " +"Configuratie > Encryptie." #: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:331 msgid "Case sensitive" -msgstr "" +msgstr "Hoofdlettergevoelig" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleLayoutMoveMode.ts:7 msgid "Change application layout" -msgstr "Layout veranderen" +msgstr "Layout van de toepassing wijzigen" #: packages/lib/services/spellChecker/SpellCheckerService.ts:210 msgid "Change language" msgstr "Taal wijzigen" #: packages/app-mobile/components/CameraView/ActionButtons.tsx:124 -#, fuzzy msgid "Change ratio" -msgstr "Configuratie" +msgstr "Beeldverhouding wijzigen" #: packages/app-desktop/gui/KeymapConfig/KeymapConfigScreen.tsx:98 msgid "Change shortcut for \"%s\"" -msgstr "" +msgstr "Snelkoppeling voor \"%s\" wijzigen" #: packages/app-desktop/gui/NoteContentPropertiesDialog.tsx:106 msgid "Characters" @@ -906,12 +902,12 @@ msgstr "Tekens zonder spaties" #: packages/app-mobile/components/EditorToolbar/ToolbarEditorDialog.tsx:168 msgid "Check elements to display in the toolbar" -msgstr "" +msgstr "Vink de elementen aan die je in de werkbalk wil zien" #: packages/app-desktop/gui/MenuBar.tsx:634 #: packages/app-desktop/gui/MenuBar.tsx:929 msgid "Check for updates..." -msgstr "Controleren op updates ..." +msgstr "Controleren op updates..." #: packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx:264 #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:465 @@ -943,7 +939,7 @@ msgstr "Chrome Webwinkel" #: packages/app-mobile/components/screens/ConfigScreen/FileSystemPathSelector.tsx:101 #: packages/app-mobile/components/screens/SearchScreen/index.tsx:111 msgid "Clear" -msgstr "Vrijmaken" +msgstr "Wissen" #: packages/app-mobile/components/SelectDateTimeDialog.tsx:169 msgid "Clear alarm" @@ -951,9 +947,8 @@ msgstr "Wis melding" #: packages/app-desktop/gui/lib/SearchInput/SearchInput.tsx:62 #: packages/app-mobile/components/screens/ConfigScreen/plugins/SearchPlugins.tsx:140 -#, fuzzy msgid "Clear search" -msgstr "Wis melding" +msgstr "Zoekopdracht wissen" #: packages/app-desktop/gui/NoteRevisionViewer.tsx:205 msgid "" @@ -966,16 +961,15 @@ msgstr "" #: packages/app-desktop/gui/NoteEditor/NoteEditor.tsx:453 msgid "Click to add tags..." -msgstr "Klik om tags toe te voegen ..." +msgstr "Klik om labels toe te voegen ..." #: packages/lib/versionInfo.ts:88 msgid "Client ID: %s" msgstr "Client ID: %s" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:23 -#, fuzzy msgid "close" -msgstr "Sluit" +msgstr "sluit" #: packages/app-desktop/gui/MenuBar.tsx:359 #: packages/app-desktop/gui/NoteContentPropertiesDialog.tsx:175 @@ -991,18 +985,16 @@ msgid "Close" msgstr "Sluit" #: packages/app-mobile/components/Dropdown.tsx:199 -#, fuzzy msgid "Close dropdown" -msgstr "Venster sluiten" +msgstr "Lijst sluiten" #: packages/app-mobile/components/accessibility/AccessibleModalMenu.tsx:46 -#, fuzzy msgid "Close menu" -msgstr "Sluit" +msgstr "Menu sluiten" #: packages/app-mobile/components/SideMenu.tsx:300 msgid "Close side menu" -msgstr "" +msgstr "Menu aan zijkant sluiten" #: packages/lib/models/settings/settingValidations.ts:33 msgid "" @@ -1010,6 +1002,9 @@ msgid "" "application again. Make sure you create a backup first by exporting all your " "notes as JEX." msgstr "" +"Sluit de toepassing af. Verwijder dan je profile in \"%s\", en start de " +"toepassing opnieuw. Zorg dat je eerst een back-up maakt door al je notities " +"als JEX te exporteren." #: packages/app-desktop/gui/KeymapConfig/utils/getLabel.ts:26 #: packages/app-desktop/gui/MenuBar.tsx:699 @@ -1018,11 +1013,11 @@ msgstr "Venster sluiten" #: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useLinkTooltips.ts:39 msgid "Cmd-click to open" -msgstr "" +msgstr "Cmd-klik om te openen" #: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useLinkTooltips.ts:45 msgid "Cmd-click to open: %s" -msgstr "" +msgstr "Cmd-klik om te openen: %s" #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:70 #: packages/app-mobile/components/NoteEditor/commandDeclarations.ts:65 @@ -1038,22 +1033,20 @@ msgid "Code View" msgstr "Code-weergave" #: packages/lib/utils/joplinCloud/index.ts:173 -#, fuzzy msgid "Collaborate on a notebook with others" -msgstr "Maak eerst een notitieboek aan" +msgstr "Werk samen met anderen aan een notitieboek" #: packages/app-desktop/gui/SyncWizard/Dialog.tsx:169 -#, fuzzy msgid "Collaborate on notebooks with others" -msgstr "Maak eerst een notitieboek aan" +msgstr "Werk samen met anderen aan notitieboeken" #: packages/app-desktop/gui/Sidebar/listItemComponents/ExpandIcon.tsx:28 msgid "Collapsed, press space to expand." -msgstr "" +msgstr "Ingeklapt, druk spatie om uit te klappen." #: packages/lib/services/ReportService.ts:351 msgid "Coming alarms" -msgstr "Komende meldingen" +msgstr "Komende alarmen" #: packages/lib/models/settings/builtInMetadata.ts:1379 msgid "" @@ -1064,8 +1057,8 @@ msgid "" msgstr "" "Komma-gescheiden lijst van paden naar mappen om de certificaten van te " "laden, of pad naar individuele cert-bestanden. Bijvoorbeeld: /my/cert_dir, /" -"other/custom.pem. Merk op dat als u wijzigingen aanbrengt in de TLS-" -"instellingen, u uw wijzigingen moet opslaan voordat u klikt op \"Verifieer " +"other/custom.pem. Merk op dat als je wijzigingen aanbrengt in de TLS-" +"instellingen, je je wijzigingen moet opslaan voordat je klikt op \"Verifieer " "de configuratie van de synchronisatie\"." #: packages/lib/services/KeymapService.ts:321 @@ -1082,24 +1075,20 @@ msgid "Command palette" msgstr "Commandopalet" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/commandPalette.ts:7 -#, fuzzy msgid "Command palette..." -msgstr "Commandopalet" +msgstr "Commandopalet..." #: packages/lib/services/noteList/defaultListRenderer.ts:24 -#, fuzzy msgid "Compact" -msgstr "Voltooid" +msgstr "Compact" #: packages/app-desktop/gui/NoteList/utils/useOnKeyDown.ts:153 -#, fuzzy msgid "Complete" msgstr "Voltooid" #: packages/app-desktop/gui/NoteListItem/utils/prepareViewProps.ts:40 -#, fuzzy msgid "Complete to-do" -msgstr "Voltooid" +msgstr "To-do voltooien" #: packages/app-desktop/gui/NoteListHeader/utils/getColumnTitle.ts:12 #: packages/app-desktop/gui/NotePropertiesDialog.tsx:70 @@ -1114,20 +1103,19 @@ msgstr "Decryptie voltooid." msgid "" "Completed with warnings:\n" "%s" -msgstr "" +msgstr "Voltooid met waarschuwingen: %s" #: packages/lib/Synchronizer.ts:207 -#, fuzzy msgid "Completed: %s (%s)" -msgstr "Voltooid: %s" +msgstr "Voltooid: %s (%s)" #: packages/lib/models/Note.ts:66 msgid "completion date" -msgstr "" +msgstr "datum voltooiing" #: packages/server/src/services/TaskService.ts:28 msgid "Compress old changes" -msgstr "" +msgstr "Comprimeer oude wijzigingen" #: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:132 #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:819 @@ -1142,13 +1130,12 @@ msgstr "Bevestiging wachtwoord kan niet leeg zijn" #: packages/app-cli/app/command-e2ee.ts:95 #: packages/app-mobile/components/screens/encryption-config.tsx:175 msgid "Confirm password:" -msgstr "Bevestig paswoord:" +msgstr "Bevestig wachtwoord:" #: packages/app-desktop/gui/Root.tsx:126 #: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:70 -#, fuzzy msgid "Confirmation" -msgstr "Configuratie" +msgstr "Bevestiging" #: packages/lib/services/ReportService.ts:330 msgid "Conflicted: %d" @@ -1159,45 +1146,39 @@ msgid "Conflicts" msgstr "Conflicten" #: packages/lib/models/Resource.ts:478 -#, fuzzy msgid "Conflicts (attachments)" -msgstr "Notitiebijlagen" +msgstr "Conflicten (bijlagen)" #: packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx:253 #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:462 -#, fuzzy msgid "Connect to Joplin Cloud" -msgstr "Joplin Forum" +msgstr "Verbinding maken met Joplin Cloud" #: packages/lib/utils/joplinCloud/index.ts:208 msgid "Consolidated billing" -msgstr "" +msgstr "Geconsolideerde facturatie" #: packages/app-desktop/gui/Sidebar/listItemComponents/NoteCount.tsx:11 -#, fuzzy msgid "Contains %d note" msgid_plural "Contains %d notes" -msgstr[0] "Converteer naar notitie" -msgstr[1] "Converteer naar notitie" +msgstr[0] "Bevat %d notitie" +msgstr[1] "Bevat %d notities" #: packages/app-desktop/gui/ConfigScreen/controls/plugins/SearchPlugins.tsx:106 -#, fuzzy msgid "Content provided by %s" -msgstr "Notitieboek titel:" +msgstr "Inhoud geleverd door %s" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginStates.tsx:102 -#, fuzzy msgid "Content provided by: %s" -msgstr "Notitieboek titel:" +msgstr "Inhoud geleverd door: %s" #: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:74 msgid "Continue" -msgstr "" +msgstr "Doorgaan" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:6 -#, fuzzy msgid "Control character" -msgstr "Tekens" +msgstr "Controleteken" #: packages/app-mobile/components/screens/Note/Note.tsx:1221 msgid "Convert to note" @@ -1208,9 +1189,8 @@ msgid "Convert to todo" msgstr "Converteer naar to-do" #: packages/app-mobile/components/voiceTyping/VoiceTypingDialog.tsx:181 -#, fuzzy msgid "Converting speech to text..." -msgstr "Converteer naar notitie" +msgstr "Bezig met omzetten van spraak naar tekst..." #: packages/app-desktop/gui/MenuBar.tsx:601 #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:35 @@ -1218,7 +1198,7 @@ msgstr "Converteer naar notitie" #: packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts:190 #: packages/app-desktop/gui/NotePropertiesDialog.tsx:387 msgid "Copy" -msgstr "Kopieer" +msgstr "Kopiëren" #: packages/app-desktop/commands/copyDevCommand.ts:9 msgid "Copy dev mode command to clipboard" @@ -1228,56 +1208,51 @@ msgstr "Kopieer dev mode commando naar klembord" #: packages/app-desktop/gui/Sidebar/hooks/useOnRenderItem.tsx:243 #: packages/app-desktop/gui/utils/NoteListUtils.ts:127 #: packages/app-mobile/components/screens/Note/Note.tsx:1239 -#, fuzzy msgid "Copy external link" -msgstr "Beëindig externe bijwerking" +msgstr "Kopieer externe link" #: packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts:173 -#, fuzzy msgid "Copy image" -msgstr "Kopieer token" +msgstr "Kopieer afbeelding" #: packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts:218 msgid "Copy Link Address" -msgstr "Kopieer koppelingslocatie" +msgstr "Kopieer linkadres" #: packages/app-desktop/gui/JoplinCloudLoginScreen.tsx:94 #: packages/app-mobile/components/screens/JoplinCloudLoginScreen.tsx:169 -#, fuzzy msgid "Copy link to website" -msgstr "Joplin website" +msgstr "Kopieer link naar website" #: packages/app-desktop/gui/utils/NoteListUtils.ts:112 #: packages/app-mobile/components/screens/Note/Note.tsx:1230 msgid "Copy Markdown link" -msgstr "Kopieer Markdown koppeling" +msgstr "Kopieer Markdownlink" # Why mention 'to clipboard'. Isn't that where something that is copied is always placed? #: packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts:158 msgid "Copy path to clipboard" -msgstr "Kopieer pad" +msgstr "Kopieer pad naar klembord" #: packages/app-desktop/gui/ShareNoteDialog.tsx:216 msgid "Copy Shareable Link" msgid_plural "Copy Shareable Links" -msgstr[0] "Kopieer deelbare koppeling" -msgstr[1] "Kopieer deelbare koppelingen" +msgstr[0] "Kopieer deelbare link" +msgstr[1] "Kopieer deelbare links" # Why mention 'to clipboard'. Isn't that where something that is copied is always placed? #: packages/app-desktop/gui/JoplinCloudConfigScreen.tsx:52 #: packages/app-mobile/components/screens/ConfigScreen/JoplinCloudConfig.tsx:75 -#, fuzzy msgid "Copy to clipboard" -msgstr "Kopieer pad" +msgstr "Kopieer naar klembord" #: packages/app-desktop/gui/ClipperConfigScreen.tsx:144 msgid "Copy token" msgstr "Kopieer token" #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:611 -#, fuzzy msgid "Copy version info" -msgstr "Weergave versie informatie" +msgstr "Kopieer versie-informatie" #: packages/lib/components/shared/dropbox-login-shared.js:43 msgid "" @@ -1301,14 +1276,13 @@ msgid "" "%s" msgstr "" "Kon geen verbinding maken met de Joplin Server. Controleer de Synchronisatie " -"opties in het configuratie scherm. Volledige fout was:\n" +"opties in het configuratiescherm. Volledige foutmelding was:\n" "\n" "%s" #: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.tsx:319 -#, fuzzy msgid "Could not connect to plugin repository." -msgstr "Kon plugin niet installeren: %s" +msgstr "Kon geen verbinding maken met de plugin-bibliotheek." #: packages/app-desktop/InteropServiceHelper.ts:220 msgid "Could not export notes: %s" @@ -1331,9 +1305,8 @@ msgstr "" "De foutmelding was: \"%s\"" #: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:59 -#, fuzzy msgid "Could not switch profile: %s" -msgstr "Kon plugin niet installeren: %s" +msgstr "Kon profiel niet wisselen: %s" #: packages/lib/components/EncryptionConfigScreen/utils.ts:224 msgid "Could not upgrade master key: %s" @@ -1344,23 +1317,20 @@ msgid "" "Could not verify the share status of this notebook - aborting. Please try " "again when you are connected to the internet." msgstr "" -"Kon de deelstatus van dit notitieblok niet nagaan - annuleren. Probeer " +"Kon de deelstatus van dit notitieboek niet nagaan - annuleren. Probeer " "opnieuw wanneer je terug een netwerkverbinding hebt." #: packages/app-mobile/components/biometrics/biometricAuthenticate.ts:30 -#, fuzzy msgid "Could not verify your identity: %s" -msgstr "Kon notities niet exporteren: %s" +msgstr "Kon je identiteit niet verifiëren: %s" #: packages/app-desktop/gui/PromptDialog.tsx:277 -#, fuzzy msgid "Create" -msgstr "Aangemaakt" +msgstr "Aanmaken" #: packages/app-cli/app/command-mkbook.ts:19 -#, fuzzy msgid "Create a new notebook under a parent notebook." -msgstr "Maakt een nieuw notitieboek aan." +msgstr "Maak een nieuw notitieboek aan onder een bestaand notitieboek." #: packages/app-mobile/components/NoteList.tsx:102 msgid "Create a notebook" @@ -1368,19 +1338,16 @@ msgstr "Maak nieuw notitieboek aan" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/addProfile.ts:9 #: packages/app-mobile/components/ProfileSwitcher/ProfileEditor.tsx:88 -#, fuzzy msgid "Create new profile..." -msgstr "Maakt een nieuwe notitie aan." +msgstr "Nieuw profiel aanmaken..." #: packages/app-desktop/gui/EditFolderDialog/Dialog.tsx:166 -#, fuzzy msgid "Create notebook" msgstr "Maak nieuw notitieboek aan" #: packages/server/src/routes/admin/users.ts:257 -#, fuzzy msgid "Create user" -msgstr "Aangemaakt: %s" +msgstr "Gebruiker aanmaken" #: packages/app-desktop/gui/NoteListHeader/utils/getColumnTitle.ts:14 #: packages/app-desktop/gui/NotePropertiesDialog.tsx:67 @@ -1398,16 +1365,15 @@ msgstr "Aangemaakte lokale items: %d." #: packages/lib/services/ReportService.ts:288 msgid "Created locally" -msgstr "Lokaal toegevoegd" +msgstr "Lokaal aangemaakt" #: packages/lib/Synchronizer.ts:201 msgid "Created remote items: %d." -msgstr "Aangemaakte remote items: %d." +msgstr "Aangemaakte externe items: %d." #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:140 -#, fuzzy msgid "Created: " -msgstr "Aangemaakt: %s" +msgstr "Aangemaakt: " #: packages/app-cli/app/command-import.ts:51 #: packages/app-desktop/gui/ImportScreen.tsx:90 @@ -1432,58 +1398,55 @@ msgid "Creates a new to-do." msgstr "Maakt nieuwe to-do aan." #: packages/app-desktop/gui/NoteEditor/NoteTitle/NoteTitleBar.tsx:123 -#, fuzzy msgid "Creating new note..." -msgstr "Nieuwe %s aanmaken ..." +msgstr "Nieuwe notitie aanmaken..." #: packages/app-desktop/gui/NoteEditor/NoteTitle/NoteTitleBar.tsx:123 -#, fuzzy msgid "Creating new to-do..." -msgstr "Nieuwe %s aanmaken ..." +msgstr "Nieuwe to-do aanmaken..." #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/ExportDebugReportButton.tsx:29 msgid "Creating report..." -msgstr "Rapport aanmaken ..." +msgstr "Rapport aanmaken..." #: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useLinkTooltips.ts:41 msgid "Ctrl-click to open" -msgstr "" +msgstr "Ctrl-klik om te openen" #: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useLinkTooltips.ts:47 msgid "Ctrl-click to open: %s" -msgstr "" +msgstr "Ctrl-klik om te openen: %s" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:24 msgid "current match" -msgstr "" +msgstr "huidige overeenkomst" #: packages/app-desktop/gui/MasterPasswordDialog/Dialog.tsx:153 -#, fuzzy msgid "Current password" -msgstr "Geef hoofdpaswoord in:" +msgstr "Huidig wachtwoord" #: packages/app-desktop/checkForUpdates.ts:90 msgid "Current version is up-to-date." -msgstr "Actuele versie is up-to-date." +msgstr "Huidige versie is up-to-date." #: packages/lib/models/Note.ts:64 msgid "custom order" -msgstr "aangepaste rangschikking" +msgstr "aangepaste volgorde" #: packages/app-desktop/gui/NoteList/utils/canManuallySortNotes.ts:10 msgid "Custom order" -msgstr "Aangepaste rangschikking" +msgstr "Aangepaste volgorde" # Contexed needed # What is a 'app style'? #: packages/lib/models/settings/builtInMetadata.ts:1167 msgid "Custom stylesheet for Joplin-wide app styles" -msgstr "Aangepaste stijlweergave voor algemene stijl" +msgstr "Aangepast stijlblad voor Joplin-brede appstijlen" # Need clarification. Should it not be '... for rendering Markdown'? #: packages/lib/models/settings/builtInMetadata.ts:1150 msgid "Custom stylesheet for rendered Markdown" -msgstr "Aangepaste stijlweergave voor gerenderde Markdown" +msgstr "Aangepast stijlblad voor gerenderde Markdown" #: packages/lib/models/settings/builtInMetadata.ts:1378 msgid "Custom TLS certificates" @@ -1491,13 +1454,13 @@ msgstr "Aangepaste TLS-certificaten" #: packages/lib/utils/joplinCloud/index.ts:194 msgid "Customise the note publishing banner" -msgstr "" +msgstr "De banner voor het publiceren van notities aanpassen" #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:40 #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useContextMenu.ts:85 #: packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts:182 msgid "Cut" -msgstr "Knip" +msgstr "Knippen" #: packages/lib/models/settings/builtInMetadata.ts:43 msgid "Dark" @@ -1505,7 +1468,7 @@ msgstr "Donker" #: packages/server/src/services/MustacheService.ts:117 msgid "Dashboard" -msgstr "" +msgstr "Dashboard" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:169 msgid "Date" @@ -1522,20 +1485,20 @@ msgstr "dagen" #: packages/app-mobile/components/NoteEditor/commandDeclarations.ts:92 msgid "Decrease indent level" -msgstr "" +msgstr "Inspringniveau verlagen" #: packages/app-cli/app/command-e2ee.ts:65 msgid "Decrypted items: %d" -msgstr "Gedecrypteerde items: %d" +msgstr "Ontsleutelde items: %d" #: packages/lib/components/EncryptionConfigScreen/utils.ts:45 msgid "Decrypted items: %s / %s" -msgstr "Gedecrypteerde items: %s / %s" +msgstr "Ontsleutelde items: %s / %s" #: packages/app-desktop/gui/Sidebar/Sidebar.tsx:48 #: packages/app-mobile/components/side-menu-content.tsx:637 msgid "Decrypting items: %d/%d" -msgstr "Items decrypteren: %d/%d" +msgstr "Items ontsleutelen: %d/%d" #: packages/lib/models/settings/builtInMetadata.ts:1081 #: packages/lib/models/settings/builtInMetadata.ts:1088 @@ -1565,53 +1528,49 @@ msgid "Delete attachment \"%s\"?" msgstr "Bijlage \"%s\" verwijderen?" #: packages/server/src/services/TaskService.ts:27 -#, fuzzy msgid "Delete expired sessions" -msgstr "Schakel wiskundige formules in" +msgstr "Verlopen sessies verwijderen" #: packages/server/src/services/TaskService.ts:22 -#, fuzzy msgid "Delete expired tokens" -msgstr "Deze notities %d verwijderen?" +msgstr "Verlopen tokens verwijderen" #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:110 msgid "Delete line" -msgstr "Lijn verwijderen" +msgstr "Regel verwijderen" #: packages/lib/models/settings/builtInMetadata.ts:1191 msgid "Delete local data and re-download from sync target" msgstr "" -"Verwijder lokale gegevens en download opnieuw van synchronisatie locatie" +"Verwijder lokale gegevens en download opnieuw van synchronisatie-locatie" #: packages/app-mobile/services/voiceTyping/VoiceTyping.ts:90 msgid "" "Delete model and re-download?\n" "This cannot be undone." msgstr "" +"Model verwijderen en opnieuw downloaden?\n" +"Dit kan niet ongedaan gemaakt worden." #: packages/lib/commands/deleteNote.ts:7 -#, fuzzy msgid "Delete note" -msgstr "Notitie verwijderen?" +msgstr "Notitie verwijderen" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/deleteFolder.ts:9 -#, fuzzy msgid "Delete notebook" -msgstr "Notitie verwijderen?" +msgstr "Notitieboek verwijderen" #: packages/lib/components/shared/config/plugins/useOnDeleteHandler.ts:16 msgid "Delete plugin \"%s\"?" msgstr "Plugin \"%s\" verwijderen?" #: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:112 -#, fuzzy msgid "Delete profile \"%s\"" -msgstr "Notities \"%s\" verwijderen?" +msgstr "Profiel \"%s\" verwijderen" #: packages/app-mobile/components/ScreenHeader/index.tsx:432 -#, fuzzy msgid "Delete selected notes" -msgstr "Deze notities verwijderen?" +msgstr "Geselecteerde notities verwijderen" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/deleteFolder.ts:22 #: packages/app-mobile/components/side-menu-content.tsx:407 @@ -1621,25 +1580,27 @@ msgid "" "If you delete the inbox notebook, any email that's recently been sent to it " "may be lost." msgstr "" +"Het Inbox notitieboek verwijderen?\n" +"\n" +"Als je het Inbox notitieboek verwijdert, gaan emails die er recent naar " +"verzonden zijn mogelijk verloren." #: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:246 msgid "" "Delete this invitation? The recipient will no longer have access to this " "shared notebook." msgstr "" -"Deze uitnodiging verwijderen? De ontvanger heeft niet langer toegang tot dit " -"gedeelde notitieblok." +"Deze uitnodiging verwijderen? De ontvanger zal niet langer toegang hebben " +"tot dit gedeelde notitieboek." #: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:108 -#, fuzzy msgid "Delete this profile?" -msgstr "Deze notities %d verwijderen?" +msgstr "Dit profiel verwijderen?" #: packages/app-desktop/gui/NotePropertiesDialog.tsx:69 #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginInfoModal.tsx:207 -#, fuzzy msgid "Deleted" -msgstr "Verwijderen" +msgstr "Verwijderd" #: packages/lib/Synchronizer.ts:203 msgid "Deleted local items: %d." @@ -1647,11 +1608,11 @@ msgstr "Verwijderde lokale items: %d." #: packages/lib/Synchronizer.ts:204 msgid "Deleted remote items: %d." -msgstr "Verwijderde remote items: %d." +msgstr "Verwijderde externe items: %d." #: packages/app-cli/app/command-rmnote.ts:20 msgid "Deletes notes permanently, skipping the trash." -msgstr "" +msgstr "Verwijder notities permanent, zonder ze naar de prullenmand te sturen." #: packages/app-cli/app/command-rmbook.ts:14 msgid "Deletes the given notebook." @@ -1670,14 +1631,12 @@ msgid "Deletes the notes without asking for confirmation." msgstr "Verwijdert de notities zonder om bevestiging te vragen." #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:551 -#, fuzzy msgid "Deletion log" -msgstr "Lijn verwijderen" +msgstr "Verwijderingslog" #: packages/app-mobile/components/NoteItem.tsx:144 -#, fuzzy msgid "Deselect" -msgstr "Selecteer alles" +msgstr "Deselecteren" #: packages/app-cli/app/command-export.ts:24 msgid "Destination format: %s" @@ -1686,11 +1645,11 @@ msgstr "Doelformaat: %s" #: packages/lib/services/noteList/defaultLeftToRightListRenderer.ts:25 #: packages/lib/services/noteList/defaultMultiColumnsRenderer.ts:8 msgid "Detailed" -msgstr "" +msgstr "Gedetailleerd" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/PluginChips.tsx:99 msgid "Dev" -msgstr "" +msgstr "Dev" #: packages/lib/services/interop/Module.ts:62 msgid "Directory" @@ -1701,18 +1660,17 @@ msgid "Directory to synchronise with (absolute path)" msgstr "Map om mee te synchroniseren (absolute pad)" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:144 -#, fuzzy msgid "Disable" -msgstr "Uitgeschakeld" +msgstr "Uitschakelen" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:226 #: packages/app-mobile/components/screens/encryption-config.tsx:292 msgid "Disable encryption" -msgstr "Schakel encryptie uit" +msgstr "Encryptie uitschakelen" #: packages/app-desktop/gui/MainScreen.tsx:502 msgid "Disable safe mode and restart" -msgstr "Veilige modues uitschakelen en opnieuw opstarten" +msgstr "Veilige modus uitschakelen en opnieuw opstarten" #: packages/app-desktop/gui/ClipperConfigScreen.tsx:94 msgid "Disable Web Clipper Service" @@ -1728,9 +1686,8 @@ msgid "Disabled" msgstr "Uitgeschakeld" #: packages/app-mobile/components/screens/encryption-config.tsx:323 -#, fuzzy msgid "Disabled keys" -msgstr "Uitgeschakelde toetsen verbergen" +msgstr "Uitgeschakelde toetsen" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:200 #: packages/app-mobile/components/screens/encryption-config.tsx:251 @@ -1744,24 +1701,23 @@ msgstr "" "zullen gestuurd worden. Wil je verdergaan?" #: packages/app-mobile/components/NoteEditor/ImageEditor/promptRestoreAutosave.ts:19 -#, fuzzy msgid "Discard" -msgstr "Wijzigingen annuleren" +msgstr "Verwerpen" #: packages/app-mobile/components/NoteEditor/ImageEditor/ImageEditor.tsx:105 #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:269 #: packages/app-mobile/components/screens/Note/Note.tsx:209 msgid "Discard changes" -msgstr "Wijzigingen annuleren" +msgstr "Wijzigingen verwerpen" # Context needed. What is being dismissed? #: packages/app-desktop/gui/NoteEditor/WarningBanner/BannerContent.tsx:20 msgid "Dismiss" -msgstr "Verwerpen" +msgstr "Afwijzen" #: packages/app-cli/app/command-geoloc.ts:13 msgid "Displays a geolocation URL for the note." -msgstr "Geeft een geo-locatie-URL voor de notitie weer." +msgstr "Toont een geo-locatie-URL voor de notitie." #: packages/app-cli/app/command-ls.ts:28 msgid "Displays only the first top notes." @@ -1780,31 +1736,31 @@ msgstr "" # Suggestion for English: 'Displays a summary of all notes and notebooks.' #: packages/app-cli/app/command-status.js:13 msgid "Displays summary about the notes and notebooks." -msgstr "Geeft een overzicht van alle notities en notitieboeken weer." +msgstr "Toont een samenvatting over alle notities en notitieboeken." #: packages/app-cli/app/command-cat.ts:18 msgid "Displays the complete information about note." -msgstr "Geeft de volledige informatie van een notitie weer." +msgstr "Toont de volledige informatie over notitie." #: packages/app-cli/app/command-cat.ts:14 msgid "Displays the given note." -msgstr "Geeft de opgegeven notitie weer." +msgstr "Toont de opgegeven notitie." #: packages/app-cli/app/command-ls.ts:19 msgid "" "Displays the notes in the current notebook. Use `ls /` to display the list " "of notebooks." msgstr "" -"Geeft notities in het huidige notitieboek weer. Gebruik `ls /` om een lijst " +"Toont de notities in het huidige notitieboek. Gebruik `ls /` om een lijst " "van notitieboeken weer te geven." #: packages/app-cli/app/command-help.ts:13 msgid "Displays usage information." -msgstr "Geeft informatie over het verbruik weer." +msgstr "Toont gebruiksinformatie." #: packages/app-cli/app/command-version.ts:11 msgid "Displays version information" -msgstr "Weergave versie informatie" +msgstr "Toont versie-informatie" #: packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx:338 #: packages/app-desktop/gui/NoteList/utils/canManuallySortNotes.ts:11 @@ -1816,26 +1772,24 @@ msgid "Do not ask for confirmation." msgstr "Vraag niet om bevestiging." #: packages/lib/components/EncryptionConfigScreen/utils.ts:55 -#, fuzzy msgid "" "Do not lose the password as, for security purposes, this will be the *only* " "way to decrypt the data! To enable encryption, please enter your password " "below." msgstr "" -"Voor beveiligingsredenen, bewaar het wachtwoord zorgvuldig. Dit is de " -"*enige* manier om je data te ontsleutelen! Gelieve je wachtwoord hieronder " -"in te geven om encrypte te activeren." +"Bewaar het wachtwoord zorgvuldig. Om beveiligingsredenen is dit de *enige* " +"manier om je data te ontsleutelen! Gelieve je wachtwoord hieronder in te " +"geven om encryptie in te schakelen." #: packages/lib/models/Setting.ts:1220 -#, fuzzy msgid "Donate, website" -msgstr "Joplin website" +msgstr "Doneren, website" #: packages/app-mobile/components/NoteEditor/EditLinkDialog.tsx:151 #: packages/app-mobile/components/voiceTyping/VoiceTypingDialog.tsx:245 #: packages/lib/models/Resource.ts:34 msgid "Done" -msgstr "" +msgstr "Klaar" #: packages/app-desktop/checkForUpdates.ts:109 msgid "Download" @@ -1843,13 +1797,11 @@ msgstr "Downloaden" #: packages/app-desktop/gui/ClipperConfigScreen.tsx:131 msgid "Download and install the relevant extension for your browser:" -msgstr "" -"Downloaden en installeren van de overeenkomstige extensie voor je browser:" +msgstr "Download en installeer de relevante extensie voor je browser:" #: packages/app-mobile/components/voiceTyping/VoiceTypingDialog.tsx:206 -#, fuzzy msgid "Download updated model" -msgstr "Gedownload" +msgstr "Download bijgewerkt model" #: packages/lib/models/Resource.ts:409 msgid "Downloaded" @@ -1857,25 +1809,24 @@ msgstr "Gedownload" #: packages/lib/services/ReportService.ts:286 msgid "Downloaded and decrypted" -msgstr "Gedownload en gedecrypteerd" +msgstr "Gedownload en ontsleuteld" #: packages/lib/services/ReportService.ts:287 msgid "Downloaded and encrypted" -msgstr "Gedownload en geëncrypteerd" +msgstr "Gedownload en versleuteld" # This text does not end with a period, but with three dots to indicate an ongoing action. #: packages/lib/models/Resource.ts:408 msgid "Downloading" -msgstr "Aan het downloaded ..." +msgstr "Bezig met downloaden" #: packages/app-mobile/components/voiceTyping/VoiceTypingDialog.tsx:182 -#, fuzzy msgid "Downloading %s language files..." -msgstr "Bijlagen downloaden ..." +msgstr "Bezig met downloaden van taalbestanden voor %s..." #: packages/app-cli/app/command-sync.ts:256 msgid "Downloading resources..." -msgstr "Bijlagen downloaden ..." +msgstr "Bezig met downloaden van hulpmiddelen..." #: packages/lib/models/settings/builtInMetadata.ts:44 msgid "Dracula" @@ -1883,11 +1834,11 @@ msgstr "Dracula" #: packages/app-mobile/components/screens/Note/Note.tsx:1162 msgid "Draw picture" -msgstr "" +msgstr "Tekening maken" #: packages/app-mobile/components/screens/Note/Note.tsx:872 msgid "Drawing" -msgstr "" +msgstr "Tekening" #: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx:1444 msgid "Drop notes or files here" @@ -1901,15 +1852,15 @@ msgstr "Dropbox" msgid "Dropbox Login" msgstr "Dropbox Login" +# Context unclear #: packages/app-desktop/gui/NoteListHeader/utils/getColumnTitle.ts:13 msgid "Due" -msgstr "" +msgstr "Uiterste datum" # Context needed #: packages/lib/models/Note.ts:65 -#, fuzzy msgid "due date" -msgstr "datum bijwerking" +msgstr "uiterste datum" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/duplicateNote.ts:7 #: packages/app-mobile/components/ScreenHeader/index.tsx:470 @@ -1918,22 +1869,20 @@ msgid "Duplicate" msgstr "Dupliceer" #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:114 -#, fuzzy msgid "Duplicate line" -msgstr "Dupliceer" +msgstr "Dupliceer regel" #: packages/app-mobile/components/ScreenHeader/index.tsx:472 -#, fuzzy msgid "Duplicate selected notes" -msgstr "Dupliceer" +msgstr "Dupliceer geselecteerde notities" #: packages/app-cli/app/command-cp.ts:13 msgid "" "Duplicates the notes matching to [notebook]. If no notebook is " "specified the note is duplicated in the current notebook." msgstr "" -"Dupliceert de notities die voldoen aan in [notitieboek]. Als er geen " -"notitieboek is gespecifieerd, zal de notitie gedupliceerd worden in het " +"Dupliceert de notities die voldoen aan naar [notitieboek]. Als er " +"geen notitieboek is gespecifieerd, zal de notitie gedupliceerd worden in het " "huidige notitieboek." #: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/openEditDialog.ts:89 @@ -1945,7 +1894,7 @@ msgstr "" #: packages/app-mobile/components/screens/Note/Note.tsx:1540 #: packages/app-mobile/components/side-menu-content.tsx:414 msgid "Edit" -msgstr "Bewerk" +msgstr "Bewerken" #: packages/app-desktop/commands/startExternalEditing.ts:10 msgid "Edit in external editor" @@ -1953,35 +1902,32 @@ msgstr "Bewerken in externe editor" #: packages/app-desktop/commands/openNoteInNewWindow.ts:10 msgid "Edit in new window" -msgstr "" +msgstr "Bewerken in nieuw venster" #: packages/app-desktop/gui/utils/NoteListUtils.ts:70 -#, fuzzy msgid "Edit in..." -msgstr "Bewerk notitieboek" +msgstr "Bewerken in..." #: packages/app-mobile/components/NoteEditor/EditLinkDialog.tsx:143 -#, fuzzy msgid "Edit link" -msgstr "Bewerk notitieboek" +msgstr "Link bewerken" #: packages/app-cli/app/command-edit.ts:17 msgid "Edit note." -msgstr "Bewerk notitie." +msgstr "Notitie bewerken." #: packages/app-desktop/gui/EditFolderDialog/Dialog.tsx:166 #: packages/app-mobile/components/screens/folder.js:97 msgid "Edit notebook" -msgstr "Bewerk notitieboek" +msgstr "Notitieboek bewerken" #: packages/app-mobile/components/ProfileSwitcher/ProfileEditor.tsx:88 -#, fuzzy msgid "Edit profile" -msgstr "Exporteer profiel" +msgstr "Profiel bewerken" #: packages/app-desktop/commands/editProfileConfig.ts:9 msgid "Edit profile configuration..." -msgstr "" +msgstr "Profielconfiguratie bewerken..." #: packages/app-desktop/gui/NoteContentPropertiesDialog.tsx:144 #: packages/lib/models/settings/builtInMetadata.ts:608 @@ -1991,36 +1937,33 @@ msgid "Editor" msgstr "Editor" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/Toolbar.tsx:38 -#, fuzzy msgid "Editor actions" -msgstr "Lettertype editor" +msgstr "Editor acties" #: packages/lib/models/settings/builtInMetadata.ts:1074 msgid "Editor font" -msgstr "Lettertype editor" +msgstr "Lettertype van editor" #: packages/lib/models/settings/builtInMetadata.ts:1100 msgid "Editor font family" -msgstr "Lettertype editor" +msgstr "Lettertypefamilie van editor" #: packages/lib/models/settings/builtInMetadata.ts:1062 msgid "Editor font size" -msgstr "Lettergrootte editor" +msgstr "Lettergrootte van editor" #: packages/lib/models/settings/builtInMetadata.ts:1121 msgid "Editor maximum width" msgstr "Maximum breedte editor" #: packages/lib/models/settings/builtInMetadata.ts:1113 -#, fuzzy msgid "Editor monospace font family" -msgstr "Lettertype editor" +msgstr "Monospace lettertypefamilie van editor" #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:118 #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:122 -#, fuzzy msgid "Editor: %s" -msgstr "Editor" +msgstr "Editor: %s" #: packages/app-cli/app/command-ls.ts:32 msgid "Either \"text\" or \"json\"" @@ -2035,65 +1978,63 @@ msgstr "Emacs" #: packages/server/src/routes/admin/emails.ts:127 #: packages/server/src/routes/admin/users.ts:140 msgid "Email" -msgstr "" +msgstr "E-mail" #: packages/app-desktop/gui/JoplinCloudConfigScreen.tsx:47 #: packages/app-mobile/components/screens/ConfigScreen/JoplinCloudConfig.tsx:23 -#, fuzzy msgid "Email to note" -msgstr "Bewerk notitie." +msgstr "E-mail naar notitie" #: packages/lib/utils/joplinCloud/index.ts:187 msgid "Email to Note" -msgstr "" +msgstr "E-mail naar Notitie" #: packages/lib/models/Setting.ts:1213 -#, fuzzy msgid "Email To Note, login information" -msgstr "Weergave versie informatie" +msgstr "E-mail Naar Notitie, login-informatie" #: packages/server/src/routes/admin/emails.ts:111 #: packages/server/src/services/MustacheService.ts:133 msgid "Emails" -msgstr "" +msgstr "E-mails" # Unclear to me what 'emphasised' means. Bold? And what is the difference with 'strong'? #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v5/CodeMirror.tsx:195 msgid "emphasised text" -msgstr "gemarkeerde tekst" +msgstr "benadrukte tekst" #: packages/app-desktop/commands/emptyTrash.ts:16 #: packages/app-desktop/commands/emptyTrash.ts:8 #: packages/app-mobile/components/side-menu-content.tsx:338 #: packages/app-mobile/components/side-menu-content.tsx:342 msgid "Empty trash" -msgstr "" +msgstr "Prullenmand leegmaken" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:144 #: packages/app-mobile/components/biometrics/BiometricPopup.tsx:86 #: packages/app-mobile/components/screens/encryption-config.tsx:189 msgid "Enable" -msgstr "Activeer" +msgstr "Inschakelen" #: packages/lib/models/settings/builtInMetadata.ts:978 msgid "Enable ^sup^ syntax" -msgstr "Activeer ^sup^ syntax" +msgstr "^sup^ syntaxis inschakelen" #: packages/lib/models/settings/builtInMetadata.ts:982 msgid "Enable ++insert++ syntax" -msgstr "Activeer ++insert++ syntax" +msgstr "++insert++ syntaxis inschakelen" #: packages/lib/models/settings/builtInMetadata.ts:974 msgid "Enable ==mark== syntax" -msgstr "Activeer ==mark== syntax" +msgstr "==mark== syntaxis inschakelen" #: packages/lib/models/settings/builtInMetadata.ts:977 msgid "Enable ~sub~ syntax" -msgstr "Activeer ~sub~ syntax" +msgstr "~sub~ syntaxis inschakelen" #: packages/lib/models/settings/builtInMetadata.ts:980 msgid "Enable abbreviation syntax" -msgstr "Activeer afkorting syntax" +msgstr "Afkortingensyntaxis inschakelen" #: packages/lib/models/settings/builtInMetadata.ts:971 msgid "Enable audio player" @@ -2101,20 +2042,20 @@ msgstr "Audiospeler inschakelen" #: packages/app-mobile/components/biometrics/BiometricPopup.tsx:82 msgid "Enable biometrics authentication?" -msgstr "" +msgstr "Authenticatie met biometrie inschakelen?" #: packages/lib/models/settings/builtInMetadata.ts:979 msgid "Enable deflist syntax" -msgstr "Activeer definitielijst syntax" +msgstr "Definitielijst syntaxis inschakelen" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:226 #: packages/app-mobile/components/screens/encryption-config.tsx:292 msgid "Enable encryption" -msgstr "Schakel encryptie in" +msgstr "Encryptie inschakelen" #: packages/lib/models/settings/builtInMetadata.ts:994 msgid "Enable file:// URLs for images and videos" -msgstr "" +msgstr "file:// URL's inschakelen voor afbeeldingen en video's" #: packages/lib/models/settings/builtInMetadata.ts:975 msgid "Enable footnotes" @@ -2122,11 +2063,11 @@ msgstr "Voetnoten inschakelen" #: packages/lib/models/settings/builtInMetadata.ts:968 msgid "Enable Fountain syntax support" -msgstr "Ondersteuning van Fountain syntax inschakelen" +msgstr "Ondersteuning van Fountain syntaxis inschakelen" #: packages/lib/models/settings/builtInMetadata.ts:965 msgid "Enable Linkify" -msgstr "Schakel Linkify in" +msgstr "Linkify inschakelen" #: packages/lib/models/settings/builtInMetadata.ts:981 msgid "Enable markdown emoji" @@ -2134,7 +2075,7 @@ msgstr "Markdown emoji inschakelen" #: packages/lib/models/settings/builtInMetadata.ts:967 msgid "Enable math expressions" -msgstr "Schakel wiskundige formules in" +msgstr "Wiskundige expressies inschakelen" #: packages/lib/models/settings/builtInMetadata.ts:969 msgid "Enable Mermaid diagrams support" @@ -2142,60 +2083,57 @@ msgstr "Ondersteuning van Mermaid diagrammen inschakelen" #: packages/lib/models/settings/builtInMetadata.ts:983 msgid "Enable multimarkdown table extension" -msgstr "Activeer multimarkdown tabel extensie" +msgstr "Multimarkdown tabel extensie inschakelen" #: packages/lib/models/settings/builtInMetadata.ts:1473 msgid "Enable note history" -msgstr "Schakel notitiehistoriek in" +msgstr "Notitiehistoriek inschakelen" #: packages/lib/models/settings/builtInMetadata.ts:500 msgid "Enable optical character recognition (OCR)" msgstr "" +"Optische tekenherkenning (optical character recognition - OCR) inschakelen" #: packages/lib/models/Setting.ts:1219 -#, fuzzy msgid "Enable or disable plugins" -msgstr "Beheer uw plugins" +msgstr "Plugins in- of uitschakelen" #: packages/lib/models/settings/builtInMetadata.ts:973 msgid "Enable PDF viewer" -msgstr "Schakel PDF weergave in" +msgstr "PDF-weergave inschakelen" #: packages/app-mobile/components/screens/ConfigScreen/plugins/EnablePluginSupportPage.tsx:119 #: packages/lib/models/settings/builtInMetadata.ts:921 -#, fuzzy msgid "Enable plugin support" -msgstr "Schakel ondersteuning voor typograaf in" +msgstr "Ondersteuning voor plugins inschakelen" #: packages/lib/models/settings/builtInMetadata.ts:963 msgid "Enable soft breaks" msgstr "Soft breaks inschakelen" #: packages/lib/models/settings/builtInMetadata.ts:1303 -#, fuzzy msgid "Enable spell checking in Markdown editor" -msgstr "Markdown emoji inschakelen" +msgstr "Spellingscontrole in de Markdown editor inschakelen" #: packages/lib/models/settings/builtInMetadata.ts:789 msgid "Enable spellcheck in the text editor" -msgstr "" +msgstr "Spellingscontrole in de teksteditor inschakelen" #: packages/lib/models/settings/builtInMetadata.ts:976 msgid "Enable table of contents extension" msgstr "Extensie voor inhoudstafel inschakelen" #: packages/lib/models/settings/builtInMetadata.ts:800 -#, fuzzy msgid "Enable the Markdown toolbar" -msgstr "Markdown emoji inschakelen" +msgstr "Markdown werkbalk inschakelen" #: packages/lib/models/settings/builtInMetadata.ts:964 msgid "Enable typographer support" -msgstr "Schakel ondersteuning voor typograaf in" +msgstr "Ondersteuning voor typografie inschakelen" #: packages/lib/models/settings/builtInMetadata.ts:972 msgid "Enable video player" -msgstr "Schakel videospeler in" +msgstr "Videospeler inschakelen" #: packages/app-desktop/gui/ClipperConfigScreen.tsx:105 msgid "Enable Web Clipper Service" @@ -2214,16 +2152,17 @@ msgid "" "Enables Markdown list continuation, auto-closing HTML tags, and other markup " "autocompletions." msgstr "" +"Schakelt automatisch aanvullen van opmaak in, o.a. Markdown-" +"lijstvoortzetting, afluitende HTML-tags, etc." #: packages/lib/components/EncryptionConfigScreen/utils.ts:50 -#, fuzzy msgid "" "Enabling encryption means *all* your notes and attachments are going to be " "re-synchronised and sent encrypted to the sync target." msgstr "" -"Encryptie uitschakelen betekent dat *al* je notities en toevoegingen opnieuw " -"gesynchroniseerd zullen worden en ontsleuteld naar het synchronisatiedoel " -"zullen gestuurd worden. Wil je verder gaan?" +"Encryptie inschakelen betekent dat *al* je notities en toevoegingen opnieuw " +"gesynchroniseerd zullen worden en versleuteld naar het synchronisatiedoel " +"zullen gestuurd worden." #: packages/lib/models/BaseItem.ts:920 msgid "Encrypted" @@ -2240,32 +2179,29 @@ msgstr "Encryptie" #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:530 #: packages/app-mobile/components/screens/encryption-config.tsx:298 msgid "Encryption Config" -msgstr "Encryptie configuratie" +msgstr "Encryptie-configuratie" #: packages/app-cli/app/command-e2ee.ts:128 #: packages/app-mobile/components/screens/encryption-config.tsx:313 msgid "Encryption is: %s" -msgstr "Encryptie is: %s" +msgstr "Gebruikte encryptie is: %s" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:160 #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:261 -#, fuzzy msgid "Encryption keys" -msgstr "Versleuteling is:" +msgstr "Encryptie-sleutels" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:237 -#, fuzzy msgid "Encryption:" -msgstr "Encryptie" +msgstr "Encryptie:" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:235 -#, fuzzy msgid "End-to-end encryption" -msgstr "Schakel encryptie in" +msgstr "End-to-end encryptie" #: packages/app-mobile/components/voiceTyping/VoiceTypingDialog.tsx:244 msgid "Ends voice typing" -msgstr "" +msgstr "Beëindigt steminvoer" # Context needed #: packages/app-mobile/components/screens/dropbox-login.tsx:70 @@ -2275,20 +2211,19 @@ msgstr "Code hier ingeven" #: packages/app-cli/app/command-e2ee.ts:39 #: packages/app-cli/app/command-e2ee.ts:85 msgid "Enter master password:" -msgstr "Geef hoofdpaswoord in:" +msgstr "Geef hoofdwachtwoord in:" #: packages/app-mobile/components/screens/folder.js:100 msgid "Enter notebook title" msgstr "Geef titel van notitieboek in" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:122 -#, fuzzy msgid "Enter password" -msgstr "Geef hoofdpaswoord in:" +msgstr "Geef wachtwoord in" #: packages/app-mobile/components/NoteItem.tsx:120 msgid "Entering selection mode" -msgstr "" +msgstr "Bezig met selectiemodus openen" #: packages/app-cli/app/help-utils.js:56 msgid "Enum" @@ -2322,13 +2257,12 @@ msgid "" "Error. Please check that URL, username, password, etc. are correct and that " "the sync target is accessible. The reported error was:" msgstr "" -"Fout. Gelieve te verifiëren of URL, gebruikersnaam, paswoord, etc. correct " -"zijn en of het synchronisatiedoel bereikbaar is. De error was:" +"Fout. Gelieve te verifiëren of URL, gebruikersnaam, wachtwoord, etc. correct " +"zijn en of het synchronisatiedoel bereikbaar is. De gemelde fout was:" #: packages/app-mobile/components/screens/LogScreen.tsx:237 -#, fuzzy msgid "Errors only" -msgstr "Fout" +msgstr "Alleen fouten" #: packages/lib/services/interop/InteropService.ts:76 msgid "Evernote Export File (as HTML)" @@ -2339,26 +2273,24 @@ msgid "Evernote Export File (as Markdown)" msgstr "Evernote Exportbestand (als Markdown)" #: packages/lib/services/interop/InteropService.ts:94 -#, fuzzy msgid "Evernote Export Files (Directory, as HTML)" -msgstr "Evernote Exportbestand (als HTML)" +msgstr "Evernote Exportbestanden (Map, als HTML)" #: packages/lib/services/interop/InteropService.ts:103 -#, fuzzy msgid "Evernote Export Files (Directory, as Markdown)" -msgstr "Evernote Exportbestand (als Markdown)" +msgstr "Evernote Exportbestanden (Map, als Markdown)" #: packages/app-cli/app/command-exit.ts:11 msgid "Exits the application." -msgstr "Sluit de applicatie." +msgstr "Sluit de applicatie af." #: packages/app-mobile/components/side-menu-content.tsx:212 msgid "Expand %s" -msgstr "" +msgstr "%s uitklappen" #: packages/app-desktop/gui/Sidebar/listItemComponents/ExpandIcon.tsx:26 msgid "Expanded, press space to collapse." -msgstr "" +msgstr "Uitgeklapt, druk spatie om in te klappen." #: packages/app-desktop/gui/KeymapConfig/KeymapConfigScreen.tsx:182 #: packages/app-desktop/gui/Sidebar/hooks/useOnRenderItem.tsx:213 @@ -2369,56 +2301,51 @@ msgstr "Exporteren" #: packages/app-desktop/gui/MenuBar.tsx:653 #: packages/app-desktop/gui/MenuBar.tsx:709 msgid "Export all" -msgstr "Exporteer alle" +msgstr "Alles exporteren" #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteExportButton.tsx:20 -#, fuzzy msgid "Export all notes as JEX" -msgstr "Exporteer alle" +msgstr "Alle notities exporteren als JEX" #: packages/app-desktop/gui/StatusScreen/StatusScreen.tsx:199 -#, fuzzy msgid "Export debug report" -msgstr "Exporteer debug rapport" +msgstr "Foutopsporingsrapport exporteren" #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/ExportDebugReportButton.tsx:14 msgid "Export Debug Report" -msgstr "Exporteer debug rapport" +msgstr "Foutopsporingsrapport Exporteren" #: packages/app-desktop/commands/exportDeletionLog.ts:11 -#, fuzzy msgid "Export deletion log" -msgstr "Exporteer alle" +msgstr "Verwijderingslog exporteren" #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/ExportProfileButton.tsx:16 msgid "Export profile" -msgstr "Exporteer profiel" +msgstr "Profiel exporteren" #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteExportButton.tsx:70 msgid "Exported successfully!" -msgstr "" +msgstr "Succesvol geëxporteerd!" #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/ExportProfileButton.tsx:36 msgid "Exporting profile..." -msgstr "Profiel exporteren ..." +msgstr "Profiel exporteren..." #: packages/app-desktop/InteropServiceHelper.ts:199 msgid "Exporting to \"%s\" as \"%s\" format. Please wait..." -msgstr "Exporteren naar \"%s\" in \"%s\" formaat. Even geduld ..." +msgstr "Exporteren naar \"%s\" in \"%s\" formaat. Even geduld..." #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteExportButton.tsx:25 -#, fuzzy msgid "Exporting..." -msgstr "Profiel exporteren ..." +msgstr "Bezig met exporteren..." #: packages/app-cli/app/command-export.ts:14 msgid "" "Exports Joplin data to the given path. By default, it will export the " "complete database including notebooks, notes, tags and resources." msgstr "" -"Exporteert Joplin-gegevens naar de opgegeven map. Standaard zal dit de " -"volledige database exporteren, inclusief notitieboeken, notities, tags en " -"bijlagen." +"Exporteert Joplin-gegevens naar het opgegeven pad. Standaard exporteert dit " +"de volledige database,, inclusief notitieboeken, notities,labels en bijlagen." #: packages/app-cli/app/command-export.ts:24 msgid "Exports only the given note." @@ -2430,16 +2357,15 @@ msgstr "Exporteert alleen het opgegeven notitieboek." #: packages/lib/models/settings/builtInMetadata.ts:1444 msgid "Fail-safe" -msgstr "Beveiligd tegen falen" +msgstr "Faalbeveiliging" #: packages/lib/models/settings/builtInMetadata.ts:1445 msgid "" "Fail-safe: Do not wipe out local data when sync target is empty (often the " "result of a misconfiguration or bug)" msgstr "" -"Beveiligd tegen falen: Wis de lokale data niet wanneer de " -"synchronisatiebestemming leeg is (vaak het resultaat van een misconfiguratie " -"of bug)" +"Faalbeveiliging: Wis de lokale data niet wanneer de synchronisatiebestemming " +"leeg is (vaak het resultaat van een misconfiguratie of softwarefout)" #: packages/app-cli/app/main.js:107 msgid "Fatal error:" @@ -2452,7 +2378,7 @@ msgstr "Feature vlaggen" #: packages/lib/Synchronizer.ts:205 msgid "Fetched items: %d/%d." -msgstr "Opgehaalde items: %d/%d." +msgstr "Items opgehaald: %d/%d." #: packages/app-desktop/gui/Sidebar/Sidebar.tsx:53 #: packages/app-mobile/components/side-menu-content.tsx:642 @@ -2469,28 +2395,24 @@ msgstr "Bestandssysteem" #: packages/app-mobile/components/screens/LogScreen.tsx:207 #: packages/app-mobile/components/screens/LogScreen.tsx:208 -#, fuzzy msgid "Filter" -msgstr "Nieuwe tags:" +msgstr "Filter" #: packages/app-mobile/components/screens/NoteTagsDialog.tsx:227 -#, fuzzy msgid "Filter tags" -msgstr "Nieuwe tags:" +msgstr "Filter labels" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:14 -#, fuzzy msgid "Find" -msgstr "Gevonden: %d." +msgstr "Vinden" #: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:253 -#, fuzzy msgid "Find: " -msgstr "Gevonden: %d." +msgstr "Vinden: " #: packages/app-desktop/gui/ExtensionBadge.tsx:65 msgid "Firefox Extension" -msgstr "Firefox extensie" +msgstr "Firefox-extensie" #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:552 msgid "Fix search index" @@ -2498,7 +2420,7 @@ msgstr "Zoekindex herstellen" #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:552 msgid "Fixing search index..." -msgstr "Zoekindex herstellen ..." +msgstr "Zoekindex herstellen..." #: packages/app-desktop/gui/MenuBar.tsx:866 #: packages/app-desktop/gui/NoteEditor/commands/focusElementNoteBody.ts:8 @@ -2511,37 +2433,35 @@ msgstr "Focus" #: packages/lib/models/settings/builtInMetadata.ts:832 #: packages/lib/models/settings/builtInMetadata.ts:849 msgid "Focus body" -msgstr "Focus tekst" +msgstr "Tekst focussen" #: packages/lib/models/settings/builtInMetadata.ts:831 #: packages/lib/models/settings/builtInMetadata.ts:848 msgid "Focus title" -msgstr "Focus titel" +msgstr "Titel focussen" #: packages/app-mobile/components/CameraView/ScannedBarcodes.tsx:97 msgid "Follow link" -msgstr "" +msgstr "Volg link" #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/ExportProfileButton.tsx:38 msgid "For debugging purpose only: export your profile to an external SD card." -msgstr "" -"Enkel met het oog op debugging: exporteer je profiel naar een externe SD " -"card." +msgstr "Alleen voor debugging: exporteer je profiel naar een externe SD-kaart." #: packages/lib/models/settings/builtInMetadata.ts:1424 msgid "For example \"%s\"" -msgstr "" +msgstr "Bijvoorbeeld \"%s\"" #: packages/app-cli/app/command-help.ts:37 msgid "For information on how to customise the shortcuts please visit %s" -msgstr "Voor informatie over hoe de snelkoppeling aan te passen, bezoek %s" +msgstr "Voor informatie over hoe de snelkoppelingen aan te passen, bezoek %s" #: packages/app-mobile/components/screens/encryption-config.tsx:302 msgid "" "For more information about End-To-End Encryption (E2EE) and advice on how to " "enable it please check the documentation:" msgstr "" -"Voor meer informatie over End-To-End Encryptie (E2EE) en advies over hoe u " +"Voor meer informatie over End-To-End Encryptie (E2EE) en advies over hoe je " "dit kunt inschakelen, gelieve de documentatie te raadplegen:" #: packages/app-cli/app/command-help.ts:85 @@ -2556,7 +2476,7 @@ msgstr "Forceer stijl van pad" #: packages/lib/commands/historyForward.ts:6 msgid "Forward" -msgstr "Verder" +msgstr "Vooruit" #: packages/app-cli/app/command-import.ts:50 #: packages/app-desktop/gui/ImportScreen.tsx:89 @@ -2564,18 +2484,16 @@ msgid "Found: %d." msgstr "Gevonden: %d." #: packages/app-mobile/utils/getVersionInfoText.ts:47 -#, fuzzy msgid "FTS enabled: %d" -msgstr "Verwijderen: %d" +msgstr "FTS ingeschakeld: %d" #: packages/app-desktop/checkForUpdates.ts:109 msgid "Full changelog" msgstr "Volledige log van wijzigingen" #: packages/server/src/routes/admin/users.ts:136 -#, fuzzy msgid "Full name" -msgstr "Volledige log van wijzigingen" +msgstr "Volledige naam" #: packages/lib/models/Setting.ts:1172 #: packages/server/src/services/MustacheService.ts:114 @@ -2583,25 +2501,26 @@ msgid "General" msgstr "Algemeen" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:240 -#, fuzzy msgid "Generated" -msgstr "Algemeen" +msgstr "Gegenereerd" #: packages/app-desktop/gui/ShareNoteDialog.tsx:186 msgid "Generating link..." msgid_plural "Generating links..." -msgstr[0] "Generatie koppeling ..." -msgstr[1] "Generatie koppelingen ..." +msgstr[0] "Link genereren..." +msgstr[1] "Links genereren..." #: packages/lib/models/Setting.ts:1215 msgid "Geolocation, spellcheck, editor toolbar, image resize" msgstr "" +"Geo-locatie, spellingscontrole, editor werkbalk, afmetingen afbeelding " +"aanpassen" # Context needed # Is 'get' a bit like download? #: packages/app-desktop/gui/ExtensionBadge.tsx:93 msgid "Get it now:" -msgstr "Nu ophalen:" +msgstr "Download nu:" #: packages/lib/models/settings/builtInMetadata.ts:1199 msgid "Get pre-releases when checking for updates" @@ -2614,26 +2533,25 @@ msgid "" "current configuration." msgstr "" "Haalt een configuratie waarde op of stelt een waarde in. Als [value] niet " -"opgegeven is, zal de waarde van [name] getoond worden. Als noch de [name] of " -"[waarde] opgegeven zijn, zal de huidige configuratie opgelijst worden." +"opgegeven is, zal de waarde van [name] getoond worden. Als noch de [name] " +"noch [waarde] opgegeven zijn, zal de huidige configuratie opgelijst worden." #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:13 msgid "go" -msgstr "" +msgstr "ga" #: packages/app-mobile/components/CameraView/CameraView.tsx:165 msgid "Go back" -msgstr "" +msgstr "Ga terug" #: packages/app-desktop/gui/JoplinCloudConfigScreen.tsx:44 #: packages/app-mobile/components/screens/ConfigScreen/JoplinCloudConfig.tsx:59 -#, fuzzy msgid "Go to Joplin Cloud profile" -msgstr "Joplin Forum" +msgstr "Ga naar Joplin Cloud-profiel" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:12 msgid "Go to line" -msgstr "" +msgstr "Ga naar regel" #: packages/app-mobile/components/screens/Note/Note.tsx:1051 msgid "Go to source URL" @@ -2642,55 +2560,51 @@ msgstr "Ga naar bron-URL" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/gotoAnything.ts:13 #: packages/app-desktop/plugins/GotoAnything.tsx:737 msgid "Goto Anything..." -msgstr "Ga naar om het even wat ..." +msgstr "Ga naar om het even wat..." #: packages/app-desktop/gui/Root.tsx:151 -#, fuzzy msgid "Grant authorisation" -msgstr "Autorisatietoken:" +msgstr "Autorisatie verlenen" +# Context unclear #: packages/app-cli/app/command-sync.ts:116 msgid "Have you authorised the application login in the above URL?" -msgstr "" +msgstr "Heb je de applicatie-login geautoriseerd op de URL hierboven?" #: packages/app-mobile/components/NoteEditor/commandDeclarations.ts:19 msgid "Header %d" -msgstr "" +msgstr "Kop %d" #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:95 msgid "Heading" -msgstr "Hoofding" +msgstr "Kop" #: packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx:228 #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:265 #: packages/app-desktop/gui/HelpButton.tsx:49 #: packages/server/src/services/MustacheService.ts:284 -#, fuzzy msgid "Help" msgstr "Help" #: packages/app-mobile/components/screens/ConfigScreen/plugins/EnablePluginSupportPage.tsx:113 msgid "Here's what we do to make plugins safer:" -msgstr "" +msgstr "Dit is wat wij doen om plugins veiliger te maken:" #: packages/app-mobile/utils/getVersionInfoText.ts:49 -#, fuzzy msgid "Hermes enabled: %d" -msgstr "Verwijderen: %d" +msgstr "Hermes ingeschakeld: %d" #: packages/app-desktop/gui/MenuBar.tsx:670 msgid "Hide %s" -msgstr "Verberg %s" +msgstr "%s verbergen" #: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:221 -#, fuzzy msgid "Hide advanced" -msgstr "Verberg metadata" +msgstr "Geavanceerd verbergen" #: packages/server/src/routes/admin/users.ts:206 -#, fuzzy msgid "Hide disabled" -msgstr "Uitgeschakelde toetsen verbergen" +msgstr "Uitgeschakeld verbergen" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:160 msgid "Hide disabled keys" @@ -2701,14 +2615,12 @@ msgid "Hide Joplin" msgstr "Verberg Joplin" #: packages/app-mobile/components/screens/Note/commands/hideKeyboard.ts:7 -#, fuzzy msgid "Hide keyboard" -msgstr "Verberg metadata" +msgstr "Toetsenbord verbergen" #: packages/app-desktop/gui/PasswordInput/PasswordInput.tsx:21 -#, fuzzy msgid "Hide password" -msgstr "Ongeldig antwoord: %s" +msgstr "Wachtwoord verbergen" #: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/setupToolbarButtons.ts:14 msgid "Highlight" @@ -2717,27 +2629,27 @@ msgstr "Markeren" #: packages/server/src/services/MustacheService.ts:150 #: packages/server/src/services/MustacheService.ts:279 msgid "Home" -msgstr "Thuis" +msgstr "Start" #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:100 msgid "Horizontal Rule" -msgstr "Horizontale lijn" +msgstr "Horizontale Lijn" #: packages/lib/services/interop/InteropService.ts:186 msgid "HTML Directory" -msgstr "HTML Map" +msgstr "HTML-Map" #: packages/lib/services/interop/InteropService.ts:112 msgid "HTML document" -msgstr "" +msgstr "HTML-document" #: packages/lib/services/interop/InteropService.ts:179 msgid "HTML File" -msgstr "HTML Bestand" +msgstr "HTML-Bestand" #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:65 msgid "Hyperlink" -msgstr "Koppeling" +msgstr "Hyperlink" #: packages/app-desktop/gui/EditFolderDialog/Dialog.tsx:141 msgid "Icon" @@ -2760,74 +2672,74 @@ msgid "" "If you have already authorised, please wait for the application to sync to " "Joplin Cloud." msgstr "" +"Als je al geautoriseerd hebt, gelieve te wachten terwijl de toepassing " +"synchroniseert met Joplin Cloud." #: packages/app-desktop/ElectronAppWrapper.ts:127 #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:360 #: packages/app-desktop/gui/StatusScreen/StatusScreen.tsx:121 #: packages/app-mobile/components/screens/status.tsx:147 msgid "Ignore" -msgstr "Negeer" +msgstr "Negeren" #: packages/lib/models/settings/builtInMetadata.ts:1403 msgid "Ignore TLS certificate errors" msgstr "Negeer TLS-certificaatfouten" #: packages/lib/services/ReportService.ts:236 -#, fuzzy msgid "Ignored items that cannot be synchronised" -msgstr "Items die niet gesynchroniseerd kunnen worden" +msgstr "Genegeerde items die niet gesynchroniseerd kunnen worden" #: packages/app-desktop/gui/EditFolderDialog/Dialog.tsx:106 msgid "Images" -msgstr "" +msgstr "Afbeeldingen" #: packages/app-desktop/gui/KeymapConfig/KeymapConfigScreen.tsx:181 #: packages/app-desktop/gui/MenuBar.tsx:649 #: packages/app-desktop/gui/MenuBar.tsx:706 #: packages/app-desktop/gui/Root.tsx:191 msgid "Import" -msgstr "Importeer" +msgstr "Importeren" #: packages/lib/models/Setting.ts:1186 -#, fuzzy msgid "Import and Export" -msgstr "Exporteer debug rapport" +msgstr "Importeren en Exporteren" #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteImportButton.tsx:66 msgid "" "Import failed. Make sure a JEX file was selected.\n" "Details: %s" msgstr "" +"Importeren gefaald. Controleer of er een JEX-bestand geselecteerd was.\n" +"Details: %s" #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteImportButton.tsx:21 msgid "Import from JEX" -msgstr "" +msgstr "Importeren van JEX" #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteImportButton.tsx:22 msgid "Import notes from a JEX (Joplin Export) file." -msgstr "" +msgstr "Importeer notities van een JEX (Joplin Export) bestand." #: packages/lib/models/Setting.ts:1218 -#, fuzzy msgid "Import or export your data" -msgstr "Exporteer alle" +msgstr "Importeer of exporteer je gegevens" #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteImportButton.tsx:76 msgid "Imported successfully!" -msgstr "" +msgstr "Succesvol geïmporteerd!" #: packages/app-desktop/gui/MenuBar.tsx:319 msgid "Importing from \"%s\" as \"%s\" format. Please wait..." -msgstr "Importeren van \"%s\" in \"%s\" formaat. Even geduld ..." +msgstr "Importeren van \"%s\" in \"%s\" formaat. Even geduld..." #: packages/app-cli/app/command-import.ts:68 msgid "Importing notes..." -msgstr "Notities importeren ..." +msgstr "Notities importeren..." #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/NoteImportButton.tsx:26 -#, fuzzy msgid "Importing..." -msgstr "Profiel exporteren ..." +msgstr "Importeren..." #: packages/app-cli/app/command-import.ts:16 msgid "Imports data into Joplin." @@ -2851,8 +2763,8 @@ msgid "" "note or notebook. `$c` can be used to refer to the currently selected item." msgstr "" "Bij ieder commando kan er naar een notitie of een notitieboek verwezen " -"worden door de titel, het ID of de snelkoppelingen `$n` of `$b` te " -"gebruiken, respectievelijk, het huidig geselecteerde notitieboek of de " +"worden door de titel of het ID, of door de snelkoppelingen `$n` of `$b` te " +"gebruiken voor, respectievelijk, het huidig geselecteerde notitieboek of de " "huidige geselecteerde notitie. `$c` kan gebruikt worden om te refereren naar " "het huidige geselecteerde item." @@ -2863,10 +2775,10 @@ msgid "" "\n" "You may turn off this option at any time in the Configuration screen." msgstr "" -"Om een geo-locatie aan de notitie te koppelen, heeft de app uw toestemming " -"nodig om toegang te krijgen tot uw locatie.\n" +"Om een geo-locatie aan de notitie te koppelen, heeft de app je toestemming " +"nodig om toegang te krijgen tot je locatie.\n" "\n" -"U kunt deze optie op elk moment uitschakelen in de instellingen." +"Je kan deze optie op elk moment uitschakelen in het 'Configuratie'-scherm." #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:346 msgid "" @@ -2884,23 +2796,24 @@ msgid "" "\n" "Important: you only need to run this ONCE on one device." msgstr "" -"Om dit te doen, moet uw volledige dataset worden versleuteld en " -"gesynchroniseerd, dus het is het beste om het 's nachts uit te voeren.\n" +"Om dit te doen, moet je volledige dataset worden versleuteld en " +"gesynchroniseerd, dus het is het best om dit 's nachts uit te voeren.\n" "\n" "Om te beginnen, gelieve deze instructies te volgen:\n" "\n" -"1. Synchroniseer al uw apparaten.\n" +"1. Synchroniseer al je apparaten.\n" "2. Klik op \"%s\".\n" -"3. Laat het tot het einde lopen. Terwijl het loopt, vermijd het veranderen " -"van enige notitie op uw andere apparaten, om conflicten te vermijden.\n" -"4. Zodra de synchronisatie op dit apparaat is voltooid, synchroniseert u " -"alle andere apparaten en laat u de synchronisatie tot het einde uitvoeren.\n" +"3. Laat het tot het einde lopen. Zorg ervoor dat je ondertussen geen " +"notities wijzigt op je andere apparaten, om conflicten te vermijden.\n" +"4. Zodra de synchronisatie op dit apparaat is voltooid, synchroniseer je " +"alle andere apparaten en laat je de synchronisatie tot het einde uitvoeren.\n" "\n" -"Belangrijk: u hoeft dit maar EEN keer op één apparaat te doen." +"Belangrijk: je hoeft dit maar ÉÉN keer op één apparaat te doen." #: packages/lib/services/synchronizer/syncInfoUtils.ts:466 msgid "In order to synchronise, please upgrade your application to version %s+" msgstr "" +"Om te synchroniseren, gelieve je toepassing te upgraden naar versie %s+" #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:122 #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:224 @@ -2908,16 +2821,16 @@ msgid "" "In order to use file system synchronisation your permission to write to " "external storage is required." msgstr "" -"Om bestandssysteemsynchronisatie te kunnen gebruiken, is uw toestemming " +"Om bestandssysteemsynchronisatie te kunnen gebruiken, is je toestemming " "vereist om naar externe opslag te schrijven." #: packages/app-desktop/gui/ClipperConfigScreen.tsx:121 msgid "In order to use the web clipper, you need to do the following:" -msgstr "Om de web clipper te gebruiken, moet u het volgende doen:" +msgstr "Om de web clipper te gebruiken, moet je het volgende doen:" #: packages/lib/Synchronizer.ts:325 msgid "In progress" -msgstr "In uitvoering" +msgstr "Bezig" #: packages/app-desktop/gui/NoteEditor/NoteEditor.tsx:628 msgid "In: %s" @@ -2925,21 +2838,19 @@ msgstr "In: %s" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/PluginChips.tsx:69 msgid "Incompatible" -msgstr "" +msgstr "Incompatibel" #: packages/app-desktop/gui/NoteList/utils/useOnKeyDown.ts:153 -#, fuzzy msgid "Incomplete" -msgstr "Voltooid" +msgstr "Niet voltooid" #: packages/app-desktop/gui/NoteListItem/utils/prepareViewProps.ts:40 -#, fuzzy msgid "Incomplete to-do" -msgstr "Toon voltooide to-do's" +msgstr "Niet-voltooide taak" #: packages/app-mobile/components/NoteEditor/commandDeclarations.ts:97 msgid "Increase indent level" -msgstr "" +msgstr "Niveau van inspringing vergroten" #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:126 msgid "Indent less" @@ -2951,7 +2862,7 @@ msgstr "Insprong vergroten" #: packages/app-mobile/components/DialogManager/hooks/useDialogControl.ts:21 msgid "Info" -msgstr "" +msgstr "Info" #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:223 msgid "Information" @@ -2968,14 +2879,13 @@ msgstr "Invoegen" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v5/CodeMirror.tsx:197 #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/useEditorCommands.ts:84 msgid "Insert Hyperlink" -msgstr "Koppeling inlassen" +msgstr "Hyperlink invoegen" #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:105 #: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx:779 #: packages/app-mobile/components/screens/Note/commands/insertDateTime.ts:8 -#, fuzzy msgid "Insert time" -msgstr "Datum en tijd inlassen" +msgstr "Tijd invoegen" #: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.tsx:191 #: packages/app-mobile/components/screens/ConfigScreen/plugins/buttons/InstallButton.tsx:18 @@ -2994,9 +2904,8 @@ msgid "Installed" msgstr "Geïnstalleerd" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginStates.tsx:202 -#, fuzzy msgid "Installed (%d):" -msgstr "Geïnstalleerd" +msgstr "Geïnstalleerd (%d):" #: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.tsx:192 #: packages/app-mobile/components/screens/ConfigScreen/plugins/buttons/InstallButton.tsx:17 @@ -3025,14 +2934,12 @@ msgid "Invalid option value: \"%s\". Possible values are: %s." msgstr "Ongeldige optie: \"%s\". Geldige waarden zijn: %s." #: packages/app-cli/app/command-e2ee.ts:47 -#, fuzzy msgid "Invalid password" -msgstr "Ongeldig antwoord: %s" +msgstr "Ongeldig wachtwoord" #: packages/app-mobile/utils/getVersionInfoText.ts:24 -#, fuzzy msgid "iOS version: %s" -msgstr "Nieuwe versie: %s" +msgstr "iOS versie: %s" #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:60 #: packages/app-mobile/components/NoteEditor/commandDeclarations.ts:59 @@ -3041,7 +2948,7 @@ msgstr "Cursief" #: packages/lib/services/ReportService.ts:194 msgid "Item \"%s\" could not be downloaded: %s" -msgstr "Item \"%s\" kon niet opgehaald worden: %s" +msgstr "Item \"%s\" kon niet gedownload worden: %s" #: packages/server/src/services/MustacheService.ts:158 #: packages/server/src/services/MustacheService.ts:281 @@ -3050,15 +2957,16 @@ msgstr "Items" #: packages/lib/services/ReportService.ts:252 msgid "Items that cannot be decrypted" -msgstr "Items die niet gedecrypteerd kunnen worden" +msgstr "Items die niet ontsleuteld kunnen worden" #: packages/lib/services/ReportService.ts:185 msgid "Items that cannot be synchronised" msgstr "Items die niet gesynchroniseerd kunnen worden" +# Context onduidelijk #: packages/app-desktop/gui/MenuBar.tsx:923 msgid "Join us on %s" -msgstr "" +msgstr "Volg ons op %s" #: packages/app-desktop/gui/SyncWizard/Dialog.tsx:267 msgid "" @@ -3069,26 +2977,25 @@ msgstr "" "een provider van onderstaande lijst." #: packages/lib/models/Setting.ts:1184 packages/lib/SyncTargetJoplinCloud.ts:30 -#, fuzzy msgid "Joplin Cloud" -msgstr "Joplin Forum" +msgstr "Joplin Cloud" #: packages/app-desktop/gui/Root.tsx:190 #: packages/app-mobile/components/screens/JoplinCloudLoginScreen.tsx:148 -#, fuzzy msgid "Joplin Cloud Login" -msgstr "Joplin Forum" +msgstr "Joplin Cloud Login" #: packages/lib/services/plugins/PluginService.ts:525 -#, fuzzy msgid "Joplin Desktop" -msgstr "Joplin website" +msgstr "Joplin Desktop" #: packages/app-desktop/bridge.ts:448 msgid "" "Joplin doesn't recognise the %s extension. Opening this file could be " "dangerous. What would you like to do?" msgstr "" +"Joplin herkent de %s extensie niet. Dit bestand openen kan gevaarlijk zijn. " +"Wat wil je doen?" #: packages/lib/services/interop/InteropService.ts:159 #: packages/lib/services/interop/InteropService.ts:68 @@ -3106,36 +3013,33 @@ msgid "" "are corrupted or too large. These items will remain on the device but Joplin " "will no longer attempt to decrypt them." msgstr "" -"Joplin is er meerdere malen niet in geslaagd deze items te decrypteren, " -"mogelijk omdat ze corrupt of te groot zijn. Deze items blijven op het " -"apparaat staan, maar Joplin zal niet langer proberen ze te decrypteren." +"Joplin is er meerdere malen niet in geslaagd deze items te ontsleutelen, " +"mogelijk omdat ze beschadigd of te groot zijn. Deze items blijven op het " +"apparaat staan, maar Joplin zal niet langer proberen ze te ontsleutelen." #: packages/app-desktop/gui/MenuBar.tsx:920 msgid "Joplin Forum" msgstr "Joplin Forum" #: packages/app-mobile/utils/lockToSingleInstance.ts:16 -#, fuzzy msgid "Joplin is already running." -msgstr "Server is reeds actief op poort %d" +msgstr "Joplin is al gestart." #: packages/lib/services/plugins/PluginService.ts:523 -#, fuzzy msgid "Joplin Mobile" -msgstr "Joplin website" +msgstr "Joplin Mobile" #: packages/lib/SyncTargetJoplinServer.ts:61 msgid "Joplin Server" msgstr "Joplin Server" #: packages/lib/models/settings/builtInMetadata.ts:321 -#, fuzzy msgid "Joplin Server email" -msgstr "Joplin Server" +msgstr "Joplin Server e-mail" #: packages/lib/models/settings/builtInMetadata.ts:333 msgid "Joplin Server password" -msgstr "Joplin Server paswoord" +msgstr "Joplin Server wachtwoord" #: packages/lib/models/settings/builtInMetadata.ts:302 msgid "Joplin Server URL" @@ -3151,14 +3055,14 @@ msgstr "" #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:605 msgid "Joplin website" -msgstr "Joplin website" +msgstr "Joplin-website" #: packages/lib/SyncTargetJoplinCloud.ts:34 msgid "" "Joplin's own sync service. Also gives access to Joplin-specific features " "such as publishing notes or collaborating on notebooks with others." msgstr "" -"Joplins eigen synchronisatie service. Geeft ook toegang tot specifieke " +"Joplins eigen synchronisatieservice. Geeft ook toegang tot Joplin-specifieke " "features zoals het publiceren van notities of samenwerken aan notitieboeken " "met anderen." @@ -3167,9 +3071,8 @@ msgid "Keep note history for" msgstr "Bewaar notitiehistoriek gedurende" #: packages/lib/models/settings/builtInMetadata.ts:1739 -#, fuzzy msgid "Keep notes in the trash for" -msgstr "Bewaar notitiehistoriek gedurende" +msgstr "Bewaar notities in de prullenmand gedurende" #: packages/lib/models/settings/builtInMetadata.ts:1285 msgid "Keyboard Mode" @@ -3188,9 +3091,8 @@ msgid "Keychain Supported: %s" msgstr "Keychain ondersteund: %s" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:74 -#, fuzzy msgid "Keys that need upgrading" -msgstr "Hoofdsleutels hebben upgrade nodig" +msgstr "Sleutels die upgrade nodig hebben" #: packages/lib/models/settings/builtInMetadata.ts:1262 msgid "Landscape" @@ -3201,9 +3103,8 @@ msgid "Language" msgstr "Taal" #: packages/lib/models/Setting.ts:1210 -#, fuzzy msgid "Language, date format" -msgstr "Datumformaat" +msgstr "Taal, datumformaat" #: packages/lib/Synchronizer.ts:208 msgid "Last error: %s" @@ -3215,7 +3116,7 @@ msgstr "Later" #: packages/app-desktop/gui/NoteListHeader/utils/getColumnTitle.ts:7 msgid "Latitude" -msgstr "" +msgstr "Breedtegraad" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v5/CodeMirror.tsx:638 #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/CodeMirror.tsx:237 @@ -3224,28 +3125,25 @@ msgstr "Layout" #: packages/app-desktop/gui/MenuBar.tsx:789 msgid "Layout button sequence" -msgstr "Volgorde layout-knop" +msgstr "Volgorde layout-knoppen" #: packages/app-desktop/bridge.ts:453 #: packages/app-mobile/components/screens/ConfigScreen/plugins/EnablePluginSupportPage.tsx:118 #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/RecommendedBadge.tsx:52 -#, fuzzy msgid "Learn more" -msgstr "Insprong vergroten" +msgstr "Meer leren" #: packages/lib/models/settings/builtInMetadata.ts:1692 msgid "Leave it blank to download the language files from the default website" -msgstr "" +msgstr "Laat leeg om de taalbestanden van de standard website te downloaden" #: packages/app-mobile/components/screens/ShareManager/AcceptedShareItem.tsx:90 -#, fuzzy msgid "Leave notebook" -msgstr "Notitie delen ..." +msgstr "Verlaat notitieboek" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/leaveSharedFolder.ts:11 -#, fuzzy msgid "Leave notebook..." -msgstr "Notitie delen ..." +msgstr "Verlaat notitieboek..." #: packages/lib/models/settings/builtInMetadata.ts:1256 msgid "Legal" @@ -3264,55 +3162,49 @@ msgid "" "Like any software you install, plugins can potentially cause security issues " "or data loss." msgstr "" +"Zoals elke software die je installeert, kunnen plugins mogelijk " +"beveiligingsproblemen of gegevensverlies veroorzaken." #: packages/app-desktop/gui/NoteContentPropertiesDialog.tsx:108 msgid "Lines" msgstr "Regels" -# Unclear to me what 'strong' means. Bold? And what is the difference with 'emphasised'? #: packages/app-mobile/components/NoteEditor/commandDeclarations.ts:107 -#, fuzzy msgid "Link" -msgstr "benadrukte text" +msgstr "Link" #: packages/app-mobile/components/NoteEditor/EditLinkDialog.tsx:97 -#, fuzzy msgid "Link description" -msgstr "Encryptie" +msgstr "Beschrijving van link" #: packages/app-desktop/gui/ShareNoteDialog.tsx:187 msgid "Link has been copied to clipboard!" msgid_plural "Links have been copied to clipboard!" -msgstr[0] "Koppeling is gekopieerd naar klembord!" -msgstr[1] "Koppelingen zijn gekopieerd naar klembord!" +msgstr[0] "Link is gekopieerd naar klembord!" +msgstr[1] "Links zijn gekopieerd naar klembord!" -# Unclear to me what 'strong' means. Bold? And what is the difference with 'emphasised'? #: packages/app-mobile/components/NoteEditor/EditLinkDialog.tsx:94 -#, fuzzy msgid "Link text" -msgstr "benadrukte text" +msgstr "Tekst van link" # Unclear. Context needed. #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v5/CodeMirror.tsx:231 #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v5/CodeMirror.tsx:233 #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v5/CodeMirror.tsx:234 msgid "List item" -msgstr "Lijst item" +msgstr "Lijstitem" #: packages/app-mobile/components/screens/encryption-config.tsx:220 -#, fuzzy msgid "Loaded" -msgstr "Opgehaald" +msgstr "Geladen" #: packages/app-desktop/gui/ConfigScreen/controls/FontSearch.tsx:123 #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginStates.tsx:117 #: packages/app-mobile/components/voiceTyping/VoiceTypingDialog.tsx:179 #: packages/app-mobile/root.tsx:1247 -#, fuzzy msgid "Loading..." -msgstr "Updaten ..." +msgstr "Laden..." -# Context needed #: packages/app-desktop/gui/NotePropertiesDialog.tsx:71 msgid "Location" msgstr "Locatie" @@ -3324,8 +3216,8 @@ msgid "" "taking place, you may delete the lock file at \"%s\" and resume the " "operation." msgstr "" -"Vergrendelingsbestand is al bezet. Als u zeker bent dat er geen " -"synchronisatie bezig is, mag u het vergrendelingsbestand verwijderen op " +"Vergrendelingsbestand is al bezet. Als je zeker bent dat er geen " +"synchronisatie bezig is, mag je het vergrendelingsbestand verwijderen op " "\"%s\" en de synchronisatie hervatten." #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:550 @@ -3335,17 +3227,16 @@ msgid "Log" msgstr "Log" #: packages/app-desktop/gui/MainScreen.tsx:563 -#, fuzzy msgid "Login to Joplin Cloud." -msgstr "Joplin Forum" +msgstr "Inloggen op Joplin Cloud." #: packages/app-mobile/components/screens/dropbox-login.tsx:59 msgid "Login with Dropbox" -msgstr "Login with Dropbox" +msgstr "Inloggen met Dropbox" #: packages/app-mobile/components/screens/onedrive-login.js:110 msgid "Login with OneDrive" -msgstr "Log in met OneDrive" +msgstr "Inloggen met OneDrive" #: packages/server/src/services/MustacheService.ts:285 msgid "Logout" @@ -3353,11 +3244,11 @@ msgstr "Afmelden" #: packages/lib/models/Setting.ts:1217 msgid "Logs, profiles, sync status" -msgstr "" +msgstr "Logs, profielen, synchronisatie-status" #: packages/app-desktop/gui/NoteListHeader/utils/getColumnTitle.ts:8 msgid "Longitude" -msgstr "" +msgstr "Lengtegraad" #: packages/app-desktop/gui/MenuBar.tsx:926 #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:604 @@ -3365,48 +3256,41 @@ msgid "Make a donation" msgstr "Doe een gift" #: packages/app-desktop/gui/MasterPasswordDialog/Dialog.tsx:221 -#, fuzzy msgid "Manage master password" -msgstr "Geef hoofdpaswoord in:" +msgstr "Beheer hoofdwachtwoord" #: packages/lib/commands/openMasterPasswordDialog.ts:6 -#, fuzzy msgid "Manage master password..." -msgstr "Geef hoofdpaswoord in:" +msgstr "Beheer hoofdwachtwoord..." #: packages/lib/utils/joplinCloud/index.ts:201 -#, fuzzy msgid "Manage multiple users" -msgstr "Geef hoofdpaswoord in:" +msgstr "Beheer meedere gebruikers" #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:548 -#, fuzzy msgid "Manage profiles" -msgstr "Exporteer profiel" +msgstr "Beheer profielen" #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:555 -#, fuzzy msgid "Manage shared notebooks" -msgstr "Exporteer profiel" +msgstr "Beheer gedeelde notitieboeken" #: packages/app-mobile/components/EditorToolbar/ToolbarEditorDialog.tsx:165 -#, fuzzy msgid "Manage toolbar options" -msgstr "Beheer uw plugins" +msgstr "Beheer werkbalk-opties" #: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.tsx:331 msgid "Manage your plugins" -msgstr "Beheer uw plugins" +msgstr "Beheer je plugins" #. `generate-ppk` #: packages/app-cli/app/command-e2ee.ts:19 -#, fuzzy msgid "" "Manages E2EE configuration. Commands are `enable`, `disable`, `decrypt`, " "`status`, `decrypt-file`, and `target-status`." msgstr "" -"Beheert E2EE configuratie. Commando's zijn `enable`, `disable`, `decrypt`, " -"`status` and `target-status`." +"Beheert E2EE-configuratie. Commando's zijn `enable`, `disable`, `decrypt`, " +"`status`, `decrypt-file`, en `target-status`." #: packages/lib/models/settings/builtInMetadata.ts:397 msgid "Manual" @@ -3426,17 +3310,16 @@ msgstr "Markdown + Front Matter" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/CodeMirror.tsx:375 #: packages/app-mobile/components/NoteEditor/NoteEditor.tsx:352 -#, fuzzy msgid "Markdown editor" -msgstr "Markdown" +msgstr "Markdown editor" #: packages/app-cli/app/command-done.ts:15 msgid "Marks a to-do as done." -msgstr "Markeert een to-do als voltooid." +msgstr "Markeert een taak als voltooid." #: packages/app-cli/app/command-undone.js:12 msgid "Marks a to-do as non-completed." -msgstr "Markeert een to-do als onvoltooid." +msgstr "Markeert een taak als onvoltooid." #: packages/app-desktop/gui/NotePropertiesDialog.tsx:74 msgid "Markup" @@ -3444,28 +3327,26 @@ msgstr "Opmaak" #: packages/app-mobile/components/screens/encryption-config.tsx:124 msgid "Master Key %s" -msgstr "Hoofdsleutel: %s" +msgstr "Hoofdsleutel %s" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:114 #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:273 #: packages/app-mobile/components/screens/encryption-config.tsx:109 -#, fuzzy msgid "Master password" -msgstr "Geef hoofdpaswoord in:" +msgstr "Hoofdwachtwoord" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:274 #: packages/app-mobile/components/screens/encryption-config.tsx:219 -#, fuzzy msgid "Master password:" -msgstr "Geef hoofdpaswoord in:" +msgstr "Hoofdwachtwoord:" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:19 msgid "match case" -msgstr "" +msgstr "hoofdlettergebruik evenaren" #: packages/app-mobile/components/NoteEditor/commandDeclarations.ts:72 msgid "Math" -msgstr "" +msgstr "Wiskunde" #: packages/lib/models/settings/builtInMetadata.ts:421 msgid "Max concurrent connections" @@ -3473,35 +3354,31 @@ msgstr "Maximum aantal gelijktijdige connecties" #: packages/server/src/routes/admin/users.ts:148 msgid "Max Item Size" -msgstr "" +msgstr "Maximale grootte van items" #: packages/lib/utils/joplinCloud/index.ts:129 -#, fuzzy msgid "Max note or attachment size" -msgstr "Notitiebijlagen" +msgstr "Maximale grootte van notities of bijlagen" #: packages/server/src/routes/admin/users.ts:156 -#, fuzzy msgid "Max Total Size" -msgstr "Huidige grootte" +msgstr "Maximale totale grootte" #: packages/lib/models/Setting.ts:1214 msgid "Media player, math, diagrams, table of contents" -msgstr "" +msgstr "Mediaspeler, wiskunde, diagrammen, inhoudstafel" #: packages/app-desktop/gui/KeymapConfig/utils/getLabel.ts:24 msgid "Minimise" -msgstr "" +msgstr "Minimaliseren" #: packages/app-mobile/components/CameraView/CameraView.tsx:163 -#, fuzzy msgid "Missing camera permission" -msgstr "Ontbrekende Hoofdsleutels" +msgstr "Toestemming voor camera ontbreekt" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:320 -#, fuzzy msgid "Missing keys" -msgstr "Ontbrekende Hoofdsleutels" +msgstr "Ontbrekende sleutels" #: packages/app-mobile/components/screens/encryption-config.tsx:282 msgid "Missing Master Keys" @@ -3509,12 +3386,11 @@ msgstr "Ontbrekende Hoofdsleutels" #: packages/app-cli/app/cli-utils.js:112 msgid "Missing required argument: %s" -msgstr "Benodigde argumenten niet voorzien: %s" +msgstr "Vereist argument ontbreekt: %s" #: packages/app-cli/app/cli-utils.js:135 -#, fuzzy msgid "Missing required flag value: %s" -msgstr "Benodigde argumenten niet voorzien: %s" +msgstr "Vereiste argumentwaarde ontbreekt: %s" #: packages/app-mobile/components/side-menu-content.tsx:663 msgid "Mobile data - auto-sync disabled" @@ -3531,12 +3407,14 @@ msgstr "Meer informatie" #: packages/app-cli/app/app.ts:67 msgid "More than one item match \"%s\". Please narrow down your query." msgstr "" -"Meer dan één item voldoet aan de zoekterm \"%s\". Verfijn uw zoekterm a.u.b." +"Meer dan één item voldoet aan de zoekterm \"%s\". Verfijn je zoekopdracht." #: packages/app-mobile/components/screens/ConfigScreen/plugins/EnablePluginSupportPage.tsx:115 msgid "" "Most plugins have source code available for review on the plugin website." msgstr "" +"De meeste plugins hebben broncode die je kunt bekijken op de website van de " +"plugin." #: packages/app-mobile/components/ScreenHeader/index.tsx:546 msgid "Move %d notes to notebook \"%s\"?" @@ -3545,17 +3423,16 @@ msgstr "Verplaats %d notities naar notitieboek \"%s\"?" #: packages/app-cli/app/command-rmbook.ts:38 #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/deleteFolder.ts:20 #: packages/app-mobile/components/side-menu-content.tsx:410 -#, fuzzy msgid "" "Move notebook \"%s\" to the trash?\n" "\n" "All notes and sub-notebooks within this notebook will also be moved to the " "trash." msgstr "" -"Notitieboek \"%s\" verwijderen?\n" +"Notitieboek \"%s\" naar de prullenmand verplaatsen?\n" "\n" -"Alle notities en sub-notitieboeken in dit notitieboek zullen ook verwijderd " -"worden." +"Alle notities en sub-notitieboeken in dit notitieboek zullen ook naar de " +"prullenmand verplaatst worden." #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/moveToFolder.ts:14 msgid "Move to notebook" @@ -3570,9 +3447,8 @@ msgid "Move to notebook..." msgstr "Verplaats naar notitieboek..." #: packages/app-cli/app/command-mv.ts:14 -#, fuzzy msgid "Moves the given to [notebook]" -msgstr "Verplaatst de notities die voldoen aan naar [notitieboek]." +msgstr "Verplaatst het gegeven naar [notitieboek]" #: packages/app-cli/app/cli-utils.js:177 #: packages/app-cli/app/setupCommand.ts:23 @@ -3585,22 +3461,19 @@ msgstr "N" #: packages/lib/models/settings/builtInMetadata.ts:868 msgid "Never resize" -msgstr "" +msgstr "Nooit formaat wijzigen" #: packages/app-mobile/setupQuickActions.ts:33 -#, fuzzy msgid "New attachment" -msgstr "Notitiebijlagen" +msgstr "Nieuwe bijlage" #: packages/app-mobile/setupQuickActions.ts:34 -#, fuzzy msgid "New drawing" -msgstr "Nieuwe tags:" +msgstr "Nieuwe tekening" #: packages/app-mobile/components/screens/ShareManager/index.tsx:120 -#, fuzzy msgid "New invitations" -msgstr "Nieuwe versie: %s" +msgstr "Nieuwe uitnodigingen" #: packages/app-desktop/gui/NoteListControls/NoteListControls.tsx:111 #: packages/app-desktop/gui/NoteListWrapper/NoteListWrapper.tsx:72 @@ -3623,13 +3496,12 @@ msgstr "Nieuw Notitieboek" msgid "" "New notebook \"%s\" will be created and file \"%s\" will be imported into it" msgstr "" -"Nieuw notitieboek \"%s\" zal aangemaakt worden en bestand \"%s\" wordt eraan " -"toegevoegd" +"Nieuw notitieboek \"%s\" zal aangemaakt worden en bestand \"%s\" wordt " +"ernaar geïmporteerd" #: packages/app-mobile/setupQuickActions.ts:32 -#, fuzzy msgid "New photo" -msgstr "Maak en foto" +msgstr "Nieuwe foto" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/newSubFolder.ts:6 msgid "New sub-notebook" @@ -3637,7 +3509,7 @@ msgstr "Nieuw sub-notitieboek" #: packages/app-mobile/components/screens/NoteTagsDialog.tsx:206 msgid "New tags:" -msgstr "Nieuwe tags:" +msgstr "Nieuwe labels:" #: packages/app-desktop/gui/NoteListControls/NoteListControls.tsx:121 #: packages/app-desktop/gui/NoteListWrapper/NoteListWrapper.tsx:72 @@ -3645,7 +3517,7 @@ msgstr "Nieuwe tags:" #: packages/app-mobile/components/screens/Notes.tsx:257 #: packages/app-mobile/setupQuickActions.ts:31 msgid "New to-do" -msgstr "Nieuwe to-do" +msgstr "Nieuwe taak" #: packages/app-desktop/checkForUpdates.ts:108 msgid "New version: %s" @@ -3653,11 +3525,11 @@ msgstr "Nieuwe versie: %s" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:16 msgid "next" -msgstr "" +msgstr "volgende" #: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:271 msgid "Next match" -msgstr "" +msgstr "Volgende overeenkomst" #: packages/lib/SyncTargetNextcloud.js:25 msgid "Nextcloud" @@ -3665,25 +3537,25 @@ msgstr "Nextcloud" #: packages/lib/models/settings/builtInMetadata.ts:165 msgid "Nextcloud password" -msgstr "Nextcloud paswoord" +msgstr "Nextcloud-wachtwoord" #: packages/lib/models/settings/builtInMetadata.ts:153 msgid "Nextcloud username" -msgstr "Nextcloud username" +msgstr "Nextcloud-gebruikersnaam" #: packages/lib/models/settings/builtInMetadata.ts:140 msgid "Nextcloud WebDAV URL" -msgstr "Nextcloud WebDAV URL" +msgstr "Nextcloud WebDAV-URL" #: packages/lib/models/settings/builtInMetadata.ts:30 msgid "no" -msgstr "neen" +msgstr "nee" #: packages/app-desktop/services/plugins/UserWebviewDialogButtonBar.tsx:22 #: packages/app-mobile/components/screens/Note/Note.tsx:714 #: packages/lib/shim-init-node.ts:265 packages/lib/versionInfo.ts:91 msgid "No" -msgstr "Neen" +msgstr "Nee" #: packages/app-cli/app/command-edit.ts:41 msgid "No active notebook." @@ -3691,7 +3563,7 @@ msgstr "Geen actief notitieboek." #: packages/app-mobile/components/screens/ShareManager/index.tsx:92 msgid "No new invitations" -msgstr "" +msgstr "Geen nieuwe uitnodigingen" #: packages/app-cli/app/app.ts:104 msgid "No notebook has been specified." @@ -3703,11 +3575,12 @@ msgstr "Geen notitieboek geselecteerd." #: packages/lib/components/shared/NoteList/getEmptyFolderMessage.ts:15 msgid "No notes in here. Create one by clicking on \"New note\"." -msgstr "Geen notities. Maak een notitie door op \"Nieuwe notitie\" te klikken." +msgstr "" +"Geen notities hier. Maak een notitie door op \"Nieuwe notitie\" te klikken." #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginStates.tsx:202 msgid "No plugins are installed." -msgstr "" +msgstr "Er zijn geen plugins geïnstalleerd." #: packages/app-desktop/gui/ResourceScreen.tsx:305 msgid "No resources!" @@ -3726,9 +3599,8 @@ msgid "No suggestions" msgstr "Geen suggesties" #: packages/app-mobile/components/plugins/dialogs/PluginPanelViewer.tsx:120 -#, fuzzy msgid "No tab selected" -msgstr "Geen notitieboek geselecteerd." +msgstr "Geen tab geselecteerd" #: packages/app-cli/app/command-edit.ts:31 msgid "" @@ -3736,14 +3608,12 @@ msgid "" msgstr "Geen editor gedefinieerd. Stel in met `config editor `" #: packages/app-desktop/gui/UpdateNotification/UpdateNotification.tsx:93 -#, fuzzy msgid "No updates available" -msgstr "Exporteer profiel" +msgstr "Geen updates beschikbaar" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/moveToFolder.ts:44 -#, fuzzy msgid "None" -msgstr "(None)" +msgstr "Geen" #: packages/lib/models/settings/builtInMetadata.ts:47 msgid "Nord" @@ -3751,21 +3621,19 @@ msgstr "Nord" #: packages/app-cli/app/command-sync.ts:123 msgid "Not authenticated with %s. Please provide any missing credentials." -msgstr "" -"Niet geverifieerd voor %s. Gelieve ontbrekende referenties in te vullen." +msgstr "Niet geauthenticeerd met %s. Voer ontbrekende inloggegevens in." #: packages/lib/models/Resource.ts:407 msgid "Not downloaded" -msgstr "Niet opgehaald" +msgstr "Niet gedownload" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:240 msgid "Not generated" msgstr "Niet gegenereerd" #: packages/app-mobile/components/biometrics/BiometricPopup.tsx:91 -#, fuzzy msgid "Not now" -msgstr "Nu doen" +msgstr "Niet nu" #: packages/app-desktop/gui/NoteListControls/NoteListControls.tsx:109 #: packages/app-desktop/gui/NoteListWrapper/NoteListWrapper.tsx:71 @@ -3782,7 +3650,7 @@ msgstr "Notitie" #: packages/lib/models/settings/builtInMetadata.ts:1549 msgid "Note area growth factor" -msgstr "Groeifactor notitiegrootte" +msgstr "Groeifactor notitiegebied" #: packages/app-desktop/gui/Root.tsx:193 msgid "Note attachments" @@ -3802,9 +3670,8 @@ msgstr "Notitie bestaat niet: \"%s\". Aanmaken?" #: packages/app-desktop/gui/NoteTextViewer.tsx:228 #: packages/app-mobile/components/NoteEditor/NoteEditor.tsx:139 -#, fuzzy msgid "Note editor" -msgstr "Notitiehistoriek" +msgstr "Notitie-editor" #: packages/app-cli/app/command-edit.ts:98 msgid "Note has been saved." @@ -3817,7 +3684,7 @@ msgstr "Notitiehistoriek" #: packages/app-cli/app/command-done.ts:23 msgid "Note is not a to-do: \"%s\"" -msgstr "Notitie is geen to-do: \"%s\"" +msgstr "Notitie is geen taak: \"%s\"" #: packages/app-desktop/gui/NoteList/commands/focusElementNoteList.ts:9 #: packages/app-desktop/gui/NoteListWrapper/NoteListWrapper.tsx:181 @@ -3829,19 +3696,18 @@ msgid "Note list growth factor" msgstr "Groeifactor notitielijst" #: packages/app-desktop/gui/MenuBar.tsx:793 -#, fuzzy msgid "Note list style" -msgstr "Notitielijst" +msgstr "Notitielijst-stijl" #: packages/app-desktop/gui/NotePropertiesDialog.tsx:451 #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showNoteProperties.ts:7 msgid "Note properties" -msgstr "Eigenschappen" +msgstr "Eigenschappen van notitie" #: packages/app-desktop/gui/NoteEditor/commands/focusElementNoteTitle.ts:7 #: packages/app-desktop/gui/NoteEditor/NoteTitle/NoteTitleBar.tsx:124 msgid "Note title" -msgstr "Notitietitel" +msgstr "Titel van notitie" # Clarification needed. # Why not '... desktop OS'? @@ -3853,19 +3719,17 @@ msgstr "Opmerking: werkt niet in alle desktop-omgevingen." msgid "" "Note: When a note is shared, it will no longer be encrypted on the server." msgstr "" -"Opmerking: wanneer een notitie gedeeld wordt, is ze niet langer " -"geëncrypteerd op de server." +"Opmerking: wanneer een notitie gedeeld wordt, is ze niet langer versleuteld " +"op de server." #: packages/app-desktop/gui/MenuBar.tsx:872 -#, fuzzy msgid "Note&book" -msgstr "Notitieboeken" +msgstr "Notitie&boek" #: packages/app-desktop/plugins/GotoAnything.tsx:570 #: packages/lib/models/Setting.ts:1176 -#, fuzzy msgid "Notebook" -msgstr "Notitieboeken" +msgstr "Notitieboek" #: packages/lib/models/settings/builtInMetadata.ts:1519 msgid "Notebook list growth factor" @@ -3877,9 +3741,8 @@ msgid "Notebook: %s" msgstr "Notitieboek: %s" #: packages/app-mobile/components/screens/ShareManager/AcceptedShareItem.tsx:81 -#, fuzzy msgid "Notebook: %s (%s)" -msgstr "Notitieboek: %s" +msgstr "Notitieboek: %s (%s)" #: packages/app-desktop/gui/Sidebar/hooks/useSidebarListData.ts:50 #: packages/app-mobile/components/side-menu-content.tsx:686 @@ -3890,15 +3753,14 @@ msgstr "Notitieboeken" #: packages/lib/models/Folder.ts:906 msgid "Notebooks cannot be named \"%s\", which is a reserved title." msgstr "" -"Notitieboeken kunnen niet \"%s\" genoemd worden, dit is een gereserveerd " -"woord." +"Notitieboeken kunnen niet \"%s\" genoemd worden, dit is een gereserveerde " +"titel." #: packages/app-desktop/gui/NoteList/NoteList2.tsx:289 #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleNotesSortOrderField.ts:8 #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleNotesSortOrderReverse.ts:9 -#, fuzzy msgid "Notes" -msgstr "Notitie" +msgstr "Notities" #: packages/lib/models/Setting.ts:1199 msgid "Notes and settings are stored in: %s" @@ -3911,16 +3773,15 @@ msgstr "Notities kunnen enkel in een notitieboek aangemaakt worden." #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:80 msgid "Numbered List" -msgstr "Nummering" +msgstr "Genummerde Lijst" #: packages/lib/models/settings/builtInMetadata.ts:531 msgid "OCR: Clear cache and re-download language data files" -msgstr "" +msgstr "OCR: Cache wissen en taalgegevensbestanden opnieuw downloaden" #: packages/lib/models/settings/builtInMetadata.ts:512 -#, fuzzy msgid "OCR: Language data URL or path" -msgstr "Datumformaat" +msgstr "OCR: Taalgegevens-URL of -pad" #: packages/app-desktop/bridge.ts:360 packages/app-desktop/bridge.ts:373 #: packages/app-desktop/bridge.ts:387 packages/app-desktop/bridge.ts:403 @@ -3958,11 +3819,11 @@ msgstr "Op %s: %s" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:27 msgid "on line" -msgstr "" +msgstr "op regel" #: packages/app-desktop/gui/MainScreen.tsx:525 msgid "One of your master keys use an obsolete encryption method." -msgstr "Eén van uw hoofdsleutels gebruikt een verouderde encryptiemethode." +msgstr "Eén van je hoofdsleutels gebruikt een verouderde encryptiemethode." #: packages/app-cli/app/gui/NoteWidget.js:48 msgid "" @@ -3971,14 +3832,14 @@ msgid "" "supplied the password, the encrypted items are being decrypted in the " "background and will be available soon." msgstr "" -"Eén of meerdere items zijn momenteel versleuteld en de hoofdsleutel kan " -"gevraagd worden. Om te ontsleutelen, typ `e2ee decrypt`. Als je de " -"hoofdsleutel al ingegeven hebt, worden de versleutelde items ontsleuteld in " -"de achtergrond. Ze zijn binnenkort beschikbaar." +"Eén of meerdere items zijn momenteel versleuteld en het hoofdwachtwoord kan " +"gevraagd worden. Om te ontsleutelen, typ `e2ee decrypt`. Als je het " +"wachtwoord al ingegeven hebt, worden de versleutelde items ontsleuteld in de " +"achtergrond. Ze zijn binnenkort beschikbaar." #: packages/app-desktop/gui/MainScreen.tsx:554 msgid "One or more master keys need a password." -msgstr "Eén of meer hoofdsleutels moeten een paswoord hebben." +msgstr "Eén of meer hoofdsleutels moeten een wachtwoord hebben." #: packages/lib/SyncTargetOneDrive.ts:36 msgid "OneDrive" @@ -3986,12 +3847,11 @@ msgstr "OneDrive" #: packages/app-desktop/gui/Root.tsx:188 msgid "OneDrive Login" -msgstr "OneDrive Login" +msgstr "OneDrive-Login" #: packages/lib/services/interop/InteropService.ts:144 -#, fuzzy msgid "OneNote Notebook" -msgstr "Nieuw Notitieboek" +msgstr "OneNote Notitieboek" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/print.ts:18 msgid "Only one note can be printed at a time." @@ -3999,35 +3859,31 @@ msgstr "Er kan slechts één notitie tegelijk afgedrukt worden." #: packages/app-mobile/components/NoteBodyViewer/hooks/useOnResourceLongPress.ts:40 msgid "Open" -msgstr "Open" +msgstr "Openen" #: packages/app-desktop/app.ts:217 msgid "Open %s" msgstr "Open %s" #: packages/app-desktop/bridge.ts:454 -#, fuzzy msgid "Open it" -msgstr "Open" +msgstr "Openen" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/openPdfViewer.ts:7 -#, fuzzy msgid "Open PDF viewer" -msgstr "Schakel PDF weergave in" +msgstr "Open PDF-weergave" #: packages/app-desktop/commands/openProfileDirectory.ts:8 msgid "Open profile directory" msgstr "Open profielmap" #: packages/app-mobile/components/CameraView/CameraView.tsx:164 -#, fuzzy msgid "Open settings" -msgstr "Toon geavanceerde opties" +msgstr "Open instellingen" #: packages/app-mobile/components/screens/ConfigScreen/plugins/EnablePluginSupportPage.tsx:115 -#, fuzzy msgid "Open Source" -msgstr "Bron" +msgstr "Open Bron" #: packages/lib/models/settings/builtInMetadata.ts:73 msgid "Open Sync Wizard..." @@ -4035,26 +3891,23 @@ msgstr "Sync Wizard openen..." #: packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts:87 msgid "Open..." -msgstr "Openen ..." +msgstr "Openen..." #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:206 msgid "Opening section %s" -msgstr "" +msgstr "Sectie %s openen" #: packages/app-mobile/components/Dropdown.tsx:215 -#, fuzzy msgid "Opens dropdown" -msgstr "Venster sluiten" +msgstr "Opent keuzelijst" #: packages/app-mobile/components/NoteItem.tsx:162 -#, fuzzy msgid "Opens note" -msgstr "Open" +msgstr "Opent notitie" #: packages/app-mobile/components/side-menu-content.tsx:273 -#, fuzzy msgid "Opens notebook" -msgstr "Nieuw notitieboek" +msgstr "Opent notitieboek" #: packages/app-cli/app/command-e2ee.ts:41 #: packages/app-cli/app/command-e2ee.ts:87 @@ -4069,14 +3922,12 @@ msgid "Options" msgstr "Opties" #: packages/app-mobile/components/NoteEditor/commandDeclarations.ts:77 -#, fuzzy msgid "Ordered list" -msgstr "Aangemaakt: %s" +msgstr "Geordende lijst" #: packages/app-desktop/gui/MenuBar.tsx:518 -#, fuzzy msgid "Other applications..." -msgstr "Sluit de applicatie." +msgstr "Andere toepassingen..." #: packages/app-cli/app/command-import.ts:29 msgid "Output format: %s" @@ -4112,12 +3963,12 @@ msgstr "Wachtwoorden komen niet overeen!" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useContextMenu.ts:105 #: packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts:197 msgid "Paste" -msgstr "Plak" +msgstr "Plakken" #: packages/app-desktop/gui/NoteEditor/commands/pasteAsText.ts:6 #: packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts:211 msgid "Paste as text" -msgstr "" +msgstr "Plakken als tekst" #: packages/app-desktop/gui/ConfigScreen/controls/SettingComponent.tsx:261 #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/ExportProfileButton.tsx:54 @@ -4127,41 +3978,40 @@ msgstr "Pad:" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/exportPdf.ts:11 #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/exportPdf.ts:25 msgid "PDF File" -msgstr "PDF Bestand" +msgstr "PDF-Bestand" #: packages/lib/utils/joplinCloud/index.ts:408 msgid "Per user. Minimum of %d users." -msgstr "" +msgstr "Per gebruiker. Minimum van %d gebruikers." #: packages/lib/commands/permanentlyDeleteNote.ts:8 -#, fuzzy msgid "Permanently delete note" -msgstr "Deze notities verwijderen?" +msgstr "Notitie permanent verwijderen" #: packages/lib/models/Note.ts:943 -#, fuzzy msgid "Permanently delete note \"%s\"?" -msgstr "Notities \"%s\" verwijderen?" +msgstr "Notitie \"%s\" permanent verwijderen?" #: packages/app-cli/app/command-rmbook.ts:36 -#, fuzzy msgid "" "Permanently delete notebook \"%s\"?\n" "\n" "All notes and sub-notebooks within this notebook will be permanently deleted." msgstr "" -"Notitieboek verwijderen? Alle notities en sub-notitieboeken in dit " -"notitieboek zullen ook verwijderd worden." +"Notitieboek \"%s\" permanent verwijderen?\n" +"\n" +"Alle notities en sub-notitieboeken in dit notitieboek zullen ook permanent " +"verwijderd worden." #: packages/lib/models/Note.ts:945 -#, fuzzy msgid "Permanently delete these %d notes?" -msgstr "Deze notities %d verwijderen?" +msgstr "Deze %d notities permanent verwijderen?" #: packages/app-cli/app/command-rmbook.ts:20 -#, fuzzy msgid "Permanently deletes the notebook, skipping the trash." -msgstr "Deze notities %d verwijderen?" +msgstr "" +"Verwijdert het notitieboek permanent, zonder het naar de prullenmand te " +"verplaatsen." #: packages/app-mobile/components/screens/Note/Note.tsx:504 msgid "Permission needed" @@ -4172,18 +4022,21 @@ msgid "" "Please click on \"%s\" to proceed, or set the passwords in the \"%s\" list " "below." msgstr "" +"Klik op \"%s\" om door te gaan, of zet de wachtwoorden in de \"%s\" lijst " +"hieronder." #: packages/lib/components/EncryptionConfigScreen/utils.ts:64 msgid "" "Please confirm that you would like to re-encrypt your complete database." -msgstr "Gelieve te bevestigen dat u uw hele databank opnieuw wil encrypteren." +msgstr "" +"Gelieve te bevestigen dat je je hele databank opnieuw wil versleutelen." #: packages/lib/components/EncryptionConfigScreen/utils.ts:213 msgid "" "Please enter your password in the master key list below before upgrading the " "key." msgstr "" -"Gelieve uw paswoord in te geven in de lijst hoofdsleutels hieronder, " +"Gelieve je wachtwoord in te geven in de lijst hoofdsleutels hieronder, " "alvorens de sleutel te upgraden." #: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:380 @@ -4203,15 +4056,15 @@ msgid "" "any files outside this directory nor to any other personal data. No data " "will be shared with any third party." msgstr "" -"Open de volgende URL in uw browser om de toepassing te verifiëren. De " +"Open de volgende URL in je browser om de toepassing te verifiëren. De " "toepassing zal een map aanmaken in \"Apps/Joplin\" en zal enkel in déze map " -"bestanden lezen en schrijven. Het zal geen toegang hebben tot bestanden " +"bestanden lezen en schrijven. Ze zal geen toegang hebben tot bestanden " "buiten deze map, noch tot andere persoonlijke gegevens. Er worden geen " "gegevens gedeeld met derden." #: packages/app-mobile/components/voiceTyping/VoiceTypingDialog.tsx:180 msgid "Please record your voice..." -msgstr "" +msgstr "Neem je stem op..." #: packages/app-cli/app/command-ls.ts:66 msgid "Please select a notebook first." @@ -4219,11 +4072,11 @@ msgstr "Selecteer eerst een notitieboek." #: packages/app-cli/app/app-gui.js:468 msgid "Please select the note or notebook to be deleted first." -msgstr "Selecteer eerst het notitieboek of de notitie om te verwijderen." +msgstr "Selecteer eerst het notitieboek of de notitie dat je wil verwijderen." #: packages/app-desktop/gui/StatusScreen/StatusScreen.tsx:31 msgid "Please select where the sync status should be exported to" -msgstr "Selecteer waar de synchronisatie status naar geëxporteerd moet worden" +msgstr "Selecteer waar de synchronisatiestatus naar geëxporteerd moet worden" #: packages/lib/services/interop/InteropService.ts:309 msgid "Please specify import format for %s" @@ -4235,46 +4088,43 @@ msgstr "" "Specifieer het notitieboek waarin de notities moeten geïmporteerd worden." #: packages/lib/services/plugins/PluginService.ts:519 -#, fuzzy msgid "Please upgrade Joplin to version %s or later to use this plugin." -msgstr "Gelieve Joplin te upgraden om deze plugin te gebruiken" +msgstr "" +"Gelieve Joplin te upgraden naar versie %s of later om deze plugin te " +"gebruiken." #: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx:1444 msgid "" "Please wait for all attachments to be downloaded and decrypted. You may also " "switch to %s to edit the note." msgstr "" -"Gelieve te wachten tot alle bijlagen opgehaald en gedecrypteerd zijn. U kan " +"Gelieve te wachten tot alle bijlagen gedownload en ontsleuteld zijn. Je kan " "ook overschakelen naar %s om de notitie te bewerken." #: packages/app-desktop/gui/ConfigScreen/controls/plugins/SearchPlugins.tsx:118 #: packages/app-desktop/gui/ResourceScreen.tsx:302 msgid "Please wait..." -msgstr "Even geduld ..." +msgstr "Even geduld..." #: packages/app-mobile/services/plugins/PlatformImplementation.ts:51 -#, fuzzy msgid "Plugin message" -msgstr "Plugins" +msgstr "Plugin-bericht" #: packages/app-mobile/components/ScreenHeader/index.tsx:400 -#, fuzzy msgid "Plugin panels" -msgstr "Plugin-hulpmiddelen" +msgstr "Plugin-panelen" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginStates.tsx:111 msgid "Plugin repository failed to load" -msgstr "" +msgstr "Plugin-bibliotheek werd niet geladen" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginStates.tsx:29 -#, fuzzy msgid "Plugin search" -msgstr "Plugins" +msgstr "Zoek plugins" #: packages/app-mobile/components/screens/ConfigScreen/plugins/EnablePluginSupportPage.tsx:107 -#, fuzzy msgid "Plugin security" -msgstr "Plugins" +msgstr "Plugin-beveiliging" #: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.tsx:329 msgid "Plugin tools" @@ -4282,7 +4132,7 @@ msgstr "Plugin-hulpmiddelen" #: packages/lib/models/settings/builtInMetadata.ts:909 msgid "Plugin WebView debugging" -msgstr "" +msgstr "Plugin WebView foutopsporing" #: packages/app-desktop/gui/ConfigScreen/Sidebar.tsx:148 #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:523 @@ -4296,6 +4146,9 @@ msgid "" "Plugins extend Joplin with features that are not present by default. Plugins " "can extend Joplin's editor, viewer, and more." msgstr "" +"Plugins bieden aanvullende functionaliteit, die niet standaard aanwezig is " +"in Joplin. Plugins kunnen extra functionaliteit verlenen aan Joplins editor, " +"viewer, en meer." #: packages/lib/models/settings/builtInMetadata.ts:1261 msgid "Portrait" @@ -4327,11 +4180,11 @@ msgstr "Voorkeurthema licht" #: packages/lib/models/settings/builtInMetadata.ts:1704 msgid "Preferred voice typing provider" -msgstr "" +msgstr "Voorkeursleverancier voor steminvoer" #: packages/lib/models/settings/builtInMetadata.ts:667 msgid "Preserve colours when pasting text in Rich Text Editor" -msgstr "" +msgstr "Behoud kleuren bij het plakken van tekst in de Rich Text Editor" #: packages/app-cli/app/app-gui.js:758 msgid "Press Ctrl+D or type \"exit\" to exit the application" @@ -4351,15 +4204,15 @@ msgstr "" #: packages/app-mobile/components/ScreenHeader/WarningBanner.tsx:40 msgid "Press to set the decryption password." -msgstr "Klik om het decryptie wachtwoord in te stellen" +msgstr "Druk om het decryptiewachtwoord in te stellen." #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:17 msgid "previous" -msgstr "" +msgstr "vorige" #: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:281 msgid "Previous match" -msgstr "" +msgstr "Vorige overeenkomst" #: packages/app-desktop/gui/NotePropertiesDialog.tsx:368 msgid "Previous versions of this note" @@ -4371,7 +4224,7 @@ msgstr "Afdrukken" #: packages/lib/utils/joplinCloud/index.ts:222 msgid "Priority support" -msgstr "" +msgstr "Ondersteuning met prioriteit" #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:606 msgid "Privacy Policy" @@ -4379,77 +4232,71 @@ msgstr "Privacybeleid" #: packages/lib/utils/joplinCloud/index.ts:369 msgid "Pro" -msgstr "" +msgstr "Pro" #: packages/server/src/services/TaskService.ts:26 msgid "Process failed payment subscriptions" -msgstr "" +msgstr "Mislukte betalingsabonnementen verwerken" #: packages/server/src/services/TaskService.ts:24 msgid "Process oversized accounts" -msgstr "" +msgstr "Verwerk te grote accounts" #: packages/server/src/services/TaskService.ts:29 msgid "Process user deletions" -msgstr "" +msgstr "Verwerk verwijdering van gebruikers" #: packages/lib/models/Resource.ts:32 msgid "Processing" -msgstr "" +msgstr "Verwerken" #: packages/app-mobile/components/CameraView/ActionButtons.tsx:111 -#, fuzzy msgid "Processing photo..." -msgstr "Rapport aanmaken ..." +msgstr "Foto verwerken..." #: packages/server/src/routes/admin/users.ts:254 msgid "Profile" -msgstr "" +msgstr "Profiel" #: packages/app-mobile/components/ProfileSwitcher/ProfileEditor.tsx:96 -#, fuzzy msgid "Profile name" -msgstr "Profielversie: %s." +msgstr "Profielnaam" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/addProfile.ts:18 -#, fuzzy msgid "Profile name:" -msgstr "Profielversie: %s." +msgstr "Profielnaam:" #: packages/lib/versionInfo.ts:90 msgid "Profile Version: %s" -msgstr "Profielversie: %s." +msgstr "Profielversie: %s" #: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:172 -#, fuzzy msgid "Profiles" -msgstr "Profielversie: %s." +msgstr "Profielen" #: packages/app-mobile/components/screens/Note/Note.tsx:1248 msgid "Properties" msgstr "Eigenschappen" #: packages/lib/models/settings/builtInMetadata.ts:1413 -#, fuzzy msgid "Proxy enabled" -msgstr "Ingeschakeld" +msgstr "Proxy ingeschakeld" #: packages/lib/models/settings/builtInMetadata.ts:1435 msgid "Proxy timeout (seconds)" -msgstr "" +msgstr "Proxy timeout (seconden)" #: packages/lib/models/settings/builtInMetadata.ts:1423 msgid "Proxy URL" -msgstr "" +msgstr "Proxy URL" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:240 msgid "Public-private key pair:" -msgstr "Publiek-private sleutelpaar" +msgstr "Publiek-private sleutelpaar:" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showShareNoteDialog.ts:6 -#, fuzzy msgid "Publish note..." -msgstr "Notitie delen ..." +msgstr "Publiceer notitie..." #: packages/app-desktop/gui/ShareNoteDialog.tsx:213 msgid "Publish Notes" @@ -4461,43 +4308,40 @@ msgid "Publish notes to the internet" msgstr "Notities publiceren op het Internet" #: packages/app-mobile/components/CameraView/ScannedBarcodes.tsx:78 -#, fuzzy msgid "QR Code" -msgstr "Code" +msgstr "QR-Code" #: packages/app-desktop/app.ts:219 #: packages/app-desktop/ElectronAppWrapper.ts:123 #: packages/app-desktop/gui/KeymapConfig/utils/getLabel.ts:16 #: packages/app-desktop/gui/MenuBar.tsx:424 msgid "Quit" -msgstr "Stop" +msgstr "Afsluiten" #: packages/app-mobile/components/voiceTyping/VoiceTypingDialog.tsx:206 msgid "Re-download model" -msgstr "" +msgstr "Model opnieuw downloaden" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:342 msgid "Re-encrypt data" -msgstr "Herencrypteer de gegevens" +msgstr "Versleutel de gegevens opnieuw" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:354 msgid "Re-encryption" -msgstr "Her-encryptie" +msgstr "Opnieuw versleutelen" #: packages/app-desktop/gui/MasterPasswordDialog/Dialog.tsx:181 -#, fuzzy msgid "Re-enter password" -msgstr "Geef hoofdpaswoord in:" +msgstr "Geef paswoord opnieuw in" #: packages/lib/models/settings/builtInMetadata.ts:1180 msgid "Re-upload local data to sync target" -msgstr "Lokale gegevens opnieuw uploaden naar synchronisatie doel" +msgstr "Lokale gegevens opnieuw uploaden naar synchronisatiedoel" #: packages/app-desktop/gui/NoteEditor/WarningBanner/WarningBanner.tsx:47 msgid "Read more about it" -msgstr "Meer hierover" +msgstr "Lees meer hierover" -# Context needed #: packages/app-desktop/gui/NoteContentPropertiesDialog.tsx:159 msgid "Read time: %s min" msgstr "Leestijd: %s min" @@ -4519,14 +4363,12 @@ msgid "Recipients:" msgstr "Ontvangers:" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/RecommendedBadge.tsx:72 -#, fuzzy msgid "Recommended" -msgstr "commando" +msgstr "Aanbevolen" #: packages/app-mobile/components/screens/ConfigScreen/plugins/EnablePluginSupportPage.tsx:114 -#, fuzzy msgid "Recommended plugins" -msgstr "commando" +msgstr "Aanbevolen plugins" #: packages/app-desktop/gui/MenuBar.tsx:754 #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:122 @@ -4539,12 +4381,11 @@ msgstr "Opnieuw" #: packages/app-mobile/components/screens/onedrive-login.js:121 #: packages/app-mobile/components/screens/status.tsx:174 msgid "Refresh" -msgstr "Vernieuwen" +msgstr "Verversen" #: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:316 -#, fuzzy msgid "Regular expression" -msgstr "Schakel wiskundige formules in" +msgstr "Reguliere expressie" #: packages/app-desktop/gui/MainScreen.tsx:543 #: packages/app-desktop/gui/Root.tsx:152 @@ -4557,17 +4398,16 @@ msgid "Remove" msgstr "Verwijderen" #: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:330 -#, fuzzy msgid "Remove %s from share" -msgstr "De tag \"%s\" verwijderen van alle notities?" +msgstr "Verwijder %s van delen" #: packages/app-desktop/gui/Sidebar/hooks/useOnRenderItem.tsx:111 msgid "Remove tag \"%s\" from all notes?" -msgstr "De tag \"%s\" verwijderen van alle notities?" +msgstr "Het label \"%s\" verwijderen van alle notities?" #: packages/app-desktop/gui/Sidebar/hooks/useOnRenderItem.tsx:113 msgid "Remove this search from the sidebar?" -msgstr "Dit item verwijderen van de zijbalk?" +msgstr "Deze zoekopdracht verwijderen uit de zijbalk?" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/renameFolder.ts:8 #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/renameTag.ts:8 @@ -4580,7 +4420,7 @@ msgstr "Hernoem notitieboek:" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/renameTag.ts:22 msgid "Rename tag:" -msgstr "Hernoem tag:" +msgstr "Hernoem label:" #: packages/app-cli/app/command-ren.ts:14 msgid "Renames the given (note or notebook) to ." @@ -4591,91 +4431,83 @@ msgid "Renew token" msgstr "Token vernieuwen" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:21 -#, fuzzy msgid "replace" -msgstr "Selecteer alles" +msgstr "vervang" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:15 #: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:291 msgid "Replace" -msgstr "" +msgstr "Vervang" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:22 -#, fuzzy msgid "replace all" -msgstr "Selecteer alles" +msgstr "alles vervangen" #: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:301 -#, fuzzy msgid "Replace all" -msgstr "Selecteer alles" +msgstr "Alles vervangen" #: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:239 msgid "Replace with..." -msgstr "" +msgstr "Vervangen door..." #: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:260 msgid "Replace: " -msgstr "" +msgstr "Vervang: " #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:25 msgid "replaced $ matches" -msgstr "" +msgstr "$ overeenkomsten vervangen" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:26 msgid "replaced match on line $" -msgstr "" +msgstr "overeenkomst vervangen op regel $" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginInfoModal.tsx:162 msgid "Report an issue" -msgstr "" +msgstr "Meld een probleem" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginInfoModal.tsx:219 msgid "Report any issues concerning the plugin." -msgstr "" +msgstr "Alle problemen met de plugin rapporteren." #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginInfoModal.tsx:224 msgid "Report fraudulent plugin" -msgstr "" +msgstr "Frauduleuze plugin rapporteren" #: packages/app-mobile/components/screens/ConfigScreen/plugins/EnablePluginSupportPage.tsx:116 -#, fuzzy msgid "Report system" -msgstr "Bestandssysteem" +msgstr "Rapporteersysteem" #: packages/server/src/services/MustacheService.ts:137 -#, fuzzy msgid "Reports" -msgstr "Bestandssysteem" +msgstr "Rapporten" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/resetLayout.ts:7 -#, fuzzy msgid "Reset application layout" -msgstr "Layout veranderen" +msgstr "Herstel de lay-out van de applicatie" #: packages/app-desktop/gui/MasterPasswordDialog/Dialog.tsx:221 #: packages/app-desktop/gui/MasterPasswordDialog/Dialog.tsx:222 -#, fuzzy msgid "Reset master password" -msgstr "Geef hoofdpaswoord in:" +msgstr "Hoofdwachtwoord opnieuw instellen" #: packages/lib/models/settings/builtInMetadata.ts:862 msgid "Resize large images:" -msgstr "" +msgstr "Formaat van grote afbeeldingen wijzigen:" #: packages/app-cli/app/command-import.ts:54 #: packages/app-desktop/gui/ImportScreen.tsx:93 msgid "Resources: %d." -msgstr "Bijlagen: %d." +msgstr "Bronnen: %d." #: packages/app-desktop/gui/MainScreen.tsx:514 msgid "Restart and upgrade" msgstr "Herstarten en upgraden" #: packages/app-desktop/ElectronAppWrapper.ts:130 -#, fuzzy msgid "Restart in safe mode" -msgstr "Herstarten en upgraden" +msgstr "Herstarten in veilige modus" #: packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx:405 #: packages/app-desktop/gui/UpdateNotification/UpdateNotification.tsx:64 @@ -4689,40 +4521,35 @@ msgstr "Nu herstarten" #: packages/app-mobile/components/screens/Note/Note.tsx:1256 #: packages/app-mobile/components/side-menu-content.tsx:359 msgid "Restore" -msgstr "Terugzetten" +msgstr "Herstellen" #: packages/app-mobile/components/EditorToolbar/ToolbarEditorDialog.tsx:156 -#, fuzzy msgid "Restore defaults" -msgstr "Teruggezette Notities" +msgstr "Standaardinstellingen herstellen" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/restoreNote.ts:10 -#, fuzzy msgid "Restore note" -msgstr "Teruggezette Notities" +msgstr "Notitie herstellen" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/restoreFolder.ts:9 -#, fuzzy msgid "Restore notebook" -msgstr "Maak nieuw notitieboek aan" +msgstr "Notitieboek herstellen" #: packages/app-cli/app/command-restore.ts:12 -#, fuzzy msgid "Restore the items matching from the trash." -msgstr "Verwijder alle notities die voldoen aan ." +msgstr "Herstel alle notities die voldoen aan uit de prullenmand." #: packages/lib/services/trash/index.ts:88 -#, fuzzy msgid "Restored items" -msgstr "Teruggezette Notities" +msgstr "Herstelde items" #: packages/lib/services/RevisionService.ts:248 msgid "Restored Notes" -msgstr "Teruggezette Notities" +msgstr "Herstelde Notities" #: packages/app-mobile/components/screens/ConfigScreen/plugins/SearchPlugins.tsx:162 msgid "Results (%d):" -msgstr "" +msgstr "Resultaten (%d):" #: packages/app-desktop/gui/StatusScreen/StatusScreen.tsx:133 #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginStates.tsx:112 @@ -4744,11 +4571,11 @@ msgstr "Toon bestand in map" #: packages/lib/models/settings/builtInMetadata.ts:688 #: packages/lib/models/settings/builtInMetadata.ts:767 msgid "Reverse sort order" -msgstr "Draai rangschikking om" +msgstr "Draai sorteervolgorde om" #: packages/app-cli/app/command-ls.ts:30 msgid "Reverses the sorting order." -msgstr "Draait de rangschikking om." +msgstr "Draait de sorteervolgorde om." #: packages/lib/versionInfo.ts:65 msgid "Revision: %s (%s)" @@ -4756,55 +4583,53 @@ msgstr "Revisie: %s (%s)" #: packages/app-desktop/gui/ToggleEditorsButton/ToggleEditorsButton.tsx:28 msgid "Rich Text" -msgstr "" +msgstr "Rich Text" #: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx:686 msgid "Rich Text editor. Press Escape then Tab to escape focus." msgstr "" +"Rich Text editor. Druk op Escape en vervolgens op Tab om de focus te " +"verbreken." #: packages/app-cli/app/command-batch.js:10 msgid "" "Runs the commands contained in the text file. There should be one command " "per line." msgstr "" -"Voert de commandos in het tekstbestand uit. Er zou een commando per lijn " -"moeten zijn." +"Voert de commando's in het tekstbestand uit. Er moet één commando per lijn " +"zijn." #: packages/lib/SyncTargetAmazonS3.js:28 msgid "S3" msgstr "S3" #: packages/lib/models/settings/builtInMetadata.ts:266 -#, fuzzy msgid "S3 access key" -msgstr "AWS sleutel" +msgstr "S3 toegangssleutel" #: packages/lib/models/settings/builtInMetadata.ts:223 -#, fuzzy msgid "S3 bucket" -msgstr "AWS S3 bucket" +msgstr "S3 bucket" #: packages/lib/models/settings/builtInMetadata.ts:254 msgid "S3 region" msgstr "S3 regio" #: packages/lib/models/settings/builtInMetadata.ts:278 -#, fuzzy msgid "S3 secret key" -msgstr "AWS secret" +msgstr "S3 geheime sleutel" #: packages/lib/models/settings/builtInMetadata.ts:239 -#, fuzzy msgid "S3 URL" -msgstr "AWS S3 URL" +msgstr "S3 URL" #: packages/app-desktop/gui/MainScreen.tsx:501 msgid "" "Safe mode is currently active. Note rendering and all plugins are " "temporarily disabled." msgstr "" -"Veilige modus is actief. Renderen van notities en alle plugins zijn " -"tijdelijk gedeactiveerd." +"Veilige modus is actief. Notitieweergave en alle plugins zijn tijdelijk " +"gedeactiveerd." #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:129 #: packages/app-desktop/gui/KeymapConfig/ShortcutRecorder.tsx:93 @@ -4817,17 +4642,16 @@ msgstr "Opslaan" #: packages/app-mobile/components/SelectDateTimeDialog.tsx:166 msgid "Save alarm" -msgstr "Melding opslaan" +msgstr "Alarm opslaan" #: packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts:107 #: packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts:114 -#, fuzzy msgid "Save as %s" -msgstr "Opslaan als ..." +msgstr "Opslaan als %s" #: packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts:94 msgid "Save as..." -msgstr "Opslaan als ..." +msgstr "Opslaan als..." #: packages/app-desktop/gui/NotePropertiesDialog.tsx:325 #: packages/app-mobile/components/NoteEditor/ImageEditor/ImageEditor.tsx:110 @@ -4838,9 +4662,8 @@ msgid "Save changes" msgstr "Wijzigingen opslaan" #: packages/app-mobile/components/NoteEditor/ImageEditor/ImageEditor.tsx:103 -#, fuzzy msgid "Save changes?" -msgstr "Wijzigingen opslaan" +msgstr "Wijzigingen opslaan?" #: packages/lib/models/settings/builtInMetadata.ts:768 msgid "Save geo-location with notes" @@ -4848,7 +4671,7 @@ msgstr "Sla geo-locatie op bij notities" #: packages/app-mobile/components/CameraView/ScannedBarcodes.tsx:89 msgid "Scanned code" -msgstr "" +msgstr "Gescande code" #: packages/app-desktop/gui/lib/SearchInput/SearchInput.tsx:62 #: packages/app-mobile/components/NoteEditor/commandDeclarations.ts:102 @@ -4862,17 +4685,15 @@ msgstr "Zoeken" #: packages/app-desktop/gui/ConfigScreen/controls/plugins/SearchPlugins.tsx:118 #: packages/app-mobile/components/screens/ConfigScreen/plugins/SearchPlugins.tsx:157 msgid "Search for plugins..." -msgstr "Plugins zoeken ..." +msgstr "Plugins zoeken..." #: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:226 -#, fuzzy msgid "Search for..." -msgstr "Zoeken ..." +msgstr "Zoeken naar..." #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:170 -#, fuzzy msgid "Search hidden" -msgstr "Zoekopdrachten" +msgstr "Zoek verborgen" #: packages/app-desktop/gui/NoteListControls/commands/focusSearch.ts:6 msgid "Search in all the notes" @@ -4880,17 +4701,16 @@ msgstr "Zoek in alle notities" #: packages/app-desktop/gui/NoteEditor/commands/showLocalSearch.ts:7 msgid "Search in current note" -msgstr "Zoeken in actuele notitie" +msgstr "Zoeken in huidige notitie" #: packages/app-desktop/plugins/GotoAnything.tsx:665 -#, fuzzy msgid "Search results" -msgstr "Geen resultaten" +msgstr "Zoekresultaten" +# Context unclear #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:170 -#, fuzzy msgid "Search shown" -msgstr "Zoekopdrachten" +msgstr "Doorzoek getoonde" #: packages/app-cli/app/gui/FolderListWidget.ts:56 msgid "Search:" @@ -4902,16 +4722,15 @@ msgstr "Zoek:" #: packages/app-desktop/gui/ResourceScreen.tsx:299 #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:785 msgid "Search..." -msgstr "Zoeken ..." +msgstr "Zoeken..." #: packages/app-cli/app/command-search.js:13 msgid "Searches for the given in all the notes." -msgstr "Zoektermen voor het opgegeven in alle notities." +msgstr "Zoekt het opgegeven in alle notities." #: packages/app-desktop/gui/UpdateNotification/UpdateNotification.tsx:63 -#, fuzzy msgid "See changelog" -msgstr "Volledige log van wijzigingen" +msgstr "Log van wijzigingen zien" #: packages/lib/models/settings/builtInMetadata.ts:1199 msgid "See the pre-release page for more details: %s" @@ -4919,44 +4738,37 @@ msgstr "Zie de pre-release pagina voor meer details: %s" #: packages/app-desktop/gui/SyncWizard/Dialog.tsx:197 #: packages/app-mobile/components/NoteItem.tsx:144 -#, fuzzy msgid "Select" -msgstr "Selecteer alles" +msgstr "Selecteren" #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:50 #: packages/app-mobile/components/ScreenHeader/index.tsx:364 msgid "Select all" -msgstr "Selecteer alles" +msgstr "Alles selecteren" #: packages/app-desktop/gui/EditFolderDialog/Dialog.tsx:145 -#, fuzzy msgid "Select emoji..." -msgstr "Selecteer datum" +msgstr "Selecteer emoji..." #: packages/app-desktop/gui/EditFolderDialog/Dialog.tsx:149 -#, fuzzy msgid "Select file..." -msgstr "Selecteer alles" +msgstr "Selecteer bestand..." #: packages/app-mobile/components/screens/folder.js:109 -#, fuzzy msgid "Select parent notebook" -msgstr "Verwijder notitieboek" +msgstr "Selecteer hoofdnotitieboek" #: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/utils/localisation.ts:9 -#, fuzzy msgid "Selection deleted" -msgstr "Verwijderen: %d" +msgstr "Selectie verwijderd" #: packages/app-mobile/components/FolderPicker.tsx:68 -#, fuzzy msgid "Selects a notebook" -msgstr "Verwijder notitieboek" +msgstr "Selecteert een notitieboek" #: packages/app-desktop/gui/MenuBar.tsx:359 -#, fuzzy msgid "Send bug report" -msgstr "Exporteer debug rapport" +msgstr "Foutopsportingsrapport verzenden" #: packages/app-cli/app/command-server.js:38 msgid "Server is already running on port %d" @@ -4975,18 +4787,19 @@ msgstr "Server is actief op poort %d" #: packages/app-mobile/components/screens/Note/Note.tsx:1169 #: packages/app-mobile/components/SelectDateTimeDialog.tsx:161 msgid "Set alarm" -msgstr "Stel melding in" +msgstr "Alarm instellen" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/editAlarm.ts:29 msgid "Set alarm:" -msgstr "Stel melding in:" +msgstr "Alarm instellen:" #: packages/lib/models/settings/builtInMetadata.ts:1121 msgid "" "Set it to 0 to make it take the complete available space. Recommended width " "is 600." msgstr "" -"Zet dit op 0 om de volledige ruimte te benutten. Aanbevolen breedte is 600" +"Stel dit in op 0 om de volledige beschikbare ruimte te benutten. Aanbevolen " +"breedte is 600." #: packages/app-desktop/gui/MainScreen.tsx:508 #: packages/app-desktop/gui/MainScreen.tsx:555 @@ -5007,7 +4820,7 @@ msgstr "" #: packages/app-mobile/components/EditorToolbar/EditorToolbar.tsx:47 msgid "Settings" -msgstr "" +msgstr "Instellingen" #: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:281 #: packages/app-mobile/components/NoteBodyViewer/hooks/useOnResourceLongPress.ts:44 @@ -5021,59 +4834,55 @@ msgid "" "Share a copy of all notes in a file format that can be imported by Joplin on " "a computer." msgstr "" +"Deel een kopie van alle notities in een format dat geïmporteerd kan worden " +"door Joplin op een computer." #: packages/lib/utils/joplinCloud/index.ts:125 -#, fuzzy msgid "Share a notebook with others" -msgstr "Maak eerst een notitieboek aan" +msgstr "Deel een notitieboek met anderen" #: packages/app-mobile/components/screens/ShareManager/AcceptedShareItem.tsx:82 #: packages/app-mobile/components/screens/ShareManager/IncomingShareItem.tsx:33 -#, fuzzy msgid "Share from %s (%s)" -msgstr "%s = %s (%s)" +msgstr "Deel van %s (%s)" #: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:400 -#, fuzzy msgid "Share Notebook" -msgstr "Notities delen" +msgstr "Notitieboek Delen" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showShareFolderDialog.ts:6 -#, fuzzy msgid "Share notebook..." -msgstr "Notitie delen ..." +msgstr "Notitieboek delen..." +# Context unclear #: packages/lib/utils/joplinCloud/index.ts:215 msgid "Share permissions" -msgstr "" +msgstr "Deelmachtigingen" #: packages/app-desktop/gui/Sidebar/listItemComponents/FolderItem.tsx:56 -#, fuzzy msgid "Shared" -msgstr "Delen" +msgstr "Gedeeld" +# Context unclear #: packages/app-mobile/components/screens/ShareManager/index.tsx:107 -#, fuzzy msgid "Shares" msgstr "Delen" #: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:364 -#, fuzzy msgid "Sharing notebook..." -msgstr "Notitie delen ..." +msgstr "Notitieboek delen..." #: packages/app-cli/app/command-help.ts:45 msgid "Shortcuts are not available in CLI mode." msgstr "Snelkoppelingen zijn niet beschikbaar in command line modus." #: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:211 -#, fuzzy msgid "Show advanced" msgstr "Toon geavanceerde opties" #: packages/app-desktop/gui/ConfigScreen/controls/ToggleAdvancedSettingsButton.tsx:24 msgid "Show Advanced Settings" -msgstr "Toon geavanceerde opties" +msgstr "Toon Geavanceerde Opties" #: packages/app-mobile/components/screens/LogScreen.tsx:237 msgid "Show all" @@ -5081,67 +4890,59 @@ msgstr "Alles tonen" #: packages/lib/models/settings/builtInMetadata.ts:617 msgid "Show completed to-dos" -msgstr "Toon voltooide to-do's" +msgstr "Toon voltooide taken" #: packages/server/src/routes/admin/users.ts:206 -#, fuzzy msgid "Show disabled" -msgstr "Toon geavanceerde opties" +msgstr "Toon uigeschakelde" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:160 -#, fuzzy msgid "Show disabled keys" -msgstr "Toon geavanceerde opties" +msgstr "Toon uitgeschakelde sleutels" #: packages/app-desktop/gui/ConfigScreen/controls/FontSearch.tsx:132 -#, fuzzy msgid "Show monospace fonts only." -msgstr "Lettertype editor" +msgstr "Toon enkel monospace-lettertypes." #: packages/lib/models/settings/builtInMetadata.ts:599 msgid "Show note counts" msgstr "Toon aantal notities" #: packages/app-mobile/components/side-menu-content.tsx:258 -#, fuzzy msgid "Show notebook options" msgstr "Toon aantal notities" #: packages/app-desktop/gui/PasswordInput/PasswordInput.tsx:21 -#, fuzzy msgid "Show password" -msgstr "Stel het wachtwoord in" +msgstr "Toon wachtwoord" #: packages/lib/models/settings/builtInMetadata.ts:698 -#, fuzzy msgid "Show sort order buttons" -msgstr "Toon aantal notities" +msgstr "Toon sorteervolgorde-knoppen" #: packages/lib/models/settings/builtInMetadata.ts:1007 msgid "Show tray icon" -msgstr "Toon tray icon" +msgstr "Toon systeemvakpictogram" #: packages/app-mobile/components/ScreenHeader/index.tsx:263 msgid "Show/hide the sidebar" -msgstr "" +msgstr "Zijbalk tonen/verbergen" #: packages/app-mobile/components/screens/tags.tsx:76 -#, fuzzy msgid "Shows notes for tag" -msgstr "Toon aantal notities" +msgstr "Toon notities voor label" #: packages/lib/models/settings/builtInMetadata.ts:863 msgid "Shrink large images before adding them to notes." -msgstr "" +msgstr "Grote afbeeldingen verkleinen alvorens ze toe te voegen aan notities." #: packages/app-mobile/components/SideMenu.tsx:258 -#, fuzzy msgid "Side menu closed" -msgstr "Verberg metadata" +msgstr "Zijmenu gesloten" #: packages/app-mobile/components/SideMenu.tsx:258 msgid "Side menu opened" -msgstr "" +msgstr "Zijmenu geopend" #: packages/app-desktop/gui/Sidebar/commands/focusElementSideBar.ts:10 #: packages/app-desktop/gui/Sidebar/Sidebar.tsx:77 @@ -5160,7 +4961,8 @@ msgstr "Deze versie overslaan" #: packages/app-cli/app/command-e2ee.ts:66 msgid "Skipped items: %d (use --retry-failed-items to retry decrypting them)" msgstr "" -"Overgeslagen items: %d (gebruik --retry-failed-items om opnieuw te proberen)" +"Overgeslagen items: %d (gebruik --retry-failed-items om ze opnieuw te " +"proberen te ontsleutelen)" #: packages/app-cli/app/command-import.ts:53 #: packages/app-desktop/gui/ImportScreen.tsx:92 @@ -5179,59 +4981,64 @@ msgstr "Gesolariseerd Licht" msgid "" "Some attachments could not be downloaded. Please try to download them again." msgstr "" +"Sommige bijlagen konden niet gedownload worden. Probeer ze opnieuw te " +"downloaden." #: packages/lib/models/settings/settingValidations.ts:18 msgid "" "Some attachments need to be downloaded. Set the attachment download mode to " "\"always\" and try again." msgstr "" +"Sommige bijlagen moeten gedownload worden. Stel de bijlage-downloadmodus in " +"op \"altijd\" en probeer opnieuw." #: packages/app-desktop/gui/MainScreen.tsx:519 #: packages/app-mobile/components/ScreenHeader/WarningBanner.tsx:52 msgid "Some items cannot be decrypted." -msgstr "Sommige items kunnen niet gedecrypteerd worden." +msgstr "Sommige items kunnen niet ontsleuteld worden." #: packages/app-desktop/gui/MainScreen.tsx:548 msgid "Some items cannot be synchronised." msgstr "Sommige items kunnen niet gesynchroniseerd worden." #: packages/app-mobile/components/ScreenHeader/WarningBanner.tsx:43 -#, fuzzy msgid "Some items cannot be synchronised. Press for more info." -msgstr "Sommige items kunnen niet gesynchroniseerd worden." +msgstr "" +"Sommige items kunnen niet gesynchroniseerd worden. Druk voor meer info." #: packages/lib/models/settings/settingValidations.ts:24 -#, fuzzy msgid "" "Some items could not be synchronised. Please try to synchronise them first." -msgstr "Sommige items kunnen niet gesynchroniseerd worden." +msgstr "" +"Sommige items konden niet gesynchroniseerd worden. Probeer ze eerst te " +"synchroniseren." #: packages/app-desktop/gui/ResourceScreen.tsx:92 msgid "Sort \"%s\" in ascending order" -msgstr "" +msgstr "Sorteer \"%s\" in oplopende volgorde" #: packages/app-desktop/gui/ResourceScreen.tsx:92 msgid "Sort \"%s\" in descending order" -msgstr "" +msgstr "Sorteer \"%s\" in aflopende volgorde" #: packages/lib/models/settings/builtInMetadata.ts:754 msgid "Sort notebooks by" -msgstr "Rangschik notitieboeken volgens" +msgstr "Sorteer notitieboeken volgens" #: packages/app-desktop/gui/NoteList/utils/canManuallySortNotes.ts:10 #: packages/app-mobile/components/ScreenHeader/index.tsx:487 #: packages/lib/models/settings/builtInMetadata.ts:625 msgid "Sort notes by" -msgstr "Rangschik notities volgens" +msgstr "Sorteer notities volgens" #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:138 msgid "Sort selected lines" -msgstr "Rangschik geselecteerde regels" +msgstr "Sorteer geselecteerde regels" #: packages/app-cli/app/command-ls.ts:29 msgid "Sorts the item by (eg. title, updated_time, created_time)." msgstr "" -"Rangschik de items volgens (bv. title, updated_time, created_time)." +"Sorteert het item volgens (bv. title, updated_time, created_time)." #: packages/app-desktop/gui/NoteListHeader/utils/getColumnTitle.ts:9 msgid "Source" @@ -5242,13 +5049,12 @@ msgid "Source format: %s" msgstr "Bronformaat: %s" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:139 -#, fuzzy msgid "Source: " -msgstr "Bron" +msgstr "Bron: " #: packages/app-desktop/gui/Sidebar/hooks/useOnRenderItem.tsx:435 msgid "Spacer" -msgstr "" +msgstr "Tussenstuk" #: packages/lib/models/settings/builtInMetadata.ts:1463 msgid "" @@ -5256,7 +5062,7 @@ msgid "" "default will be used." msgstr "" "Specifieer de poort te gebruiken door de API-server. Indien niet ingesteld " -"wordt een default gebruikt." +"wordt een standaardpoort gebruikt." #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showSpellCheckerMenu.ts:11 #: packages/lib/services/spellChecker/SpellCheckerService.ts:218 @@ -5267,11 +5073,11 @@ msgstr "Spellingscontrole" #: packages/lib/models/settings/builtInMetadata.ts:610 #: packages/lib/models/settings/builtInMetadata.ts:611 msgid "Split View" -msgstr "Naast elkaar" +msgstr "Gesplitste Weergave" #: packages/lib/models/settings/builtInMetadata.ts:1022 msgid "Start application minimised in the tray icon" -msgstr "Start application minimised in the tray" +msgstr "Start applicatie geminimaliseerd in het systeemvak" #: packages/app-cli/app/command-server.js:14 msgid "" @@ -5301,11 +5107,11 @@ msgstr "" #: packages/app-desktop/gui/NoteContentPropertiesDialog.tsx:163 msgid "Statistics" -msgstr "Statistiek" +msgstr "Statistieken" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showNoteContentProperties.ts:8 msgid "Statistics..." -msgstr "Statistiek ..." +msgstr "Statistieken..." #: packages/app-mobile/components/screens/encryption-config.tsx:312 #: packages/app-mobile/components/screens/status.tsx:172 @@ -5318,28 +5124,27 @@ msgstr "Status: %s" #: packages/app-desktop/gui/ClipperConfigScreen.tsx:82 msgid "Status: Started on port %d" -msgstr "Status: gestart op poort %d" +msgstr "Status: Gestart op poort %d" #: packages/app-desktop/gui/ClipperConfigScreen.tsx:124 msgid "Step 1: Enable the clipper service" -msgstr "Step 1: de clipper service inschakelen" +msgstr "Stap 1: de clipper-service inschakelen" #: packages/app-cli/app/command-sync.ts:82 #: packages/app-desktop/gui/DropboxLoginScreen.tsx:46 #: packages/app-mobile/components/screens/dropbox-login.tsx:63 msgid "Step 1: Open this URL in your browser to authorise the application:" -msgstr "" -"Stap 1: Open deze koppeling in je browser om de applicatie te autoriseren:" +msgstr "Stap 1: Open deze URL in je browser om de applicatie te autoriseren:" #: packages/app-cli/app/command-sync.ts:84 #: packages/app-desktop/gui/DropboxLoginScreen.tsx:50 #: packages/app-mobile/components/screens/dropbox-login.tsx:69 msgid "Step 2: Enter the code provided by Dropbox:" -msgstr "Step 2: voer de door Dropbox verstrekte code in:" +msgstr "Stap 2: Voer de door Dropbox verstrekte code in:" #: packages/app-desktop/gui/ClipperConfigScreen.tsx:130 msgid "Step 2: Install the extension" -msgstr "Step 2: installeer de extensie" +msgstr "Stap 2: Installeer de extensie" # Context could be useful #: packages/app-desktop/commands/toggleExternalEditing.ts:29 @@ -5348,11 +5153,11 @@ msgstr "Stop" #: packages/app-desktop/commands/stopExternalEditing.ts:8 msgid "Stop external editing" -msgstr "Beëindig externe bijwerking" +msgstr "Stop met extern bewerken" #: packages/lib/utils/joplinCloud/index.ts:141 msgid "Storage space" -msgstr "" +msgstr "Opslagruimte" #: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/setupToolbarButtons.ts:19 msgid "Strikethrough" @@ -5370,79 +5175,74 @@ msgstr "Verzenden" #: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/setupToolbarButtons.ts:36 msgid "Subscript" -msgstr "Subschrift" +msgstr "Subscript" #: packages/lib/components/shared/config/config-shared.ts:99 msgid "Success! Synchronisation configuration appears to be correct." -msgstr "Succes! De configuratie van de synchronisatie is blijkbaar correct." +msgstr "Succes! De configuratie van de synchronisatie lijkt correct te zijn." #: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/setupToolbarButtons.ts:30 msgid "Superscript" -msgstr "Superschrift" +msgstr "Superscript" #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:146 msgid "Swap line down" -msgstr "Een regel omlaag" +msgstr "Verplaats een regel omlaag" #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:142 msgid "Swap line up" -msgstr "Een regel omhoog" +msgstr "Verplaats een regel omhoog" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleNoteType.ts:7 msgid "Switch between note and to-do type" -msgstr "Wissel tussen notitie en to-do" +msgstr "Wissel tussen notitie en taak" #: packages/app-desktop/gui/MenuBar.tsx:552 #: packages/app-mobile/components/side-menu-content.tsx:625 -#, fuzzy msgid "Switch profile" -msgstr "Exporteer profiel" +msgstr "Wissel van profiel" #: packages/app-mobile/components/CameraView/ActionButtons.tsx:101 msgid "Switch to back-facing camera" -msgstr "" +msgstr "Overschakelen naar camera aan achterkant" #: packages/app-mobile/components/CameraView/ActionButtons.tsx:101 -#, fuzzy msgid "Switch to front-facing camera" -msgstr "Wissel naar notitie" +msgstr "Overschakelen naar camera aan voorkant" #: packages/app-desktop/gui/utils/NoteListUtils.ts:93 msgid "Switch to note type" -msgstr "Wissel naar notitie" +msgstr "Overschakelen naar notitie-type" #: packages/app-desktop/commands/switchProfile1.ts:7 #: packages/app-desktop/commands/switchProfile2.ts:7 #: packages/app-desktop/commands/switchProfile3.ts:7 -#, fuzzy msgid "Switch to profile %d" -msgstr "Wissel naar notitie" +msgstr "Overschakelen naar profile %d" #: packages/app-desktop/gui/ToggleEditorsButton/ToggleEditorsButton.tsx:28 -#, fuzzy msgid "Switch to the %s Editor" -msgstr "Wissel naar notitie" +msgstr "Overschakelen naar de %s Editor" #: packages/app-desktop/gui/NoteEditor/WarningBanner/WarningBanner.tsx:78 -#, fuzzy msgid "Switch to the legacy editor" -msgstr "Wissel naar notitie" +msgstr "Overschakelen naar de oudere editor" #: packages/app-desktop/gui/utils/NoteListUtils.ts:102 msgid "Switch to to-do type" -msgstr "Wissel naar to-do" +msgstr "Wissel naar taak" #: packages/app-cli/app/command-use.ts:12 msgid "" "Switches to [notebook] - all further operations will happen within this " "notebook." msgstr "" -"Wisselt naar [notitieboek] - Alle verdere acties zullen op dit notitieboek " -"toegepast worden." +"Schakelt over naar naar [notebook] - Alle verdere acties zullen op dit " +"notitieboek toegepast worden." #: packages/lib/utils/joplinCloud/index.ts:160 msgid "Sync as many devices as you want" -msgstr "" +msgstr "Synchroniseer met zoveel apparaten als je wil" #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:549 msgid "Sync Status" @@ -5455,7 +5255,7 @@ msgstr "Synchronisatiestatus (gesynchroniseerde items / totaal aantal items)" #: packages/app-cli/app/command-sync.ts:271 msgid "Sync target must be upgraded! Run `%s` to proceed." msgstr "" -"Synchronisatiedoel moet upgraded krijgen! Voer `%s` uit om verder te gaan." +"Synchronisatiedoel moet worden geüpgraded! Voer `%s` uit om verder te gaan." #: packages/app-mobile/components/screens/UpgradeSyncTargetScreen.tsx:59 msgid "Sync Target Upgrade" @@ -5464,21 +5264,20 @@ msgstr "Synchronisatiedoel Upgrade" #: packages/app-cli/app/command-sync.ts:41 msgid "Sync to provided target (defaults to sync.target config value)" msgstr "" -"Synchroniseer naar opgegeven doel (standaard sync.target configuratie optie)" +"Synchroniseer naar opgegeven doel (standaard is dit sync.target configuratie " +"optie)" #: packages/lib/versionInfo.ts:89 msgid "Sync Version: %s" msgstr "Synchronisatieversie: %s" #: packages/app-desktop/gui/SyncWizard/Dialog.tsx:167 -#, fuzzy msgid "Sync your notes" -msgstr "Rangschik notities volgens" +msgstr "Synchroniseer je notities" #: packages/lib/models/Setting.ts:1212 -#, fuzzy msgid "Sync, encryption, proxy" -msgstr "Schakel encryptie in" +msgstr "Synchronisatie, encryptie, proxy" #: packages/lib/models/Setting.ts:1173 msgid "Synchronisation" @@ -5521,12 +5320,11 @@ msgstr "Synchroniseert met externe opslag." #: packages/app-desktop/gui/ShareNoteDialog.tsx:185 msgid "Synchronising..." -msgstr "Synchroniseren ..." +msgstr "Synchroniseren..." #: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:363 -#, fuzzy msgid "Synchronizing..." -msgstr "Synchroniseren ..." +msgstr "Synchroniseren..." #: packages/lib/models/settings/builtInMetadata.ts:1255 msgid "Tabloid" @@ -5534,12 +5332,12 @@ msgstr "Tabloid" #: packages/app-mobile/components/screens/NoteTagsDialog.tsx:215 msgid "tag1, tag2, ..." -msgstr "" +msgstr "label1, label2, ..." #: packages/app-cli/app/command-import.ts:55 #: packages/app-desktop/gui/ImportScreen.tsx:94 msgid "Tagged: %d." -msgstr "Getagd: %d." +msgstr "Gelabeld: %d." #: packages/app-desktop/gui/NoteListHeader/utils/getColumnTitle.ts:10 #: packages/app-desktop/gui/Sidebar/hooks/useSidebarListData.ts:69 @@ -5548,21 +5346,20 @@ msgstr "Getagd: %d." #: packages/app-mobile/components/screens/tags.tsx:87 #: packages/app-mobile/components/side-menu-content.tsx:622 msgid "Tags" -msgstr "Tags" +msgstr "Labels" #: packages/app-mobile/components/CameraView/ActionButtons.tsx:111 #: packages/app-mobile/components/screens/Note/commands/attachFile.ts:83 msgid "Take photo" -msgstr "Maak en foto" +msgstr "Foto maken" #: packages/app-mobile/components/screens/ConfigScreen/NoteExportSection/TaskButton.tsx:73 msgid "Task \"%s\" failed with error: %s" -msgstr "" +msgstr "Taken \"%s\" faalden met fout: %s" #: packages/app-mobile/components/NoteEditor/commandDeclarations.ts:87 -#, fuzzy msgid "Task list" -msgstr "Taken" +msgstr "Takenlijst" #: packages/server/src/services/MustacheService.ts:129 #: packages/server/src/services/MustacheService.ts:283 @@ -5571,31 +5368,31 @@ msgstr "Taken" #: packages/lib/utils/joplinCloud/index.ts:391 msgid "Teams" -msgstr "" +msgstr "Teams" #: packages/lib/services/interop/InteropService.ts:136 -#, fuzzy msgid "Text document" -msgstr "Teksteditorcommando" +msgstr "Tekstdocument" #: packages/lib/models/settings/builtInMetadata.ts:1248 msgid "Text editor command" msgstr "Teksteditorcommando" #: packages/lib/utils/joplinCloud/index.ts:167 -#, fuzzy msgid "" "The [Web Clipper](%s) is a browser extension that allows you to save web " "pages and screenshots from your browser." msgstr "" -"Joplin Web Clipper laat toe webpagina's en schermafbeeldingen van je browser " -"op te slaan in Joplin." +"De [Web Clipper](%s) is een browserextensie die je toelaat webpagina's en " +"schermafbeeldingen van je browser op te slaan in Joplin." #: packages/lib/services/profileConfig/index.ts:106 msgid "" "The active profile cannot be deleted. Switch to a different profile and try " "again." msgstr "" +"Het actieve profiel kan niet verwijderd worden. Schakel over naar een ander " +"profiel en probeer opieuw." #: packages/app-desktop/bridge.ts:504 msgid "" @@ -5607,15 +5404,16 @@ msgstr "" msgid "" "The application did not close properly. Would you like to start in safe mode?" msgstr "" +"De applicatie is niet correct afgesloten. Wil je starten in veilige modus?" #: packages/lib/onedrive-api-node-utils.js:87 msgid "" "The application has been authorised - you may now close this browser tab." -msgstr "De applicatie werd geautoriseerd - U kan deze tab sluiten." +msgstr "De applicatie werd geautoriseerd - Je kan deze tab nu sluiten." #: packages/lib/components/shared/dropbox-login-shared.js:39 msgid "The application has been authorised!" -msgstr "De applicatie is succesvol geautoriseerd!" +msgstr "De applicatie is geautoriseerd!" #: packages/lib/onedrive-api-node-utils.js:89 msgid "The application has been successfully authorised." @@ -5633,19 +5431,19 @@ msgid "" "The attachments will no longer be watched when you switch to a different " "note." msgstr "" -"De bijlagen worden niet langer opgevolgd als u naar een andere notitie " +"De bijlagen worden niet langer opgevolgd wanneer je naar een andere notitie " "wisselt." #: packages/app-cli/app/app.ts:282 msgid "The command \"%s\" is only available in GUI mode" -msgstr "Het opgegeven commando \"%s\" is alleen beschikbaar in de GUI versie" +msgstr "Het commando \"%s\" is alleen beschikbaar in de GUI-modus" #: packages/server/src/middleware/notificationHandler.ts:25 msgid "" "The default admin password is insecure and has not been changed! [Change it " "now](%s)" msgstr "" -"Het standaard admin paswoord is onveilig en is nog niet gewijzigd! [Wijzig " +"Het standaard admin-wachtwoord is onveilig en is nog niet gewijzigd! [Wijzig " "het nu](%s)" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:344 @@ -5653,28 +5451,28 @@ msgid "" "The default encryption method has been changed to a more secure one and it " "is recommended that you apply it to your data." msgstr "" -"De standaard encryptiemethode is veranderd naar een veiliger methode en het " -"wordt aanbevolen dat u deze toepast op uw gegevens." +"De standaard encryptiemethode is veranderd naar een veiligere methode en het " +"wordt aanbevolen dat je deze toepast op je gegevens." #: packages/app-desktop/gui/MainScreen.tsx:531 msgid "" "The default encryption method has been changed, you should re-encrypt your " "data." msgstr "" -"De standaard encryptiemethode is veranderd, u moet uw data opnieuw " -"encrypteren." +"De standaard encryptiemethode is veranderd, je moet je data opnieuw " +"versleutelen." #: packages/lib/services/profileConfig/index.ts:105 msgid "The default profile cannot be deleted" -msgstr "" +msgstr "Het standaardprofiel kan niet verwijderd worden" #: packages/lib/models/settings/builtInMetadata.ts:1248 msgid "" "The editor command (may include arguments) that will be used to open a note. " "If none is provided it will try to auto-detect the default editor." msgstr "" -"Het commando (mogelijk met parameters) dat zal gebruikt worden om de notitie " -"te openen in de externe editor. Als er geen opgegeven wordt, zal het " +"Het editor-commando (mogelijk met argumenten) dat zal gebruikt worden om de " +"notitie te openen in de externe editor. Als er geen opgegeven wordt, zal het " "programma de standaard editor proberen te detecteren." #: packages/lib/models/settings/builtInMetadata.ts:1521 @@ -5686,37 +5484,36 @@ msgid "" "item with a factor of 2 will take twice as much space as an item with a " "factor of 1.Restart app to see changes." msgstr "" -"De factor-eigenschap bepaalt hoe het item zal groeien of krimpen om de " +"De factor-eigenschap bepaalt hoe het item zal groeien of krimpen om in de " "beschikbare ruimte in zijn container te passen ten opzichte van de andere " "items. Zo zal een item met factor 2 twee keer zoveel ruimte innemen als een " "item met factor 1. Herstart de app om de veranderingen te zien." #: packages/app-desktop/gui/NoteEditor/NoteEditor.tsx:612 -#, fuzzy msgid "The following attachment matches your search query:" msgid_plural "The following attachments match your search query:" -msgstr[0] "Van volgende bijlagen wordt het wijzigen opgevolgd:" -msgstr[1] "Van volgende bijlagen wordt het wijzigen opgevolgd:" +msgstr[0] "De volgende bijlage komt overeen met je zoekopdracht:" +msgstr[1] "De volgende bijlagen komen overeen met je zoekopdracht:" #: packages/app-desktop/gui/NoteEditor/NoteEditor.tsx:596 msgid "The following attachments are being watched for changes:" -msgstr "Van volgende bijlagen wordt het wijzigen opgevolgd:" +msgstr "De volgende bijlagen worden gecontroleerd op wijzigingen:" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:75 -#, fuzzy msgid "" "The following keys use an out-dated encryption algorithm and it is " "recommended to upgrade them. The upgraded key will still be able to decrypt " "and encrypt your data as usual." msgstr "" -"De volgende hoofdsleutels gebruiken een verouderd versleutelingsalgoritme en " -"het wordt aanbevolen om ze te upgraden. De geüpgrade hoofdsleutel zal nog " -"steeds in staat zijn om uw gegevens te decrypteren en te encrypteren zoals " +"De volgende sleutels gebruiken een verouderd versleutelingsalgoritme en het " +"wordt aanbevolen om ze te upgraden. De geüpgrade sleutel zal nog steeds in " +"staat zijn om je gegevens te ontsleutelen en te versleutelen zoals " "gewoonlijk." #: packages/app-desktop/gui/NoteEditor/WarningBanner/WarningBanner.tsx:83 msgid "The following plugins may not support the current markdown editor:" msgstr "" +"De volgende plugins ondersteunen de huidige markdown-editor mogelijk niet:" #: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.tsx:257 #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/RecommendedBadge.tsx:49 @@ -5725,23 +5522,22 @@ msgid "" "security and performance." msgstr "" "Het Joplin-team heeft deze plugin geaudit en het voldoet aan de standaarden " -"voor performantie en veiligheid." +"voor veiligheid en prestaties." #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:321 -#, fuzzy msgid "" "The keys with these IDs are used to encrypt some of your items, however the " "application does not currently have access to them. It is likely they will " "eventually be downloaded via synchronisation." msgstr "" -"De hoofdsleutels met deze ID's worden gebruikt om sommige van uw items te " +"De sleutels met deze ID's worden gebruikt om sommige van je items te " "versleutelen, maar de toepassing heeft daar momenteel geen toegang toe. Het " "is waarschijnlijk dat ze uiteindelijk via synchronisatie zullen worden " "opgehaald." #: packages/lib/components/EncryptionConfigScreen/utils.ts:222 msgid "The master key has been upgraded successfully!" -msgstr "De hoofdsleutel is met succes geüpgrade!" +msgstr "De hoofdsleutel is met succes geüpgraded!" #: packages/app-mobile/components/screens/encryption-config.tsx:283 msgid "" @@ -5749,7 +5545,7 @@ msgid "" "however the application does not currently have access to them. It is likely " "they will eventually be downloaded via synchronisation." msgstr "" -"De hoofdsleutels met deze ID's worden gebruikt om sommige van uw items te " +"De hoofdsleutels met deze ID's worden gebruikt om sommige van je items te " "versleutelen, maar de toepassing heeft daar momenteel geen toegang toe. Het " "is waarschijnlijk dat ze uiteindelijk via synchronisatie zullen worden " "opgehaald." @@ -5757,22 +5553,17 @@ msgstr "" #: packages/lib/services/RevisionService.ts:272 msgid "The note \"%s\" has been successfully restored to the notebook \"%s\"." msgstr "" -"De notitie \"%s\" werd met succes teruggezet naar het notitieboek \"%s\"." +"De notitie \"%s\" werd met success hersteld naar het notitieboek \"%s\"." #: packages/app-desktop/gui/TrashNotification/TrashNotification.tsx:68 -#, fuzzy msgid "The note was successfully moved to the trash." msgid_plural "The notes were successfully moved to the trash." -msgstr[0] "" -"De notitie \"%s\" werd met succes teruggezet naar het notitieboek \"%s\"." -msgstr[1] "" -"De notitie \"%s\" werd met succes teruggezet naar het notitieboek \"%s\"." +msgstr[0] "De notitie werd naar de prullenmand verplaatst." +msgstr[1] "De notities werden naar de prullenmand verplaatst." #: packages/app-desktop/gui/TrashNotification/TrashNotification.tsx:66 -#, fuzzy msgid "The notebook and its content was successfully moved to the trash." -msgstr "" -"De notitie \"%s\" werd met succes teruggezet naar het notitieboek \"%s\"." +msgstr "Het notitieboek en alle inhoud warden naar de prullenmand verplaatst." #: packages/app-mobile/components/screens/folder.js:76 msgid "The notebook could not be saved: %s" @@ -5806,6 +5597,12 @@ msgid "" "\n" "%s" msgstr "" +"Het synchronisatiedoel kon niet gewijzigd worden, om de volgende reden: %s\n" +"\n" +"Als het problem niet kan worden opgelost, moet je mogelijk eerst je gegevens " +"wissen door deze instructies te volgen:\n" +"\n" +"%s" #: packages/app-desktop/gui/MainScreen.tsx:513 msgid "" @@ -5815,23 +5612,22 @@ msgid "" msgstr "" "Het synchronisatiedoel moet worden geüpgraded voordat Joplin kan " "synchroniseren. Het kan een paar minuten duren voordat deze operatie " -"voltooid is en de app moet dan opnieuw worden opgestart. Klik op de " -"koppeling om verder te gaan." +"voltooid is en de app moet dan opnieuw worden opgestart. Klik op de link om " +"verder te gaan." #: packages/app-mobile/components/ScreenHeader/WarningBanner.tsx:46 -#, fuzzy msgid "The sync target needs to be upgraded. Press this banner to proceed." msgstr "" -"Synchronisatiedoel moet upgraded krijgen! Voer `%s` uit om verder te gaan." +"Synchronisatiedoel moet geüpgraded worden. Druk op deze banner om verder te " +"gaan." #: packages/app-desktop/gui/MainScreen.tsx:507 -#, fuzzy msgid "The synchronisation password is missing." -msgstr "Verifieer de configuratie van de synchronisatie" +msgstr "Het synchronisatie-wachtwoord ontbreekt." #: packages/lib/models/Tag.ts:233 msgid "The tag \"%s\" already exists. Please choose a different name." -msgstr "De tag \"%s\" bestaat al. Kies een andere naam." +msgstr "Het label \"%s\" bestaat al. Kies een andere naam." #: packages/lib/models/settings/builtInMetadata.ts:86 msgid "" @@ -5849,35 +5645,41 @@ msgid "" "\n" "Error: \"%s\"" msgstr "" +"De webclient ondersteunt het aanvaarden van versleutelde gedeelde " +"notitieboeken niet. Schakel over naar de desktop- of mobiele applicatie om " +"het delen te aanvaarden.\n" +"\n" +"Foutmelding: \"%s\"" #: packages/app-desktop/gui/Root.tsx:150 msgid "The Web Clipper needs your authorisation to access your data." msgstr "" -"De Web Clipper plugin heeft jouw authorisatie nodig om je gegevens te " -"raadplegen." +"De Web Clipper plugin heeft jouw authorisatie nodig om toegang te krijgen " +"tot je gegevens." #: packages/app-desktop/gui/ClipperConfigScreen.tsx:76 msgid "The web clipper service is enabled and set to auto-start." -msgstr "De web clipper service is ingeschakeld en ingesteld als auto-start." +msgstr "De webclipper-dienst is ingeschakeld en wordt automatisch opgestart." #: packages/app-desktop/gui/ClipperConfigScreen.tsx:100 msgid "The web clipper service is not enabled." -msgstr "De web clipper service is niet ingeschakeld." +msgstr "De webclipper-dienst is niet ingeschakeld." #: packages/lib/utils/webDAVUtils.ts:28 msgid "" "The WebDAV implementation of %s is incompatible with Joplin, and as such is " "no longer supported. Please use a different sync method." msgstr "" +"De WebDAV-implementatie van %s is niet compatible met Joplin, en wordt niet " +"langer ondersteund. Gebruik een andere synchronisatie-methode." #: packages/lib/models/settings/builtInMetadata.ts:543 msgid "Theme" msgstr "Thema" #: packages/lib/models/Setting.ts:1211 -#, fuzzy msgid "Themes, editor font" -msgstr "Lettertype editor" +msgstr "Thema's, lettertype van editor" #: packages/lib/components/shared/NoteList/getEmptyFolderMessage.ts:17 msgid "There are currently no notes. Create one by clicking on the (+) button." @@ -5885,13 +5687,12 @@ msgstr "" "Er zijn momenteel geen notities. Maak een notitie door op (+) te klikken." #: packages/lib/components/shared/NoteList/getEmptyFolderMessage.ts:9 -#, fuzzy msgid "There are no notes in the trash folder." -msgstr "Bewaar notitiehistoriek gedurende" +msgstr "Er zijn geen notities in de prullenmand-map." #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:268 msgid "There are unsaved changes." -msgstr "" +msgstr "Er zijn niet-opgeslagen wijzigingen." #: packages/lib/services/interop/InteropService_Exporter_Jex.ts:36 msgid "There is no data to export." @@ -5909,7 +5710,7 @@ msgstr "" #: packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts:52 msgid "There was an error downloading this attachment:" -msgstr "Er was een fout bij het ophalen van deze bijlage:" +msgstr "Er was een fout bij het downloaden van deze bijlage:" #: packages/lib/services/ReportService.ts:237 msgid "" @@ -5917,6 +5718,10 @@ msgid "" "cause the sync warning to appear, but still aren't synced. To unignore, " "click \"retry\"." msgstr "" +"Deze items warden niet succesvol gesynchroniseerd, maar zijn gemarkeerd als " +"\"genegeerd\". Ze zullen geen nieuwe synchronisatie-waarschuwing " +"veroorzaken, maar ze zijn nog steeds niet gesynchroniseerd. Om het negeren " +"ongedaan te maken, klik \"opnieuw proberen\"." #: packages/lib/services/ReportService.ts:187 msgid "" @@ -5942,7 +5747,7 @@ msgstr "" "op dat, hoewel deze functies nuttig kunnen zijn, ze geen standaard Markdown " "zijn en dat de meeste dus alleen in Joplin zullen werken. Bovendien zijn " "sommige *incompatibel* met de WYSIWYG editor. Als je een nota opent die een " -"van deze plugins gebruikt in die editor, zal je de opmaak van de plugins " +"van deze plugins gebruikt in die editor, zal je de opmaak van de plugin " "verliezen. Hieronder wordt aangegeven welke plugins al dan niet compatibel " "zijn met de WYSIWYG editor." @@ -5952,15 +5757,18 @@ msgid "" "collaborate on it. It does not however allow you to share a notebook with " "someone else, unless you have the feature \"%s\"." msgstr "" +"Dit laat een andere gebruiker toe om een notitieboek te delen met jou, zodat " +"jullie er samen aan kunnen werken. Het laat jou echter niet toe om een " +"notitieboek met iemand anders te delen, tenzij je de functie \"%s\" hebt." #: packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts:150 msgid "This attachment does not have OCR data (Status: %s)" -msgstr "" +msgstr "Deze bijlage heft geen OCR-gegevens (Status: %s)" #: packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts:54 #: packages/lib/services/ResourceEditWatcher/index.ts:241 msgid "This attachment is not downloaded or not decrypted yet" -msgstr "Deze bijlage is nog niet opgehaald of nog niet gedecrypteerd" +msgstr "Deze bijlage is niet gedownload of nog niet ontsleuteld" #: packages/app-desktop/gui/ClipperConfigScreen.tsx:147 msgid "" @@ -5972,7 +5780,7 @@ msgstr "" #: packages/app-mobile/components/NoteEditor/ImageEditor/ImageEditor.tsx:103 msgid "This drawing may have unsaved changes." -msgstr "" +msgstr "Deze tekening heft mogelijk niet-opgelagen wijzigingen." #: packages/app-desktop/gui/ResourceScreen.tsx:291 msgid "" @@ -5980,30 +5788,27 @@ msgid "" "notes. Please be careful when deleting one of them as they cannot be " "restored afterwards." msgstr "" -"Dit is een geavanceerd hulpmiddel om de bijlagen te tonen die aan uw " -"notities zijn gekoppeld. Wees voorzichtig als u er een verwijdert, want ze " +"Dit is een geavanceerd hulpmiddel om de bijlagen te tonen die aan je " +"notities zijn gekoppeld. Wees voorzichtig als je er een verwijdert, want ze " "kunnen nadien niet meer worden hersteld." #: packages/app-mobile/components/ScreenHeader/index.tsx:237 -#, fuzzy msgid "This note could not be deleted: %s" msgid_plural "These notes could not be deleted: %s" -msgstr[0] "Het notitieboek kon niet opgeslaan worden: %s" -msgstr[1] "Het notitieboek kon niet opgeslaan worden: %s" +msgstr[0] "Deze notitie kon niet verwijderd worden: %s" +msgstr[1] "Deze notities konden niet verwijderd worden: %s" #: packages/app-mobile/components/ScreenHeader/index.tsx:224 -#, fuzzy msgid "This note could not be duplicated: %s" msgid_plural "These notes could not be duplicated: %s" -msgstr[0] "Het notitieboek kon niet opgeslagen worden: %s" -msgstr[1] "Het notitieboek kon niet opgeslagen worden: %s" +msgstr[0] "Deze notitie kon niet gedupliceerd worden: %s" +msgstr[1] "Deze notities konden niet gedupliceerd worden: %s" #: packages/app-mobile/components/ScreenHeader/index.tsx:563 -#, fuzzy msgid "This note could not be moved: %s" msgid_plural "These notes could not be moved: %s" -msgstr[0] "Het notitieboek kon niet opgeslagen worden: %s" -msgstr[1] "Het notitieboek kon niet opgeslagen worden: %s" +msgstr[0] "Deze notitie kon niet verplaatst worden: %s" +msgstr[1] "Deze notities konden niet verplaatst worden: %s" #: packages/lib/models/Note.ts:130 msgid "This note does not have geolocation information." @@ -6018,7 +5823,9 @@ msgstr "Deze notitie werd aangepast:" msgid "" "This note has no content. Click on \"%s\" to toggle the editor and edit the " "note." -msgstr "Deze notitie heeft geen inhoud. Klik op \"%s\" om ze te bewerken." +msgstr "" +"Deze notitie heeft geen inhoud. Klik op \"%s\" om de editor te openen en de " +"notitie te bewerken." #: packages/app-desktop/gui/NoteRevisionViewer.tsx:130 msgid "This note has no history" @@ -6026,15 +5833,15 @@ msgstr "Deze notitie heeft geen historiek" #: packages/lib/services/plugins/PluginService.ts:527 msgid "This plugin doesn't support %s." -msgstr "" +msgstr "Deze plugin ondersteunt %s niet." #: packages/app-desktop/gui/NoteEditor/WarningBanner/WarningBanner.tsx:52 msgid "" "This Rich Text editor has a number of limitations and it is recommended to " "be aware of them before using it." msgstr "" -"Deze Rich Text editor heeft een aantal beperkingen en het is aanbevolen om u " -"daarvan bewust te zijn vooraleer hem te gebruiken." +"Deze Rich Text editor heeft een aantal beperkingen en het is aanbevolen dat " +"je weet wat die zijn vooraleer hem te gebruiken." #: packages/app-desktop/gui/ClipperConfigScreen.tsx:125 msgid "" @@ -6043,12 +5850,12 @@ msgid "" "to a particular port." msgstr "" "Deze dienst laat de browserextensie toe om te communiceren met Joplin. " -"Wanneer u deze inschakelt, kan uw firewall u vragen om Joplin toestemming te " -"geven om op een bepaalde poort te luisteren." +"Wanneer je deze inschakelt, kan je firewall je vragen om Joplin toestemming " +"te geven om op een bepaalde poort te luisteren." #: packages/lib/components/shared/NoteList/getEmptyFolderMessage.ts:11 msgid "This subfolder of the trash has no notes." -msgstr "" +msgstr "Deze submap in de prullenmand bevat geen notities." #: packages/lib/models/settings/builtInMetadata.ts:1009 msgid "" @@ -6056,9 +5863,9 @@ msgid "" "this setting so that your notes are constantly being synchronised, thus " "reducing the number of conflicts." msgstr "" -"Dit laat Joplin toe in de achtergrond actief te blijven. Dit is aanbevolen " -"omdat zo uw notities voortdurend gesynchroniseerd worden en het aantal " -"conflicten verminderd wordt." +"Dit laat Joplin toe in de achtergrond actief te blijven. Het is aanbevolen " +"om deze instlling in te schakelen, zodat je notities voortdurend " +"gesynchroniseerd worden, waardoor het aantal conflicten wordt beperkt." #: packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx:148 msgid "This will open a new screen. Save your current changes?" @@ -6067,12 +5874,11 @@ msgstr "Dit opent een nieuw venster. Lopende wijzigingen opslaan?" #: packages/app-desktop/commands/emptyTrash.ts:14 #: packages/app-mobile/components/side-menu-content.tsx:340 msgid "This will permanently delete all items in the trash. Continue?" -msgstr "" +msgstr "Dit zal alle items in de prullenmand permanent verwijderen. Doorgaan?" #: packages/app-cli/app/command-rmnote.ts:40 -#, fuzzy msgid "This will permanently delete the note \"%s\". Continue?" -msgstr "Notities \"%s\" verwijderen?" +msgstr "Dit zal de notitie \"%s\" permanent verwijderen. Doorgaan?" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/leaveSharedFolder.ts:17 #: packages/app-mobile/components/screens/ShareManager/AcceptedShareItem.tsx:60 @@ -6080,8 +5886,8 @@ msgid "" "This will remove the notebook from your collection and you will no longer " "have access to its content. Do you wish to continue?" msgstr "" -"Dit zal de notitieboek van je verzameling verwijderen. Je zal niet langer " -"toegang hebben tot deze inhoud. Wil je verder gaan?" +"Dit zal het notitieboek van je verzameling verwijderen. Je zal niet langer " +"toegang hebben tot de inhoud ervan. Wil je verder gaan?" #: packages/lib/models/settings/builtInMetadata.ts:481 msgid "Time format" @@ -6104,49 +5910,48 @@ msgstr "Titel" msgid "" "To allow Joplin to synchronise with Dropbox, please follow the steps below:" msgstr "" -"Om Joplin toe te staan with Dropbox te synchroniseren, gelieve de " +"Om Joplin toe te staan met Dropbox te synchroniseren, gelieve de " "onderstaande stappen te volgen:" #: packages/app-cli/app/command-sync.ts:110 #: packages/app-desktop/gui/JoplinCloudLoginScreen.tsx:84 #: packages/app-mobile/components/screens/JoplinCloudLoginScreen.tsx:153 -#, fuzzy msgid "" "To allow Joplin to synchronise with Joplin Cloud, please login using this " "URL:" msgstr "" -"Om Joplin toe te staan with Dropbox te synchroniseren, gelieve de " -"onderstaande stappen te volgen:" +"Om Joplin toe te staan met Joplin Cloud te synchroniseren, log in via deze " +"URL:" #: packages/lib/components/EncryptionConfigScreen/utils.ts:53 -#, fuzzy msgid "To continue, please enter your master password below." -msgstr "Geef hoofdpaswoord in:" +msgstr "Geef je hoofdwachtwoord hieronder in om verder te gaan." #: packages/app-cli/app/app-gui.js:458 msgid "To delete a tag, untag the associated notes." msgstr "" -"Om een tag te verwijderen, wis hem eerst bij alle notities die hem hebben." +"Om een label te verwijderen, verwijder het eerst van elke notitie waaraan " +"het is toegevoegd." #: packages/lib/services/ReportService.ts:331 msgid "To delete: %d" -msgstr "Verwijderen: %d" +msgstr "Te verwijderen: %d" #: packages/app-cli/app/command-help.ts:83 msgid "To enter command line mode, press \":\"" -msgstr "Om de command line modus te gebruiken, gebruik \":\"" +msgstr "Om de command line modus te gebruiken, druk \":\"" #: packages/app-cli/app/command-help.ts:84 msgid "To exit command line mode, press ESCAPE" -msgstr "Om de command line modus te verlaten, gebruik ESCAPE" +msgstr "Om de command line modus te verlaten, druk ESCAPE" #: packages/app-desktop/gui/NoteList/utils/canManuallySortNotes.ts:10 msgid "" "To manually sort the notes, the sort order must be changed to \"%s\" in the " "menu \"%s\" > \"%s\"" msgstr "" -"Om de notities manueel te rangschikken, moet de rangschikking veranderd " -"worden in \"%s\" in het menu \"%s\" > \"%s\"" +"Om de notities manueel te sorteren, moet de sorteervolgorde veranderd worden " +"naar \"%s\" in het menu \"%s\" > \"%s\"" #: packages/app-cli/app/command-help.ts:82 msgid "To maximise/minimise the console, press \"tc\"." @@ -6169,90 +5974,85 @@ msgid "" "To switch the profile, the app is going to close and you will need to " "restart it." msgstr "" +"Om van profiel te kunnen wisselen, gaat de applicatie afsluiten, en je zal " +"die zelf opnieuw moeten starten." #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:587 msgid "" "To work correctly, the app needs the following permissions. Please enable " "them in your phone settings, in Apps > Joplin > Permissions" msgstr "" -"Om correct te werken, heeft de app de volgende permissies nodig. Schakel ze " -"in uw telefooninstellingen in, in Apps > Joplin > Machtigingen" +"Om correct te werken, heeft de app de volgende machtigingen nodig. Schakel " +"ze in je telefooninstellingen in, in Apps > Joplin > Machtigingen" # Context needed #: packages/app-desktop/gui/NoteListControls/NoteListControls.tsx:119 #: packages/app-desktop/gui/NoteListWrapper/NoteListWrapper.tsx:71 msgid "to-do" -msgstr "to-do" +msgstr "taak" # Context needed #: packages/app-desktop/gui/NoteListHeader/utils/getColumnTitle.ts:6 -#, fuzzy msgid "To-do" -msgstr "to-do" +msgstr "Taak" # Context needed #: packages/app-mobile/components/NoteItem.tsx:172 -#, fuzzy msgid "to-do: %s" -msgstr "to-do" +msgstr "taak: %s" #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:134 msgid "Toggle comment" -msgstr "In commentaar zetten" +msgstr "Commentaar tonen/verbergen" #: packages/app-desktop/gui/MenuBar.tsx:939 msgid "Toggle development tools" -msgstr "Toon / Verberg ontwikkelingshulpmiddelen" +msgstr "Ontwikkelingshulpmiddelen tonen/verbergen" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleVisiblePanes.ts:6 msgid "Toggle editor layout" -msgstr "Wissel editor layout" +msgstr "Schakel tussen editor lay-outs" +# Context unclear #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleEditorPlugin.ts:11 -#, fuzzy msgid "Toggle editor plugin" -msgstr "Wissel editor layout" +msgstr "Schakel tussen editor-plugins" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleEditors.ts:8 msgid "Toggle editors" -msgstr "Verwissel van editor" +msgstr "Schakel tussen editors" #: packages/app-desktop/commands/toggleExternalEditing.ts:8 msgid "Toggle external editing" -msgstr "Aan- of uitschakelen externe editor" +msgstr "Extern bewerken in-/uitschakelen" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleMenuBar.ts:7 -#, fuzzy msgid "Toggle menu bar" -msgstr "Toon / Verberg zijbalk" +msgstr "Menubalk tonen/verbergen" #: packages/lib/models/Setting.ts:1216 -#, fuzzy msgid "Toggle note history, keep notes for" -msgstr "Bewaar notitiehistoriek gedurende" +msgstr "Notitiehistoriek in-/uitschakelen, bewaar notities gedurende" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleNoteList.ts:9 msgid "Toggle note list" -msgstr "Toon / Verberg notitielijst" +msgstr "Notitielijst tonen/verbergen" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/togglePerFolderSortOrder.ts:7 -#, fuzzy msgid "Toggle own sort order" -msgstr "Toon / Verberg zijbalk" +msgstr "Eigen sorteervolgorde in-/uitschakelen" #: packages/app-desktop/commands/toggleSafeMode.ts:8 -#, fuzzy msgid "Toggle safe mode" -msgstr "Toon / Verberg zijbalk" +msgstr "Veilige modus in-/uitschakelen" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleSideBar.ts:9 msgid "Toggle sidebar" -msgstr "Toon / Verberg zijbalk" +msgstr "Zijbalk tonen/verbergen" #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleNotesSortOrderField.ts:7 -#, fuzzy msgid "Toggle sort order field" -msgstr "Toon / Verberg zijbalk" +msgstr "Sorteervolgordeveld tonen/verbergen" #: packages/app-desktop/gui/ClipperConfigScreen.tsx:34 msgid "Token has been copied to the clipboard!" @@ -6263,9 +6063,8 @@ msgid "Tools" msgstr "Hulpmiddelen" #: packages/server/src/routes/admin/users.ts:152 -#, fuzzy msgid "Total Size" -msgstr "Huidige grootte" +msgstr "Totale Grootte" #: packages/lib/services/ReportService.ts:328 msgid "Total: %d/%d" @@ -6273,7 +6072,7 @@ msgstr "Totaal: %d/%d" #: packages/lib/services/trash/index.ts:44 msgid "Trash" -msgstr "" +msgstr "Prullenmand" #: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.tsx:319 #: packages/app-mobile/components/biometrics/BiometricPopup.tsx:123 @@ -6283,9 +6082,8 @@ msgstr "Probeer opnieuw" #: packages/lib/utils/joplinCloud/index.ts:362 #: packages/lib/utils/joplinCloud/index.ts:384 #: packages/lib/utils/joplinCloud/index.ts:406 -#, fuzzy msgid "Try it now" -msgstr "Nu doen" +msgstr "Probeer het nu" #: packages/app-cli/app/command-help.ts:72 msgid "" @@ -6293,7 +6091,7 @@ msgid "" "all` for the complete usage information." msgstr "" "Typ `help [commando]` voor meer informatie over een commando; of typ `help " -"all` voor de volledige gebruiksaanwijzing." +"all` voor de volledige gebruiksinformatie." #: packages/app-cli/app/main.js:105 msgid "Type `joplin help` for usage information." @@ -6306,12 +6104,12 @@ msgid "" "commands." msgstr "" "Typ de titel van een notitie of een deel van de inhoud om er naartoe te " -"springen. Of typ # gevolgd door de naam van een tag, of @ gevolgd door de " +"springen. Of typ # gevolgd door de naam van een label, of @ gevolgd door de " "naam van een notitieboek. Of typ : om naar commando's te zoeken." #: packages/app-mobile/components/screens/NoteTagsDialog.tsx:235 msgid "Type new tags or select from list" -msgstr "Typ nieuwe tags of selecteer uit lijst" +msgstr "Typ nieuwe labels of selecteer uit lijst" #: packages/app-cli/app/help-utils.js:56 msgid "Type: %s." @@ -6319,15 +6117,15 @@ msgstr "Type: %s." #: packages/app-mobile/components/screens/Note/Note.tsx:946 msgid "Unable to edit resource of type %s" -msgstr "" +msgstr "Bron van het type %s kan niet bewerkt worden" #: packages/app-mobile/components/screens/LogScreen.tsx:108 msgid "Unable to share log data. Reason: %s" -msgstr "" +msgstr "Loggegevens kunnen niet gedeeld worden. Reden: %s" #: packages/lib/models/settings/builtInMetadata.ts:616 msgid "Uncompleted to-dos on top" -msgstr "Toon onvoltooide to-do's bovenaan" +msgstr "Toon onvoltooide taken bovenaan" #: packages/app-desktop/gui/MenuBar.tsx:750 #: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:118 @@ -6341,17 +6139,18 @@ msgid "" "Uninstall and reinstall the application. Make sure you create a backup first " "by exporting all your notes as JEX from the desktop application." msgstr "" +"Verwijder de applicatie en installeer ze opnieuw. Zorg dat je eerst een back-" +"up creëert door al je notities als JEX te exporteren van de desktop-" +"applicatie." #: packages/app-mobile/utils/getVersionInfoText.ts:13 #: packages/app-mobile/utils/getVersionInfoText.ts:14 -#, fuzzy msgid "Unknown" -msgstr "Onbekende optie: %s" +msgstr "Onbekend" #: packages/app-desktop/bridge.ts:446 -#, fuzzy msgid "Unknown file type" -msgstr "Onbekende optie: %s" +msgstr "Onbekend bestandstype" #: packages/lib/utils/processStartFlags.ts:185 msgid "Unknown flag: %s" @@ -6361,28 +6160,24 @@ msgstr "Onbekende optie: %s" msgid "" "Unknown item type downloaded - please upgrade Joplin to the latest version" msgstr "" -"Onbekend item type opgehaald - gelieve Joplin te upgraden naar de recentste " -"versie" +"Onbekend itemtype gedownload - gelieve Joplin te upgraden naar de meest " +"recente versie" #: packages/app-mobile/utils/getVersionInfoText.ts:28 -#, fuzzy msgid "Unknown platform" -msgstr "Onbekende optie: %s" +msgstr "Onbekend platform" #: packages/app-mobile/components/NoteEditor/commandDeclarations.ts:82 -#, fuzzy msgid "Unordered list" -msgstr "Aangemaakt: %s" +msgstr "Ongeordende lijst" #: packages/app-desktop/gui/ShareNoteDialog.tsx:165 -#, fuzzy msgid "Unpublish note" -msgstr "Delen" +msgstr "Publicatie van notitie ongedaan maken" #: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:168 -#, fuzzy msgid "Unshare" -msgstr "Delen" +msgstr "Stoppen met delen" #: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.tsx:387 msgid "" @@ -6394,25 +6189,26 @@ msgstr "" #: packages/app-mobile/components/screens/Note/Note.tsx:811 msgid "Unsupported image type: %s" -msgstr "Afbeeldingstype %s wordt niet ondersteund" +msgstr "Niet-ondersteund afbeeldingstype: %s" #: packages/app-desktop/gui/NoteRevisionViewer.tsx:173 #: packages/app-desktop/gui/WindowCommandsAndDialogs/commands/openItem.ts:47 msgid "Unsupported link or message: %s" -msgstr "Niet-ondersteunde koppeling of bericht: %s" +msgstr "Niet-ondersteunde link of bericht: %s" #: packages/app-mobile/commands/openItem.ts:60 -#, fuzzy msgid "" "Unsupported link or message: %s.\n" "Error: %s" -msgstr "Niet-ondersteunde koppeling of bericht: %s" +msgstr "" +"Niet-ondersteunde link of bericht: %s\n" +"Foutmelding: %s" #: packages/app-desktop/gui/ResourceScreen.tsx:123 #: packages/lib/models/BaseItem.ts:921 packages/lib/path-utils.ts:27 #: packages/lib/path-utils.ts:71 msgid "Untitled" -msgstr "Untitled" +msgstr "Zonder titel" # Context needed. #: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.tsx:206 @@ -6421,26 +6217,22 @@ msgid "Update" msgstr "Bijwerken" #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/PluginChips.tsx:77 -#, fuzzy msgid "Update available" -msgstr "Exporteer profiel" +msgstr "Update beschikbaar" # Context needed #: packages/app-desktop/gui/UpdateNotification/UpdateNotification.tsx:65 -#, fuzzy msgid "Update later" -msgstr "datum bijwerking" +msgstr "Later bijwerken" #: packages/server/src/routes/admin/users.ts:257 #: packages/server/src/routes/index/users.ts:91 -#, fuzzy msgid "Update profile" -msgstr "Exporteer profiel" +msgstr "Profiel bijwerken" #: packages/server/src/services/TaskService.ts:23 -#, fuzzy msgid "Update total sizes" -msgstr "Bijgewerkte lokale items: %d." +msgstr "Totale groottes bijwerken" #: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.tsx:208 #: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.tsx:209 @@ -6461,12 +6253,11 @@ msgstr "Bijgewerkte lokale items: %d." #: packages/lib/Synchronizer.ts:202 msgid "Updated remote items: %d." -msgstr "Bijgewerkte remote items: %d." +msgstr "Bijgewerkte externe items: %d." #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:140 -#, fuzzy msgid "Updated: " -msgstr "Bijgewerkt: %s" +msgstr "Bijgewerkt: " #: packages/app-cli/app/command-import.ts:52 #: packages/app-desktop/gui/ImportScreen.tsx:91 @@ -6480,7 +6271,7 @@ msgstr "Bijgewerkt: %s" #: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.tsx:207 #: packages/app-mobile/components/screens/ConfigScreen/plugins/PluginInfoModal.tsx:170 msgid "Updating..." -msgstr "Updaten ..." +msgstr "Bezig met updaten..." #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:80 msgid "Upgrade" @@ -6488,7 +6279,7 @@ msgstr "Upgraden" #: packages/app-cli/app/command-sync.ts:42 msgid "Upgrade the sync target to the latest version." -msgstr "Upgrade het synchronisatiedoel naar de laatste versie." +msgstr "Upgrade het synchronisatiedoel naar de meest recente versie." #: packages/app-desktop/gui/NotePropertiesDialog.tsx:72 #: packages/app-mobile/components/NoteEditor/EditLinkDialog.tsx:114 @@ -6504,7 +6295,7 @@ msgstr "Gebruik: %s" #: packages/lib/models/settings/builtInMetadata.ts:1601 msgid "Use biometrics to secure access to the app" -msgstr "" +msgstr "Gebruik biometrie om toegang tot de app te beveiligen" #: packages/app-cli/app/command-ls.ts:33 packages/app-cli/app/command-tag.js:18 msgid "" @@ -6512,11 +6303,11 @@ msgid "" "TODO_CHECKED (for to-dos), TITLE" msgstr "" "Gebruik lange lijstopmaak. Opmaak is ID, NOTE_COUNT (voor notitieboek), " -"DATE, TODO_CHECKED (voor to-do's), TITLE" +"DATE, TODO_CHECKED (voor taken), TITLE" #: packages/lib/services/spellChecker/SpellCheckerService.ts:185 msgid "Use spell checker" -msgstr "Spellingscontrole inschakelen" +msgstr "Spellingscontrole gebruiken" #: packages/app-cli/app/command-help.ts:81 msgid "" @@ -6529,13 +6320,12 @@ msgstr "" #: packages/app-desktop/gui/MainScreen.tsx:750 msgid "Use the arrows to move the layout items. Press \"Escape\" to exit." msgstr "" -"Gebruik de pijlen om de schermonderdelen te verplaatsen. Druk op \"escape\" " -"om te eindigen." +"Gebruik de pijlen om schermonderdelen te verplaatsen. Druk op \"Escape\" om " +"te eindigen." #: packages/lib/models/settings/builtInMetadata.ts:1347 -#, fuzzy msgid "Use the legacy Markdown editor" -msgstr "Markdown emoji inschakelen" +msgstr "Gebruik de oudere Markdown-editor" #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:552 msgid "" @@ -6550,14 +6340,16 @@ msgid "" "Use your biometrics to secure access to your application. You can always set " "it up later in Settings." msgstr "" +"Gebruik biometrie om toegang tot je applicatie te beveiligen. Je kan dit " +"altijd later instellen in Instellingen." #: packages/lib/models/settings/builtInMetadata.ts:1102 msgid "" "Used for most text in the markdown editor. If not found, a generic " "proportional (variable width) font is used." msgstr "" -"Wordt gebruikt voor de voornaamste tekst in de markdown bewerken. Wanneer " -"dit niet gevonden wordt, zal een proportioneel (variabele breedte) " +"Wordt gebruikt voor de meeste tekst in de Markdown-editor. Wanneer dit niet " +"gevonden wordt, zal een generiek proportioneel (variabele breedte) " "lettertype gebruikt worden." #: packages/lib/models/settings/builtInMetadata.ts:1115 @@ -6567,13 +6359,14 @@ msgid "" "font is used." msgstr "" "Wordt gebruikt waar een lettertype met vaste breedte nodig is om de tekst " -"leesbaar uit te lijnen (e.g. tabellen, checkboxes, code). Indien niet " -"gevonden zal er een algemeen monoscape lettertype met vaste breedte worden " +"leesbaar uit te lijnen (e.g. tabellen, selectievakjes, code). Indien niet " +"gevonden zal er een generiek monospace lettertype met vaste breedte worden " "gebruikt." +# Context unclear #: packages/server/src/services/MustacheService.ts:125 msgid "User deletions" -msgstr "" +msgstr "Verwijderingen van gebruikers" #: packages/server/src/routes/admin/users.ts:197 #: packages/server/src/services/MustacheService.ts:121 @@ -6583,13 +6376,12 @@ msgstr "Gebruikers" #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:171 #: packages/app-desktop/gui/PasswordInput/LabelledPasswordInput.tsx:23 -#, fuzzy msgid "Valid" -msgstr "Ongeldig" +msgstr "Geldig" #: packages/app-mobile/components/biometrics/biometricAuthenticate.ts:10 msgid "Verify your identity" -msgstr "" +msgstr "Verifieer je identiteit" #: packages/app-desktop/gui/NoteList/utils/canManuallySortNotes.ts:10 msgid "View" @@ -6597,7 +6389,7 @@ msgstr "Weergave" #: packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts:141 msgid "View OCR text" -msgstr "" +msgstr "OCR-tekst zien" #: packages/app-mobile/components/screens/Note/Note.tsx:1044 msgid "View on map" @@ -6614,7 +6406,7 @@ msgstr "Bekijk ze nu" #: packages/lib/models/settings/builtInMetadata.ts:609 #: packages/lib/models/settings/builtInMetadata.ts:611 msgid "Viewer" -msgstr "Weergave" +msgstr "Viewer" #: packages/lib/models/settings/builtInMetadata.ts:1291 msgid "Vim" @@ -6622,21 +6414,20 @@ msgstr "Vim" #: packages/lib/models/settings/builtInMetadata.ts:1693 msgid "Voice typing language files (URL)" -msgstr "" +msgstr "Taalbestanden voor steminvoer (URL)" #: packages/app-mobile/components/screens/Note/Note.tsx:1191 #: packages/app-mobile/components/voiceTyping/VoiceTypingDialog.tsx:225 msgid "Voice typing..." -msgstr "" +msgstr "Steminvoer..." #: packages/lib/models/settings/builtInMetadata.ts:1712 msgid "Vosk" -msgstr "" +msgstr "Vosk" #: packages/lib/services/joplinCloudUtils.ts:27 -#, fuzzy msgid "Waiting for authorisation..." -msgstr "Autorisatietoken:" +msgstr "Wachten op autorisatie…." #: packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx:224 #: packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx:122 @@ -6646,18 +6437,22 @@ msgstr "Waarschuwing" #: packages/app-desktop/gui/ResourceScreen.tsx:309 msgid "Warning: not all resources shown for performance reasons (limit: %s)." msgstr "" -"Waarschuwing: om redenen van performantie worden niet alle bijlagen getoond " -"(beperking: %s)." +"Waarschuwing: om redenen van performantie worden niet alle bronnen getoond " +"(limiet: %s)." #: packages/app-mobile/components/screens/ConfigScreen/plugins/EnablePluginSupportPage.tsx:116 msgid "We have a system for reporting and removing problematic plugins." msgstr "" +"We hebben een system om problematische plugins te rapporteren en te " +"verwijderen." #: packages/app-mobile/components/screens/ConfigScreen/plugins/EnablePluginSupportPage.tsx:114 msgid "" "We mark plugins developed by trusted Joplin community members as " "\"recommended\"." msgstr "" +"We markeren plugins die ontwikkeld zijn door vertrouwde leden van de Joplin-" +"community als \"aanbevolen\"." #: packages/lib/models/Setting.ts:1182 #: packages/lib/utils/joplinCloud/index.ts:166 @@ -6687,12 +6482,11 @@ msgstr "Website en documentatie" #: packages/app-mobile/utils/getVersionInfoText.ts:14 msgid "WebView package: %s" -msgstr "" +msgstr "WebView packet: %s" #: packages/app-mobile/utils/getVersionInfoText.ts:13 -#, fuzzy msgid "WebView version: %s" -msgstr "Nieuwe versie: %s" +msgstr "WebView versie: %s" #: packages/app-cli/app/gui/NoteWidget.js:36 msgid "" @@ -6708,40 +6502,40 @@ msgstr "" "Typ `:help shortcuts` voor een lijst van shortcuts, of `:help` voor " "gebruiksinformatie.\n" "\n" -"Om bijvoorbeeld een notitieboek aan te maken, typ `mb`; om een notitie te " +"Bijvoorbeeld, om een notitieboek aan te maken, typ `mb`; om een notitie te " "maken, typ `mn`." #: packages/lib/WelcomeUtils.ts:63 -#, fuzzy msgid "Welcome!" -msgstr "Welkom" +msgstr "Welkom!" #: packages/app-mobile/components/screens/ConfigScreen/plugins/EnablePluginSupportPage.tsx:100 -#, fuzzy msgid "What are plugins?" -msgstr "Plugin \"%s\" verwijderen?" +msgstr "Wat zijn plugins?" #: packages/lib/models/settings/builtInMetadata.ts:845 msgid "When creating a new note:" -msgstr "Wanneer u een nieuwe notitie aanmaakt:" +msgstr "Wanneer je een nieuwe notitie aanmaakt:" #: packages/lib/models/settings/builtInMetadata.ts:828 msgid "When creating a new to-do:" -msgstr "Wanneer u een nieuwe to-do aanmaakt:" +msgstr "Wanneer je een nieuwe taak aanmaakt:" #: packages/lib/models/settings/builtInMetadata.ts:501 msgid "" "When enabled, the application will scan your attachments and extract the " "text from it. This will allow you to search for text in these attachments." msgstr "" +"Wanneer ingeschakeld, zal de applicatie je bijlagen scannen en de tekst " +"ervan extraheren. Dit zal je toelaten om tekst te zoeken in deze bijlagen." #: packages/lib/models/settings/builtInMetadata.ts:1713 msgid "Whisper" -msgstr "" +msgstr "Fluister" #: packages/app-desktop/ElectronAppWrapper.ts:222 msgid "Window unresponsive." -msgstr "" +msgstr "Venster reageert niet." #: packages/app-desktop/gui/NoteContentPropertiesDialog.tsx:105 msgid "Words" @@ -6774,69 +6568,63 @@ msgid "" "You are about to attach a large image (%dx%d pixels). Would you like to " "resize it down to %d pixels before attaching it?" msgstr "" -"U staat op het punt een grote afbeelding (%dx%d pixels) bij te voegen. Wil u " -"ze verkleinen tot %d pixels vooraleer ze bij te voegen?" +"Je staat op het punt een grote afbeelding (%dx%d pixels) bij te voegen. Wil " +"je die verkleinen tot %d pixels vooraleer ze bij te voegen?" #: packages/lib/services/joplinCloudUtils.ts:45 msgid "You are logged in into Joplin Cloud, you can leave this screen now." -msgstr "" +msgstr "Je bent ingelogd op Joplin Cloud, je mag dit scherm nu sluiten." #: packages/app-mobile/components/NoteList.tsx:98 msgid "You currently have no notebooks." -msgstr "U heeft momenteel geen notitieboeken." +msgstr "Je hebt momenteel geen notitieboeken." #: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.tsx:280 msgid "You do not have any installed plugin." -msgstr "U heeft geen enkele geïnstalleerde plugin." +msgstr "Je hebt geen enkele geïnstalleerde plugin." #: packages/app-cli/app/gui/NoteWidget.js:50 msgid "You may also type `status` for more information." -msgstr "U kan ook `status` typen voor meer informatie." +msgstr "Je kan ook `status` typen voor meer informatie." #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:344 msgid "" "You may use the tool below to re-encrypt your data, for example if you know " "that some of your notes are encrypted with an obsolete encryption method." msgstr "" -"U kunt het onderstaande hulpmiddel gebruiken om uw gegevens opnieuw te " -"encrypteren, bijvoorbeeld als u weet dat sommige van uw notities " -"geëncrypteerd zijn met een verouderde encryptiemethode." +"Je kan het onderstaande hulpmiddel gebruiken om je gegevens opnieuw te " +"encrypteren, bijvoorbeeld als je weet dat sommige van je notities " +"versleuteld zijn met een verouderde encryptiemethode." #: packages/lib/services/joplinCloudUtils.ts:53 -#, fuzzy msgid "" "You were unable to connect to Joplin Cloud. Please check your credentials " "and try again. Error:" msgstr "" -"Er is een probleem opgetreden bij het configureren van je Joplin Cloud " -"gebruiker. Gelievee je e-mailadres en wachtwoord te controleren en opnieuw " -"te proberen. Fout was:\n" -"\n" -"%s" +"Je kon geen verbinding maken met Joplin Cloud. Controleer je inloggegevens " +"en probeer opnieuw. Foutmelding:" #: packages/app-desktop/gui/JoplinCloudConfigScreen.tsx:55 #: packages/app-mobile/components/screens/ConfigScreen/JoplinCloudConfig.tsx:70 msgid "Your account doesn't have access to this feature" -msgstr "" +msgstr "Je account heeft geen toegang tot deze functie" #: packages/app-cli/app/cli-utils.js:160 msgid "Your choice: " -msgstr "Uw keuze: " +msgstr "Jouw keuze: " #: packages/lib/components/EncryptionConfigScreen/utils.ts:70 msgid "Your data is going to be re-encrypted and synced again." -msgstr "Uw data zullen opnieuw geëncrypteerd en gesynchroniseerd worden." +msgstr "Je gegevens zullen opnieuw verseluteld en gesynchroniseerd worden." #: packages/app-desktop/gui/MainScreen.tsx:562 #: packages/app-mobile/components/ScreenHeader/WarningBanner.tsx:55 msgid "Your Joplin Cloud credentials are invalid, please login." -msgstr "" +msgstr "Je gegevens voor Joplin Cloud zijn ongeldig, gelieve in te loggen." #: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx:259 -#, fuzzy msgid "Your password is needed to decrypt some of your data." -msgstr "" -"Je masterwachtwoord is nodig om een deel van je gegevens te decrypteren." +msgstr "Je wachtwoord is nodig om een deel van je gegevens te decrypteren." #: packages/app-cli/app/command-sync.ts:262 msgid "" @@ -6848,7 +6636,7 @@ msgstr "" #: packages/app-desktop/checkForUpdates.ts:108 msgid "Your version: %s" -msgstr "Uw versie: %s" +msgstr "Jouw versie: %s" #: packages/app-desktop/gui/MenuBar.tsx:839 #: packages/app-desktop/gui/MenuBar.tsx:845 From fc92a6ea63fe388552b34f5560c572a4af09f6bf Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Thu, 10 Apr 2025 14:08:03 +0100 Subject: [PATCH 147/158] Doc: Update sponsors --- .../images/sponsors/EssayWriterPro.png | Bin 0 -> 57195 bytes packages/tools/sponsors.json | 6 ++++++ 2 files changed, 6 insertions(+) create mode 100644 Assets/WebsiteAssets/images/sponsors/EssayWriterPro.png diff --git a/Assets/WebsiteAssets/images/sponsors/EssayWriterPro.png b/Assets/WebsiteAssets/images/sponsors/EssayWriterPro.png new file mode 100644 index 0000000000000000000000000000000000000000..3840bf5372cec33749c49690da897c127af29980 GIT binary patch literal 57195 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 Date: Fri, 11 Apr 2025 13:47:09 +0100 Subject: [PATCH 148/158] Doc: Recommend against using WSL --- readme/dev/BUILD.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme/dev/BUILD.md b/readme/dev/BUILD.md index e0981b66bf..fa8bf4eaf9 100644 --- a/readme/dev/BUILD.md +++ b/readme/dev/BUILD.md @@ -43,7 +43,7 @@ Then you can test the various applications: cd packages/app-desktop yarn start -You can also run it under WSL 2. To do so, [follow these instructions](https://www.beekeeperstudio.io/blog/building-electron-windows-ubuntu-wsl2) to setup your environment. +Use the regular Command Prompt to develop in Windows. We [do not recommend using WSL for this](https://github.com/laurent22/joplin/blob/dev/readme/dev/build_troubleshooting.md#other-issues) and we do not support this use case. ## Testing the Terminal application From 5ad891e1f35295599bf566916cbf80bd0e5ee621 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Fri, 11 Apr 2025 13:50:32 +0100 Subject: [PATCH 149/158] Doc: Fix build troubleshooting file --- readme/dev/build_troubleshooting.md | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/readme/dev/build_troubleshooting.md b/readme/dev/build_troubleshooting.md index 1704825d0b..cc799b2a07 100644 --- a/readme/dev/build_troubleshooting.md +++ b/readme/dev/build_troubleshooting.md @@ -1,8 +1,6 @@ # Build troubleshooting -## Desktop application - -### On Windows +## Desktop application - on Windows If `yarn dist` fails, it may need administrative rights. @@ -15,7 +13,7 @@ call "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliar set "PATH=C:\Program Files\nodejs;%PATH%" ``` -### On Linux and macOS +## Desktop application - on Linux and macOS If there's an error `while loading shared libraries: libgconf-2.so.4: cannot open shared object file: No such file or directory`, run `sudo apt-get install libgconf-2-4` @@ -24,18 +22,20 @@ If you get a node-gyp related error, you might need to manually install it: `npm If you get unexpected `npm` dependency errors on a fresh git pull, try `npm run clean` If `npm i` gives you a fatal error like the following: + ``` node-pre-gyp WARN Tried to download(403): https://mapbox-node-binary.s3.amazonaws.com/sqlite3/v5.0.1/napi-v6-linux-x64.tar.gz node-pre-gyp WARN Pre-built binaries not found for sqlite3@5.0.1 and node@14.15.4 (node-v83 ABI, glibc) (falling back to source compile with node-gyp) /bin/sh: 1: python: not found ``` + Try `sudo apt install python` (or the `apt` equivalent for your operating system) and then run `npm i` again. If you get the error `libtool: unrecognized option '-static'`, follow the instructions [in this post](https://stackoverflow.com/a/38552393/561309) to use the correct libtool version. -### Other issues +## Desktop application - other issues -> The application window doesn't open or is white +### The application window doesn't open or is white This is an indication that there's an early initialisation error. Try this: @@ -44,19 +44,13 @@ This is an indication that there's an early initialisation error. Try this: - Also try to delete node_modules and rebuild. - If all else fails, switch your computer off and on again, to make sure you start clean. -> How to work on the app from Windows? +### How to work on the app from Windows? **You should not use WSL at all** because this is a GUI app that lives outside of WSL, and the WSL layer can cause all kind of very hard to debug issues. It can also lock files in node_modules that cannot be unlocked when the app crashes. (You need to restart your computer.) Likewise, don't run the TypeScript watch command from WSL. So everything should be done from a Windows Command prompt or Windows PowerShell running as Administrator. All build and start commands are designed to work cross-platform, including on Windows. -> Error when building the application - -If you find a error when building the application, [verify that you have all the requirements](https://github.com/laurent22/joplin/blob/dev/readme/dev/BUILD.md), including Rust. - -## Mobile application - -### iOS +## Mobile application - iOS If there is an error `/joplin/packages/app-mobile/ios/Pods/Target Support Files/Pods-Joplin/Pods-Joplin.debug.xcconfig: unable to open file (in target "Joplin" in project "Joplin") (in target 'Joplin' from project 'Joplin')` run the following commands: From 9638cab9eaa825ad9ec665198b52b85896874245 Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Sat, 12 Apr 2025 03:46:55 -0700 Subject: [PATCH 150/158] Desktop: Rich Text Editor: Add KaTeX to supported auto-replacements (#12081) --- .eslintignore | 1 + .gitignore | 1 + packages/app-desktop/commands/index.ts | 8 +-- .../NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx | 49 ++++++++++++------- .../TinyMCE/utils/useTextPatternsLookup.ts | 40 +++++++++++++++ .../app-desktop/gui/NoteEditor/NoteEditor.tsx | 5 +- .../app-desktop/gui/NoteEditor/utils/types.ts | 1 + readme/apps/rich_text_editor.md | 23 +++++++++ 8 files changed, 106 insertions(+), 22 deletions(-) create mode 100644 packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useTextPatternsLookup.ts diff --git a/.eslintignore b/.eslintignore index 24a0bd1a93..34c16a619e 100644 --- a/.eslintignore +++ b/.eslintignore @@ -266,6 +266,7 @@ packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useKeyboardRefocusHan packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useLinkTooltips.js packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useScroll.js packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useTabIndenter.js +packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useTextPatternsLookup.js packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useWebViewApi.js packages/app-desktop/gui/NoteEditor/NoteEditor.js packages/app-desktop/gui/NoteEditor/NoteTitle/NoteTitleBar.js diff --git a/.gitignore b/.gitignore index ab0fe5484a..f0e643e35d 100644 --- a/.gitignore +++ b/.gitignore @@ -241,6 +241,7 @@ packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useKeyboardRefocusHan packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useLinkTooltips.js packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useScroll.js packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useTabIndenter.js +packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useTextPatternsLookup.js packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useWebViewApi.js packages/app-desktop/gui/NoteEditor/NoteEditor.js packages/app-desktop/gui/NoteEditor/NoteTitle/NoteTitleBar.js diff --git a/packages/app-desktop/commands/index.ts b/packages/app-desktop/commands/index.ts index 3161eceedd..d1801e1dac 100644 --- a/packages/app-desktop/commands/index.ts +++ b/packages/app-desktop/commands/index.ts @@ -6,10 +6,10 @@ import * as exportDeletionLog from './exportDeletionLog'; import * as exportFolders from './exportFolders'; import * as exportNotes from './exportNotes'; import * as focusElement from './focusElement'; -import * as openSecondaryAppInstance from './openSecondaryAppInstance'; -import * as openPrimaryAppInstance from './openPrimaryAppInstance'; import * as openNoteInNewWindow from './openNoteInNewWindow'; +import * as openPrimaryAppInstance from './openPrimaryAppInstance'; import * as openProfileDirectory from './openProfileDirectory'; +import * as openSecondaryAppInstance from './openSecondaryAppInstance'; import * as replaceMisspelling from './replaceMisspelling'; import * as restoreNoteRevision from './restoreNoteRevision'; import * as startExternalEditing from './startExternalEditing'; @@ -30,10 +30,10 @@ const index: any[] = [ exportFolders, exportNotes, focusElement, - openSecondaryAppInstance, - openPrimaryAppInstance, openNoteInNewWindow, + openPrimaryAppInstance, openProfileDirectory, + openSecondaryAppInstance, replaceMisspelling, restoreNoteRevision, startExternalEditing, diff --git a/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx index 8d51ddc8ae..5a16f4b523 100644 --- a/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx +++ b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx @@ -43,6 +43,7 @@ import useKeyboardRefocusHandler from './utils/useKeyboardRefocusHandler'; import useDocument from '../../../hooks/useDocument'; import useEditDialog from './utils/useEditDialog'; import useEditDialogEventListeners from './utils/useEditDialogEventListeners'; +import useTextPatternsLookup from './utils/useTextPatternsLookup'; const logger = Logger.create('TinyMCE'); @@ -654,6 +655,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => { // Create and setup the editor // ----------------------------------------------------------------------------------------- + const textPatternsLookupRef = useTextPatternsLookup({ enabled: props.enableTextPatterns, enableMath: props.mathEnabled }); useEffect(() => { if (!scriptLoaded) return; if (!editorContainer) return; @@ -740,25 +742,38 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => { // button to work. See https://github.com/tinymce/tinymce/issues/5026. forecolor: { inline: 'span', styles: { color: '%value' }, remove_similar: true }, }, - text_patterns: props.enableTextPatterns ? [ - // See https://www.tiny.cloud/docs/tinymce/latest/content-behavior-options/#text_patterns - // for the default value - { start: '==', end: '==', format: 'joplinHighlight' }, - { start: '`', end: '`', format: 'code' }, - { start: '*', end: '*', format: 'italic' }, - { start: '**', end: '**', format: 'bold' }, - { start: '#', format: 'h1' }, - { start: '##', format: 'h2' }, - { start: '###', format: 'h3' }, - { start: '####', format: 'h4' }, - { start: '#####', format: 'h5' }, - { start: '######', format: 'h6' }, - { start: '1.', cmd: 'InsertOrderedList' }, - { start: '*', cmd: 'InsertUnorderedList' }, - { start: '-', cmd: 'InsertUnorderedList' }, - ] : [], + text_patterns: [], + text_patterns_lookup: () => textPatternsLookupRef.current(), setup: (editor: Editor) => { + editor.addCommand('joplinMath', async () => { + const katex = editor.selection.getContent(); + const md = `$${katex}$`; + + // Save and clear the selection -- when this command is activated by a text pattern, + // TinyMCE: + // 1. Adjusts the selection just before calling the command to include the to-be-formatted text. + // 2. Calls the command. + // 3. Removes the "$" characters and restores the selection. + // + // As a result, the selection needs to be saved and restored. + const mathSelection = editor.selection.getBookmark(); + + const result = await markupToHtml.current(MarkupLanguage.Markdown, md, { bodyOnly: true }); + + // Replace the math... + const finalSelection = editor.selection.getBookmark(); + editor.selection.moveToBookmark(mathSelection); + editor.selection.setContent(result.html); + editor.selection.moveToBookmark(finalSelection); // ...then move the selection back. + + // Fire update events + editor.fire(TinyMceEditorEvents.JoplinChange); + dispatchDidUpdate(editor); + // The last replacement seems to need to be manually added to the undo history + editor.undoManager.add(); + }); + editor.addCommand('joplinAttach', () => { insertResourcesIntoContentRef.current(); }); diff --git a/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useTextPatternsLookup.ts b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useTextPatternsLookup.ts new file mode 100644 index 0000000000..9dc57701b2 --- /dev/null +++ b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useTextPatternsLookup.ts @@ -0,0 +1,40 @@ +import { useRef } from 'react'; + +interface TextPatternOptions { + enabled: boolean; + enableMath: boolean; +} + +const useTextPatternsLookup = ({ enabled, enableMath }: TextPatternOptions) => { + const getTextPatterns = () => { + if (!enabled) return []; + + return [ + // See https://www.tiny.cloud/docs/tinymce/latest/content-behavior-options/#text_patterns + // for the default TinyMCE text patterns + { start: '==', end: '==', format: 'joplinHighlight' }, + // Only replace math if math rendering is enabled. + enableMath && { start: '$', end: '$', cmd: 'joplinMath' }, + { start: '`', end: '`', format: 'code' }, + { start: '*', end: '*', format: 'italic' }, + { start: '**', end: '**', format: 'bold' }, + { start: '#', format: 'h1' }, + { start: '##', format: 'h2' }, + { start: '###', format: 'h3' }, + { start: '####', format: 'h4' }, + { start: '#####', format: 'h5' }, + { start: '######', format: 'h6' }, + { start: '1.', cmd: 'InsertOrderedList' }, + { start: '*', cmd: 'InsertUnorderedList' }, + { start: '-', cmd: 'InsertUnorderedList' }, + ].filter(pattern => !!pattern); + }; + + // Store the lookup callback in a ref so that the editor doesn't need to be reloaded + // to use the new patterns: + const patternLookupRef = useRef(getTextPatterns); + patternLookupRef.current = getTextPatterns; + return patternLookupRef; +}; + +export default useTextPatternsLookup; diff --git a/packages/app-desktop/gui/NoteEditor/NoteEditor.tsx b/packages/app-desktop/gui/NoteEditor/NoteEditor.tsx index 30f4a2f730..c139a591e4 100644 --- a/packages/app-desktop/gui/NoteEditor/NoteEditor.tsx +++ b/packages/app-desktop/gui/NoteEditor/NoteEditor.tsx @@ -423,6 +423,7 @@ function NoteEditorContent(props: NoteEditorProps) { const searchMarkers = useSearchMarkers(showLocalSearch, localSearchMarkerOptions, props.searches, props.selectedSearchId, props.highlightedWords); + const markupLanguage = formNote.markup_language; const editorProps: NoteBodyEditorProps = { ref: editorRef, contentKey: formNote.id, @@ -432,7 +433,7 @@ function NoteEditorContent(props: NoteEditorProps) { onWillChange: onBodyWillChange, onMessage: onMessage, content: formNote.body, - contentMarkupLanguage: formNote.markup_language, + contentMarkupLanguage: markupLanguage, contentOriginalCss: formNote.originalCss, resourceInfos: resourceInfos, resourceDirectory: Setting.value('resourceDir'), @@ -457,6 +458,8 @@ function NoteEditorContent(props: NoteEditorProps) { onDrop: onDrop, noteToolbarButtonInfos: props.toolbarButtonInfos, plugins: props.plugins, + // KaTeX isn't supported in HTML notes + mathEnabled: markupLanguage === MarkupLanguage.Markdown && Setting.value('markdown.plugin.katex'), fontSize: Setting.value('style.editor.fontSize'), contentMaxWidth: props.contentMaxWidth, scrollbarSize: props.scrollbarSize, diff --git a/packages/app-desktop/gui/NoteEditor/utils/types.ts b/packages/app-desktop/gui/NoteEditor/utils/types.ts index e886c476bf..8a139226dc 100644 --- a/packages/app-desktop/gui/NoteEditor/utils/types.ts +++ b/packages/app-desktop/gui/NoteEditor/utils/types.ts @@ -132,6 +132,7 @@ export interface NoteBodyEditorProps { onDrop: DropHandler; noteToolbarButtonInfos: ToolbarItem[]; plugins: PluginStates; + mathEnabled: boolean; fontSize: number; contentMaxWidth: number; isSafeMode: boolean; diff --git a/readme/apps/rich_text_editor.md b/readme/apps/rich_text_editor.md index 65954d130b..4a4239ace5 100644 --- a/readme/apps/rich_text_editor.md +++ b/readme/apps/rich_text_editor.md @@ -6,6 +6,8 @@ At its core, Joplin stores notes in [Markdown format](https://github.com/laurent In some cases however, the extra markup format that appears in notes can be seen as a drawback. Bold text will `look **like this**` for example, and tables might not be particularly readable. For that reason, Joplin also features a Rich Text editor, which allows you to edit notes with a [WYSIWYG](https://en.wikipedia.org/wiki/WYSIWYG) editing experience. Bold text will "look **like this**" and tables will be more readable, among others. +## Limitations + However **there is a catch**: in Joplin, notes, even when edited with this Rich Text editor, are **still Markdown** under the hood. This is generally a good thing, because it means you can switch at any time between Markdown and Rich Text editor, and the note is still readable. It is also good if you sync with the mobile application, which doesn't have a rich text editor. The catch is that since Markdown is used under the hood, it means the rich text editor has a number of limitations it inherits from that format: - For a start, **most Markdown plugins will not be compatible**. If you open a Markdown note that makes use of such plugin in the Rich Text editor, it is likely you will lose the plugin special formatting. The only supported plugins are the "fenced" plugins - those that wrap a section of text in triple backticks (for example, KaTeX, Mermaid, etc. are working). You can see a plugin's compatibility on the Markdown config screen. @@ -21,3 +23,24 @@ However **there is a catch**: in Joplin, notes, even when edited with this Rich - All reference links (`[title][link-name]`) are converted to inline links (`[title](https://example.com)`) when Joplin saves changes from the Rich Text editor. Those are the known limitations but if you notice any other issue not listed here, please let us know [in the forum](https://discourse.joplinapp.org/). + +## Markup autocompletion + +By default, the Rich Text Editor automatically replaces certain text patterns with formatted content. Replacements are applied after each pattern is typed. + +By default, the following patterns are replaced: + +- `**bold**`: Formats `bold` as **bold**. +- `*italic*`: Formats `italic` as *italic*. +- `==highlighted==`: Highlights `highlighted`. +- `code`: Formats `code` as inline code. +- `$math$`: Auto-formats to inline math (using KaTeX math syntax). After rendering, equations can be edited by double-clicking or with the "edit" option in the right click menu. +- `# Heading 1`: Creates a level 1 heading. The `#` should be at the start of the line. +- `## Heading 2`: Creates a level 2 heading. +- `## Heading 3`: Creates a level 3 heading. +- `- List`: Creates a bulleted list. +- `1. List`: Creates a numbered list. + +Most replacements require pressing the space or enter key after the closing formatting character. For example, typing `==test==` does not highlight "test", but pressing a space after the last `=` does. + +These replacements can be disabled in settings > note, using the "Auto-format Markdown" setting. From 527627b8bb3c654ee9c630ac5ad37f2c8343d488 Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Sat, 12 Apr 2025 03:49:03 -0700 Subject: [PATCH 151/158] Desktop: Plugins: Prevent plugin dialogs, panels, and editors from accessing the main JavaScript context (#12083) --- .eslintignore | 3 + .gitignore | 3 + packages/app-desktop/ElectronAppWrapper.ts | 5 +- packages/app-desktop/app.ts | 3 - packages/app-desktop/bridge.ts | 9 +- .../services/plugins/UserWebview.tsx | 57 ++++--------- .../services/plugins/UserWebviewIndex.js | 83 +++++++++++++++++-- .../services/plugins/hooks/useContentSize.ts | 47 ++--------- .../services/plugins/hooks/useFormData.ts | 39 +++++++++ .../services/plugins/hooks/useHtmlLoader.ts | 42 ++++------ .../plugins/hooks/useMessageHandler.ts | 27 ++++++ .../services/plugins/hooks/useScriptLoader.ts | 25 ++++-- .../plugins/hooks/useSubmitHandler.ts | 47 +++-------- .../services/plugins/hooks/useViewIsReady.ts | 49 +++++------ .../hooks/useWebviewToPluginMessages.ts | 23 +++-- .../app-desktop/services/plugins/types.ts | 1 + .../utils/customProtocols/constants.ts | 1 - .../handleCustomProtocols.test.ts | 9 +- .../customProtocols/handleCustomProtocols.ts | 49 ++++++++--- packages/lib/commands/renderMarkup.ts | 8 +- 20 files changed, 300 insertions(+), 230 deletions(-) create mode 100644 packages/app-desktop/services/plugins/hooks/useFormData.ts create mode 100644 packages/app-desktop/services/plugins/hooks/useMessageHandler.ts create mode 100644 packages/app-desktop/services/plugins/types.ts diff --git a/.eslintignore b/.eslintignore index 34c16a619e..7a0702e09d 100644 --- a/.eslintignore +++ b/.eslintignore @@ -555,13 +555,16 @@ packages/app-desktop/services/plugins/UserWebview.js packages/app-desktop/services/plugins/UserWebviewDialog.js packages/app-desktop/services/plugins/UserWebviewDialogButtonBar.js packages/app-desktop/services/plugins/hooks/useContentSize.js +packages/app-desktop/services/plugins/hooks/useFormData.js packages/app-desktop/services/plugins/hooks/useHtmlLoader.js +packages/app-desktop/services/plugins/hooks/useMessageHandler.js packages/app-desktop/services/plugins/hooks/useScriptLoader.js packages/app-desktop/services/plugins/hooks/useSubmitHandler.js packages/app-desktop/services/plugins/hooks/useThemeCss.test.js packages/app-desktop/services/plugins/hooks/useThemeCss.js packages/app-desktop/services/plugins/hooks/useViewIsReady.js packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.js +packages/app-desktop/services/plugins/types.js packages/app-desktop/services/restart.js packages/app-desktop/services/sortOrder/PerFolderSortOrderService.test.js packages/app-desktop/services/sortOrder/PerFolderSortOrderService.js diff --git a/.gitignore b/.gitignore index f0e643e35d..eb28468f58 100644 --- a/.gitignore +++ b/.gitignore @@ -530,13 +530,16 @@ packages/app-desktop/services/plugins/UserWebview.js packages/app-desktop/services/plugins/UserWebviewDialog.js packages/app-desktop/services/plugins/UserWebviewDialogButtonBar.js packages/app-desktop/services/plugins/hooks/useContentSize.js +packages/app-desktop/services/plugins/hooks/useFormData.js packages/app-desktop/services/plugins/hooks/useHtmlLoader.js +packages/app-desktop/services/plugins/hooks/useMessageHandler.js packages/app-desktop/services/plugins/hooks/useScriptLoader.js packages/app-desktop/services/plugins/hooks/useSubmitHandler.js packages/app-desktop/services/plugins/hooks/useThemeCss.test.js packages/app-desktop/services/plugins/hooks/useThemeCss.js packages/app-desktop/services/plugins/hooks/useViewIsReady.js packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.js +packages/app-desktop/services/plugins/types.js packages/app-desktop/services/restart.js packages/app-desktop/services/sortOrder/PerFolderSortOrderService.test.js packages/app-desktop/services/sortOrder/PerFolderSortOrderService.js diff --git a/packages/app-desktop/ElectronAppWrapper.ts b/packages/app-desktop/ElectronAppWrapper.ts index 078ed82d29..67257d6010 100644 --- a/packages/app-desktop/ElectronAppWrapper.ts +++ b/packages/app-desktop/ElectronAppWrapper.ts @@ -706,10 +706,6 @@ export default class ElectronAppWrapper { return true; } - public initializeCustomProtocolHandler(logger: LoggerWrapper) { - this.customProtocolHandler_ ??= handleCustomProtocols(logger); - } - // Electron's autoUpdater has to be init from the main process public initializeAutoUpdaterService(logger: LoggerWrapper, devMode: boolean, includePreReleases: boolean) { if (shim.isWindows() || shim.isMac()) { @@ -748,6 +744,7 @@ export default class ElectronAppWrapper { const alreadyRunning = await this.ensureSingleInstance(); if (alreadyRunning) return; + this.customProtocolHandler_ = handleCustomProtocols(); this.createWindow(); this.electronApp_.on('before-quit', () => { diff --git a/packages/app-desktop/app.ts b/packages/app-desktop/app.ts index d43d25fb0e..1b3d75c01d 100644 --- a/packages/app-desktop/app.ts +++ b/packages/app-desktop/app.ts @@ -456,9 +456,6 @@ class Application extends BaseApplication { bridge().openDevTools(); } - bridge().electronApp().initializeCustomProtocolHandler( - Logger.create('handleCustomProtocols'), - ); this.protocolHandler_ = bridge().electronApp().getCustomProtocolHandler(); this.protocolHandler_.allowReadAccessToDirectory(__dirname); // App bundle directory this.protocolHandler_.allowReadAccessToDirectory(Setting.value('cacheDir')); diff --git a/packages/app-desktop/bridge.ts b/packages/app-desktop/bridge.ts index ade7e0785c..7439a9f688 100644 --- a/packages/app-desktop/bridge.ts +++ b/packages/app-desktop/bridge.ts @@ -6,7 +6,6 @@ import { dirname, toSystemSlashes } from '@joplin/lib/path-utils'; import { fileUriToPath } from '@joplin/utils/url'; import { urlDecode } from '@joplin/lib/string-utils'; import * as Sentry from '@sentry/electron/main'; -import { ErrorEvent } from '@sentry/types/types'; import { homedir } from 'os'; import { msleep } from '@joplin/utils/time'; import { pathExists, pathExistsSync, writeFileSync } from 'fs-extra'; @@ -101,9 +100,9 @@ export class Bridge { if (logAttachment) hint.attachments = [logAttachment]; const date = (new Date()).toISOString().replace(/[:-]/g, '').split('.')[0]; - interface ErrorEventWithLog extends ErrorEvent { + type ErrorEventWithLog = (typeof event) & { log: string[]; - } + }; const errorEventWithLog: ErrorEventWithLog = { ...event, @@ -123,6 +122,10 @@ export class Bridge { }, integrations: [Sentry.electronMinidumpIntegration()], + + // Using the default ipcMode value causes ; } diff --git a/packages/app-desktop/services/plugins/UserWebviewIndex.js b/packages/app-desktop/services/plugins/UserWebviewIndex.js index b2d22f8492..8ad9681ea7 100644 --- a/packages/app-desktop/services/plugins/UserWebviewIndex.js +++ b/packages/app-desktop/services/plugins/UserWebviewIndex.js @@ -1,6 +1,43 @@ // This is the API that JS files loaded from the webview can see const webviewApiPromises_ = {}; let viewMessageHandler_ = () => {}; +const postMessage = (message) => { + parent.postMessage(message, '*'); +}; + + +function serializeForm(form) { + const output = {}; + const formData = new FormData(form); + for (const key of formData.keys()) { + output[key] = formData.get(key); + } + return output; +} + +function serializeForms(document) { + const forms = document.getElementsByTagName('form'); + const output = {}; + let untitledIndex = 0; + + for (const form of forms) { + const name = `${form.getAttribute('name')}` || (`form${untitledIndex++}`); + output[name] = serializeForm(form); + } + + return output; +} + +function watchElementSize(element, onChange) { + const emitSizeChange = () => { + onChange(element.getBoundingClientRect()); + }; + const observer = new ResizeObserver(emitSizeChange); + observer.observe(element); + + // Initial size + requestAnimationFrame(emitSizeChange); +} // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars const webviewApi = { @@ -11,7 +48,7 @@ const webviewApi = { webviewApiPromises_[messageId] = { resolve, reject }; }); - window.postMessage({ + postMessage({ target: 'postMessageService.message', message: { from: 'userWebview', @@ -26,7 +63,7 @@ const webviewApi = { onMessage: function(viewMessageHandler) { viewMessageHandler_ = viewMessageHandler; - window.postMessage({ + postMessage({ target: 'postMessageService.registerViewMessageHandler', }); }, @@ -90,14 +127,14 @@ const webviewApi = { window.requestAnimationFrame(() => { // eslint-disable-next-line no-console console.debug('UserWebviewIndex: setting html callback', args.hash); - window.postMessage({ target: 'UserWebview', message: 'htmlIsSet', hash: args.hash }, '*'); + postMessage({ target: 'UserWebview', message: 'htmlIsSet', hash: args.hash }); }); }, setScript: (args) => { const { script, key } = args; - const scriptPath = `file://${script}`; + const scriptPath = `joplin-content://plugin-webview/${script}`; const elementId = `joplin-script-${key}`; if (addedScripts[elementId]) { @@ -114,7 +151,7 @@ const webviewApi = { if (!scripts) return; for (let i = 0; i < scripts.length; i++) { - const scriptPath = `file://${scripts[i]}`; + const scriptPath = `joplin-content://plugin-webview/${scripts[i]}`; if (addedScripts[scriptPath]) continue; addedScripts[scriptPath] = true; @@ -123,6 +160,14 @@ const webviewApi = { } }, + serializeForms: () => { + postMessage({ + target: 'UserWebview', + message: 'serializedForms', + formData: serializeForms(document), + }); + }, + 'postMessageService.response': (event) => { const message = event.message; const promise = webviewApiPromises_[message.responseId]; @@ -171,7 +216,33 @@ const webviewApi = { window.requestAnimationFrame(() => { // eslint-disable-next-line no-console console.debug('UserWebViewIndex: calling isReady'); - window.postMessage({ target: 'UserWebview', message: 'ready' }, '*'); + postMessage({ target: 'UserWebview', message: 'ready' }); + }); + + + const sendFormSubmit = () => { + postMessage({ target: 'UserWebview', message: 'form-submit' }); + }; + const sendDismiss = () => { + postMessage({ target: 'UserWebview', message: 'dismiss' }); + }; + document.addEventListener('submit', () => { + sendFormSubmit(); + }); + document.addEventListener('keydown', event => { + if (event.key === 'Enter' && event.target.tagName === 'INPUT' && event.target.type === 'text') { + sendFormSubmit(); + } else if (event.key === 'Escape') { + sendDismiss(); + } + }); + + watchElementSize(document.getElementById('joplin-plugin-content'), size => { + postMessage({ + target: 'UserWebview', + message: 'updateContentSize', + size, + }); }); }); })(); diff --git a/packages/app-desktop/services/plugins/hooks/useContentSize.ts b/packages/app-desktop/services/plugins/hooks/useContentSize.ts index 54382eb6e1..4a5156f6e9 100644 --- a/packages/app-desktop/services/plugins/hooks/useContentSize.ts +++ b/packages/app-desktop/services/plugins/hooks/useContentSize.ts @@ -1,4 +1,5 @@ -import { useEffect, useState } from 'react'; +import { RefObject, useState } from 'react'; +import useMessageHandler from './useMessageHandler'; interface Size { width: number; @@ -6,59 +7,29 @@ interface Size { hash: string; } -// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied -export default function(frameWindow: any, htmlHash: string, minWidth: number, minHeight: number, fitToContent: boolean, isReady: boolean) { +export default function(viewRef: RefObject, htmlHash: string, minWidth: number, minHeight: number) { const [contentSize, setContentSize] = useState({ width: minWidth, height: minHeight, hash: '', }); - function updateContentSize(hash: string) { - if (!frameWindow) return; - - const rect = frameWindow.document.getElementById('joplin-plugin-content').getBoundingClientRect(); + useMessageHandler(viewRef, event => { + if (event.data.message !== 'updateContentSize') return; + const rect = event.data.size; let w = rect.width; let h = rect.height; if (w < minWidth) w = minWidth; if (h < minHeight) h = minHeight; - const newSize = { width: w, height: h, hash: hash }; + const newSize = { width: w, height: h, hash: htmlHash }; setContentSize((current: Size) => { - if (current.width === newSize.width && current.height === newSize.height && current.hash === hash) return current; + if (current.width === newSize.width && current.height === newSize.height && current.hash === htmlHash) return current; return newSize; }); - } - - useEffect(() => { - updateContentSize(htmlHash); - // eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied - }, [htmlHash]); - - useEffect(() => { - if (!fitToContent || !isReady) return () => {}; - - function onTick() { - updateContentSize(htmlHash); - } - - // The only reliable way to make sure that the iframe has the same dimensions - // as its content is to poll the dimensions at regular intervals. Other methods - // work most of the time but will fail in various edge cases. Most reliable way - // is probably iframe-resizer package, but still with 40 unfixed bugs. - // - // Polling in our case is fine since this is only used when displaying plugin - // dialogs, which should be short lived. updateContentSize() is also optimised - // to do nothing when size hasn't changed. - const updateFrameSizeIID = setInterval(onTick, 100); - - return () => { - clearInterval(updateFrameSizeIID); - }; - // eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied - }, [fitToContent, isReady, minWidth, minHeight, htmlHash]); + }); return contentSize; } diff --git a/packages/app-desktop/services/plugins/hooks/useFormData.ts b/packages/app-desktop/services/plugins/hooks/useFormData.ts new file mode 100644 index 0000000000..39e2d45388 --- /dev/null +++ b/packages/app-desktop/services/plugins/hooks/useFormData.ts @@ -0,0 +1,39 @@ +import { RefObject, useMemo, useRef } from 'react'; +import { PostMessage } from '../types'; +import useMessageHandler from './useMessageHandler'; + +type FormDataRecord = Record; +type FormDataListener = (formData: FormDataRecord)=> void; + +const useFormData = (viewRef: RefObject, postMessage: PostMessage) => { + const formDataListenersRef = useRef([]); + useMessageHandler(viewRef, (event) => { + if (event.data.message === 'serializedForms') { + const formData = event.data.formData; + if (typeof formData !== 'object') { + throw new Error('Invalid formData result.'); + } + + const listeners = [...formDataListenersRef.current]; + formDataListenersRef.current = []; + for (const listener of listeners) { + listener(event.data.formData); + } + } + }); + + return useMemo(() => { + return { + getFormData: () => { + return new Promise(resolve => { + postMessage('getFormData', null); + formDataListenersRef.current.push((data) => { + resolve(data); + }); + }); + }, + }; + }, [postMessage]); +}; + +export default useFormData; diff --git a/packages/app-desktop/services/plugins/hooks/useHtmlLoader.ts b/packages/app-desktop/services/plugins/hooks/useHtmlLoader.ts index 8affdf09a2..a5c439a4d2 100644 --- a/packages/app-desktop/services/plugins/hooks/useHtmlLoader.ts +++ b/packages/app-desktop/services/plugins/hooks/useHtmlLoader.ts @@ -1,41 +1,31 @@ -import { useEffect, useState, useMemo } from 'react'; +import { useEffect, useState, useMemo, RefObject } from 'react'; +import useMessageHandler from './useMessageHandler'; const md5 = require('md5'); -// eslint-disable-next-line @typescript-eslint/ban-types, @typescript-eslint/no-explicit-any -- Old code before rule was applied, Old code before rule was applied -export default function(frameWindow: any, isReady: boolean, postMessage: Function, html: string) { +// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied, Old code before rule was applied +export default function(viewRef: RefObject, isReady: boolean, postMessage: Function, html: string) { const [loadedHtmlHash, setLoadedHtmlHash] = useState(''); const htmlHash = useMemo(() => { return md5(html); }, [html]); - useEffect(() => { - if (!frameWindow) return () => {}; + useMessageHandler(viewRef, event => { + const data = event.data; - // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied - function onMessage(event: any) { - const data = event.data; + if (!data || data.target !== 'UserWebview') return; - if (!data || data.target !== 'UserWebview') return; + // eslint-disable-next-line no-console + console.info('useHtmlLoader: message', data); - // eslint-disable-next-line no-console - console.info('useHtmlLoader: message', data); - - // We only update if the HTML that was loaded is the same as - // the active one. Otherwise it means the content has been - // changed between the moment it was set by the user and the - // moment it was loaded in the view. - if (data.message === 'htmlIsSet' && data.hash === htmlHash) { - setLoadedHtmlHash(data.hash); - } + // We only update if the HTML that was loaded is the same as + // the active one. Otherwise it means the content has been + // changed between the moment it was set by the user and the + // moment it was loaded in the view. + if (data.message === 'htmlIsSet' && data.hash === htmlHash) { + setLoadedHtmlHash(data.hash); } - - frameWindow.addEventListener('message', onMessage); - - return () => { - if (frameWindow.removeEventListener) frameWindow.removeEventListener('message', onMessage); - }; - }, [frameWindow, htmlHash]); + }); useEffect(() => { // eslint-disable-next-line no-console diff --git a/packages/app-desktop/services/plugins/hooks/useMessageHandler.ts b/packages/app-desktop/services/plugins/hooks/useMessageHandler.ts new file mode 100644 index 0000000000..7b38da0abd --- /dev/null +++ b/packages/app-desktop/services/plugins/hooks/useMessageHandler.ts @@ -0,0 +1,27 @@ +import { RefObject, useEffect, useRef } from 'react'; + +type OnMessage = (event: MessageEvent)=> void; + +const useMessageHandler = (viewRef: RefObject, onMessage: OnMessage) => { + const onMessageRef = useRef(onMessage); + onMessageRef.current = onMessage; + + useEffect(() => { + function onMessage_(event: MessageEvent) { + if (event.source !== viewRef.current.contentWindow) { + return; + } + + onMessageRef.current(event); + } + + const containerWindow = (viewRef.current.getRootNode() as Document).defaultView; + containerWindow.addEventListener('message', onMessage_); + + return () => { + containerWindow.removeEventListener('message', onMessage_); + }; + }, [viewRef]); +}; + +export default useMessageHandler; diff --git a/packages/app-desktop/services/plugins/hooks/useScriptLoader.ts b/packages/app-desktop/services/plugins/hooks/useScriptLoader.ts index 37874827b8..4008fadb3f 100644 --- a/packages/app-desktop/services/plugins/hooks/useScriptLoader.ts +++ b/packages/app-desktop/services/plugins/hooks/useScriptLoader.ts @@ -1,16 +1,23 @@ -import { useEffect } from 'react'; +import { useEffect, useMemo } from 'react'; +import bridge from '../../bridge'; // eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied export default function(postMessage: Function, isReady: boolean, scripts: string[], cssFilePath: string) { - useEffect(() => { - if (!isReady) return; - postMessage('setScripts', { scripts: scripts }); - // eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied - }, [scripts, isReady]); + const protocolHandler = useMemo(() => { + return bridge().electronApp().getCustomProtocolHandler(); + }, []); useEffect(() => { - if (!isReady || !cssFilePath) return; + if (!isReady) return () => {}; + postMessage('setScripts', { scripts: scripts }); + const { remove } = protocolHandler.allowReadAccessToFiles(scripts); + return remove; + }, [scripts, isReady, postMessage, protocolHandler]); + + useEffect(() => { + if (!isReady || !cssFilePath) return () => {}; postMessage('setScript', { script: cssFilePath, key: 'themeCss' }); - // eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied - }, [isReady, cssFilePath]); + const { remove } = protocolHandler.allowReadAccessToFile(cssFilePath); + return remove; + }, [isReady, cssFilePath, postMessage, protocolHandler]); } diff --git a/packages/app-desktop/services/plugins/hooks/useSubmitHandler.ts b/packages/app-desktop/services/plugins/hooks/useSubmitHandler.ts index 49a5b49198..d25eab8470 100644 --- a/packages/app-desktop/services/plugins/hooks/useSubmitHandler.ts +++ b/packages/app-desktop/services/plugins/hooks/useSubmitHandler.ts @@ -1,41 +1,14 @@ -import { useEffect } from 'react'; +import { RefObject } from 'react'; +import useMessageHandler from './useMessageHandler'; // eslint-disable-next-line @typescript-eslint/ban-types, @typescript-eslint/no-explicit-any -- Old code before rule was applied, Old code before rule was applied -export default function(frameWindow: any, onSubmit: Function, onDismiss: Function, loadedHtmlHash: string) { - const document = frameWindow && frameWindow.document ? frameWindow.document : null; - - useEffect(() => { - if (!document) return () => {}; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied - function onFormSubmit(event: any) { - event.preventDefault(); - if (onSubmit) onSubmit(); +export default function(viewRef: RefObject, onSubmit: Function, onDismiss: Function) { + useMessageHandler(viewRef, event => { + const message = event.data?.message; + if (message === 'form-submit') { + onSubmit(); + } else if (message === 'dismiss') { + onDismiss(); } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied - function onKeyDown(event: any) { - if (event.key === 'Escape') { - if (onDismiss) onDismiss(); - } - - if (event.key === 'Enter') { - // - // Disable enter key from submitting when a text area is in focus! - // https://github.com/laurent22/joplin/issues/4766 - // - if (document.activeElement.tagName !== 'TEXTAREA') { - if (onSubmit) onSubmit(); - } - } - } - - document.addEventListener('submit', onFormSubmit); - document.addEventListener('keydown', onKeyDown); - - return () => { - if (document) document.removeEventListener('submit', onFormSubmit); - if (document) document.removeEventListener('keydown', onKeyDown); - }; - }, [document, loadedHtmlHash, onSubmit, onDismiss]); + }); } diff --git a/packages/app-desktop/services/plugins/hooks/useViewIsReady.ts b/packages/app-desktop/services/plugins/hooks/useViewIsReady.ts index f3141d84cc..c28997fef3 100644 --- a/packages/app-desktop/services/plugins/hooks/useViewIsReady.ts +++ b/packages/app-desktop/services/plugins/hooks/useViewIsReady.ts @@ -1,7 +1,7 @@ -import { useEffect, useState } from 'react'; +import { RefObject, useEffect, useState } from 'react'; +import useMessageHandler from './useMessageHandler'; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied -export default function useViewIsReady(viewRef: any) { +export default function useViewIsReady(viewRef: RefObject) { // Just checking if the iframe is ready is not sufficient because its content // might not be ready (for example, IPC listeners might not be initialised). // So we also listen to a custom "ready" message coming from the webview content @@ -9,6 +9,18 @@ export default function useViewIsReady(viewRef: any) { const [iframeReady, setIFrameReady] = useState(false); const [iframeContentReady, setIFrameContentReady] = useState(false); + useMessageHandler(viewRef, event => { + const data = event.data; + if (!data || data.target !== 'UserWebview') return; + + // eslint-disable-next-line no-console + console.debug('useViewIsReady: message', data); + + if (data.message === 'ready') { + setIFrameContentReady(true); + } + }); + useEffect(() => { // eslint-disable-next-line no-console console.debug('useViewIsReady ============== Setup Listeners'); @@ -19,20 +31,6 @@ export default function useViewIsReady(viewRef: any) { setIFrameReady(true); } - // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied - function onMessage(event: any) { - const data = event.data; - - if (!data || data.target !== 'UserWebview') return; - - // eslint-disable-next-line no-console - console.debug('useViewIsReady: message', data); - - if (data.message === 'ready') { - setIFrameContentReady(true); - } - } - const iframeDocument = viewRef.current.contentWindow.document; // eslint-disable-next-line no-console @@ -42,20 +40,15 @@ export default function useViewIsReady(viewRef: any) { onIFrameReady(); } - viewRef.current.addEventListener('dom-ready', onIFrameReady); - viewRef.current.addEventListener('load', onIFrameReady); - viewRef.current.contentWindow.addEventListener('message', onMessage); + const view = viewRef.current; + view.addEventListener('dom-ready', onIFrameReady); + view.addEventListener('load', onIFrameReady); return () => { - if (viewRef.current) { - viewRef.current.removeEventListener('dom-ready', onIFrameReady); - viewRef.current.removeEventListener('load', onIFrameReady); - // eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied - viewRef.current.contentWindow.removeEventListener('message', onMessage); - } + view.removeEventListener('dom-ready', onIFrameReady); + view.removeEventListener('load', onIFrameReady); }; - // eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied - }, []); + }, [viewRef]); return iframeReady && iframeContentReady; } diff --git a/packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.ts b/packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.ts index aacf8758f5..779fc740bc 100644 --- a/packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.ts +++ b/packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.ts @@ -1,8 +1,9 @@ import PostMessageService, { MessageResponse, ResponderComponentType } from '@joplin/lib/services/PostMessageService'; -import { useEffect } from 'react'; +import { RefObject, useEffect } from 'react'; -// eslint-disable-next-line @typescript-eslint/ban-types, @typescript-eslint/no-explicit-any -- Old code before rule was applied, Old code before rule was applied -export default function(frameWindow: any, isReady: boolean, pluginId: string, viewId: string, windowId: string, postMessage: Function) { + +// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied, Old code before rule was applied +export default function(webviewRef: RefObject, isReady: boolean, pluginId: string, viewId: string, windowId: string, postMessage: Function) { useEffect(() => { PostMessageService.instance().registerResponder(ResponderComponentType.UserWebview, viewId, windowId, (message: MessageResponse) => { postMessage('postMessageService.response', { message }); @@ -15,12 +16,8 @@ export default function(frameWindow: any, isReady: boolean, pluginId: string, vi }, [viewId]); useEffect(() => { - if (!frameWindow) return () => {}; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied - function onMessage_(event: any) { - - if (!event.data || !event.data.target) { + function onMessage_(event: MessageEvent) { + if (!event.data || event.source !== webviewRef.current.contentWindow) { return; } @@ -38,11 +35,11 @@ export default function(frameWindow: any, isReady: boolean, pluginId: string, vi } } - frameWindow.addEventListener('message', onMessage_); + const containerWindow = (webviewRef.current.getRootNode() as Document).defaultView; + containerWindow.addEventListener('message', onMessage_); return () => { - if (frameWindow?.removeEventListener) frameWindow.removeEventListener('message', onMessage_); + containerWindow.removeEventListener('message', onMessage_); }; - // eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied - }, [frameWindow, isReady, pluginId, windowId, viewId]); + }, [webviewRef, isReady, pluginId, windowId, viewId, postMessage]); } diff --git a/packages/app-desktop/services/plugins/types.ts b/packages/app-desktop/services/plugins/types.ts new file mode 100644 index 0000000000..f7ed9fc593 --- /dev/null +++ b/packages/app-desktop/services/plugins/types.ts @@ -0,0 +1 @@ +export type PostMessage = (message: string, args: unknown)=> void; diff --git a/packages/app-desktop/utils/customProtocols/constants.ts b/packages/app-desktop/utils/customProtocols/constants.ts index 64ed9ee3e0..6a5853f54a 100644 --- a/packages/app-desktop/utils/customProtocols/constants.ts +++ b/packages/app-desktop/utils/customProtocols/constants.ts @@ -1,3 +1,2 @@ - // eslint-disable-next-line import/prefer-default-export export const contentProtocolName = 'joplin-content'; diff --git a/packages/app-desktop/utils/customProtocols/handleCustomProtocols.test.ts b/packages/app-desktop/utils/customProtocols/handleCustomProtocols.test.ts index a5a488df42..e066a635b6 100644 --- a/packages/app-desktop/utils/customProtocols/handleCustomProtocols.test.ts +++ b/packages/app-desktop/utils/customProtocols/handleCustomProtocols.test.ts @@ -19,7 +19,6 @@ jest.doMock('electron', () => { }; }); -import Logger from '@joplin/utils/Logger'; import handleCustomProtocols from './handleCustomProtocols'; import { supportDir } from '@joplin/lib/testing/test-utils'; import { join } from 'path'; @@ -27,8 +26,7 @@ import { stat } from 'fs-extra'; import { toForwardSlashes } from '@joplin/utils/path'; const setUpProtocolHandler = () => { - const logger = Logger.create('test-logger'); - const protocolHandler = handleCustomProtocols(logger); + const protocolHandler = handleCustomProtocols(); expect(handleProtocolMock).toHaveBeenCalledTimes(1); @@ -56,9 +54,8 @@ const toAccessUrl = (path: string, { host = 'note-viewer' }: ExpectBlockedOption const expectPathToBeBlocked = async (onRequestListener: ProtocolHandler, filePath: string, options?: ExpectBlockedOptions) => { const url = toAccessUrl(filePath, options); - await expect( - async () => await onRequestListener(new Request(url)), - ).rejects.toThrow(/Read access not granted for URL|Invalid or missing media access key|Media access denied/); + const response = await onRequestListener(new Request(url)); + expect(response.status).toBe(403); // Forbidden }; const expectPathToBeUnblocked = async (onRequestListener: ProtocolHandler, filePath: string, options?: ExpectBlockedOptions) => { diff --git a/packages/app-desktop/utils/customProtocols/handleCustomProtocols.ts b/packages/app-desktop/utils/customProtocols/handleCustomProtocols.ts index 354be211ce..6bd1996a0a 100644 --- a/packages/app-desktop/utils/customProtocols/handleCustomProtocols.ts +++ b/packages/app-desktop/utils/customProtocols/handleCustomProtocols.ts @@ -3,7 +3,6 @@ import { dirname, resolve, normalize } from 'path'; import { fileURLToPath, pathToFileURL } from 'url'; import { contentProtocolName } from './constants'; import resolvePathWithinDir from '@joplin/lib/utils/resolvePathWithinDir'; -import { LoggerWrapper } from '@joplin/utils/Logger'; import * as fs from 'fs-extra'; import { createReadStream } from 'fs'; import { fromFilename } from '@joplin/lib/mime-utils'; @@ -17,6 +16,7 @@ export interface CustomProtocolHandler { // note-viewer/ URLs allowReadAccessToDirectory(path: string): void; allowReadAccessToFile(path: string): AccessController; + allowReadAccessToFiles(paths: string[]): AccessController; // file-media/ URLs setMediaAccessEnabled(enabled: boolean): void; @@ -124,6 +124,12 @@ const handleRangeRequest = async (request: Request, targetPath: string) => { ); }; +const makeAccessDeniedResponse = (message: string) => { + return new Response(message, { + status: 403, // Forbidden + }); +}; + // Creating a custom protocol allows us to isolate iframes by giving them // different domain names from the main Joplin app. // @@ -134,10 +140,10 @@ const handleRangeRequest = async (request: Request, targetPath: string) => { // // TODO: Use Logger.create (doesn't work for now because Logger is only initialized // in the main process.) -const handleCustomProtocols = (logger: LoggerWrapper): CustomProtocolHandler => { - logger = { - ...logger, - debug: () => {}, +const handleCustomProtocols = (): CustomProtocolHandler => { + const logger = { + // Disabled for now + debug: (..._message: unknown[]) => {}, }; // Allow-listed files/directories for joplin-content://note-viewer/ @@ -155,14 +161,16 @@ const handleCustomProtocols = (logger: LoggerWrapper): CustomProtocolHandler => // See https://security.stackexchange.com/a/123723 if (pathname.startsWith('..')) { - throw new Error(`Invalid URL (not absolute), ${request.url}`); + return new Response('Invalid URL (not absolute)', { + status: 400, + }); } pathname = resolve(appBundleDirectory, pathname); let canRead = false; let mediaOnly = true; - if (host === 'note-viewer') { + if (host === 'note-viewer' || host === 'plugin-webview') { if (readableFiles.has(pathname)) { canRead = true; } else { @@ -177,7 +185,7 @@ const handleCustomProtocols = (logger: LoggerWrapper): CustomProtocolHandler => mediaOnly = false; } else if (host === 'file-media') { if (!mediaAccessKey) { - throw new Error('Media access denied. This must be enabled with .setMediaAccessEnabled'); + return makeAccessDeniedResponse('Media access denied. This must be enabled with .setMediaAccessEnabled'); } canRead = true; @@ -185,14 +193,16 @@ const handleCustomProtocols = (logger: LoggerWrapper): CustomProtocolHandler => const accessKey = url.searchParams.get('access-key'); if (accessKey !== mediaAccessKey) { - throw new Error(`Invalid or missing media access key (was ${accessKey}). An allow-listed ?access-key= parameter must be provided.`); + return makeAccessDeniedResponse('Invalid or missing media access key. An allow-listed ?access-key= parameter must be provided.'); } } else { - throw new Error(`Invalid URL ${request.url}`); + return new Response(`Invalid request URL (${request.url})`, { + status: 400, + }); } if (!canRead) { - throw new Error(`Read access not granted for URL ${request.url}`); + return makeAccessDeniedResponse(`Read access not granted for URL (${request.url})`); } const asFileUrl = pathToFileURL(pathname).toString(); @@ -214,7 +224,7 @@ const handleCustomProtocols = (logger: LoggerWrapper): CustomProtocolHandler => // This is an extra check to prevent loading text/html and arbitrary non-media content from the URL. const contentType = response.headers.get('Content-Type'); if (!contentType || !contentType.match(/^(image|video|audio)\//)) { - throw new Error(`Attempted to access non-media file from ${request.url}, which is media-only. Content type was ${contentType}.`); + return makeAccessDeniedResponse(`Attempted to access non-media file from ${request.url}, which is media-only. Content type was ${contentType}.`); } } @@ -222,7 +232,7 @@ const handleCustomProtocols = (logger: LoggerWrapper): CustomProtocolHandler => }); const appBundleDirectory = dirname(dirname(__dirname)); - return { + const result: CustomProtocolHandler = { allowReadAccessToDirectory: (path: string) => { path = resolve(appBundleDirectory, path); logger.debug('protocol handler: Allow read access to directory', path); @@ -250,6 +260,18 @@ const handleCustomProtocols = (logger: LoggerWrapper): CustomProtocolHandler => }, }; }, + allowReadAccessToFiles: (paths: string[]) => { + const handles = paths.map(path => { + return result.allowReadAccessToFile(path); + }); + return { + remove: () => { + for (const handle of handles) { + handle.remove(); + } + }, + }; + }, setMediaAccessEnabled: (enabled: boolean) => { if (enabled) { mediaAccessKey ||= createSecureRandom(); @@ -263,6 +285,7 @@ const handleCustomProtocols = (logger: LoggerWrapper): CustomProtocolHandler => return mediaAccessKey || null; }, }; + return result; }; export default handleCustomProtocols; diff --git a/packages/lib/commands/renderMarkup.ts b/packages/lib/commands/renderMarkup.ts index a5cdb35a32..196d74fda9 100644 --- a/packages/lib/commands/renderMarkup.ts +++ b/packages/lib/commands/renderMarkup.ts @@ -1,6 +1,7 @@ import markupLanguageUtils from '../markupLanguageUtils'; import Setting from '../models/Setting'; import { CommandRuntime, CommandDeclaration, CommandContext } from '../services/CommandService'; +import shim from '../shim'; import { themeStyle } from '../theme'; import attachedResources from '../utils/attachedResources'; import { MarkupLanguage } from '@joplin/renderer'; @@ -12,8 +13,13 @@ export const declaration: CommandDeclaration = { }; const getMarkupToHtml = () => { + // In the desktop app, resources accessed with file:// URLs can't be displayed in certain places (e.g. the note + // viewer and plugin WebViews). On mobile, however, joplin-content:// URLs don't work. As such, use different + // protocols on different platforms: + const protocol = shim.isElectron() ? 'joplin-content://note-viewer/' : 'file://'; + return markupLanguageUtils.newMarkupToHtml({}, { - resourceBaseUrl: `file://${Setting.value('resourceDir')}/`, + resourceBaseUrl: `${protocol}${Setting.value('resourceDir')}/`, customCss: '', }); }; From fd486e298adde9f806f39868c579f1eae4042230 Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Sat, 12 Apr 2025 04:12:26 -0700 Subject: [PATCH 152/158] Desktop: Rich Text Editor: Fix editor content not updated in some cases when switching notes (#12084) --- .../NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx | 9 ++++-- .../models/NoteEditorScreen.ts | 6 +++- .../integration-tests/richTextEditor.spec.ts | 28 +++++++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx index 5a16f4b523..10a3f7e629 100644 --- a/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx +++ b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx @@ -1017,6 +1017,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => { return true; } + const lastNoteIdRef = useRef(props.noteId); useEffect(() => { if (!editor) return () => {}; @@ -1030,7 +1031,10 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => { const loadContent = async () => { const resourcesEqual = resourceInfosEqual(lastOnChangeEventInfo.current.resourceInfos, props.resourceInfos); - if (lastOnChangeEventInfo.current.content !== props.content || !resourcesEqual) { + // Use nextOnChangeEventInfo's noteId -- lastOnChangeEventInfo can be slightly out-of-date. + const differentNoteId = lastNoteIdRef.current !== props.noteId; + const differentContent = lastOnChangeEventInfo.current.content !== props.content; + if (differentNoteId || differentContent || !resourcesEqual) { const result = await props.markupToHtml( props.contentMarkupLanguage, props.content, @@ -1053,6 +1057,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => { const offsetBookmarkId = 2; const bookmark = editor.selection.getBookmark(offsetBookmarkId); editor.setContent(awfulInitHack(result.html)); + lastNoteIdRef.current = props.noteId; if (lastOnChangeEventInfo.current.contentKey !== props.contentKey) { // Need to clear UndoManager to avoid this problem: @@ -1101,7 +1106,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => { cancelled = true; }; // eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied - }, [editor, props.themeId, props.scrollbarSize, props.markupToHtml, props.allAssets, props.content, props.resourceInfos, props.contentKey, props.contentMarkupLanguage, props.whiteBackgroundNoteRendering]); + }, [editor, props.noteId, props.themeId, props.scrollbarSize, props.markupToHtml, props.allAssets, props.content, props.resourceInfos, props.contentKey, props.contentMarkupLanguage, props.whiteBackgroundNoteRendering]); useEffect(() => { if (!editor) return () => {}; diff --git a/packages/app-desktop/integration-tests/models/NoteEditorScreen.ts b/packages/app-desktop/integration-tests/models/NoteEditorScreen.ts index 4ffe0d2cc5..fed766a16a 100644 --- a/packages/app-desktop/integration-tests/models/NoteEditorScreen.ts +++ b/packages/app-desktop/integration-tests/models/NoteEditorScreen.ts @@ -80,7 +80,11 @@ export default class NoteEditorPage { // We use frameLocator(':scope') to convert the richTextEditor Locator into // a FrameLocator. (:scope selects the locator itself). // https://playwright.dev/docs/api/class-framelocator - return this.richTextEditor.frameLocator(':scope'); + return this.richTextEditor.contentFrame(); + } + + public getRichTextEditorBody() { + return this.richTextEditor.contentFrame().locator('body'); } public focusCodeMirrorEditor() { diff --git a/packages/app-desktop/integration-tests/richTextEditor.spec.ts b/packages/app-desktop/integration-tests/richTextEditor.spec.ts index 21402f03db..9529907589 100644 --- a/packages/app-desktop/integration-tests/richTextEditor.spec.ts +++ b/packages/app-desktop/integration-tests/richTextEditor.spec.ts @@ -212,5 +212,33 @@ test.describe('richTextEditor', () => { await expect(editor.noteTitleInput).not.toBeFocused(); await expect(editor.richTextEditor).toBeFocused(); }); + + test('note should have correct content even if opened quickly after last edit', async ({ mainWindow }) => { + const mainScreen = await new MainScreen(mainWindow).setup(); + await mainScreen.createNewNote('Test 1'); + await mainScreen.createNewNote('Test 2'); + const test1Header = mainScreen.noteList.getNoteItemByTitle('Test 1'); + const test2Header = mainScreen.noteList.getNoteItemByTitle('Test 2'); + + const editor = mainScreen.noteEditor; + await editor.toggleEditorsButton.click(); + await editor.richTextEditor.waitFor(); + + const editorBody = editor.getRichTextEditorBody(); + const setEditorText = async (targetText: string) => { + await editorBody.pressSequentially(targetText); + await expect(editorBody).toHaveText(targetText); + }; + + await test1Header.click(); + await expect(editorBody).toHaveText(''); + await setEditorText('Test 1'); + + await test2Header.click(); + // Previously, after switching to note 2, the "Test 1" text would remain present in the + // editor. + await expect(editorBody).toHaveText(''); + }); + }); From 90f622b3e687678eb2fd968bd6c9aec4a5744eb8 Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Sat, 12 Apr 2025 04:12:34 -0700 Subject: [PATCH 153/158] Chore: Testing: Make Rich Text Editor attachment test more reliable (#12085) --- packages/app-desktop/integration-tests/richTextEditor.spec.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/app-desktop/integration-tests/richTextEditor.spec.ts b/packages/app-desktop/integration-tests/richTextEditor.spec.ts index 9529907589..d736aa0bc2 100644 --- a/packages/app-desktop/integration-tests/richTextEditor.spec.ts +++ b/packages/app-desktop/integration-tests/richTextEditor.spec.ts @@ -62,6 +62,9 @@ test.describe('richTextEditor', () => { await setFilePickerResponse(electronApp, [pathToAttach]); await editor.attachFileButton.click(); + // Wait for it to render + await expect(editor.getNoteViewerFrameLocator().getByText('test-file.txt')).toBeVisible(); + // Switch to the RTE await editor.toggleEditorsButton.click(); await editor.richTextEditor.waitFor(); From 5876d57845c4c8c41ec3e0fec84d8d1a31a792e9 Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Sat, 12 Apr 2025 15:04:08 -0700 Subject: [PATCH 154/158] Chore: Desktop: Disable WebView tag in window config (#12086) --- packages/app-desktop/ElectronAppWrapper.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/app-desktop/ElectronAppWrapper.ts b/packages/app-desktop/ElectronAppWrapper.ts index 67257d6010..004680dcba 100644 --- a/packages/app-desktop/ElectronAppWrapper.ts +++ b/packages/app-desktop/ElectronAppWrapper.ts @@ -212,7 +212,6 @@ export default class ElectronAppWrapper { spellcheck: true, enableRemoteModule: true, }, - webviewTag: true, // We start with a hidden window, which is then made visible depending on the showTrayIcon setting // https://github.com/laurent22/joplin/issues/2031 // From a8b18e9ab09d8cd6ee481b1229dcd83cce090a6d Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Sat, 12 Apr 2025 15:04:19 -0700 Subject: [PATCH 155/158] Mobile: Update to js-draw v1.29.2 (#12074) --- packages/app-mobile/package.json | 4 ++-- yarn.lock | 30 +++++++++++++++--------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/app-mobile/package.json b/packages/app-mobile/package.json index 28194d2991..2254237367 100644 --- a/packages/app-mobile/package.json +++ b/packages/app-mobile/package.json @@ -92,7 +92,7 @@ "@babel/preset-env": "7.24.7", "@babel/runtime": "7.24.7", "@joplin/tools": "~3.3", - "@js-draw/material-icons": "1.27.2", + "@js-draw/material-icons": "1.29.1", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.15", "@react-native/babel-preset": "0.74.86", "@react-native/metro-config": "0.74.87", @@ -118,7 +118,7 @@ "jest": "29.7.0", "jest-environment-jsdom": "29.7.0", "jetifier": "2.0.0", - "js-draw": "1.27.2", + "js-draw": "1.29.2", "jsdom": "24.1.1", "nodemon": "3.1.7", "punycode": "2.3.1", diff --git a/yarn.lock b/yarn.lock index 64fbc962bf..5b7c21086f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8361,7 +8361,7 @@ __metadata: "@joplin/renderer": ~3.3 "@joplin/tools": ~3.3 "@joplin/utils": ~3.3 - "@js-draw/material-icons": 1.27.2 + "@js-draw/material-icons": 1.29.1 "@pmmmwh/react-refresh-webpack-plugin": ^0.5.15 "@react-native-clipboard/clipboard": 1.14.3 "@react-native-community/datetimepicker": 8.2.0 @@ -8402,7 +8402,7 @@ __metadata: jest: 29.7.0 jest-environment-jsdom: 29.7.0 jetifier: 2.0.0 - js-draw: 1.27.2 + js-draw: 1.29.2 jsdom: 24.1.1 lodash: 4.17.21 md5: 2.3.0 @@ -9131,21 +9131,21 @@ __metadata: languageName: node linkType: hard -"@js-draw/material-icons@npm:1.27.2": - version: 1.27.2 - resolution: "@js-draw/material-icons@npm:1.27.2" +"@js-draw/material-icons@npm:1.29.1": + version: 1.29.1 + resolution: "@js-draw/material-icons@npm:1.29.1" peerDependencies: js-draw: ^1.0.1 - checksum: dcaac6c45d20df6542fe874e0cd6f7a40f77faaebe494f4eb45c6b1c3595223a01b36067549159341a18af018253ea5c1c99bd82c47060a8b33596263ae83026 + checksum: e3de5520b4154228ab3d593ae06d7310f3e1a100e5f2507e8b8b317a51cc3566d907c252e2cc92b89274059e05b0a57eb69b2f27483cab45fcbc1ccae7bac0d2 languageName: node linkType: hard -"@js-draw/math@npm:^1.27.2": - version: 1.27.2 - resolution: "@js-draw/math@npm:1.27.2" +"@js-draw/math@npm:^1.29.2": + version: 1.29.2 + resolution: "@js-draw/math@npm:1.29.2" dependencies: bezier-js: 6.1.3 - checksum: 021dce0af104890312cf4eeb8a645d89bb2eaf0d3cdc181cdfcb6bb7b90deeeae484f5bec06bc96ac1ebc4f83918eff9a63239d8165a493b3794fd36e92bd330 + checksum: e8c1fa984a06d3f80351363c10c63d3f648df0de14a9a37f92cd4c1670dbecc1840cf9c837fdd7d436deb13648132288ef2bd8926d389100e0dc82ad2ba448cf languageName: node linkType: hard @@ -31118,13 +31118,13 @@ __metadata: languageName: node linkType: hard -"js-draw@npm:1.27.2": - version: 1.27.2 - resolution: "js-draw@npm:1.27.2" +"js-draw@npm:1.29.2": + version: 1.29.2 + resolution: "js-draw@npm:1.29.2" dependencies: - "@js-draw/math": ^1.27.2 + "@js-draw/math": ^1.29.2 "@melloware/coloris": 0.22.0 - checksum: 0dc5c1531ca7bd86dfe50817d00209d19836357fcdd58657cb83faa27a81d7f00327adcc5c668db17e026d7cec01c470a0da49d0163c2f83901bbcd3969adc74 + checksum: 29937a44c048c3927f4851b8bac66ce71316ce36b2de2ab6bfa2d1a9c1f634f51a10126e3491a7de5559fc5af442822a6a66ebd892ac8d793923a9f9f958c8c9 languageName: node linkType: hard From 3d15e6476229bb3c684c5426e32e3ecd90daa625 Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Sun, 13 Apr 2025 11:28:56 -0700 Subject: [PATCH 156/158] Desktop: Fix returning form data from plugin dialogs (#12092) --- .../integration-tests/pluginApi.spec.ts | 21 ++++++++ .../resources/test-plugins/dialogs.js | 51 +++++++++++++++++++ .../services/plugins/UserWebviewDialog.tsx | 4 +- .../services/plugins/hooks/useFormData.ts | 4 +- 4 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 packages/app-desktop/integration-tests/resources/test-plugins/dialogs.js diff --git a/packages/app-desktop/integration-tests/pluginApi.spec.ts b/packages/app-desktop/integration-tests/pluginApi.spec.ts index 99b77b9ff7..adbaaa5027 100644 --- a/packages/app-desktop/integration-tests/pluginApi.spec.ts +++ b/packages/app-desktop/integration-tests/pluginApi.spec.ts @@ -23,6 +23,27 @@ test.describe('pluginApi', () => { await editor.expectToHaveText('PASS'); }); + test('should return form data from the dialog API', async ({ startAppWithPlugins }) => { + const { app, mainWindow } = await startAppWithPlugins(['resources/test-plugins/dialogs.js']); + const mainScreen = await new MainScreen(mainWindow).setup(); + await mainScreen.createNewNote('First note'); + + const editor = mainScreen.noteEditor; + await editor.expectToHaveText(''); + + await mainScreen.goToAnything.runCommand(app, 'showTestDialog'); + // Wait for the iframe to load + const dialogContent = mainScreen.dialog.locator('iframe').contentFrame(); + await dialogContent.locator('form').waitFor(); + + // Submitting the dialog should include form data in the output + await mainScreen.dialog.getByRole('button', { name: 'Okay' }).click(); + await editor.expectToHaveText(JSON.stringify({ + id: 'ok', + hasFormData: true, + })); + }); + test('should be possible to create multiple toasts with the same text from a plugin', async ({ startAppWithPlugins }) => { const { app, mainWindow } = await startAppWithPlugins(['resources/test-plugins/showToast.js']); const mainScreen = await new MainScreen(mainWindow).setup(); diff --git a/packages/app-desktop/integration-tests/resources/test-plugins/dialogs.js b/packages/app-desktop/integration-tests/resources/test-plugins/dialogs.js new file mode 100644 index 0000000000..a6251c7776 --- /dev/null +++ b/packages/app-desktop/integration-tests/resources/test-plugins/dialogs.js @@ -0,0 +1,51 @@ +// Allows referencing the Joplin global: +/* eslint-disable no-undef */ + +// Allows the `joplin-manifest` block comment: +/* eslint-disable multiline-comment-style */ + +/* joplin-manifest: +{ + "id": "org.joplinapp.plugins.example.dialogs", + "manifest_version": 1, + "app_min_version": "3.1", + "name": "JS Bundle test", + "description": "JS Bundle Test plugin", + "version": "1.0.0", + "author": "", + "homepage_url": "https://joplinapp.org" +} +*/ + +joplin.plugins.register({ + onStart: async function() { + const dialogs = joplin.views.dialogs; + const dialogHandle = await dialogs.create('test-dialog'); + await dialogs.setHtml( + dialogHandle, + ` +

+ +
+ `, + ); + await dialogs.setButtons(dialogHandle, [ + { + id: 'ok', + title: 'Okay', + }, + ]); + await joplin.commands.register({ + name: 'showTestDialog', + label: 'showTestDialog', + iconName: 'fas fa-drum', + execute: async () => { + const result = await joplin.views.dialogs.open(dialogHandle); + await joplin.commands.execute('editor.setText', JSON.stringify({ + id: result.id, + hasFormData: !!result.formData, + })); + }, + }); + }, +}); diff --git a/packages/app-desktop/services/plugins/UserWebviewDialog.tsx b/packages/app-desktop/services/plugins/UserWebviewDialog.tsx index 6c74eb419d..8d7b86b6db 100644 --- a/packages/app-desktop/services/plugins/UserWebviewDialog.tsx +++ b/packages/app-desktop/services/plugins/UserWebviewDialog.tsx @@ -46,9 +46,9 @@ export default function UserWebviewDialog(props: Props) { const buttons: ButtonSpec[] = (props.buttons ? props.buttons : defaultButtons()).map((b: ButtonSpec) => { return { ...b, - onClick: () => { + onClick: async () => { const response: DialogResult = { id: b.id }; - const formData = webviewRef.current.formData(); + const formData = await webviewRef.current.formData(); if (formData && Object.keys(formData).length) response.formData = formData; viewController().closeWithResponse(response); }, diff --git a/packages/app-desktop/services/plugins/hooks/useFormData.ts b/packages/app-desktop/services/plugins/hooks/useFormData.ts index 39e2d45388..337495b5a7 100644 --- a/packages/app-desktop/services/plugins/hooks/useFormData.ts +++ b/packages/app-desktop/services/plugins/hooks/useFormData.ts @@ -17,7 +17,7 @@ const useFormData = (viewRef: RefObject, postMessage: PostMes const listeners = [...formDataListenersRef.current]; formDataListenersRef.current = []; for (const listener of listeners) { - listener(event.data.formData); + listener(formData); } } }); @@ -26,7 +26,7 @@ const useFormData = (viewRef: RefObject, postMessage: PostMes return { getFormData: () => { return new Promise(resolve => { - postMessage('getFormData', null); + postMessage('serializeForms', null); formDataListenersRef.current.push((data) => { resolve(data); }); From 5389e590571ad4e72f7f80b2a492a87fd532f0aa Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Sun, 13 Apr 2025 11:29:18 -0700 Subject: [PATCH 157/158] Desktop,Mobile: Markdown Editor: Fix numbered sublist renumbering (#12091) --- .../utils/renumberSelectedLists.test.ts | 88 +++++++++++++++++++ .../markdown/utils/renumberSelectedLists.ts | 21 +++-- 2 files changed, 100 insertions(+), 9 deletions(-) diff --git a/packages/editor/CodeMirror/markdown/utils/renumberSelectedLists.test.ts b/packages/editor/CodeMirror/markdown/utils/renumberSelectedLists.test.ts index 17d777a0bb..ee7e9a0f0a 100644 --- a/packages/editor/CodeMirror/markdown/utils/renumberSelectedLists.test.ts +++ b/packages/editor/CodeMirror/markdown/utils/renumberSelectedLists.test.ts @@ -64,4 +64,92 @@ describe('renumberSelectedLists', () => { '# End', ].join('\n')); }); + + it.each([ + { + // Should handle the case where a single item is over-indented + before: [ + '- This', + '- is', + '\t1. a', + '\t\t2. test', + '\t3. of', + '\t4. lists', + ].join('\n'), + after: [ + '- This', + '- is', + '\t1. a', + '\t\t1. test', + '\t2. of', + '\t3. lists', + ].join('\n'), + }, + { + // Should handle the case where multiple sublists need to be renumbered + before: [ + '- This', + '- is', + '\t1. a', + '\t\t2. test', + '\t3. of', + '\t\t4. lists', + '\t\t5. lists', + '\t\t6. lists', + '\t7. lists', + '', + '', + '1. New list', + '\t3. Item', + ].join('\n'), + after: [ + '- This', + '- is', + '\t1. a', + '\t\t1. test', + '\t2. of', + '\t\t1. lists', + '\t\t2. lists', + '\t\t3. lists', + '\t3. lists', + '', + '', + '1. New list', + '\t1. Item', + ].join('\n'), + }, + { + before: [ + '2. This', + '\t1. is', + '\t2. a', + '\t\t3. test', + '\t4. test', + '\t5. test', + '\t6. test', + ].join('\n'), + after: [ + '2. This', + '\t1. is', + '\t2. a', + '\t\t1. test', + '\t3. test', + '\t4. test', + '\t5. test', + ].join('\n'), + }, + ])('should handle nested lists (case %#)', async ({ before, after }) => { + const suffix = '\n\n# End'; + before += suffix; + after += suffix; + const editor = await createTestEditor( + before, + EditorSelection.range(0, before.length - suffix.length), + ['OrderedList', 'ATXHeading1'], + ); + + editor.dispatch(renumberSelectedLists(editor.state)); + + expect(editor.state.doc.toString()).toBe(after); + }); }); diff --git a/packages/editor/CodeMirror/markdown/utils/renumberSelectedLists.ts b/packages/editor/CodeMirror/markdown/utils/renumberSelectedLists.ts index e67db80b3e..3ec3ca6260 100644 --- a/packages/editor/CodeMirror/markdown/utils/renumberSelectedLists.ts +++ b/packages/editor/CodeMirror/markdown/utils/renumberSelectedLists.ts @@ -49,11 +49,16 @@ const renumberSelectedLists = (state: EditorState): TransactionSpec => { const indentation = match[1]; const indentationLen = tabsToSpaces(state, indentation).length; - let targetIndentLen = tabsToSpaces(state, currentGroupIndentation).length; - if (targetIndentLen < indentationLen) { - listNumberStack.push({ nextListNumber, indentationLength: indentationLen }); + let currentGroupIndentLength = tabsToSpaces(state, currentGroupIndentation).length; + const indentIncreased = indentationLen > currentGroupIndentLength; + const indentDecreased = indentationLen < currentGroupIndentLength; + if (indentIncreased) { + // Save the state of the previous group so that it can be restored later. + listNumberStack.push({ + nextListNumber, indentationLength: currentGroupIndentLength, + }); nextListNumber = 1; - } else if (targetIndentLen > indentationLen) { + } else if (indentDecreased) { nextListNumber = parseInt(match[2], 10); // Handle the case where we deindent multiple times. For example, @@ -61,22 +66,20 @@ const renumberSelectedLists = (state: EditorState): TransactionSpec => { // 1. test // 1. test // 2. test - while (targetIndentLen > indentationLen) { + while (indentationLen < currentGroupIndentLength) { const listNumberRecord = listNumberStack.pop(); if (!listNumberRecord) { break; } else { - targetIndentLen = listNumberRecord.indentationLength; + currentGroupIndentLength = listNumberRecord.indentationLength; nextListNumber = listNumberRecord.nextListNumber; } } } - if (targetIndentLen !== indentationLen) { - currentGroupIndentation = indentation; - } + currentGroupIndentation = indentation; const from = line.to - filteredText.length; const to = from + match[0].length; From cb3c9b46076cf63867f50476dd666c416c7381d7 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Mon, 14 Apr 2025 09:20:51 +0100 Subject: [PATCH 158/158] Desktop: Resolves #12095: By default keep 7 days of backup --- .../services/plugins/defaultPlugins/desktopDefaultPluginsInfo.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/lib/services/plugins/defaultPlugins/desktopDefaultPluginsInfo.ts b/packages/lib/services/plugins/defaultPlugins/desktopDefaultPluginsInfo.ts index 0f79c79c8b..ccb1f494c8 100644 --- a/packages/lib/services/plugins/defaultPlugins/desktopDefaultPluginsInfo.ts +++ b/packages/lib/services/plugins/defaultPlugins/desktopDefaultPluginsInfo.ts @@ -8,6 +8,7 @@ const getDefaultPluginsInfo = (): DefaultPluginsInfo => { settings: { 'path': `${Setting.value('homeDir')}`, 'createSubfolderPerProfile': true, + 'backupRetention': 7, }, // Joplin Portable is more likely to run on a device with low write speeds